Skip to main content

esp_emac/dma/
ring.rs

1// SPDX-License-Identifier: GPL-2.0-or-later OR Apache-2.0
2// Copyright (c) Viacheslav Bocharov <v@baodeep.com> and JetHome (r)
3
4//! Generic circular ring buffer for DMA descriptors.
5//!
6//! The ring wraps a fixed-size array of descriptors and maintains a
7//! current-index that advances with wraparound. This is the core
8//! data structure used by the DMA engine to walk TX and RX rings.
9
10/// Circular descriptor ring with wraparound index.
11pub struct DescriptorRing<D, const N: usize> {
12    /// Array of descriptors.
13    descriptors: [D; N],
14    /// Current processing index.
15    current: usize,
16}
17
18impl<D, const N: usize> DescriptorRing<D, N> {
19    /// Create a new descriptor ring from an existing array.
20    #[must_use]
21    pub const fn new(descriptors: [D; N]) -> Self {
22        Self {
23            descriptors,
24            current: 0,
25        }
26    }
27
28    /// Number of descriptors in the ring.
29    #[inline(always)]
30    #[must_use]
31    pub const fn len(&self) -> usize {
32        N
33    }
34
35    /// Check if the ring is empty (always false for non-zero `N`).
36    #[inline(always)]
37    #[must_use]
38    pub const fn is_empty(&self) -> bool {
39        N == 0
40    }
41
42    /// Current index.
43    #[inline(always)]
44    #[must_use]
45    pub const fn current_index(&self) -> usize {
46        self.current
47    }
48
49    /// Advance the current index by one, wrapping around.
50    #[inline(always)]
51    pub fn advance(&mut self) {
52        self.current = (self.current + 1) % N;
53    }
54
55    /// Advance the current index by `count`, wrapping around.
56    #[inline(always)]
57    pub fn advance_by(&mut self, count: usize) {
58        self.current = (self.current + count) % N;
59    }
60
61    /// Reset the current index to 0.
62    #[inline(always)]
63    pub fn reset(&mut self) {
64        self.current = 0;
65    }
66
67    /// Reference to the current descriptor.
68    #[inline(always)]
69    pub fn current(&self) -> &D {
70        &self.descriptors[self.current]
71    }
72
73    /// Mutable reference to the current descriptor.
74    #[inline(always)]
75    pub fn current_mut(&mut self) -> &mut D {
76        &mut self.descriptors[self.current]
77    }
78
79    /// Reference to the descriptor at `index` (wraps around).
80    #[inline(always)]
81    pub fn get(&self, index: usize) -> &D {
82        &self.descriptors[index % N]
83    }
84
85    /// Mutable reference to the descriptor at `index` (wraps around).
86    #[inline(always)]
87    pub fn get_mut(&mut self, index: usize) -> &mut D {
88        &mut self.descriptors[index % N]
89    }
90
91    /// Pointer to the first descriptor (for programming DMA base-address registers).
92    #[inline(always)]
93    pub fn base_addr(&self) -> *const D {
94        self.descriptors.as_ptr()
95    }
96
97    /// Iterate over all descriptors.
98    pub fn iter(&self) -> impl Iterator<Item = &D> {
99        self.descriptors.iter()
100    }
101
102    /// Iterate mutably over all descriptors.
103    pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut D> {
104        self.descriptors.iter_mut()
105    }
106}
107
108// =============================================================================
109// Tests
110// =============================================================================
111
112#[cfg(test)]
113mod tests {
114    use super::*;
115
116    #[test]
117    fn ring_len() {
118        let ring = DescriptorRing::new([0u32; 8]);
119        assert_eq!(ring.len(), 8);
120        assert!(!ring.is_empty());
121    }
122
123    #[test]
124    fn ring_advance_wraps() {
125        let mut ring = DescriptorRing::new([0u32; 4]);
126        assert_eq!(ring.current_index(), 0);
127        ring.advance();
128        assert_eq!(ring.current_index(), 1);
129        ring.advance();
130        assert_eq!(ring.current_index(), 2);
131        ring.advance();
132        assert_eq!(ring.current_index(), 3);
133        ring.advance();
134        assert_eq!(ring.current_index(), 0); // wrapped
135    }
136
137    #[test]
138    fn ring_current_changes_after_advance() {
139        let mut ring = DescriptorRing::new([10u32, 20, 30]);
140        assert_eq!(*ring.current(), 10);
141        ring.advance();
142        assert_eq!(*ring.current(), 20);
143        ring.advance();
144        assert_eq!(*ring.current(), 30);
145    }
146
147    #[test]
148    fn ring_reset() {
149        let mut ring = DescriptorRing::new([0u32; 4]);
150        ring.advance();
151        ring.advance();
152        assert_eq!(ring.current_index(), 2);
153        ring.reset();
154        assert_eq!(ring.current_index(), 0);
155    }
156
157    #[test]
158    fn ring_base_addr() {
159        let ring = DescriptorRing::new([10u32, 20, 30]);
160        let ptr = ring.base_addr();
161        assert!(!ptr.is_null());
162        // SAFETY: `base_addr` points to the first element of a valid array.
163        unsafe {
164            assert_eq!(*ptr, 10);
165        }
166    }
167
168    #[test]
169    fn ring_get_by_index() {
170        let ring = DescriptorRing::new([10u32, 20, 30, 40]);
171        assert_eq!(*ring.get(0), 10);
172        assert_eq!(*ring.get(1), 20);
173        assert_eq!(*ring.get(3), 40);
174    }
175
176    #[test]
177    fn ring_get_wraps() {
178        let ring = DescriptorRing::new([10u32, 20, 30, 40]);
179        assert_eq!(*ring.get(4), 10); // wraps
180        assert_eq!(*ring.get(5), 20);
181    }
182
183    #[test]
184    fn ring_get_mut_modifies() {
185        let mut ring = DescriptorRing::new([10u32, 20, 30]);
186        *ring.get_mut(1) = 999;
187        assert_eq!(*ring.get(1), 999);
188    }
189
190    #[test]
191    fn ring_current_mut_modifies() {
192        let mut ring = DescriptorRing::new([10u32, 20, 30]);
193        *ring.current_mut() = 42;
194        assert_eq!(*ring.current(), 42);
195    }
196
197    #[test]
198    fn ring_iter() {
199        let ring = DescriptorRing::new([1u32, 2, 3, 4]);
200        let mut iter = ring.iter();
201        assert_eq!(iter.next(), Some(&1));
202        assert_eq!(iter.next(), Some(&2));
203        assert_eq!(iter.next(), Some(&3));
204        assert_eq!(iter.next(), Some(&4));
205        assert_eq!(iter.next(), None);
206    }
207
208    #[test]
209    fn ring_iter_mut() {
210        let mut ring = DescriptorRing::new([1u32, 2, 3, 4]);
211        for val in ring.iter_mut() {
212            *val *= 10;
213        }
214        assert_eq!(*ring.get(0), 10);
215        assert_eq!(*ring.get(1), 20);
216        assert_eq!(*ring.get(2), 30);
217        assert_eq!(*ring.get(3), 40);
218    }
219
220    #[test]
221    fn ring_single_element() {
222        let mut ring = DescriptorRing::new([42u32]);
223        assert_eq!(ring.len(), 1);
224        assert_eq!(*ring.current(), 42);
225        ring.advance();
226        assert_eq!(ring.current_index(), 0); // wraps immediately
227    }
228
229    #[test]
230    fn ring_wraparound_stress() {
231        let mut ring = DescriptorRing::new([0u32; 7]);
232        for i in 0..100 {
233            assert_eq!(ring.current_index(), i % 7);
234            ring.advance();
235        }
236    }
237}