mirror of
https://github.com/embassy-rs/embassy.git
synced 2025-09-27 12:20:37 +00:00
feat: wip, write buffer in halves
This commit is contained in:
parent
78364b966e
commit
a4d3b4b6ae
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user