feat: wip, write buffer in halves

This commit is contained in:
elagil 2025-08-25 21:10:59 +02:00 committed by Dario Nieuwenhuis
parent 78364b966e
commit a4d3b4b6ae
3 changed files with 54 additions and 108 deletions

View File

@ -46,29 +46,11 @@ impl<'a> DmaCtrl for DmaCtrlImpl<'a> {
}
}
/// The current buffer half (e.g. for DMA or the user application).
#[derive(Debug, PartialEq, PartialOrd)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
enum BufferHalf {
First,
Second,
}
impl BufferHalf {
fn toggle(&mut self) {
*self = match *self {
Self::First => Self::Second,
Self::Second => Self::First,
};
}
}
/// Ringbuffer for receiving data using GPDMA linked-list mode.
pub struct ReadableRingBuffer<'a, W: Word> {
channel: PeripheralRef<'a, AnyChannel>,
ringbuf: ReadableDmaRingBuffer<'a, W>,
table: Table<2>,
user_buffer_half: BufferHalf,
}
impl<'a, W: Word> ReadableRingBuffer<'a, W> {
@ -99,7 +81,6 @@ impl<'a, W: Word> ReadableRingBuffer<'a, W> {
channel,
ringbuf: ReadableDmaRingBuffer::new(buffer),
table,
user_buffer_half: BufferHalf::First,
}
}
@ -217,7 +198,6 @@ pub struct WritableRingBuffer<'a, W: Word> {
channel: PeripheralRef<'a, AnyChannel>,
ringbuf: WritableDmaRingBuffer<'a, W>,
table: Table<2>,
user_buffer_half: BufferHalf,
}
impl<'a, W: Word> WritableRingBuffer<'a, W> {
@ -246,7 +226,6 @@ impl<'a, W: Word> WritableRingBuffer<'a, W> {
channel,
ringbuf: WritableDmaRingBuffer::new(buffer),
table,
user_buffer_half: BufferHalf::First,
};
this
@ -280,62 +259,21 @@ impl<'a, W: Word> WritableRingBuffer<'a, W> {
/// Write an exact number of elements to the ringbuffer.
pub async fn write_exact(&mut self, buffer: &[W]) -> Result<usize, Error> {
return self
.ringbuf
.write_exact(&mut DmaCtrlImpl(self.channel.reborrow()), buffer)
.await;
let mut written_len = 0;
let len = buffer.len();
// return self
// .ringbuf
// .write_exact(&mut DmaCtrlImpl(self.channel.reborrow()), buffer)
// .await;
let mut remaining_cap = 0;
let cap = self.ringbuf.cap();
let mut written_len = 0;
let dma = &mut DmaCtrlImpl(self.channel.reborrow());
let user_buffer_half = &mut self.user_buffer_half;
let ringbuf = &mut self.ringbuf;
let table = &mut self.table;
while written_len != len {
// info!(
// "read {}, write {}, cap {}",
// ringbuf.read_index(0),
// ringbuf.write_index(0),
// ringbuf.cap()
// );
let dma_buffer_half = if ringbuf.read_index(0) < ringbuf.cap() / 2 {
BufferHalf::First
} else {
BufferHalf::Second
};
// if dma_buffer_half == *user_buffer_half {
// info!("swap user from {}", user_buffer_half);
// table.unlink();
// match user_buffer_half {
// BufferHalf::First => table.link_indices(1, 0),
// BufferHalf::Second => table.link_indices(0, 1),
// }
// user_buffer_half.toggle();
// }
let index = match dma_buffer_half {
BufferHalf::First => {
// Fill up second buffer half when DMA reads the first.
cap - 1
}
BufferHalf::Second => {
// Fill up first buffer half when DMA reads the second.
cap / 2 - 1
}
};
(written_len, remaining_cap) = ringbuf.write_until(dma, &buffer, index).await?;
while written_len < buffer.len() {
(written_len, remaining_cap) = self
.ringbuf
.write_half(&mut DmaCtrlImpl(self.channel.reborrow()), buffer)
.await?;
// info!("Written: {}/{}", written_len, buffer.len());
}
info!("done");
Ok(remaining_cap)
}

View File

@ -3,6 +3,14 @@ use core::task::{Poll, Waker};
use crate::dma::word::Word;
/// The current buffer half (e.g. for DMA or the user application).
#[derive(Debug, PartialEq, PartialOrd)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
enum BufferHalf {
First,
Second,
}
pub trait DmaCtrl {
/// Get the NDTR register value, i.e. the space left in the underlying
/// buffer until the dma writer wraps.
@ -92,16 +100,6 @@ impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> {
}
}
/// The current ring-buffer read index.
pub fn read_index(&self, offset: usize) -> usize {
self.read_index.as_index(self.cap(), offset)
}
/// The current ring-buffer write index.
pub fn write_index(&self, offset: usize) -> usize {
self.write_index.as_index(self.cap(), offset)
}
/// Reset the ring buffer to its initial state.
pub fn reset(&mut self, dma: &mut impl DmaCtrl) {
dma.reset_complete_count();
@ -218,14 +216,13 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> {
}
}
/// The current ring-buffer read index.
pub fn read_index(&self, offset: usize) -> usize {
self.read_index.as_index(self.cap(), offset)
}
/// The current ring-buffer write index.
pub fn write_index(&self, offset: usize) -> usize {
self.write_index.as_index(self.cap(), offset)
/// The buffer half that is in use by the DMA.
fn dma_half(&self) -> BufferHalf {
if self.read_index.as_index(self.cap(), 0) < self.cap() / 2 {
BufferHalf::First
} else {
BufferHalf::Second
}
}
/// Reset the ring buffer to its initial state. The buffer after the reset will be full.
@ -305,6 +302,7 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> {
/// Write an exact number of elements to the ringbuffer.
///
/// Returns the remaining write capacity in the buffer.
#[allow(dead_code)]
pub async fn write_exact(&mut self, dma: &mut impl DmaCtrl, buffer: &[W]) -> Result<usize, Error> {
let mut written_len = 0;
let buffer_len = buffer.len();
@ -327,31 +325,41 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> {
.await
}
/// Write until a given write index.
/// Write the user's current buffer half - not used by the DMA.
///
/// Returns a tuple of the written length, and the remaining write capacity in the buffer.
pub async fn write_until(
&mut self,
dma: &mut impl DmaCtrl,
buffer: &[W],
index: usize,
) -> Result<(usize, usize), Error> {
#[allow(dead_code)]
pub async fn write_half(&mut self, dma: &mut impl DmaCtrl, buffer: &[W]) -> Result<(usize, usize), Error> {
let mut written_len = 0;
let write_len = index
.saturating_sub(self.write_index.as_index(self.cap(), 0))
.min(buffer.len());
if write_len == 0 {
return Err(Error::Overrun);
}
let buffer_len = buffer.len();
poll_fn(|cx| {
dma.set_waker(cx.waker());
match self.write(dma, &buffer[written_len..write_len]) {
let dma_half = self.dma_half();
// let user_half = self.user_half();
// if dma_half == user_half {
// info!("ups");
// return Poll::Ready(Err(Error::Overrun));
// }
let write_index = self.write_index.as_index(self.cap(), 0);
let target_write_len = match dma_half {
BufferHalf::First => self.cap().saturating_sub(write_index),
BufferHalf::Second => (self.cap() / 2).saturating_sub(write_index),
};
let write_end_index = (target_write_len + written_len).min(buffer_len);
// info!(
// "buf_len: {}, write_len: {}, write_index: {}",
// buffer_len, target_write_len, write_index
// );
match self.write(dma, &buffer[written_len..write_end_index]) {
Ok((len, remaining)) => {
written_len += len;
if written_len == write_len {
if written_len == write_end_index {
Poll::Ready(Ok((written_len, remaining)))
} else {
Poll::Pending

View File

@ -381,7 +381,7 @@ impl ReadReady for RingBufferedUartRx<'_> {
crate::dma::ringbuffer::Error::Overrun => Self::Error::Overrun,
crate::dma::ringbuffer::Error::DmaUnsynced => {
error!(
"Ringbuffer error: DmaUNsynced, driver implementation is
"Ringbuffer error: DmaUNsynced, driver implementation is
probably bugged please open an issue"
);
// we report this as overrun since its recoverable in the same way