Merge pull request #1681 from alexferro/feature/stm32-dma-read-exact
Add a STM32/DMARingBuffer::read_exact helper
This commit is contained in:
commit
44c8db2911
@ -466,15 +466,53 @@ impl<'a, C: Channel, W: Word> RingBuffer<'a, C, W> {
|
|||||||
self.ringbuf.clear(DmaCtrlImpl(self.channel.reborrow()));
|
self.ringbuf.clear(DmaCtrlImpl(self.channel.reborrow()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read bytes from the ring buffer
|
/// Read elements from the ring buffer
|
||||||
/// 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 bytes were read, then there will be some bytes 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 bytes 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.
|
||||||
pub fn read(&mut self, buf: &mut [W]) -> Result<(usize, usize), OverrunError> {
|
pub fn read(&mut self, buf: &mut [W]) -> Result<(usize, usize), OverrunError> {
|
||||||
self.ringbuf.read(DmaCtrlImpl(self.channel.reborrow()), buf)
|
self.ringbuf.read(DmaCtrlImpl(self.channel.reborrow()), buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Read an exact number of elements from the ringbuffer.
|
||||||
|
///
|
||||||
|
/// Returns the remaining number of elements available for immediate reading.
|
||||||
|
/// OverrunError is returned if the portion to be read was overwritten by the DMA controller.
|
||||||
|
///
|
||||||
|
/// Async/Wake Behavior:
|
||||||
|
/// The underlying DMA peripheral only can wake us when its buffer pointer has reached the halfway point,
|
||||||
|
/// and when it wraps around. This means that when called with a buffer of length 'M', when this
|
||||||
|
/// ring buffer was created with a buffer of size 'N':
|
||||||
|
/// - If M equals N/2 or N/2 divides evenly into M, this function will return every N/2 elements read on the DMA source.
|
||||||
|
/// - Otherwise, this function may need up to N/2 extra elements to arrive before returning.
|
||||||
|
pub async fn read_exact(&mut self, buffer: &mut [W]) -> Result<usize, OverrunError> {
|
||||||
|
use core::future::poll_fn;
|
||||||
|
use core::sync::atomic::compiler_fence;
|
||||||
|
|
||||||
|
let mut read_data = 0;
|
||||||
|
let buffer_len = buffer.len();
|
||||||
|
|
||||||
|
poll_fn(|cx| {
|
||||||
|
self.set_waker(cx.waker());
|
||||||
|
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
|
||||||
|
match self.read(&mut buffer[read_data..buffer_len]) {
|
||||||
|
Ok((len, remaining)) => {
|
||||||
|
read_data += len;
|
||||||
|
if read_data == buffer_len {
|
||||||
|
Poll::Ready(Ok(remaining))
|
||||||
|
} else {
|
||||||
|
Poll::Pending
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => Poll::Ready(Err(e)),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
/// The capacity of the ringbuffer
|
/// The capacity of the ringbuffer
|
||||||
pub fn cap(&self) -> usize {
|
pub fn cap(&self) -> usize {
|
||||||
self.ringbuf.cap()
|
self.ringbuf.cap()
|
||||||
|
@ -711,15 +711,53 @@ impl<'a, C: Channel, W: Word> RingBuffer<'a, C, W> {
|
|||||||
self.ringbuf.clear(DmaCtrlImpl(self.channel.reborrow()));
|
self.ringbuf.clear(DmaCtrlImpl(self.channel.reborrow()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read bytes from the ring buffer
|
/// Read elements from the ring buffer
|
||||||
/// 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 bytes were read, then there will be some bytes 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 bytes 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.
|
||||||
pub fn read(&mut self, buf: &mut [W]) -> Result<(usize, usize), OverrunError> {
|
pub fn read(&mut self, buf: &mut [W]) -> Result<(usize, usize), OverrunError> {
|
||||||
self.ringbuf.read(DmaCtrlImpl(self.channel.reborrow()), buf)
|
self.ringbuf.read(DmaCtrlImpl(self.channel.reborrow()), buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Read an exact number of elements from the ringbuffer.
|
||||||
|
///
|
||||||
|
/// Returns the remaining number of elements available for immediate reading.
|
||||||
|
/// OverrunError is returned if the portion to be read was overwritten by the DMA controller.
|
||||||
|
///
|
||||||
|
/// Async/Wake Behavior:
|
||||||
|
/// The underlying DMA peripheral only can wake us when its buffer pointer has reached the halfway point,
|
||||||
|
/// and when it wraps around. This means that when called with a buffer of length 'M', when this
|
||||||
|
/// ring buffer was created with a buffer of size 'N':
|
||||||
|
/// - If M equals N/2 or N/2 divides evenly into M, this function will return every N/2 elements read on the DMA source.
|
||||||
|
/// - Otherwise, this function may need up to N/2 extra elements to arrive before returning.
|
||||||
|
pub async fn read_exact(&mut self, buffer: &mut [W]) -> Result<usize, OverrunError> {
|
||||||
|
use core::future::poll_fn;
|
||||||
|
use core::sync::atomic::compiler_fence;
|
||||||
|
|
||||||
|
let mut read_data = 0;
|
||||||
|
let buffer_len = buffer.len();
|
||||||
|
|
||||||
|
poll_fn(|cx| {
|
||||||
|
self.set_waker(cx.waker());
|
||||||
|
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
|
||||||
|
match self.read(&mut buffer[read_data..buffer_len]) {
|
||||||
|
Ok((len, remaining)) => {
|
||||||
|
read_data += len;
|
||||||
|
if read_data == buffer_len {
|
||||||
|
Poll::Ready(Ok(remaining))
|
||||||
|
} else {
|
||||||
|
Poll::Pending
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => Poll::Ready(Err(e)),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
// The capacity of the ringbuffer
|
// The capacity of the ringbuffer
|
||||||
pub fn cap(&self) -> usize {
|
pub fn cap(&self) -> usize {
|
||||||
self.ringbuf.cap()
|
self.ringbuf.cap()
|
||||||
|
@ -72,10 +72,10 @@ impl<'a, W: Word> DmaRingBuffer<'a, W> {
|
|||||||
self.cap() - remaining_transfers
|
self.cap() - remaining_transfers
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read bytes from the ring buffer
|
/// Read elements from the ring buffer
|
||||||
/// 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 bytes were read, then there will be some bytes 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 bytes 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.
|
||||||
pub fn read(&mut self, mut dma: impl DmaCtrl, buf: &mut [W]) -> Result<(usize, usize), OverrunError> {
|
pub fn read(&mut self, mut dma: impl DmaCtrl, buf: &mut [W]) -> Result<(usize, usize), OverrunError> {
|
||||||
/*
|
/*
|
||||||
@ -95,11 +95,11 @@ impl<'a, W: Word> DmaRingBuffer<'a, W> {
|
|||||||
*/
|
*/
|
||||||
let end = self.pos(dma.get_remaining_transfers());
|
let end = self.pos(dma.get_remaining_transfers());
|
||||||
if self.start == end && dma.get_complete_count() == 0 {
|
if self.start == end && dma.get_complete_count() == 0 {
|
||||||
// No bytes are available in the buffer
|
// No elements are available in the buffer
|
||||||
Ok((0, self.cap()))
|
Ok((0, self.cap()))
|
||||||
} else if self.start < end {
|
} else if self.start < end {
|
||||||
// The available, unread portion in the ring buffer DOES NOT wrap
|
// The available, unread portion in the ring buffer DOES NOT wrap
|
||||||
// Copy out the bytes from the dma buffer
|
// Copy out the elements from the dma buffer
|
||||||
let len = self.copy_to(buf, self.start..end);
|
let len = self.copy_to(buf, self.start..end);
|
||||||
|
|
||||||
compiler_fence(Ordering::SeqCst);
|
compiler_fence(Ordering::SeqCst);
|
||||||
@ -128,7 +128,7 @@ impl<'a, W: Word> DmaRingBuffer<'a, W> {
|
|||||||
// The DMA writer has wrapped since we last read and is currently
|
// The DMA writer has wrapped since we last read and is currently
|
||||||
// writing (or the next byte added will be) in the beginning of the ring buffer.
|
// writing (or the next byte added will be) in the beginning of the ring buffer.
|
||||||
|
|
||||||
// The provided read buffer is not large enough to include all bytes from the tail of the dma buffer.
|
// The provided read buffer is not large enough to include all elements from the tail of the dma buffer.
|
||||||
|
|
||||||
// Copy out from the dma buffer
|
// Copy out from the dma buffer
|
||||||
let len = self.copy_to(buf, self.start..self.cap());
|
let len = self.copy_to(buf, self.start..self.cap());
|
||||||
@ -154,8 +154,8 @@ impl<'a, W: Word> DmaRingBuffer<'a, W> {
|
|||||||
// The DMA writer has wrapped since we last read and is currently
|
// The DMA writer has wrapped since we last read and is currently
|
||||||
// writing (or the next byte added will be) in the beginning of the ring buffer.
|
// writing (or the next byte added will be) in the beginning of the ring buffer.
|
||||||
|
|
||||||
// The provided read buffer is large enough to include all bytes from the tail of the dma buffer,
|
// The provided read buffer is large enough to include all elements from the tail of the dma buffer,
|
||||||
// so the next read will not have any unread tail bytes in the ring buffer.
|
// so the next read will not have any unread tail elements in the ring buffer.
|
||||||
|
|
||||||
// Copy out from the dma buffer
|
// Copy out from the dma buffer
|
||||||
let tail = self.copy_to(buf, self.start..self.cap());
|
let tail = self.copy_to(buf, self.start..self.cap());
|
||||||
@ -180,7 +180,7 @@ impl<'a, W: Word> DmaRingBuffer<'a, W> {
|
|||||||
}
|
}
|
||||||
/// Copy from the dma buffer at `data_range` into `buf`
|
/// Copy from the dma buffer at `data_range` into `buf`
|
||||||
fn copy_to(&mut self, buf: &mut [W], data_range: Range<usize>) -> usize {
|
fn copy_to(&mut self, buf: &mut [W], data_range: Range<usize>) -> usize {
|
||||||
// Limit the number of bytes that can be copied
|
// Limit the number of elements that can be copied
|
||||||
let length = usize::min(data_range.len(), buf.len());
|
let length = usize::min(data_range.len(), buf.len());
|
||||||
|
|
||||||
// Copy from dma buffer into read buffer
|
// Copy from dma buffer into read buffer
|
||||||
|
Loading…
Reference in New Issue
Block a user