diff options
| author | Alexandros Liarokapis <[email protected]> | 2024-09-23 02:49:05 +0300 |
|---|---|---|
| committer | Alexandros Liarokapis <[email protected]> | 2024-10-15 12:29:12 +0300 |
| commit | 85fb890b0025db386459f8b6a573c29f00bf3ed1 (patch) | |
| tree | 94ec57caad2ab1fb5d73c7bdd6a4bdf98c081b9a | |
| parent | f4ec0cb4d4d16bd4e1c242864c5ca828745704c0 (diff) | |
add auto-clear functionality to ringbuffer
| -rw-r--r-- | embassy-stm32/src/dma/ringbuffer/mod.rs | 56 | ||||
| -rw-r--r-- | embassy-stm32/src/dma/ringbuffer/tests/prop_test/reader.rs | 3 | ||||
| -rw-r--r-- | embassy-stm32/src/dma/ringbuffer/tests/prop_test/writer.rs | 3 |
3 files changed, 40 insertions, 22 deletions
diff --git a/embassy-stm32/src/dma/ringbuffer/mod.rs b/embassy-stm32/src/dma/ringbuffer/mod.rs index d4d119a69..abc01e3cc 100644 --- a/embassy-stm32/src/dma/ringbuffer/mod.rs +++ b/embassy-stm32/src/dma/ringbuffer/mod.rs | |||
| @@ -85,7 +85,7 @@ impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> { | |||
| 85 | } | 85 | } |
| 86 | } | 86 | } |
| 87 | 87 | ||
| 88 | /// Reset the ring buffer to its initial state | 88 | /// Reset the ring buffer to its initial state. |
| 89 | pub fn clear(&mut self, dma: &mut impl DmaCtrl) { | 89 | pub fn clear(&mut self, dma: &mut impl DmaCtrl) { |
| 90 | dma.reset_complete_count(); | 90 | dma.reset_complete_count(); |
| 91 | self.write_index.reset(); | 91 | self.write_index.reset(); |
| @@ -113,17 +113,12 @@ impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> { | |||
| 113 | /// Return a tuple of the length read and the length remaining in the buffer | 113 | /// Return a tuple of the length read and the length remaining in the buffer |
| 114 | /// If not all of the elements were read, then there will be some elements in the buffer remaining | 114 | /// If not all of the elements were read, then there will be some elements in the buffer remaining |
| 115 | /// The length remaining is the capacity, ring_buf.len(), less the elements remaining after the read | 115 | /// The length remaining is the capacity, ring_buf.len(), less the elements remaining after the read |
| 116 | /// OverrunError is returned if the portion to be read was overwritten by the DMA controller. | 116 | /// OverrunError is returned if the portion to be read was overwritten by the DMA controller, |
| 117 | /// in which case the rinbuffer will automatically clear itself. | ||
| 117 | pub fn read(&mut self, dma: &mut impl DmaCtrl, buf: &mut [W]) -> Result<(usize, usize), OverrunError> { | 118 | pub fn read(&mut self, dma: &mut impl DmaCtrl, buf: &mut [W]) -> Result<(usize, usize), OverrunError> { |
| 118 | self.sync_write_index(dma); | 119 | self.read_raw(dma, buf).inspect_err(|_e| { |
| 119 | let readable = self.len()?.min(buf.len()); | 120 | self.clear(dma); |
| 120 | for i in 0..readable { | 121 | }) |
| 121 | buf[i] = self.read_buf(i); | ||
| 122 | } | ||
| 123 | self.sync_write_index(dma); | ||
| 124 | let available = self.len()?; | ||
| 125 | self.read_index.advance(self.cap(), readable); | ||
| 126 | Ok((readable, available - readable)) | ||
| 127 | } | 122 | } |
| 128 | 123 | ||
| 129 | /// Read an exact number of elements from the ringbuffer. | 124 | /// Read an exact number of elements from the ringbuffer. |
| @@ -159,6 +154,18 @@ impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> { | |||
| 159 | .await | 154 | .await |
| 160 | } | 155 | } |
| 161 | 156 | ||
| 157 | fn read_raw(&mut self, dma: &mut impl DmaCtrl, buf: &mut [W]) -> Result<(usize, usize), OverrunError> { | ||
| 158 | self.sync_write_index(dma); | ||
| 159 | let readable = self.len()?.min(buf.len()); | ||
| 160 | for i in 0..readable { | ||
| 161 | buf[i] = self.read_buf(i); | ||
| 162 | } | ||
| 163 | self.sync_write_index(dma); | ||
| 164 | let available = self.len()?; | ||
| 165 | self.read_index.advance(self.cap(), readable); | ||
| 166 | Ok((readable, available - readable)) | ||
| 167 | } | ||
| 168 | |||
| 162 | fn read_buf(&self, offset: usize) -> W { | 169 | fn read_buf(&self, offset: usize) -> W { |
| 163 | unsafe { | 170 | unsafe { |
| 164 | core::ptr::read_volatile( | 171 | core::ptr::read_volatile( |
| @@ -222,16 +229,13 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> { | |||
| 222 | 229 | ||
| 223 | /// Append data to the ring buffer. | 230 | /// Append data to the ring buffer. |
| 224 | /// Returns a tuple of the data written and the remaining write capacity in the buffer. | 231 | /// Returns a tuple of the data written and the remaining write capacity in the buffer. |
| 232 | /// OverrunError is returned if the portion to be written was previously read by the DMA controller. | ||
| 233 | /// In this case, the ringbuffer will automatically reset itself, giving a full buffer worth of | ||
| 234 | /// leeway between the write index and the DMA. | ||
| 225 | pub fn write(&mut self, dma: &mut impl DmaCtrl, buf: &[W]) -> Result<(usize, usize), OverrunError> { | 235 | pub fn write(&mut self, dma: &mut impl DmaCtrl, buf: &[W]) -> Result<(usize, usize), OverrunError> { |
| 226 | self.sync_read_index(dma); | 236 | self.write_raw(dma, buf).inspect_err(|_e| { |
| 227 | let writable = self.len()?.min(buf.len()); | 237 | self.clear(dma); |
| 228 | for i in 0..writable { | 238 | }) |
| 229 | self.write_buf(i, buf[i]); | ||
| 230 | } | ||
| 231 | self.sync_read_index(dma); | ||
| 232 | let available = self.len()?; | ||
| 233 | self.write_index.advance(self.cap(), writable); | ||
| 234 | Ok((writable, available - writable)) | ||
| 235 | } | 239 | } |
| 236 | 240 | ||
| 237 | /// Write elements directly to the buffer. | 241 | /// Write elements directly to the buffer. |
| @@ -266,6 +270,18 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> { | |||
| 266 | .await | 270 | .await |
| 267 | } | 271 | } |
| 268 | 272 | ||
| 273 | pub fn write_raw(&mut self, dma: &mut impl DmaCtrl, buf: &[W]) -> Result<(usize, usize), OverrunError> { | ||
| 274 | self.sync_read_index(dma); | ||
| 275 | let writable = self.len()?.min(buf.len()); | ||
| 276 | for i in 0..writable { | ||
| 277 | self.write_buf(i, buf[i]); | ||
| 278 | } | ||
| 279 | self.sync_read_index(dma); | ||
| 280 | let available = self.len()?; | ||
| 281 | self.write_index.advance(self.cap(), writable); | ||
| 282 | Ok((writable, available - writable)) | ||
| 283 | } | ||
| 284 | |||
| 269 | fn write_buf(&mut self, offset: usize, value: W) { | 285 | fn write_buf(&mut self, offset: usize, value: W) { |
| 270 | unsafe { | 286 | unsafe { |
| 271 | core::ptr::write_volatile( | 287 | core::ptr::write_volatile( |
diff --git a/embassy-stm32/src/dma/ringbuffer/tests/prop_test/reader.rs b/embassy-stm32/src/dma/ringbuffer/tests/prop_test/reader.rs index 6555ebfb0..6e640a813 100644 --- a/embassy-stm32/src/dma/ringbuffer/tests/prop_test/reader.rs +++ b/embassy-stm32/src/dma/ringbuffer/tests/prop_test/reader.rs | |||
| @@ -38,8 +38,9 @@ impl ReferenceStateMachine for ReaderSM { | |||
| 38 | Status::Available(x + y) | 38 | Status::Available(x + y) |
| 39 | } | 39 | } |
| 40 | } | 40 | } |
| 41 | (Status::Failed, ReaderTransition::Write(_)) => Status::Failed, | ||
| 41 | (Status::Available(x), ReaderTransition::ReadUpTo(y)) => Status::Available(x.saturating_sub(*y)), | 42 | (Status::Available(x), ReaderTransition::ReadUpTo(y)) => Status::Available(x.saturating_sub(*y)), |
| 42 | (Status::Failed, _) => Status::Failed, | 43 | (Status::Failed, ReaderTransition::ReadUpTo(_)) => Status::Available(0), |
| 43 | } | 44 | } |
| 44 | } | 45 | } |
| 45 | } | 46 | } |
diff --git a/embassy-stm32/src/dma/ringbuffer/tests/prop_test/writer.rs b/embassy-stm32/src/dma/ringbuffer/tests/prop_test/writer.rs index 15f54c672..c1b3859b2 100644 --- a/embassy-stm32/src/dma/ringbuffer/tests/prop_test/writer.rs +++ b/embassy-stm32/src/dma/ringbuffer/tests/prop_test/writer.rs | |||
| @@ -38,8 +38,9 @@ impl ReferenceStateMachine for WriterSM { | |||
| 38 | Status::Available(x - y) | 38 | Status::Available(x - y) |
| 39 | } | 39 | } |
| 40 | } | 40 | } |
| 41 | (Status::Failed, WriterTransition::Read(_)) => Status::Failed, | ||
| 41 | (Status::Available(x), WriterTransition::WriteUpTo(y)) => Status::Available((x + *y).min(CAP)), | 42 | (Status::Available(x), WriterTransition::WriteUpTo(y)) => Status::Available((x + *y).min(CAP)), |
| 42 | (Status::Failed, _) => Status::Failed, | 43 | (Status::Failed, WriterTransition::WriteUpTo(_)) => Status::Available(CAP), |
| 43 | } | 44 | } |
| 44 | } | 45 | } |
| 45 | } | 46 | } |
