stm32f1_hal/common/dma/
circular_buffer_rx.rs

1use super::*;
2use crate::common::os::*;
3
4/// A buffer used for DMA cyclic data reception, continuously read by the user.
5pub struct DmaCircularBufferRx<T: Sized, CH> {
6    ch: CH,
7    buf: CircularBuffer<T>,
8}
9
10impl<T, CH> DmaCircularBufferRx<T, CH>
11where
12    T: Sized + Copy,
13    CH: DmaChannel,
14{
15    pub fn new(mut ch: CH, peripheral_addr: usize, buf_size: usize) -> Self {
16        let buf = CircularBuffer::<T>::new(buf_size);
17        ch.stop();
18        ch.set_memory_buf_for_peripheral(buf.as_slice());
19        ch.set_peripheral_address::<T>(peripheral_addr, false, false, true);
20        ch.start();
21        Self { ch, buf }
22    }
23
24    pub fn read(&mut self, max: usize) -> Option<&[T]> {
25        self.buf.read(self.ch.get_left_len(), max)
26    }
27}
28
29pub struct CircularBuffer<T> {
30    recv_buf: Vec<T>,
31    read_idx: usize,
32}
33
34impl<T: Sized + Copy> CircularBuffer<T> {
35    fn new(buf_size: usize) -> Self {
36        let mut recv_buf = Vec::<T>::with_capacity(buf_size);
37        #[allow(clippy::uninit_vec)]
38        unsafe {
39            recv_buf.set_len(buf_size)
40        }
41
42        Self {
43            recv_buf,
44            read_idx: 0,
45        }
46    }
47
48    fn read(&mut self, left_len: usize, max: usize) -> Option<&[T]> {
49        let dma_recv_idx = if left_len == 0 {
50            0
51        } else {
52            self.recv_buf.len() - left_len
53        };
54
55        if self.read_idx == dma_recv_idx {
56            return None;
57        }
58
59        let ret;
60        if dma_recv_idx < self.read_idx {
61            if max > self.recv_buf.len() - self.read_idx {
62                ret = Some(&self.recv_buf[self.read_idx..]);
63                self.read_idx = 0;
64            } else {
65                let end = self.read_idx + max;
66                ret = Some(&self.recv_buf[self.read_idx..end]);
67                self.read_idx = end;
68            }
69        } else if max > dma_recv_idx - self.read_idx {
70            ret = Some(&self.recv_buf[self.read_idx..dma_recv_idx]);
71            self.read_idx = dma_recv_idx;
72        } else {
73            let end = self.read_idx + max;
74            ret = Some(&self.recv_buf[self.read_idx..end]);
75            self.read_idx = end;
76        }
77        ret
78    }
79
80    fn as_slice(&self) -> &[T] {
81        self.recv_buf.as_slice()
82    }
83}
84
85#[cfg(test)]
86mod tests {
87    use super::*;
88
89    #[test]
90    fn circular_buffer() {
91        let buf_size = 13;
92        let mut buf = CircularBuffer::new(buf_size);
93        assert_eq!(buf.recv_buf.len(), buf_size);
94
95        for i in 0..buf_size {
96            buf.recv_buf[i] = i as u8;
97        }
98
99        assert_eq!(
100            buf.read(5, usize::MAX),
101            Some([0u8, 1, 2, 3, 4, 5, 6, 7].as_slice())
102        );
103        assert_eq!(buf.read(5, usize::MAX), None);
104        // Single wraparound
105        assert_eq!(
106            buf.read(0, usize::MAX),
107            Some([8u8, 9, 10, 11, 12].as_slice())
108        );
109        assert_eq!(buf.read(0, usize::MAX), None);
110        assert_eq!(buf.read(buf_size, usize::MAX), None);
111        // small max
112        assert_eq!(buf.read(5, 5), Some([0u8, 1, 2, 3, 4].as_slice()));
113        assert_eq!(buf.read(5, 5), Some([5u8, 6, 7].as_slice()));
114        assert_eq!(buf.read(5, 5), None);
115        assert_eq!(
116            buf.read(0, usize::MAX),
117            Some([8u8, 9, 10, 11, 12].as_slice())
118        );
119        // Multiple wraparounds
120        assert_eq!(
121            buf.read(5, usize::MAX),
122            Some([0u8, 1, 2, 3, 4, 5, 6, 7].as_slice())
123        );
124        assert_eq!(
125            buf.read(10, usize::MAX),
126            Some([8u8, 9, 10, 11, 12].as_slice())
127        );
128        assert_eq!(buf.read(10, usize::MAX), Some([0u8, 1, 2].as_slice()));
129        assert_eq!(buf.read(10, usize::MAX), None);
130    }
131}