#![deny(missing_docs)]
#![deny(warnings)]
#![no_std]
use embedded_hal::digital::v2::InputPin;
pub type Velocity = f32;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Direction {
None,
Clockwise,
Anticlockwise,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Sensitivity {
Default = 2,
Low = 4,
}
const STATES: [i8; 16] = [0, -1, 1, 0, 1, 0, 0, -1, -1, 0, 0, 1, 0, 1, -1, 0];
#[cfg(feature = "angular-velocity")]
const DEFAULT_VELOCITY_INC_FACTOR: f32 = 0.2;
#[cfg(feature = "angular-velocity")]
const DEFAULT_VELOCITY_DEC_FACTOR: f32 = 0.01;
#[cfg(feature = "angular-velocity")]
const DEFAULT_VELOCITY_ACTION_MS: u64 = 25;
pub struct RotaryEncoder<DT, CLK> {
pin_dt: DT,
pin_clk: CLK,
pos_calc: i8,
sensitivity: Sensitivity,
transition: u8,
direction: Direction,
}
#[cfg(feature = "angular-velocity")]
pub struct RotaryEncoderWithVelocity<DT, CLK> {
inner: RotaryEncoder<DT, CLK>,
velocity: Velocity,
velocity_inc_factor: f32,
velocity_dec_factor: f32,
velocity_action_ms: u64,
previous_time: u64,
}
impl<DT, CLK> RotaryEncoder<DT, CLK>
where
DT: InputPin,
CLK: InputPin,
{
pub fn new(pin_dt: DT, pin_clk: CLK) -> Self {
RotaryEncoder {
pin_dt,
pin_clk,
pos_calc: 0,
transition: 0,
sensitivity: Sensitivity::Default,
direction: Direction::None,
}
}
pub fn set_sensitivity(&mut self, sensitivity: Sensitivity) {
self.sensitivity = sensitivity;
}
pub fn borrow_pins(&mut self) -> (&mut DT, &mut CLK) {
(&mut self.pin_dt, &mut self.pin_clk)
}
pub fn release(self) -> (DT, CLK) {
(self.pin_dt, self.pin_clk)
}
pub fn update(&mut self) {
let dt_state = self.pin_dt.is_high().unwrap_or_default() as u8;
let clk_state = self.pin_clk.is_high().unwrap_or_default() as u8;
let current = (dt_state << 1) | clk_state;
self.transition = (self.transition << 2) | current;
let index = (self.transition & 0x0F) as usize;
self.pos_calc += STATES[index];
let sensitivity = self.sensitivity as i8;
if self.pos_calc == sensitivity || self.pos_calc == -sensitivity {
self.direction = if self.pos_calc == sensitivity {
Direction::Clockwise
} else {
Direction::Anticlockwise
};
self.pos_calc = 0;
return;
}
self.direction = Direction::None;
}
pub fn direction(&self) -> Direction {
self.direction
}
}
#[cfg(feature = "angular-velocity")]
impl<DT, CLK> RotaryEncoderWithVelocity<DT, CLK>
where
DT: InputPin,
CLK: InputPin,
{
pub fn new(pin_dt: DT, pin_clk: CLK) -> Self {
RotaryEncoderWithVelocity {
inner: RotaryEncoder::new(pin_dt, pin_clk),
velocity: 0.0,
velocity_inc_factor: DEFAULT_VELOCITY_INC_FACTOR,
velocity_dec_factor: DEFAULT_VELOCITY_DEC_FACTOR,
velocity_action_ms: DEFAULT_VELOCITY_ACTION_MS,
previous_time: 0,
}
}
pub fn set_velocity_inc_factor(&mut self, inc_factor: f32) {
self.velocity_inc_factor = inc_factor;
}
pub fn set_velocity_dec_factor(&mut self, dec_factor: f32) {
self.velocity_dec_factor = dec_factor;
}
pub fn set_velocity_action_ms(&mut self, action_ms: u64) {
self.velocity_action_ms = action_ms;
}
pub fn decay_velocity(&mut self) {
self.velocity -= self.velocity_dec_factor;
if self.velocity < 0.0 {
self.velocity = 0.0;
}
}
pub fn borrow_pins(&mut self) -> (&mut DT, &mut CLK) {
self.inner.borrow_pins()
}
pub fn set_sensitivity(&mut self, sensitivity: Sensitivity) {
self.inner.sensitivity = sensitivity;
}
pub fn borrow_inner(&mut self) -> &mut RotaryEncoder<DT, CLK> {
&mut self.inner
}
pub fn release(self) -> (DT, CLK) {
self.inner.release()
}
pub fn update(&mut self, current_time: u64) {
self.inner.update();
if self.inner.direction() != Direction::None {
if current_time - self.previous_time < self.velocity_action_ms && self.velocity < 1.0 {
self.velocity += self.velocity_inc_factor;
if self.velocity > 1.0 {
self.velocity = 1.0;
}
}
return;
}
self.previous_time = current_time;
}
pub fn direction(&self) -> Direction {
self.inner.direction
}
pub fn velocity(&self) -> Velocity {
self.velocity
}
}