1use core::{marker::PhantomData, ops::Range};
8
9use atsamd_hal_macros::hal_macro_helper;
10
11use crate::dmac::{
12    self, Beat, Buffer, Transfer, TriggerAction,
13    channel::{AnyChannel, Busy, Channel, InterruptFlags, Ready},
14    sram::DmacDescriptor,
15    transfer::BufferPair,
16};
17use crate::sercom::{
18    Sercom,
19    uart::{self, Uart},
20};
21
22#[doc(hidden)]
31pub(crate) struct SharedSliceBuffer<'a, T: Beat> {
32    ptrs: Range<*mut T>,
33    _lifetime: PhantomData<&'a T>,
34}
35
36impl<'a, T: Beat> SharedSliceBuffer<'a, T> {
37    #[inline]
38    pub(in super::super) fn from_slice(slice: &'a [T]) -> Self {
39        unsafe { Self::from_slice_unchecked(slice) }
40    }
41
42    #[inline]
43    pub(in super::super) unsafe fn from_slice_unchecked(slice: &[T]) -> Self {
44        let ptrs = slice.as_ptr_range();
45
46        let ptrs = Range {
47            start: ptrs.start.cast_mut(),
48            end: ptrs.end.cast_mut(),
49        };
50
51        Self {
52            ptrs,
53            _lifetime: PhantomData,
54        }
55    }
56}
57
58unsafe impl<T: Beat> Buffer for SharedSliceBuffer<'_, T> {
59    type Beat = T;
60    #[inline]
61    fn dma_ptr(&mut self) -> *mut Self::Beat {
62        if self.incrementing() {
63            self.ptrs.end
64        } else {
65            self.ptrs.start
66        }
67    }
68
69    #[inline]
70    fn incrementing(&self) -> bool {
71        self.buffer_len() > 1
72    }
73
74    #[inline]
75    fn buffer_len(&self) -> usize {
76        self.ptrs.end as usize - self.ptrs.start as usize
77    }
78}
79
80pub(super) struct SinkSourceBuffer<'a, T: Beat> {
90    word: &'a mut T,
91    length: usize,
92}
93
94impl<'a, T: Beat> SinkSourceBuffer<'a, T> {
95    pub(super) fn new(word: &'a mut T, length: usize) -> Self {
96        Self { word, length }
97    }
98}
99unsafe impl<T: Beat> Buffer for SinkSourceBuffer<'_, T> {
100    type Beat = T;
101    #[inline]
102    fn incrementing(&self) -> bool {
103        false
104    }
105
106    #[inline]
107    fn buffer_len(&self) -> usize {
108        self.length
109    }
110
111    #[inline]
112    fn dma_ptr(&mut self) -> *mut Self::Beat {
113        self.word as *mut _
114    }
115}
116#[doc(hidden)]
120#[derive(Clone)]
121pub(crate) struct SercomPtr<T: Beat>(pub(in super::super) *mut T);
122
123unsafe impl<T: Beat> Buffer for SercomPtr<T> {
124    type Beat = T;
125
126    #[inline]
127    fn dma_ptr(&mut self) -> *mut Self::Beat {
128        self.0
129    }
130
131    #[inline]
132    fn incrementing(&self) -> bool {
133        false
134    }
135
136    #[inline]
137    fn buffer_len(&self) -> usize {
138        1
139    }
140}
141
142unsafe impl<C, D> Buffer for Uart<C, D>
146where
147    C: uart::ValidConfig,
148    C::Word: Beat,
149    D: uart::Capability,
150{
151    type Beat = C::Word;
152
153    #[inline]
154    fn dma_ptr(&mut self) -> *mut Self::Beat {
155        self.data_ptr()
156    }
157
158    #[inline]
159    fn incrementing(&self) -> bool {
160        false
161    }
162
163    #[inline]
164    fn buffer_len(&self) -> usize {
165        1
166    }
167}
168
169impl<C, D> Uart<C, D>
170where
171    Self: Buffer<Beat = C::Word>,
172    C: uart::ValidConfig,
173    D: uart::Receive,
174{
175    #[inline]
184    #[hal_macro_helper]
185    pub fn receive_with_dma<Ch, B>(
186        self,
187        buf: B,
188        mut channel: Ch,
189    ) -> Transfer<Channel<Ch::Id, Busy>, BufferPair<Self, B>>
190    where
191        Ch: AnyChannel<Status = Ready>,
192        B: Buffer<Beat = C::Word> + 'static,
193    {
194        channel
195            .as_mut()
196            .enable_interrupts(InterruptFlags::new().with_tcmpl(true));
197
198        #[hal_cfg("sercom0-d5x")]
199        let trigger_action = TriggerAction::Burst;
200
201        #[hal_cfg(any("sercom0-d11", "sercom0-d21"))]
202        let trigger_action = TriggerAction::Beat;
203
204        let xfer = unsafe { dmac::Transfer::new_unchecked(channel, self, buf, false) };
207        xfer.begin(C::Sercom::DMA_RX_TRIGGER, trigger_action)
208    }
209}
210
211impl<C, D> Uart<C, D>
212where
213    Self: Buffer<Beat = C::Word>,
214    C: uart::ValidConfig,
215    D: uart::Transmit,
216{
217    #[inline]
226    #[hal_macro_helper]
227    pub fn send_with_dma<Ch, B>(
228        self,
229        buf: B,
230        mut channel: Ch,
231    ) -> Transfer<Channel<Ch::Id, Busy>, BufferPair<B, Self>>
232    where
233        Ch: AnyChannel<Status = Ready>,
234        B: Buffer<Beat = C::Word> + 'static,
235    {
236        channel
237            .as_mut()
238            .enable_interrupts(InterruptFlags::new().with_tcmpl(true));
239
240        #[hal_cfg("sercom0-d5x")]
241        let trigger_action = TriggerAction::Burst;
242
243        #[hal_cfg(any("sercom0-d11", "sercom0-d21"))]
244        let trigger_action = TriggerAction::Beat;
245
246        let xfer = unsafe { dmac::Transfer::new_unchecked(channel, buf, self, false) };
249        xfer.begin(C::Sercom::DMA_TX_TRIGGER, trigger_action)
250    }
251}
252
253#[hal_macro_helper]
260pub(super) unsafe fn read_dma<T, B, S>(
261    channel: &mut impl AnyChannel<Status = Ready>,
262    sercom_ptr: SercomPtr<T>,
263    buf: &mut B,
264) where
265    T: Beat,
266    B: Buffer<Beat = T>,
267    S: Sercom,
268{
269    unsafe {
270        read_dma_linked::<_, _, S>(channel, sercom_ptr, buf, None);
271    }
272}
273
274#[hal_macro_helper]
282pub(super) unsafe fn read_dma_linked<T, B, S>(
283    channel: &mut impl AnyChannel<Status = Ready>,
284    mut sercom_ptr: SercomPtr<T>,
285    buf: &mut B,
286    next: Option<&mut DmacDescriptor>,
287) where
288    T: Beat,
289    B: Buffer<Beat = T>,
290    S: Sercom,
291{
292    #[hal_cfg("dmac-d5x")]
293    let trigger_action = TriggerAction::Burst;
294
295    #[hal_cfg(any("dmac-d11", "dmac-d21"))]
296    let trigger_action = TriggerAction::Beat;
297
298    unsafe {
301        channel.as_mut().transfer_unchecked(
302            &mut sercom_ptr,
303            buf,
304            S::DMA_RX_TRIGGER,
305            trigger_action,
306            next,
307        );
308    }
309}
310
311#[hal_macro_helper]
318pub(super) unsafe fn write_dma<T, B, S>(
319    channel: &mut impl AnyChannel<Status = Ready>,
320    sercom_ptr: SercomPtr<T>,
321    buf: &mut B,
322) where
323    T: Beat,
324    B: Buffer<Beat = T>,
325    S: Sercom,
326{
327    unsafe {
328        write_dma_linked::<_, _, S>(channel, sercom_ptr, buf, None);
329    }
330}
331
332#[hal_macro_helper]
340pub(super) unsafe fn write_dma_linked<T, B, S>(
341    channel: &mut impl AnyChannel<Status = Ready>,
342    mut sercom_ptr: SercomPtr<T>,
343    buf: &mut B,
344    next: Option<&mut DmacDescriptor>,
345) where
346    T: Beat,
347    B: Buffer<Beat = T>,
348    S: Sercom,
349{
350    #[hal_cfg("dmac-d5x")]
351    let trigger_action = TriggerAction::Burst;
352
353    #[hal_cfg(any("dmac-d11", "dmac-d21"))]
354    let trigger_action = TriggerAction::Beat;
355
356    unsafe {
359        channel.as_mut().transfer_unchecked(
360            buf,
361            &mut sercom_ptr,
362            S::DMA_TX_TRIGGER,
363            trigger_action,
364            next,
365        );
366    }
367}
368
369#[cfg(feature = "async")]
375pub(crate) mod async_dma {
376    use dmac::{Error, ReadyFuture};
377
378    use super::*;
379
380    #[inline]
382    pub(in super::super) async fn read_dma<T, B, S>(
383        channel: &mut impl AnyChannel<Status = ReadyFuture>,
384        sercom_ptr: SercomPtr<T>,
385        buf: &mut B,
386    ) -> Result<(), Error>
387    where
388        B: Buffer<Beat = T>,
389        T: Beat,
390        S: Sercom,
391    {
392        unsafe { read_dma_linked::<_, _, S>(channel, sercom_ptr, buf, None).await }
393    }
394
395    #[inline]
404    #[hal_macro_helper]
405    pub(in super::super) async unsafe fn read_dma_linked<T, B, S>(
406        channel: &mut impl AnyChannel<Status = ReadyFuture>,
407        mut sercom_ptr: SercomPtr<T>,
408        buf: &mut B,
409        next: Option<&mut DmacDescriptor>,
410    ) -> Result<(), Error>
411    where
412        T: Beat,
413        B: Buffer<Beat = T>,
414        S: Sercom,
415    {
416        #[hal_cfg("dmac-d5x")]
417        let trigger_action = TriggerAction::Burst;
418
419        #[hal_cfg(any("dmac-d11", "dmac-d21"))]
420        let trigger_action = TriggerAction::Beat;
421
422        unsafe {
425            channel
426                .as_mut()
427                .transfer_future_linked(
428                    &mut sercom_ptr,
429                    buf,
430                    S::DMA_RX_TRIGGER,
431                    trigger_action,
432                    next,
433                )
434                .await
435        }
436    }
437
438    #[inline]
440    pub(in super::super) async fn write_dma<T, B, S>(
441        channel: &mut impl AnyChannel<Status = ReadyFuture>,
442        sercom_ptr: SercomPtr<T>,
443        buf: &mut B,
444    ) -> Result<(), Error>
445    where
446        B: Buffer<Beat = T>,
447        T: Beat,
448        S: Sercom,
449    {
450        unsafe { write_dma_linked::<_, _, S>(channel, sercom_ptr, buf, None).await }
451    }
452
453    #[inline]
462    #[hal_macro_helper]
463    pub(in super::super) async unsafe fn write_dma_linked<T, B, S>(
464        channel: &mut impl AnyChannel<Status = ReadyFuture>,
465        mut sercom_ptr: SercomPtr<T>,
466        buf: &mut B,
467        next: Option<&mut DmacDescriptor>,
468    ) -> Result<(), Error>
469    where
470        B: Buffer<Beat = T>,
471        T: Beat,
472        S: Sercom,
473    {
474        #[hal_cfg("dmac-d5x")]
475        let trigger_action = TriggerAction::Burst;
476
477        #[hal_cfg(any("dmac-d11", "dmac-d21"))]
478        let trigger_action = TriggerAction::Beat;
479
480        unsafe {
483            channel
484                .as_mut()
485                .transfer_future_linked(
486                    buf,
487                    &mut sercom_ptr,
488                    S::DMA_TX_TRIGGER,
489                    trigger_action,
490                    next,
491                )
492                .await
493        }
494    }
495}