quadrature_decoder/decoder/
indexed.rs

1//! Quadrature-based decoder.
2
3use num_traits::{One, SaturatingAdd, Zero};
4
5use crate::{index_decoder::IndexDecoder, Change, Error, IncrementalDecoder, StepMode};
6
7/// A robust indexed quadrature decoder with support for multiple step-modes,
8/// based on which channel (A vs. B) is leading the other.
9///
10/// ```plain
11///                ┌ ─ ┐   ┌───┐   ┌───┐   ┌───┐   ┌ ─ ─ high
12///            A           │   │   │   │   │                  
13///              ─ ┘   └───┘   └───┘   └───┘   └ ─ ┘     low  
14/// AB:                                                  
15///                  ┌ ─ ┐   ┌───┐   ┌───┐   ┌───┐   ┌ ─ high
16///            B             │   │   │   │   │                
17///              ─ ─ ┘   └───┘   └───┘   └───┘   └ ─ ┘   low  
18///
19///                          ┌─┐                         high
20///            Z             │ │                              
21///              ─ ─ ─ ──────┘ └────────────────── ─ ─ ─ low  
22/// Time: ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─▶
23///                  ┌ ─ ┐   ┌───┐   ┌───┐   ┌───┐   ┌ ─ high
24///            A             │   │   │   │   │                
25///              ─ ─ ┘   └───┘   └───┘   └───┘   └ ─ ┘   low  
26/// BA:                                                  
27///                ┌ ─ ┐   ┌───┐   ┌───┐   ┌───┐   ┌ ─ ─ high
28///            B           │   │   │   │   │                  
29///              ─ ┘   └───┘   └───┘   └───┘   └ ─ ┘     low  
30///
31///                          ┌─┐                         high
32///            Z             │ │                              
33///              ─ ─ ─ ──────┘ └────────────────── ─ ─ ─ low  
34/// ```
35#[derive(Debug)]
36pub struct IndexedIncrementalDecoder<Mode, T = i32> {
37    decoder: IncrementalDecoder<Mode, T>,
38    indexer: IndexDecoder,
39}
40
41impl<Mode, T> Default for IndexedIncrementalDecoder<Mode, T>
42where
43    Mode: StepMode,
44    IncrementalDecoder<Mode, T>: Default,
45{
46    fn default() -> Self {
47        Self::new(IncrementalDecoder::default())
48    }
49}
50
51impl<Mode, T> IndexedIncrementalDecoder<Mode, T>
52where
53    Mode: StepMode,
54{
55    pub(crate) fn new(decoder: IncrementalDecoder<Mode, T>) -> Self {
56        Self {
57            decoder,
58            indexer: Default::default(),
59        }
60    }
61}
62
63impl<Mode, T> IndexedIncrementalDecoder<Mode, T>
64where
65    Mode: StepMode,
66    T: Copy + Zero + One + SaturatingAdd + From<i8>,
67{
68    /// Updates the decoder's state based on the given `a` and `b` pulse train (aka channel) readings,
69    /// returning the direction if a change was detected, `None` if no change was detected,
70    /// or `Err(_)` if an invalid input (i.e. a counteral "jump") was detected.
71    ///
72    /// Upon detection of a raising edge on the `z` pulse train the counter gets reset back to `0`.
73    ///
74    /// Depending on whether it matters why the decoder did not detect a change
75    /// (e.g. due to actual lack of change or an erroneous read)
76    /// you would either call `decoder.update(a, b)` directly, or via `decoder.update(a, b).unwrap_or_default()`
77    /// to fall back to `None` in case of `Err(_)`.
78    pub fn update(&mut self, a: bool, b: bool, z: bool) -> Result<Option<Change>, Error> {
79        let result = self.decoder.update(a, b);
80
81        if self.indexer.update(z) {
82            self.decoder.set_counter(Zero::zero());
83        }
84
85        result
86    }
87
88    /// Resets the decoder to its initial state and its counter counter back to `0`.
89    pub fn reset(&mut self) {
90        self.decoder.reset();
91        self.indexer.reset();
92    }
93
94    /// Returns the decoder's counter counter relative to its initial counter in number of cycles.
95    ///
96    /// A change of `Change::Positive` increments the counter counter,
97    /// while a change of `Change::Negative` decrements it.
98    pub fn counter(&self) -> T {
99        self.decoder.counter()
100    }
101
102    /// Sets the decoder's counter.
103    pub fn set_counter(&mut self, counter: T) {
104        self.decoder.set_counter(counter);
105    }
106}
107
108#[cfg(test)]
109mod tests {
110    use crate::HalfStep;
111
112    use super::*;
113
114    #[test]
115    fn index() {
116        let a: Vec<bool> = vec![false, false, true, true, false, false, true, true];
117        let b: Vec<bool> = vec![true, false, false, true, true, false, false, true];
118        let z: Vec<bool> = vec![false, false, false, false, true, false, false, false];
119
120        let pulse_trains = a.into_iter().zip(b).zip(z);
121
122        let changes: Vec<Option<Change>> = vec![
123            None,
124            Some(Change::Positive),
125            None,
126            Some(Change::Positive),
127            None,
128            Some(Change::Positive),
129            None,
130            Some(Change::Positive),
131        ];
132        let counters: Vec<i32> = vec![0, 1, 1, 2, 0, 1, 1, 2];
133
134        let expected = changes.into_iter().zip(counters);
135
136        let mut decoder: IndexedIncrementalDecoder<HalfStep> = Default::default();
137
138        for (input, expected) in pulse_trains.zip(expected) {
139            let ((a, b), z) = input;
140            let (expected_change, expected_counter) = expected;
141
142            let change = decoder.update(a, b, z).unwrap();
143
144            assert_eq!(change, expected_change);
145            assert_eq!(decoder.counter(), expected_counter);
146        }
147    }
148}