stm32f1_hal/common/dma/
circular_buffer_rx.rs1use super::*;
2
3pub struct DmaCircularBufferRx<T: Sized, CH> {
5 ch: CH,
6 buf: CircularBuffer<T>,
7}
8
9impl<T, CH> DmaCircularBufferRx<T, CH>
10where
11 T: Sized + Copy,
12 CH: DmaChannel,
13{
14 pub fn new(mut ch: CH, peripheral_addr: usize, buf_size: usize) -> Self {
15 let buf = CircularBuffer::<T>::new(buf_size);
16 ch.stop();
17 ch.set_memory_buf_for_peripheral(buf.as_slice());
18 ch.set_peripheral_address::<T>(peripheral_addr, false, false, true);
19 ch.start();
20 Self { ch, buf }
21 }
22
23 #[inline]
24 pub fn pop_slice(&mut self, max: usize) -> Option<&[T]> {
25 self.buf.pop_slice(self.ch.get_unprocessed_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 pop_slice(&mut self, unprocessed_len: usize, max: usize) -> Option<&[T]> {
49 let dma_recv_idx = if unprocessed_len == 0 {
50 0
51 } else {
52 self.recv_buf.len() - unprocessed_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.pop_slice(5, usize::MAX),
101 Some([0u8, 1, 2, 3, 4, 5, 6, 7].as_slice())
102 );
103 assert_eq!(buf.pop_slice(5, usize::MAX), None);
104 assert_eq!(
106 buf.pop_slice(0, usize::MAX),
107 Some([8u8, 9, 10, 11, 12].as_slice())
108 );
109 assert_eq!(buf.pop_slice(0, usize::MAX), None);
110 assert_eq!(buf.pop_slice(buf_size, usize::MAX), None);
111 assert_eq!(buf.pop_slice(5, 5), Some([0u8, 1, 2, 3, 4].as_slice()));
113 assert_eq!(buf.pop_slice(5, 5), Some([5u8, 6, 7].as_slice()));
114 assert_eq!(buf.pop_slice(5, 5), None);
115 assert_eq!(
116 buf.pop_slice(0, usize::MAX),
117 Some([8u8, 9, 10, 11, 12].as_slice())
118 );
119 assert_eq!(
121 buf.pop_slice(5, usize::MAX),
122 Some([0u8, 1, 2, 3, 4, 5, 6, 7].as_slice())
123 );
124 assert_eq!(
125 buf.pop_slice(10, usize::MAX),
126 Some([8u8, 9, 10, 11, 12].as_slice())
127 );
128 assert_eq!(buf.pop_slice(10, usize::MAX), Some([0u8, 1, 2].as_slice()));
129 assert_eq!(buf.pop_slice(10, usize::MAX), None);
130 }
131}