use embedded_hal::digital::InputPin;
use crate::Direction;
use crate::RotaryEncoder;
const DEFAULT_VELOCITY_INC_FACTOR: f32 = 0.2;
const DEFAULT_VELOCITY_DEC_FACTOR: f32 = 0.01;
const DEFAULT_VELOCITY_ACTION_MS: u64 = 25;
pub type Velocity = f32;
const PIN_MASK: u8 = 0x03;
const PIN_EDGE: u8 = 0x02;
pub struct AngularVelocityMode {
pin_state: [u8; 2],
velocity: Velocity,
velocity_inc_factor: f32,
velocity_dec_factor: f32,
velocity_action_ms: u64,
previous_time_millis: u64,
}
impl<DT, CLK> RotaryEncoder<AngularVelocityMode, DT, CLK>
where
DT: InputPin,
CLK: InputPin,
{
pub fn set_velocity_inc_factor(&mut self, inc_factor: f32) {
self.mode.velocity_inc_factor = inc_factor;
}
pub fn set_velocity_dec_factor(&mut self, dec_factor: f32) {
self.mode.velocity_dec_factor = dec_factor;
}
pub fn set_velocity_action_ms(&mut self, action_ms: u64) {
self.mode.velocity_action_ms = action_ms;
}
pub fn decay_velocity(&mut self) {
self.mode.velocity -= self.mode.velocity_dec_factor;
if self.mode.velocity < 0.0 {
self.mode.velocity = 0.0;
}
}
pub fn update(&mut self, current_time_millis: u64) -> Direction {
self.mode.update(
self.pin_dt.is_high().unwrap_or_default(),
self.pin_clk.is_high().unwrap_or_default(),
current_time_millis,
)
}
pub fn velocity(&self) -> Velocity {
self.mode.velocity
}
}
impl AngularVelocityMode {
pub fn new() -> Self {
Self {
pin_state: [0xFF, 2],
velocity: 0.0,
previous_time_millis: 0,
velocity_action_ms: DEFAULT_VELOCITY_ACTION_MS,
velocity_dec_factor: DEFAULT_VELOCITY_DEC_FACTOR,
velocity_inc_factor: DEFAULT_VELOCITY_INC_FACTOR,
}
}
pub fn update(
&mut self,
dt_state: bool,
clk_state: bool,
current_time_millis: u64,
) -> Direction {
self.pin_state[0] = (self.pin_state[0] << 1) | dt_state as u8;
self.pin_state[1] = (self.pin_state[1] << 1) | clk_state as u8;
let a = self.pin_state[0] & PIN_MASK;
let b = self.pin_state[1] & PIN_MASK;
let mut dir: Direction = Direction::None;
if a == PIN_EDGE && b == 0x00 {
dir = Direction::Anticlockwise;
} else if b == PIN_EDGE && a == 0x00 {
dir = Direction::Clockwise;
}
if dir != Direction::None {
if current_time_millis - self.previous_time_millis < self.velocity_action_ms
&& self.velocity < 1.0
{
self.velocity += self.velocity_inc_factor;
if self.velocity > 1.0 {
self.velocity = 1.0;
}
}
} else {
self.previous_time_millis = current_time_millis;
}
dir
}
}
impl Default for AngularVelocityMode {
fn default() -> Self {
Self::new()
}
}
impl<DT, CLK, MODE> RotaryEncoder<MODE, DT, CLK>
where
DT: InputPin,
CLK: InputPin,
{
pub fn into_angular_velocity_mode(self) -> RotaryEncoder<AngularVelocityMode, DT, CLK> {
RotaryEncoder {
pin_dt: self.pin_dt,
pin_clk: self.pin_clk,
mode: AngularVelocityMode::new(),
}
}
}