add auto-clear functionality to ringbuffer

This commit is contained in:
Alexandros Liarokapis 2024-09-23 02:49:05 +03:00
parent f4ec0cb4d4
commit 85fb890b00
3 changed files with 40 additions and 22 deletions

View File

@ -85,7 +85,7 @@ impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> {
} }
} }
/// Reset the ring buffer to its initial state /// Reset the ring buffer to its initial state.
pub fn clear(&mut self, dma: &mut impl DmaCtrl) { pub fn clear(&mut self, dma: &mut impl DmaCtrl) {
dma.reset_complete_count(); dma.reset_complete_count();
self.write_index.reset(); self.write_index.reset();
@ -113,17 +113,12 @@ impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> {
/// Return a tuple of the length read and the length remaining in the buffer /// Return a tuple of the length read and the length remaining in the buffer
/// If not all of the elements were read, then there will be some elements in the buffer remaining /// If not all of the elements were read, then there will be some elements in the buffer remaining
/// The length remaining is the capacity, ring_buf.len(), less the elements remaining after the read /// The length remaining is the capacity, ring_buf.len(), less the elements remaining after the read
/// OverrunError is returned if the portion to be read was overwritten by the DMA controller. /// OverrunError is returned if the portion to be read was overwritten by the DMA controller,
/// in which case the rinbuffer will automatically clear itself.
pub fn read(&mut self, dma: &mut impl DmaCtrl, buf: &mut [W]) -> Result<(usize, usize), OverrunError> { pub fn read(&mut self, dma: &mut impl DmaCtrl, buf: &mut [W]) -> Result<(usize, usize), OverrunError> {
self.sync_write_index(dma); self.read_raw(dma, buf).inspect_err(|_e| {
let readable = self.len()?.min(buf.len()); self.clear(dma);
for i in 0..readable { })
buf[i] = self.read_buf(i);
}
self.sync_write_index(dma);
let available = self.len()?;
self.read_index.advance(self.cap(), readable);
Ok((readable, available - readable))
} }
/// Read an exact number of elements from the ringbuffer. /// Read an exact number of elements from the ringbuffer.
@ -159,6 +154,18 @@ impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> {
.await .await
} }
fn read_raw(&mut self, dma: &mut impl DmaCtrl, buf: &mut [W]) -> Result<(usize, usize), OverrunError> {
self.sync_write_index(dma);
let readable = self.len()?.min(buf.len());
for i in 0..readable {
buf[i] = self.read_buf(i);
}
self.sync_write_index(dma);
let available = self.len()?;
self.read_index.advance(self.cap(), readable);
Ok((readable, available - readable))
}
fn read_buf(&self, offset: usize) -> W { fn read_buf(&self, offset: usize) -> W {
unsafe { unsafe {
core::ptr::read_volatile( core::ptr::read_volatile(
@ -222,16 +229,13 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> {
/// Append data to the ring buffer. /// Append data to the ring buffer.
/// Returns a tuple of the data written and the remaining write capacity in the buffer. /// Returns a tuple of the data written and the remaining write capacity in the buffer.
/// OverrunError is returned if the portion to be written was previously read by the DMA controller.
/// In this case, the ringbuffer will automatically reset itself, giving a full buffer worth of
/// leeway between the write index and the DMA.
pub fn write(&mut self, dma: &mut impl DmaCtrl, buf: &[W]) -> Result<(usize, usize), OverrunError> { pub fn write(&mut self, dma: &mut impl DmaCtrl, buf: &[W]) -> Result<(usize, usize), OverrunError> {
self.sync_read_index(dma); self.write_raw(dma, buf).inspect_err(|_e| {
let writable = self.len()?.min(buf.len()); self.clear(dma);
for i in 0..writable { })
self.write_buf(i, buf[i]);
}
self.sync_read_index(dma);
let available = self.len()?;
self.write_index.advance(self.cap(), writable);
Ok((writable, available - writable))
} }
/// Write elements directly to the buffer. /// Write elements directly to the buffer.
@ -266,6 +270,18 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> {
.await .await
} }
pub fn write_raw(&mut self, dma: &mut impl DmaCtrl, buf: &[W]) -> Result<(usize, usize), OverrunError> {
self.sync_read_index(dma);
let writable = self.len()?.min(buf.len());
for i in 0..writable {
self.write_buf(i, buf[i]);
}
self.sync_read_index(dma);
let available = self.len()?;
self.write_index.advance(self.cap(), writable);
Ok((writable, available - writable))
}
fn write_buf(&mut self, offset: usize, value: W) { fn write_buf(&mut self, offset: usize, value: W) {
unsafe { unsafe {
core::ptr::write_volatile( core::ptr::write_volatile(

View File

@ -38,8 +38,9 @@ impl ReferenceStateMachine for ReaderSM {
Status::Available(x + y) Status::Available(x + y)
} }
} }
(Status::Failed, ReaderTransition::Write(_)) => Status::Failed,
(Status::Available(x), ReaderTransition::ReadUpTo(y)) => Status::Available(x.saturating_sub(*y)), (Status::Available(x), ReaderTransition::ReadUpTo(y)) => Status::Available(x.saturating_sub(*y)),
(Status::Failed, _) => Status::Failed, (Status::Failed, ReaderTransition::ReadUpTo(_)) => Status::Available(0),
} }
} }
} }

View File

@ -38,8 +38,9 @@ impl ReferenceStateMachine for WriterSM {
Status::Available(x - y) Status::Available(x - y)
} }
} }
(Status::Failed, WriterTransition::Read(_)) => Status::Failed,
(Status::Available(x), WriterTransition::WriteUpTo(y)) => Status::Available((x + *y).min(CAP)), (Status::Available(x), WriterTransition::WriteUpTo(y)) => Status::Available((x + *y).min(CAP)),
(Status::Failed, _) => Status::Failed, (Status::Failed, WriterTransition::WriteUpTo(_)) => Status::Available(CAP),
} }
} }
} }