stm32/dma: consolidate ringbuf
This commit is contained in:
parent
30358c435e
commit
7e269f6f17
@ -393,6 +393,10 @@ impl<'a, C: Channel> DmaCtrl for DmaCtrlImpl<'a, C> {
|
|||||||
fn reset_complete_count(&mut self) -> usize {
|
fn reset_complete_count(&mut self) -> usize {
|
||||||
STATE.complete_count[self.0.index()].swap(0, Ordering::AcqRel)
|
STATE.complete_count[self.0.index()].swap(0, Ordering::AcqRel)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_waker(&mut self, waker: &Waker) {
|
||||||
|
STATE.ch_wakers[self.0.index()].register(waker);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ReadableRingBuffer<'a, C: Channel, W: Word> {
|
pub struct ReadableRingBuffer<'a, C: Channel, W: Word> {
|
||||||
@ -463,7 +467,7 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear(&mut self) {
|
pub fn clear(&mut self) {
|
||||||
self.ringbuf.clear(DmaCtrlImpl(self.channel.reborrow()));
|
self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read elements from the ring buffer
|
/// Read elements from the ring buffer
|
||||||
@ -472,7 +476,7 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
|
|||||||
/// 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.
|
||||||
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(&mut DmaCtrlImpl(self.channel.reborrow()), buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read an exact number of elements from the ringbuffer.
|
/// Read an exact number of elements from the ringbuffer.
|
||||||
@ -487,30 +491,9 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
|
|||||||
/// - 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.
|
/// - 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.
|
/// - 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> {
|
pub async fn read_exact(&mut self, buffer: &mut [W]) -> Result<usize, OverrunError> {
|
||||||
use core::future::poll_fn;
|
self.ringbuf
|
||||||
use core::sync::atomic::compiler_fence;
|
.read_exact(&mut DmaCtrlImpl(self.channel.reborrow()), buffer)
|
||||||
|
.await
|
||||||
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.
|
||||||
@ -519,7 +502,7 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_waker(&mut self, waker: &Waker) {
|
pub fn set_waker(&mut self, waker: &Waker) {
|
||||||
STATE.ch_wakers[self.channel.index()].register(waker);
|
DmaCtrlImpl(self.channel.reborrow()).set_waker(waker);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clear_irqs(&mut self) {
|
fn clear_irqs(&mut self) {
|
||||||
@ -628,41 +611,20 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear(&mut self) {
|
pub fn clear(&mut self) {
|
||||||
self.ringbuf.clear(DmaCtrlImpl(self.channel.reborrow()));
|
self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write elements to the ring buffer
|
/// Write elements to the ring buffer
|
||||||
/// Return a tuple of the length written and the length remaining in the buffer
|
/// Return a tuple of the length written and the length remaining in the buffer
|
||||||
pub fn write(&mut self, buf: &[W]) -> Result<(usize, usize), OverrunError> {
|
pub fn write(&mut self, buf: &[W]) -> Result<(usize, usize), OverrunError> {
|
||||||
self.ringbuf.write(DmaCtrlImpl(self.channel.reborrow()), buf)
|
self.ringbuf.write(&mut DmaCtrlImpl(self.channel.reborrow()), buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write an exact number of elements to the ringbuffer.
|
/// Write an exact number of elements to the ringbuffer.
|
||||||
pub async fn write_exact(&mut self, buffer: &[W]) -> Result<usize, OverrunError> {
|
pub async fn write_exact(&mut self, buffer: &[W]) -> Result<usize, OverrunError> {
|
||||||
use core::future::poll_fn;
|
self.ringbuf
|
||||||
use core::sync::atomic::compiler_fence;
|
.write_exact(&mut DmaCtrlImpl(self.channel.reborrow()), buffer)
|
||||||
|
.await
|
||||||
let mut written_data = 0;
|
|
||||||
let buffer_len = buffer.len();
|
|
||||||
|
|
||||||
poll_fn(|cx| {
|
|
||||||
self.set_waker(cx.waker());
|
|
||||||
|
|
||||||
compiler_fence(Ordering::SeqCst);
|
|
||||||
|
|
||||||
match self.write(&buffer[written_data..buffer_len]) {
|
|
||||||
Ok((len, remaining)) => {
|
|
||||||
written_data += len;
|
|
||||||
if written_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.
|
||||||
@ -671,7 +633,7 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_waker(&mut self, waker: &Waker) {
|
pub fn set_waker(&mut self, waker: &Waker) {
|
||||||
STATE.ch_wakers[self.channel.index()].register(waker);
|
DmaCtrlImpl(self.channel.reborrow()).set_waker(waker);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clear_irqs(&mut self) {
|
fn clear_irqs(&mut self) {
|
||||||
|
@ -623,6 +623,10 @@ impl<'a, C: Channel> DmaCtrl for DmaCtrlImpl<'a, C> {
|
|||||||
fn reset_complete_count(&mut self) -> usize {
|
fn reset_complete_count(&mut self) -> usize {
|
||||||
STATE.complete_count[self.0.index()].swap(0, Ordering::AcqRel)
|
STATE.complete_count[self.0.index()].swap(0, Ordering::AcqRel)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_waker(&mut self, waker: &Waker) {
|
||||||
|
STATE.ch_wakers[self.0.index()].register(waker);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ReadableRingBuffer<'a, C: Channel, W: Word> {
|
pub struct ReadableRingBuffer<'a, C: Channel, W: Word> {
|
||||||
@ -708,7 +712,7 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear(&mut self) {
|
pub fn clear(&mut self) {
|
||||||
self.ringbuf.clear(DmaCtrlImpl(self.channel.reborrow()));
|
self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read elements from the ring buffer
|
/// Read elements from the ring buffer
|
||||||
@ -717,7 +721,7 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
|
|||||||
/// 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.
|
||||||
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(&mut DmaCtrlImpl(self.channel.reborrow()), buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read an exact number of elements from the ringbuffer.
|
/// Read an exact number of elements from the ringbuffer.
|
||||||
@ -732,30 +736,9 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
|
|||||||
/// - 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.
|
/// - 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.
|
/// - 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> {
|
pub async fn read_exact(&mut self, buffer: &mut [W]) -> Result<usize, OverrunError> {
|
||||||
use core::future::poll_fn;
|
self.ringbuf
|
||||||
use core::sync::atomic::compiler_fence;
|
.read_exact(&mut DmaCtrlImpl(self.channel.reborrow()), buffer)
|
||||||
|
.await
|
||||||
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
|
||||||
@ -890,41 +873,20 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear(&mut self) {
|
pub fn clear(&mut self) {
|
||||||
self.ringbuf.clear(DmaCtrlImpl(self.channel.reborrow()));
|
self.ringbuf.clear(&mut DmaCtrlImpl(self.channel.reborrow()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write elements from the ring buffer
|
/// Write elements from the ring buffer
|
||||||
/// Return a tuple of the length written and the length remaining in the buffer
|
/// Return a tuple of the length written and the length remaining in the buffer
|
||||||
pub fn write(&mut self, buf: &[W]) -> Result<(usize, usize), OverrunError> {
|
pub fn write(&mut self, buf: &[W]) -> Result<(usize, usize), OverrunError> {
|
||||||
self.ringbuf.write(DmaCtrlImpl(self.channel.reborrow()), buf)
|
self.ringbuf.write(&mut DmaCtrlImpl(self.channel.reborrow()), buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write an exact number of elements to the ringbuffer.
|
/// Write an exact number of elements to the ringbuffer.
|
||||||
pub async fn write_exact(&mut self, buffer: &[W]) -> Result<usize, OverrunError> {
|
pub async fn write_exact(&mut self, buffer: &[W]) -> Result<usize, OverrunError> {
|
||||||
use core::future::poll_fn;
|
self.ringbuf
|
||||||
use core::sync::atomic::compiler_fence;
|
.write_exact(&mut DmaCtrlImpl(self.channel.reborrow()), buffer)
|
||||||
|
.await
|
||||||
let mut written_data = 0;
|
|
||||||
let buffer_len = buffer.len();
|
|
||||||
|
|
||||||
poll_fn(|cx| {
|
|
||||||
self.set_waker(cx.waker());
|
|
||||||
|
|
||||||
compiler_fence(Ordering::SeqCst);
|
|
||||||
|
|
||||||
match self.write(&buffer[written_data..buffer_len]) {
|
|
||||||
Ok((len, remaining)) => {
|
|
||||||
written_data += len;
|
|
||||||
if written_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
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
#![cfg_attr(gpdma, allow(unused))]
|
#![cfg_attr(gpdma, allow(unused))]
|
||||||
|
|
||||||
|
use core::future::poll_fn;
|
||||||
use core::ops::Range;
|
use core::ops::Range;
|
||||||
use core::sync::atomic::{compiler_fence, Ordering};
|
use core::sync::atomic::{compiler_fence, Ordering};
|
||||||
|
use core::task::{Poll, Waker};
|
||||||
|
|
||||||
use super::word::Word;
|
use super::word::Word;
|
||||||
|
|
||||||
@ -49,6 +51,9 @@ pub trait DmaCtrl {
|
|||||||
|
|
||||||
/// Reset the transfer completed counter to 0 and return the value just prior to the reset.
|
/// Reset the transfer completed counter to 0 and return the value just prior to the reset.
|
||||||
fn reset_complete_count(&mut self) -> usize;
|
fn reset_complete_count(&mut self) -> usize;
|
||||||
|
|
||||||
|
/// Set the waker for a running poll_fn
|
||||||
|
fn set_waker(&mut self, waker: &Waker);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> {
|
impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> {
|
||||||
@ -57,7 +62,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, mut dma: impl DmaCtrl) {
|
pub fn clear(&mut self, dma: &mut impl DmaCtrl) {
|
||||||
self.start = 0;
|
self.start = 0;
|
||||||
dma.reset_complete_count();
|
dma.reset_complete_count();
|
||||||
}
|
}
|
||||||
@ -68,8 +73,43 @@ impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The current position of the ringbuffer
|
/// The current position of the ringbuffer
|
||||||
fn pos(&self, remaining_transfers: usize) -> usize {
|
fn pos(&self, dma: &mut impl DmaCtrl) -> usize {
|
||||||
self.cap() - remaining_transfers
|
self.cap() - dma.get_remaining_transfers()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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, dma: &mut impl DmaCtrl, buffer: &mut [W]) -> Result<usize, OverrunError> {
|
||||||
|
let mut read_data = 0;
|
||||||
|
let buffer_len = buffer.len();
|
||||||
|
|
||||||
|
poll_fn(|cx| {
|
||||||
|
dma.set_waker(cx.waker());
|
||||||
|
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
|
||||||
|
match self.read(dma, &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
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read elements from the ring buffer
|
/// Read elements from the ring buffer
|
||||||
@ -77,7 +117,7 @@ impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> {
|
|||||||
/// 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.
|
||||||
pub fn read(&mut self, mut dma: 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> {
|
||||||
/*
|
/*
|
||||||
This algorithm is optimistic: we assume we haven't overrun more than a full buffer and then check
|
This algorithm is optimistic: we assume we haven't overrun more than a full buffer and then check
|
||||||
after we've done our work to see we have. This is because on stm32, an interrupt is not guaranteed
|
after we've done our work to see we have. This is because on stm32, an interrupt is not guaranteed
|
||||||
@ -93,7 +133,7 @@ impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> {
|
|||||||
rather than the data we actually copied because it costs nothing and confirms an error condition
|
rather than the data we actually copied because it costs nothing and confirms an error condition
|
||||||
earlier.
|
earlier.
|
||||||
*/
|
*/
|
||||||
let end = self.pos(dma.get_remaining_transfers());
|
let end = self.pos(dma);
|
||||||
if self.start == end && dma.get_complete_count() == 0 {
|
if self.start == end && dma.get_complete_count() == 0 {
|
||||||
// No elements are available in the buffer
|
// No elements are available in the buffer
|
||||||
Ok((0, self.cap()))
|
Ok((0, self.cap()))
|
||||||
@ -114,8 +154,7 @@ impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> {
|
|||||||
then, get the current position of of the dma write and check
|
then, get the current position of of the dma write and check
|
||||||
if it's inside data we could have copied
|
if it's inside data we could have copied
|
||||||
*/
|
*/
|
||||||
let (pos, complete_count) =
|
let (pos, complete_count) = critical_section::with(|_| (self.pos(dma), dma.get_complete_count()));
|
||||||
critical_section::with(|_| (self.pos(dma.get_remaining_transfers()), dma.get_complete_count()));
|
|
||||||
if (pos >= self.start && pos < end) || (complete_count > 0 && pos >= end) || complete_count > 1 {
|
if (pos >= self.start && pos < end) || (complete_count > 0 && pos >= end) || complete_count > 1 {
|
||||||
Err(OverrunError)
|
Err(OverrunError)
|
||||||
} else {
|
} else {
|
||||||
@ -141,7 +180,7 @@ impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> {
|
|||||||
then, get the current position of of the dma write and check
|
then, get the current position of of the dma write and check
|
||||||
if it's inside data we could have copied
|
if it's inside data we could have copied
|
||||||
*/
|
*/
|
||||||
let pos = self.pos(dma.get_remaining_transfers());
|
let pos = self.pos(dma);
|
||||||
if pos > self.start || pos < end || dma.get_complete_count() > 1 {
|
if pos > self.start || pos < end || dma.get_complete_count() > 1 {
|
||||||
Err(OverrunError)
|
Err(OverrunError)
|
||||||
} else {
|
} else {
|
||||||
@ -169,7 +208,7 @@ impl<'a, W: Word> ReadableDmaRingBuffer<'a, W> {
|
|||||||
then, get the current position of of the dma write and check
|
then, get the current position of of the dma write and check
|
||||||
if it's inside data we could have copied
|
if it's inside data we could have copied
|
||||||
*/
|
*/
|
||||||
let pos = self.pos(dma.get_remaining_transfers());
|
let pos = self.pos(dma);
|
||||||
if pos > self.start || pos < end || dma.reset_complete_count() > 1 {
|
if pos > self.start || pos < end || dma.reset_complete_count() > 1 {
|
||||||
Err(OverrunError)
|
Err(OverrunError)
|
||||||
} else {
|
} else {
|
||||||
@ -209,7 +248,7 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Reset the ring buffer to its initial state
|
/// Reset the ring buffer to its initial state
|
||||||
pub fn clear(&mut self, mut dma: impl DmaCtrl) {
|
pub fn clear(&mut self, dma: &mut impl DmaCtrl) {
|
||||||
self.end = 0;
|
self.end = 0;
|
||||||
dma.reset_complete_count();
|
dma.reset_complete_count();
|
||||||
}
|
}
|
||||||
@ -220,14 +259,39 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The current position of the ringbuffer
|
/// The current position of the ringbuffer
|
||||||
fn pos(&self, remaining_transfers: usize) -> usize {
|
fn pos(&self, dma: &mut impl DmaCtrl) -> usize {
|
||||||
self.cap() - remaining_transfers
|
self.cap() - dma.get_remaining_transfers()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Write an exact number of elements to the ringbuffer.
|
||||||
|
pub async fn write_exact(&mut self, dma: &mut impl DmaCtrl, buffer: &[W]) -> Result<usize, OverrunError> {
|
||||||
|
let mut written_data = 0;
|
||||||
|
let buffer_len = buffer.len();
|
||||||
|
|
||||||
|
poll_fn(|cx| {
|
||||||
|
dma.set_waker(cx.waker());
|
||||||
|
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
|
||||||
|
match self.write(dma, &buffer[written_data..buffer_len]) {
|
||||||
|
Ok((len, remaining)) => {
|
||||||
|
written_data += len;
|
||||||
|
if written_data == buffer_len {
|
||||||
|
Poll::Ready(Ok(remaining))
|
||||||
|
} else {
|
||||||
|
Poll::Pending
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => Poll::Ready(Err(e)),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write elements from the ring buffer
|
/// Write elements from the ring buffer
|
||||||
/// Return a tuple of the length written and the capacity remaining to be written in the buffer
|
/// Return a tuple of the length written and the capacity remaining to be written in the buffer
|
||||||
pub fn write(&mut self, mut dma: impl DmaCtrl, buf: &[W]) -> Result<(usize, usize), OverrunError> {
|
pub fn write(&mut self, dma: &mut impl DmaCtrl, buf: &[W]) -> Result<(usize, usize), OverrunError> {
|
||||||
let start = self.pos(dma.get_remaining_transfers());
|
let start = self.pos(dma);
|
||||||
if start > self.end {
|
if start > self.end {
|
||||||
// The occupied portion in the ring buffer DOES wrap
|
// The occupied portion in the ring buffer DOES wrap
|
||||||
let len = self.copy_from(buf, self.end..start);
|
let len = self.copy_from(buf, self.end..start);
|
||||||
@ -235,8 +299,7 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> {
|
|||||||
compiler_fence(Ordering::SeqCst);
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
|
||||||
// Confirm that the DMA is not inside data we could have written
|
// Confirm that the DMA is not inside data we could have written
|
||||||
let (pos, complete_count) =
|
let (pos, complete_count) = critical_section::with(|_| (self.pos(dma), dma.get_complete_count()));
|
||||||
critical_section::with(|_| (self.pos(dma.get_remaining_transfers()), dma.get_complete_count()));
|
|
||||||
if (pos >= self.end && pos < start) || (complete_count > 0 && pos >= start) || complete_count > 1 {
|
if (pos >= self.end && pos < start) || (complete_count > 0 && pos >= start) || complete_count > 1 {
|
||||||
Err(OverrunError)
|
Err(OverrunError)
|
||||||
} else {
|
} else {
|
||||||
@ -256,7 +319,7 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> {
|
|||||||
compiler_fence(Ordering::SeqCst);
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
|
||||||
// Confirm that the DMA is not inside data we could have written
|
// Confirm that the DMA is not inside data we could have written
|
||||||
let pos = self.pos(dma.get_remaining_transfers());
|
let pos = self.pos(dma);
|
||||||
if pos > self.end || pos < start || dma.get_complete_count() > 1 {
|
if pos > self.end || pos < start || dma.get_complete_count() > 1 {
|
||||||
Err(OverrunError)
|
Err(OverrunError)
|
||||||
} else {
|
} else {
|
||||||
@ -274,7 +337,7 @@ impl<'a, W: Word> WritableDmaRingBuffer<'a, W> {
|
|||||||
compiler_fence(Ordering::SeqCst);
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
|
||||||
// Confirm that the DMA is not inside data we could have written
|
// Confirm that the DMA is not inside data we could have written
|
||||||
let pos = self.pos(dma.get_remaining_transfers());
|
let pos = self.pos(dma);
|
||||||
if pos > self.end || pos < start || dma.reset_complete_count() > 1 {
|
if pos > self.end || pos < start || dma.reset_complete_count() > 1 {
|
||||||
Err(OverrunError)
|
Err(OverrunError)
|
||||||
} else {
|
} else {
|
||||||
@ -323,7 +386,7 @@ mod tests {
|
|||||||
requests: cell::RefCell<vec::Vec<TestCircularTransferRequest>>,
|
requests: cell::RefCell<vec::Vec<TestCircularTransferRequest>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DmaCtrl for &mut TestCircularTransfer {
|
impl DmaCtrl for TestCircularTransfer {
|
||||||
fn get_remaining_transfers(&self) -> usize {
|
fn get_remaining_transfers(&self) -> usize {
|
||||||
match self.requests.borrow_mut().pop().unwrap() {
|
match self.requests.borrow_mut().pop().unwrap() {
|
||||||
TestCircularTransferRequest::PositionRequest(pos) => {
|
TestCircularTransferRequest::PositionRequest(pos) => {
|
||||||
@ -350,6 +413,8 @@ mod tests {
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_waker(&mut self, waker: &Waker) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TestCircularTransfer {
|
impl TestCircularTransfer {
|
||||||
|
Loading…
Reference in New Issue
Block a user