use super::*;
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub(crate) struct ScopedDmaTxBuf<'a> {
descriptors: DescriptorSet<'a>,
buffer: DmaAlignedMut<'a, [u8]>,
burst: BurstConfig,
}
impl<'a> ScopedDmaTxBuf<'a> {
pub fn new(
descriptors: DmaAlignedMut<'a, [DmaDescriptor]>,
buffer: DmaAlignedMut<'a, [u8]>,
) -> Result<Self, DmaBufError> {
Self::new_with_config(descriptors, buffer, BurstConfig::default())
}
pub fn new_with_config(
descriptors: DmaAlignedMut<'a, [DmaDescriptor]>,
buffer: DmaAlignedMut<'a, [u8]>,
config: impl Into<BurstConfig>,
) -> Result<Self, DmaBufError> {
let mut buf = Self {
descriptors: DescriptorSet::new(descriptors)?,
buffer,
burst: BurstConfig::default(),
};
let capacity = buf.capacity();
buf.configure(config, capacity)?;
Ok(buf)
}
fn configure(
&mut self,
burst: impl Into<BurstConfig>,
length: usize,
) -> Result<(), DmaBufError> {
let burst = burst.into();
self.set_length_fallible(length, burst)?;
let max_chunk_size = burst.max_chunk_size_for(&self.buffer, TransferDirection::Out);
self.descriptors
.link_with_buffer(&mut self.buffer, max_chunk_size)?;
self.burst = burst;
Ok(())
}
pub fn set_burst_config(&mut self, burst: BurstConfig) -> Result<(), DmaBufError> {
let len = self.len();
self.configure(burst, len)
}
pub fn split(self) -> (DmaAlignedMut<'a, [DmaDescriptor]>, DmaAlignedMut<'a, [u8]>) {
(self.descriptors.descriptors, self.buffer)
}
pub fn capacity(&self) -> usize {
self.buffer.len()
}
#[allow(clippy::len_without_is_empty)]
pub fn len(&self) -> usize {
self.descriptors
.linked_iter()
.map(|d| d.len())
.sum::<usize>()
}
fn set_length_fallible(&mut self, len: usize, burst: BurstConfig) -> Result<(), DmaBufError> {
if len > self.capacity() {
return Err(DmaBufError::BufferTooSmall);
}
burst.ensure_buffer_compatible(&self.buffer[..len], TransferDirection::Out)?;
let max_chunk_size = burst.max_chunk_size_for(&self.buffer, TransferDirection::Out);
self.descriptors.set_tx_length(len, max_chunk_size)?;
for desc in self.descriptors.linked_iter_mut() {
desc.reset_for_tx(desc.next.is_null());
}
Ok(())
}
pub fn set_length(&mut self, len: usize) {
unwrap!(self.set_length_fallible(len, self.burst))
}
pub fn fill(&mut self, data: &[u8]) {
self.set_length(data.len());
self.as_mut_slice()[..data.len()].copy_from_slice(data);
}
pub fn as_mut_slice(&mut self) -> &mut [u8] {
&mut self.buffer
}
pub fn as_slice(&self) -> &[u8] {
&self.buffer
}
}
unsafe impl<'a> DmaTxBuffer for ScopedDmaTxBuf<'a> {
type View = BufView<ScopedDmaTxBuf<'a>>;
type Final = ScopedDmaTxBuf<'a>;
fn prepare(&mut self) -> Preparation {
#[cfg(soc_internal_memory_cached)]
self.descriptors.descriptors.writeback();
#[cfg(dma_can_access_psram)]
let is_data_in_psram = !is_valid_ram_address(self.buffer.as_ptr() as usize);
#[cfg(any(soc_internal_memory_cached, dma_can_access_psram))]
self.buffer.writeback();
Preparation {
start: self.descriptors.head(),
#[cfg(dma_can_access_psram)]
accesses_psram: is_data_in_psram,
burst_transfer: self.burst,
check_owner: None,
auto_write_back: false,
}
}
fn into_view(self) -> BufView<ScopedDmaTxBuf<'a>> {
BufView(self)
}
fn from_view(view: Self::View) -> Self {
view.0
}
}
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub(crate) struct ScopedDmaRxBuf<'a> {
descriptors: DescriptorSet<'a>,
buffer: DmaAlignedMut<'a, [u8]>,
burst: BurstConfig,
}
impl<'a> ScopedDmaRxBuf<'a> {
pub fn new(
descriptors: DmaAlignedMut<'a, [DmaDescriptor]>,
buffer: DmaAlignedMut<'a, [u8]>,
) -> Result<Self, DmaBufError> {
Self::new_with_config(descriptors, buffer, BurstConfig::default())
}
pub fn new_with_config(
descriptors: DmaAlignedMut<'a, [DmaDescriptor]>,
buffer: DmaAlignedMut<'a, [u8]>,
config: impl Into<BurstConfig>,
) -> Result<Self, DmaBufError> {
let mut buf = Self {
descriptors: DescriptorSet::new(descriptors)?,
buffer,
burst: BurstConfig::default(),
};
buf.configure(config, buf.capacity())?;
Ok(buf)
}
fn configure(
&mut self,
burst: impl Into<BurstConfig>,
length: usize,
) -> Result<(), DmaBufError> {
let burst = burst.into();
self.set_length_fallible(length, burst)?;
let max_chunk_size = burst.max_chunk_size_for(&self.buffer, TransferDirection::In);
self.descriptors
.link_with_buffer(&mut self.buffer, max_chunk_size)?;
self.burst = burst;
Ok(())
}
pub fn set_burst_config(&mut self, burst: BurstConfig) -> Result<(), DmaBufError> {
let len = self.len();
self.configure(burst, len)
}
pub fn split(self) -> (DmaAlignedMut<'a, [DmaDescriptor]>, DmaAlignedMut<'a, [u8]>) {
(self.descriptors.descriptors, self.buffer)
}
pub fn capacity(&self) -> usize {
self.buffer.len()
}
#[allow(clippy::len_without_is_empty)]
pub fn len(&self) -> usize {
self.descriptors
.linked_iter()
.map(|d| d.size())
.sum::<usize>()
}
fn set_length_fallible(&mut self, len: usize, burst: BurstConfig) -> Result<(), DmaBufError> {
if len > self.capacity() {
return Err(DmaBufError::BufferTooSmall);
}
burst.ensure_buffer_compatible(&self.buffer[..len], TransferDirection::In)?;
self.descriptors.set_rx_length(
len,
burst.max_chunk_size_for(&self.buffer[..len], TransferDirection::In),
)
}
pub fn set_length(&mut self, len: usize) {
unwrap!(self.set_length_fallible(len, self.burst));
}
pub fn as_slice(&self) -> &[u8] {
&self.buffer
}
pub fn as_mut_slice(&mut self) -> &mut [u8] {
&mut self.buffer
}
pub fn number_of_received_bytes(&self) -> usize {
self.sync_received_from_dma();
self.descriptors
.linked_iter()
.map(|d| d.len())
.sum::<usize>()
}
pub fn read_received_data(&self, mut buf: &mut [u8]) -> usize {
let capacity = buf.len();
for chunk in self.received_data() {
if buf.is_empty() {
break;
}
let to_fill;
(to_fill, buf) = buf.split_at_mut(chunk.len());
to_fill.copy_from_slice(chunk);
}
capacity - buf.len()
}
pub fn received_data(&self) -> impl Iterator<Item = &[u8]> {
self.sync_received_from_dma();
self.descriptors.linked_iter().map(|desc| {
unsafe { core::slice::from_raw_parts(desc.buffer.cast_const(), desc.len()) }
})
}
fn sync_received_from_dma(&self) {
#[cfg(any(soc_internal_memory_cached, dma_can_access_psram))]
{
let descriptors = &*self.descriptors.descriptors;
unsafe {
crate::soc::cache_invalidate_addr(
descriptors.as_ptr() as u32,
core::mem::size_of_val(descriptors) as u32,
);
}
for desc in self.descriptors.linked_iter() {
let len = desc.len();
if len > 0 {
unsafe {
crate::soc::cache_invalidate_addr(desc.buffer as u32, len as u32);
}
}
}
}
}
}
unsafe impl<'a> DmaRxBuffer for ScopedDmaRxBuf<'a> {
type View = BufView<ScopedDmaRxBuf<'a>>;
type Final = ScopedDmaRxBuf<'a>;
fn prepare(&mut self) -> Preparation {
for desc in self.descriptors.linked_iter_mut() {
desc.reset_for_rx();
}
#[cfg(soc_internal_memory_cached)]
self.descriptors.descriptors.writeback();
#[cfg(dma_can_access_psram)]
let is_data_in_psram = !is_valid_ram_address(self.buffer.as_ptr() as usize);
#[cfg(any(soc_internal_memory_cached, dma_can_access_psram))]
self.buffer.invalidate();
Preparation {
start: self.descriptors.head(),
#[cfg(dma_can_access_psram)]
accesses_psram: is_data_in_psram,
burst_transfer: self.burst,
check_owner: None,
auto_write_back: true,
}
}
fn into_view(self) -> BufView<Self> {
BufView(self)
}
fn from_view(view: Self::View) -> Self {
view.0
}
}