1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
#![no_std]
#![warn(missing_docs)]

//! This crate allows you to wrap a Qei counter in a larger type. This is usefull when your Timer
//! counter is on 16 bit and spend a lot of time overflowing/underflowing.
//! To use this wrapper you have to take samples regularly, but be carefull because the counter
//! **should not** change for more than (2^16 - 1)/2 between two samples otherwise we can not
//! detect overflows/underflows.
//! 
//! The internal counter is an i64 which should be enough for most use cases.
//! 
//! An example is provided for the stm32f103 µcontroller in this repository.


extern crate embedded_hal;

use embedded_hal::Qei;

const THRESHOLD: u16 = 32768;

/// The error returned when we update the internal counter
// TODO : Implement all error traits
#[derive(Debug)]
pub enum SamplingError {
    /// The sample were taken too far apart : you have to make sure that the samples were at a
    /// distance of (2^16-1)/2 maximum.
    SampleTooFar,
}

/// Extend a Qei peripherals by tracking overflows and underflows.
#[derive(Debug)]
pub struct QeiManager<T> {
    counter: i64,
    previous_count: u16,
    qei: T,
}

impl<T, K> QeiManager<T>
where
    T: Qei<Count = K>,
    K: Into<u16>,
{
    /// Create a new Qei from an existing one.
    /// The implemntation assume that the counter can't change for more than (2^16-1)/2, because
    /// otherwise we can't detect overflows/underflows
    pub fn new(qei: T) -> QeiManager<T> {
        QeiManager {
            counter: 0,
            previous_count: 0,
            qei,
        }
    }

    /// Take a new sample from the Qei and update the internal counter.
    pub fn sample(&mut self) -> Result<(), SamplingError> {
        let count = self.qei.count().into();
        self.update(count)
    }

    /// Take a new sample from the Qei and update the internal counter, unwrapping all errors.
    pub fn sample_unwrap(&mut self) {
        let count = self.qei.count().into();
        self.update(count).unwrap();
    }

    #[allow(dead_code)]
    pub(crate) fn update_unwrap(&mut self, current_count: u16) {
        self.update(current_count).unwrap();
    }

    pub(crate) fn update(&mut self, current_count: u16) -> Result<(), SamplingError> {
        if current_count == self.previous_count {
            return Ok(());
        } else if self.previous_count < current_count {
            if current_count - self.previous_count < THRESHOLD {
                // Counterclockwise rotation no overflow
                self.counter += (current_count - self.previous_count) as i64;
            } else if current_count - self.previous_count > THRESHOLD {
                // Clockwise rotation underflow
                self.counter -= (u16::max_value() - current_count + self.previous_count + 1) as i64;
            } else {
                // The constraint was not resepected
                return Err(SamplingError::SampleTooFar);
            }
        } else {
            if self.previous_count - current_count < THRESHOLD {
                // Clockwise rotation, no overflow
                self.counter -= (self.previous_count - current_count) as i64;
            } else if self.previous_count - current_count > THRESHOLD {
                // Counterclockwise rotation with overflow
                self.counter += (u16::max_value() - self.previous_count + current_count + 1) as i64;
            } else {
                // The constraint was not respeccted
                return Err(SamplingError::SampleTooFar);
            }
        }
        self.previous_count = current_count;
        Ok(())
    }

    /// Returns the internal counter value
    pub fn count(&self) -> i64 {
        self.counter
    }
    
    /// Resets the internal counter
    pub fn reset(&mut self) {
        self.counter = 0;
    }
}

#[cfg(test)]
mod test {
    use embedded_hal::{Direction, Qei};
    use QeiManager;

    struct DummyQei {}

    impl Qei for DummyQei {
        type Count = u16;
        fn count(&self) -> u16 {
            0
        }
        fn direction(&self) -> Direction {
            Direction::Downcounting
        }
    }

    #[test]
    fn no_trap() {
        let mut qei = QeiManager::new(DummyQei {});
        qei.update_unwrap(55);
        assert_eq!(qei.count(), 55)
    }

    #[test]
    fn underflow() {
        let mut qei = QeiManager::new(DummyQei {});
        qei.update_unwrap(5);
        qei.update_unwrap(65532);
        assert_eq!(qei.count(), -4); // -4 et pas -3
        let mut qei = QeiManager::new(DummyQei {});
        qei.update_unwrap(5);
        qei.update_unwrap(65535);
        assert_eq!(qei.count(), -1);
    }

    #[test]
    fn overflow() {
        let mut qei = QeiManager::new(DummyQei {});
        qei.update_unwrap(65522);
        qei.update_unwrap(55);
        assert_eq!(qei.count(), 55_i64);
        let mut qei = QeiManager::new(DummyQei {});
        qei.update_unwrap(65535);
        qei.update_unwrap(0);
        assert_eq!(qei.count(), 0);
        qei.update_unwrap(65535);
        qei.update_unwrap(1);
        assert_eq!(qei.count(), 1);
    }

    #[test]
    fn middle_values() {
        let mut qei = QeiManager::new(DummyQei {});
        qei.update_unwrap(13546);
        qei.update_unwrap(13500);
        qei.update_unwrap(15678);
        assert_eq!(qei.count(), 15678);
        let mut qei = QeiManager::new(DummyQei {});
        qei.update_unwrap(16000);
        qei.update_unwrap(15000);
        assert_eq!(qei.count(), 15000);
    }

    #[test]
    fn going_back() {
        let mut qei = QeiManager::new(DummyQei {});
        qei.update_unwrap(65489);
        qei.update_unwrap(65000);
        assert_eq!(qei.count(), -536); // -536 et pas 535 : 65000 - (-536) doit faire 0
        qei.update_unwrap(63000);
        assert_eq!(qei.count(), -2536); // idem
        qei.update_unwrap(62999);
        assert_eq!(qei.count(), -2537); // idem
    }

    #[test]
    fn no_changes() {
        let mut qei = QeiManager::new(DummyQei {});
        qei.update_unwrap(0);
        qei.update_unwrap(0);
        assert_eq!(qei.count(), 0);
    }

    #[test]
    fn small_changes() {
        let mut qei = QeiManager::new(DummyQei {});
        qei.update_unwrap(0);
        qei.update_unwrap(u16::max_value());
        assert_eq!(qei.count(), -1);
        let mut qei = QeiManager::new(DummyQei {});
        qei.update_unwrap(u16::max_value());
        qei.update_unwrap(0);
        assert_eq!(qei.count(), 0);
        qei.update_unwrap(1);
        assert_eq!(qei.count(), 1);
        qei.update_unwrap(65535);
        assert_eq!(qei.count(), -1);
        qei.update_unwrap(65534);
        assert_eq!(qei.count(), -2);
    }
}