use crate::{Control, DebouncedInput, DebouncedInputConfig, DebouncedInputEvent};
use core::ops::AddAssign;
use num_integer::Integer;
use num_traits::{One, Signed, Zero};
use switch_hal::InputSwitch;
pub trait EncoderConfig: DebouncedInputConfig {
type Counts: AddAssign + Integer + Signed + Copy;
const COUNTS_DIV: Self::Counts;
}
pub struct Encoder<SwitchA: InputSwitch, SwitchB: InputSwitch, Config: EncoderConfig> {
debounced_input_a: DebouncedInput<SwitchA, Config>,
debounced_input_b: DebouncedInput<SwitchB, Config>,
counts: Config::Counts,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum EncoderEvent {
NoTurn,
ClockwiseTurn,
CounterClockwiseTurn,
}
impl<SwitchA: InputSwitch, SwitchB: InputSwitch, Config: EncoderConfig>
Encoder<SwitchA, SwitchB, Config>
{
pub fn new(input_switch_a: SwitchA, input_switch_b: SwitchB) -> Self {
Encoder {
debounced_input_a: DebouncedInput::new(input_switch_a),
debounced_input_b: DebouncedInput::new(input_switch_b),
counts: Zero::zero(),
}
}
pub fn release_input_switches(self) -> (SwitchA, SwitchB) {
(
self.debounced_input_a.release_input_switch(),
self.debounced_input_b.release_input_switch(),
)
}
}
impl<SwitchA: InputSwitch, SwitchB: InputSwitch, Config: EncoderConfig> Control
for Encoder<SwitchA, SwitchB, Config>
where
<DebouncedInput<SwitchA, Config> as Control>::Error:
From<<DebouncedInput<SwitchB, Config> as Control>::Error>,
{
type Event = EncoderEvent;
type Error = <DebouncedInput<SwitchA, Config> as Control>::Error;
fn update(&mut self) -> Result<Self::Event, Self::Error> {
let a_event = self.debounced_input_a.update()?;
let b_event = self.debounced_input_b.update()?;
fn check_event<Counts: Signed>(
event: DebouncedInputEvent,
antogonist_state: bool,
direct: Counts,
) -> Counts {
match event {
DebouncedInputEvent::Rise if antogonist_state => -direct,
DebouncedInputEvent::Rise => direct,
DebouncedInputEvent::Fall if antogonist_state => direct,
DebouncedInputEvent::Fall => -direct,
_ => Zero::zero(),
}
}
let direct = One::one();
self.counts += check_event(a_event, self.debounced_input_b.is_high(), direct);
self.counts += check_event(b_event, self.debounced_input_a.is_high(), -direct);
let result_event = if !self.counts.is_zero() && (self.counts % Config::COUNTS_DIV).is_zero()
{
let counts = self.counts;
self.counts = Zero::zero();
match counts.is_positive() {
true => EncoderEvent::ClockwiseTurn,
false => EncoderEvent::CounterClockwiseTurn,
}
} else {
EncoderEvent::NoTurn
};
Ok(result_event)
}
}