1#![expect(unsafe_code)]
4
5use portable_atomic::{AtomicBool, Ordering};
6
7use ariel_os_embassy_common::{impl_async_uart_for_driver_enum, uart::ConfigError};
8
9use embassy_rp::{
10 bind_interrupts, peripherals,
11 uart::{BufferedInterruptHandler, BufferedUart, RxPin, TxPin},
12};
13
14#[derive(Debug, Copy, Clone, PartialEq, Eq)]
16#[cfg_attr(feature = "defmt", derive(defmt::Format))]
17#[non_exhaustive]
18pub struct Config {
19 pub baudrate: ariel_os_embassy_common::uart::Baudrate<Baudrate>,
21 pub data_bits: DataBits,
23 pub stop_bits: StopBits,
25 pub parity: Parity,
27}
28
29impl Default for Config {
30 fn default() -> Self {
31 Self {
32 baudrate: ariel_os_embassy_common::uart::Baudrate::_115200,
33 data_bits: DataBits::Data8,
34 stop_bits: StopBits::Stop1,
35 parity: Parity::None,
36 }
37 }
38}
39
40#[derive(Debug, Copy, Clone, PartialEq, Eq)]
42#[cfg_attr(feature = "defmt", derive(defmt::Format))]
43pub struct Baudrate {
44 baud: u32,
46}
47
48impl From<Baudrate> for u32 {
49 fn from(baud: Baudrate) -> u32 {
50 baud.baud
51 }
52}
53
54impl From<u32> for Baudrate {
55 fn from(baudrate: u32) -> Baudrate {
56 Baudrate { baud: baudrate }
57 }
58}
59
60impl From<ariel_os_embassy_common::uart::Baudrate<Self>> for Baudrate {
61 fn from(baud: ariel_os_embassy_common::uart::Baudrate<Self>) -> Baudrate {
62 match baud {
63 ariel_os_embassy_common::uart::Baudrate::Hal(baud) => baud,
64 ariel_os_embassy_common::uart::Baudrate::_2400 => Baudrate { baud: 2400 },
65 ariel_os_embassy_common::uart::Baudrate::_4800 => Baudrate { baud: 4800 },
66 ariel_os_embassy_common::uart::Baudrate::_9600 => Baudrate { baud: 9600 },
67 ariel_os_embassy_common::uart::Baudrate::_19200 => Baudrate { baud: 19_200 },
68 ariel_os_embassy_common::uart::Baudrate::_38400 => Baudrate { baud: 38_400 },
69 ariel_os_embassy_common::uart::Baudrate::_57600 => Baudrate { baud: 57_600 },
70 ariel_os_embassy_common::uart::Baudrate::_115200 => Baudrate { baud: 115_200 },
71 }
72 }
73}
74
75#[derive(Debug, Copy, Clone, PartialEq, Eq)]
77#[cfg_attr(feature = "defmt", derive(defmt::Format))]
78pub enum DataBits {
79 Data5,
81 Data6,
83 Data7,
85 Data8,
87}
88
89fn from_data_bits(databits: DataBits) -> embassy_rp::uart::DataBits {
90 match databits {
91 DataBits::Data5 => embassy_rp::uart::DataBits::DataBits5,
92 DataBits::Data6 => embassy_rp::uart::DataBits::DataBits6,
93 DataBits::Data7 => embassy_rp::uart::DataBits::DataBits7,
94 DataBits::Data8 => embassy_rp::uart::DataBits::DataBits8,
95 }
96}
97
98impl From<ariel_os_embassy_common::uart::DataBits<Self>> for DataBits {
99 fn from(databits: ariel_os_embassy_common::uart::DataBits<Self>) -> DataBits {
100 match databits {
101 ariel_os_embassy_common::uart::DataBits::Hal(bits) => bits,
102 ariel_os_embassy_common::uart::DataBits::Data8 => DataBits::Data8,
103 }
104 }
105}
106
107#[derive(Debug, Copy, Clone, PartialEq, Eq)]
109#[cfg_attr(feature = "defmt", derive(defmt::Format))]
110pub enum Parity {
111 None,
113 Even,
115 Odd,
117}
118
119fn from_parity(parity: Parity) -> embassy_rp::uart::Parity {
120 match parity {
121 Parity::None => embassy_rp::uart::Parity::ParityNone,
122 Parity::Even => embassy_rp::uart::Parity::ParityEven,
123 Parity::Odd => embassy_rp::uart::Parity::ParityOdd,
124 }
125}
126
127impl From<ariel_os_embassy_common::uart::Parity<Self>> for Parity {
128 fn from(parity: ariel_os_embassy_common::uart::Parity<Self>) -> Self {
129 match parity {
130 ariel_os_embassy_common::uart::Parity::Hal(parity) => parity,
131 ariel_os_embassy_common::uart::Parity::None => Self::None,
132 ariel_os_embassy_common::uart::Parity::Even => Self::Even,
133 }
134 }
135}
136
137#[derive(Debug, Copy, Clone, PartialEq, Eq)]
139#[cfg_attr(feature = "defmt", derive(defmt::Format))]
140pub enum StopBits {
141 Stop1,
143 Stop2,
145}
146
147fn from_stop_bits(stop_bits: StopBits) -> embassy_rp::uart::StopBits {
148 match stop_bits {
149 StopBits::Stop1 => embassy_rp::uart::StopBits::STOP1,
150 StopBits::Stop2 => embassy_rp::uart::StopBits::STOP2,
151 }
152}
153
154impl From<ariel_os_embassy_common::uart::StopBits<Self>> for StopBits {
155 fn from(stopbits: ariel_os_embassy_common::uart::StopBits<Self>) -> Self {
156 match stopbits {
157 ariel_os_embassy_common::uart::StopBits::Hal(stopbits) => stopbits,
158 ariel_os_embassy_common::uart::StopBits::Stop1 => StopBits::Stop1,
159 }
160 }
161}
162
163macro_rules! define_uart_drivers {
164 ($( $interrupt:ident => $peripheral:ident ),* $(,)?) => {
165 $(
166 pub struct $peripheral<'d> {
168 uart: BufferedUart,
169 _phantom: core::marker::PhantomData<&'d ()>
173 }
174
175 paste::paste! {
178 #[allow(dead_code)]
179 static [<PREVENT_MULTIPLE_ $peripheral>]: () = ();
180 }
181
182 paste::paste! {
184 static [< ACTIVE_ $peripheral >]: AtomicBool = AtomicBool::new(false);
185 }
186
187 impl<'d> $peripheral<'d> {
188 #[expect(clippy::new_ret_no_self)]
195 pub fn new<RX: RxPin<peripherals::$peripheral>, TX: TxPin<peripherals::$peripheral>>(
196 rx_pin: impl $crate::IntoPeripheral<'d, RX>,
197 tx_pin: impl $crate::IntoPeripheral<'d, TX>,
198 rx_buf: &mut [u8],
199 tx_buf: &mut [u8],
200 config: Config,
201 ) -> Result<Uart<'d>, ConfigError> {
202 let mut uart_config = embassy_rp::uart::Config::default();
203 uart_config.baudrate = Baudrate::from(config.baudrate).into();
204 uart_config.data_bits = from_data_bits(config.data_bits);
205 uart_config.stop_bits = from_stop_bits(config.stop_bits);
206 uart_config.parity = from_parity(config.parity);
207 bind_interrupts!(struct Irqs {
208 $interrupt => BufferedInterruptHandler<peripherals::$peripheral>;
209 });
210
211 paste::paste! {
213 if [< ACTIVE_ $peripheral >].swap(true, Ordering::AcqRel) {
214 panic!("UART peripheral already initialized")
215 }
216 }
217
218 let uart_peripheral = unsafe { peripherals::$peripheral::steal() };
222
223 let uart = BufferedUart::new(
224 uart_peripheral,
225 tx_pin.into_hal_peripheral(),
227 rx_pin.into_hal_peripheral(),
228 Irqs,
229 tx_buf,
230 rx_buf,
231 uart_config,
232 );
233
234 Ok(Uart::$peripheral(Self { uart, _phantom: core::marker::PhantomData }))
235 }
236 }
237
238 impl<'d> Drop for $peripheral<'d> {
239 fn drop(&mut self) {
240 paste::paste! {
241 [< ACTIVE_ $peripheral >].store(false, Ordering::Release);
242 }
243 }
244 }
245 )*
246
247 pub enum Uart<'d> {
249 $(
250 #[doc = concat!(stringify!($peripheral), " peripheral.")]
251 $peripheral($peripheral<'d>)
252 ),*
253 }
254
255 impl embedded_io_async::ErrorType for Uart<'_> {
256 type Error = embassy_rp::uart::Error;
257 }
258
259 impl_async_uart_for_driver_enum!(Uart, $( $peripheral ),*);
260 }
261}
262
263define_uart_drivers!(
264 UART0_IRQ => UART0,
265 UART1_IRQ => UART1,
266);
267
268#[doc(hidden)]
269pub fn init(peripherals: &mut crate::OptionalPeripherals) {
270 cfg_select! {
272 any(context = "rp2040", context = "rp235xa") => {
273 let _ = peripherals.UART0.take().unwrap();
274 let _ = peripherals.UART1.take().unwrap();
275 }
276 _ => {
277 compile_error!("this RP chip is not supported");
278 }
279 }
280}