quadrature_decoder/decoder/incremental.rs
1//! Quadrature-based decoder.
2
3use core::marker::PhantomData;
4
5use num_traits::{One, SaturatingAdd, Zero};
6
7use crate::{
8 state_transducer::{Input, Output},
9 validator::InputValidator,
10 Change, Error, FullStep, HalfStep, QuadStep, StateTransducer, StepMode,
11};
12
13/// A robust quadrature decoder with support for multiple step-modes,
14/// based on which channel (A vs. B) is leading the other.
15///
16/// ```plain
17/// ┌ ─ ┐ ┌───┐ ┌───┐ ┌───┐ ┌ ─ ─ high
18/// A │ │ │ │ │
19/// ─ ┘ └───┘ └───┘ └───┘ └ ─ ┘ low
20/// AB:
21/// ┌ ─ ┐ ┌───┐ ┌───┐ ┌───┐ ┌ ─ high
22/// B │ │ │ │ │
23/// ─ ─ ┘ └───┘ └───┘ └───┘ └ ─ ┘ low
24/// Time: ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─▶
25/// ┌ ─ ┐ ┌───┐ ┌───┐ ┌───┐ ┌ ─ high
26/// A │ │ │ │ │
27/// ─ ─ ┘ └───┘ └───┘ └───┘ └ ─ ┘ low
28/// BA:
29/// ┌ ─ ┐ ┌───┐ ┌───┐ ┌───┐ ┌ ─ ─ high
30/// B │ │ │ │ │
31/// ─ ┘ └───┘ └───┘ └───┘ └ ─ ┘ low
32/// ```
33#[derive(Debug)]
34pub struct IncrementalDecoder<Mode, T = i32> {
35 transducer: StateTransducer<'static, 8, 4>,
36 validator: InputValidator,
37 counter: T,
38 _phantom: PhantomData<Mode>,
39}
40
41impl<T> Default for IncrementalDecoder<FullStep, T>
42where
43 T: Zero,
44{
45 fn default() -> Self {
46 Self::new(StateTransducer::new(
47 &crate::state_transducer::full_step::TRANSITIONS,
48 ))
49 }
50}
51
52impl<T> Default for IncrementalDecoder<HalfStep, T>
53where
54 T: Zero,
55{
56 fn default() -> Self {
57 Self::new(StateTransducer::new(
58 &crate::state_transducer::half_step::TRANSITIONS,
59 ))
60 }
61}
62
63impl<T> Default for IncrementalDecoder<QuadStep, T>
64where
65 T: Zero,
66{
67 fn default() -> Self {
68 Self::new(StateTransducer::new(
69 &crate::state_transducer::quad_step::TRANSITIONS,
70 ))
71 }
72}
73
74impl<Mode, T> IncrementalDecoder<Mode, T>
75where
76 Mode: StepMode,
77 T: Zero,
78{
79 pub(crate) fn new(transducer: StateTransducer<'static, 8, 4>) -> Self {
80 Self {
81 transducer,
82 validator: Default::default(),
83 counter: Zero::zero(),
84 _phantom: PhantomData,
85 }
86 }
87}
88
89impl<Mode, T> IncrementalDecoder<Mode, T>
90where
91 Mode: StepMode,
92 T: Copy + Zero + One + SaturatingAdd + From<i8>,
93{
94 /// Updates the decoder's state based on the given `a` and `b` pulse train (aka channel) readings,
95 /// returning the direction if a change was detected, `None` if no change was detected,
96 /// or `Err(_)` if an invalid input (i.e. a counteral "jump") was detected.
97 ///
98 /// Depending on whether it matters why the decoder did not detect a change
99 /// (e.g. due to actual lack of change or an erroneous read)
100 /// you would either call `decoder.update(a, b)` directly, or via `decoder.update(a, b).unwrap_or_default()`
101 /// to fall back to `None` in case of `Err(_)`.
102 pub fn update(&mut self, a: bool, b: bool) -> Result<Option<Change>, Error> {
103 let input = Input::new(a, b);
104
105 let validation_result = self.validator.validate(input);
106 let transducer_output = self.transducer.step(input);
107
108 match (validation_result, transducer_output) {
109 (Err(error), output) => {
110 debug_assert_eq!(output, Output::N, "Expected `None` output from transducer.");
111 Err(error)
112 }
113 (Ok(_), Output::N) => Ok(None),
114 (Ok(_), Output::AB) => {
115 let change = Change::Positive;
116 let delta: T = (change as i8).into();
117 self.counter = self.counter.saturating_add(&delta);
118 Ok(Some(change))
119 }
120 (Ok(_), Output::BA) => {
121 let change = Change::Negative;
122 let delta: T = (change as i8).into();
123 self.counter = self.counter.saturating_add(&delta);
124 Ok(Some(change))
125 }
126 (_, Output::E) => {
127 // Transducers are expected to not return error outputs since their states tend to
128 // be insufficient for reliable detection without false positives/negatives.
129 panic!("Unexpected error output from transducer.")
130 }
131 }
132 }
133
134 /// Resets the decoder to its initial state and its counter counter back to `0`.
135 pub fn reset(&mut self) {
136 self.transducer.reset();
137 self.validator.reset();
138 self.counter = Zero::zero();
139 }
140
141 /// Returns the decoder's counter counter relative to its initial counter in number of cycles.
142 ///
143 /// A change of `Change::Positive` increments the counter counter,
144 /// while a change of `Change::Negative` decrements it.
145 pub fn counter(&self) -> T {
146 self.counter
147 }
148
149 /// Sets the decoder's counter.
150 pub fn set_counter(&mut self, counter: T) {
151 self.counter = counter;
152 }
153}