use crate::{resets::SubsystemReset, typelevel::Sealed};
use core::marker::PhantomData;
use embedded_dma::{ReadBuffer, WriteBuffer};
use rp2040_pac::DMA;
pub mod bidirectional;
pub mod double_buffer;
pub mod single_buffer;
mod single_channel;
pub use crate::dma::single_channel::SingleChannel;
pub trait DMAExt: Sealed {
fn split(self, resets: &mut pac::RESETS) -> Channels;
fn dyn_split(self, resets: &mut pac::RESETS) -> DynChannels;
}
pub struct Channel<CH: ChannelIndex> {
_phantom: PhantomData<CH>,
}
pub trait ChannelIndex: Sealed {
fn id() -> u8;
}
macro_rules! channels {
(
$($CHX:ident: ($chX:ident, $x:expr),)+
) => {
impl DMAExt for DMA {
fn split(self, resets: &mut pac::RESETS) -> Channels {
self.reset_bring_down(resets);
self.reset_bring_up(resets);
Channels {
$(
$chX: Channel {
_phantom: PhantomData,
},
)+
}
}
fn dyn_split(self, resets: &mut pac::RESETS) -> DynChannels{
self.reset_bring_down(resets);
self.reset_bring_up(resets);
DynChannels {
$(
$chX: Some(Channel {
_phantom: PhantomData,
}),
)+
}
}
}
impl Sealed for DMA {}
pub struct Channels {
$(
pub $chX: Channel<$CHX>,
)+
}
$(
pub struct $CHX;
impl ChannelIndex for $CHX {
fn id() -> u8 {
$x
}
}
impl Sealed for $CHX {}
)+
pub struct DynChannels {
$(
pub $chX: Option<Channel<$CHX>>,
)+
}
}
}
channels! {
CH0: (ch0, 0),
CH1: (ch1, 1),
CH2: (ch2, 2),
CH3: (ch3, 3),
CH4: (ch4, 4),
CH5: (ch5, 5),
CH6: (ch6, 6),
CH7: (ch7, 7),
CH8: (ch8, 8),
CH9: (ch9, 9),
CH10:(ch10, 10),
CH11:(ch11, 11),
}
trait ChannelRegs {
unsafe fn ptr() -> *const rp2040_pac::dma::CH;
fn regs(&self) -> &rp2040_pac::dma::CH;
}
impl<CH: ChannelIndex> ChannelRegs for Channel<CH> {
unsafe fn ptr() -> *const rp2040_pac::dma::CH {
&(*rp2040_pac::DMA::ptr()).ch[CH::id() as usize] as *const _
}
fn regs(&self) -> &rp2040_pac::dma::CH {
unsafe { &*Self::ptr() }
}
}
pub trait ReadTarget {
type ReceivedWord;
fn rx_treq() -> Option<u8>;
fn rx_address_count(&self) -> (u32, u32);
fn rx_increment(&self) -> bool;
}
pub trait EndlessReadTarget: ReadTarget {}
impl<B: ReadBuffer> ReadTarget for B {
type ReceivedWord = <B as ReadBuffer>::Word;
fn rx_treq() -> Option<u8> {
None
}
fn rx_address_count(&self) -> (u32, u32) {
let (ptr, len) = unsafe { self.read_buffer() };
(ptr as u32, len as u32)
}
fn rx_increment(&self) -> bool {
true
}
}
pub trait WriteTarget {
type TransmittedWord;
fn tx_treq() -> Option<u8>;
fn tx_address_count(&mut self) -> (u32, u32);
fn tx_increment(&self) -> bool;
}
pub trait EndlessWriteTarget: WriteTarget {}
impl<B: WriteBuffer> WriteTarget for B {
type TransmittedWord = <B as WriteBuffer>::Word;
fn tx_treq() -> Option<u8> {
None
}
fn tx_address_count(&mut self) -> (u32, u32) {
let (ptr, len) = unsafe { self.write_buffer() };
(ptr as u32, len as u32)
}
fn tx_increment(&self) -> bool {
true
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Pace {
PreferSource,
PreferSink,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum DMAError {
Alignment,
IllegalConfig,
}