stm32f1_hal/common/uart/
uart_dma.rs

1use super::*;
2use crate::{
3    Steal,
4    common::{
5        dma::*,
6        embedded_io::{ErrorType, Read, Write},
7    },
8};
9
10// TX -------------------------------------------------------------------------
11
12pub struct UartDmaBufTx<U, CH, OS: OsInterface> {
13    _uart: U,
14    w: DmaRingbufTxWriter<u8, CH>,
15    timeout: MicrosDurationU32,
16    flush_timeout: MicrosDurationU32,
17    waiter: OS::NotifyWaiter,
18}
19
20impl<U, CH, OS> UartDmaBufTx<U, CH, OS>
21where
22    U: UartPeriphWithDma,
23    CH: DmaChannel,
24    OS: OsInterface,
25{
26    pub fn new(
27        mut uart: U,
28        dma_ch: CH,
29        buf_size: usize,
30        baudrate: u32,
31        timeout: MicrosDurationU32,
32    ) -> (Self, DmaRingbufTxLoader<u8, CH, OS>) {
33        let (notifier, waiter) = OS::notify();
34
35        uart.enable_dma_tx(true);
36        let (w, l) = DmaRingbufTx::new(dma_ch, uart.get_tx_data_reg_addr(), buf_size, notifier);
37        (
38            Self {
39                _uart: uart,
40                w,
41                timeout,
42                flush_timeout: calculate_timeout(baudrate, buf_size + 10),
43                waiter,
44            },
45            l,
46        )
47    }
48}
49
50impl<U, CH, OS> ErrorType for UartDmaBufTx<U, CH, OS>
51where
52    OS: OsInterface,
53{
54    type Error = Error;
55}
56
57impl<U, CH, OS> Write for UartDmaBufTx<U, CH, OS>
58where
59    CH: DmaChannel,
60    OS: OsInterface,
61{
62    #[inline(always)]
63    fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
64        if buf.is_empty() {
65            return Err(Error::Other);
66        }
67
68        self.waiter
69            .wait_with(OS::O, self.timeout, 2, || {
70                if let n @ 1.. = self.w.write(buf) {
71                    Some(n)
72                } else {
73                    None
74                }
75            })
76            .ok_or(Error::Busy)
77    }
78
79    fn flush(&mut self) -> Result<(), Self::Error> {
80        self.waiter
81            .wait_with(OS::O, self.flush_timeout, 4, || {
82                if !self.w.in_progress() {
83                    Some(())
84                } else {
85                    None
86                }
87            })
88            .ok_or(Error::Other)
89    }
90}
91
92// RX -------------------------------------------------------------------------
93
94pub struct UartDmaRx<U, CH, OS: OsInterface> {
95    _uart: U,
96    ch: DmaCircularBufferRx<u8, CH>,
97    timeout: MicrosDurationU32,
98    waiter: OS::NotifyWaiter,
99}
100
101impl<U, CH, OS> UartDmaRx<U, CH, OS>
102where
103    U: UartPeriphWithDma,
104    CH: DmaChannel + Steal,
105    OS: OsInterface,
106{
107    pub fn new(
108        mut uart: U,
109        mut dma_ch: CH,
110        buf_size: usize,
111        timeout: MicrosDurationU32,
112    ) -> (Self, UartDmaRxNotify<CH, OS>) {
113        let (notifier, waiter) = OS::notify();
114        let dma_ch2 = unsafe { dma_ch.steal() };
115        let ch = DmaCircularBufferRx::<u8, CH>::new(dma_ch2, uart.get_rx_data_reg_addr(), buf_size);
116        uart.enable_dma_rx(true);
117        dma_ch.set_interrupt(DmaEvent::HalfTransfer, true);
118        dma_ch.set_interrupt(DmaEvent::TransferComplete, true);
119        (
120            Self {
121                _uart: uart,
122                ch,
123                timeout,
124                waiter,
125            },
126            UartDmaRxNotify {
127                notifier,
128                ch: dma_ch,
129            },
130        )
131    }
132}
133
134impl<U, CH, OS> ErrorType for UartDmaRx<U, CH, OS>
135where
136    OS: OsInterface,
137{
138    type Error = Error;
139}
140
141impl<U, CH, OS> Read for UartDmaRx<U, CH, OS>
142where
143    CH: DmaChannel,
144    OS: OsInterface,
145{
146    fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
147        if buf.is_empty() {
148            return Err(Error::Other);
149        }
150
151        self.waiter
152            .wait_with(OS::O, self.timeout, 2, || {
153                if let Some(d) = self.ch.pop_slice(buf.len()) {
154                    buf[..d.len()].copy_from_slice(d);
155                    Some(d.len())
156                } else {
157                    None
158                }
159            })
160            .ok_or(Error::Other)
161    }
162}
163
164pub struct UartDmaRxNotify<CH, OS: OsInterface> {
165    notifier: OS::Notifier,
166    ch: CH,
167}
168
169impl<CH, OS> UartDmaRxNotify<CH, OS>
170where
171    CH: DmaChannel,
172    OS: OsInterface,
173{
174    pub fn interrupt_notify(&mut self) {
175        if self.ch.is_interrupted(DmaEvent::HalfTransfer)
176            || self.ch.is_interrupted(DmaEvent::TransferComplete)
177        {
178            self.notifier.notify();
179        }
180    }
181}