1#![expect(unsafe_code)]
4
5use ariel_os_embassy_common::{impl_async_uart_for_driver_enum, uart::ConfigError};
6
7use esp_hal::{
8 Async,
9 gpio::interconnect::{PeripheralInput, PeripheralOutput},
10 peripherals,
11 uart::Uart as EspUart,
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) -> esp_hal::uart::DataBits {
90 match databits {
91 DataBits::Data5 => esp_hal::uart::DataBits::_5,
92 DataBits::Data6 => esp_hal::uart::DataBits::_6,
93 DataBits::Data7 => esp_hal::uart::DataBits::_7,
94 DataBits::Data8 => esp_hal::uart::DataBits::_8,
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) -> esp_hal::uart::Parity {
120 match parity {
121 Parity::None => esp_hal::uart::Parity::None,
122 Parity::Even => esp_hal::uart::Parity::Even,
123 Parity::Odd => esp_hal::uart::Parity::Odd,
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 Stop1P5,
145 Stop2,
147}
148
149fn from_stop_bits(stop_bits: StopBits) -> esp_hal::uart::StopBits {
150 match stop_bits {
151 StopBits::Stop1 => esp_hal::uart::StopBits::_1,
152 StopBits::Stop1P5 => esp_hal::uart::StopBits::_1p5,
153 StopBits::Stop2 => esp_hal::uart::StopBits::_2,
154 }
155}
156
157impl From<ariel_os_embassy_common::uart::StopBits<Self>> for StopBits {
158 fn from(stopbits: ariel_os_embassy_common::uart::StopBits<Self>) -> Self {
159 match stopbits {
160 ariel_os_embassy_common::uart::StopBits::Hal(stopbits) => stopbits,
161 ariel_os_embassy_common::uart::StopBits::Stop1 => StopBits::Stop1,
162 }
163 }
164}
165
166fn convert_error(_err: esp_hal::uart::ConfigError) -> ConfigError {
167 ConfigError::ConfigurationNotSupported
168}
169
170macro_rules! define_uart_drivers {
171 ($( $peripheral:ident ),* $(,)?) => {
172 $(
173 pub struct $peripheral<'d> {
175 uart: EspUart<'d, Async>
176 }
177
178 paste::paste! {
181 #[allow(dead_code)]
182 static [<PREVENT_MULTIPLE_ $peripheral>]: () = ();
183 }
184
185 impl<'d> $peripheral<'d> {
186 #[expect(clippy::new_ret_no_self)]
197 pub fn new<RX: PeripheralInput<'d>, TX: PeripheralOutput<'d>>(
198 rx_pin: impl $crate::IntoPeripheral<'d, RX>,
199 tx_pin: impl $crate::IntoPeripheral<'d, TX>,
200 _rx_buf: &'d mut [u8],
201 _tx_buf: &'d mut [u8],
202 config: Config,
203 ) -> Result<Uart<'d>, ConfigError> {
204
205 let uart_config = esp_hal::uart::Config::default()
206 .with_baudrate(config.baudrate.into())
207 .with_data_bits(from_data_bits(config.data_bits))
208 .with_stop_bits(from_stop_bits(config.stop_bits))
209 .with_parity(from_parity(config.parity));
210
211 let uart_peripheral = unsafe { peripherals::$peripheral::steal() };
215
216 let uart = EspUart::new(
217 uart_peripheral,
218 uart_config
219 )
220 .map_err(convert_error)?
221 .with_tx(tx_pin.into_hal_peripheral())
222 .with_rx(rx_pin.into_hal_peripheral())
223 .into_async();
224
225 Ok(Uart::$peripheral(Self { uart }))
226 }
227 }
228 )*
229
230 pub enum Uart<'d> {
232 $(
233 #[doc = concat!(stringify!($peripheral), " peripheral.")]
234 $peripheral($peripheral<'d>)
235 ),*
236 }
237
238 impl embedded_io_async::ErrorType for Uart<'_> {
239 type Error = esp_hal::uart::IoError;
240 }
241
242 impl_async_uart_for_driver_enum!(Uart, $( $peripheral ),*);
243 }
244}
245
246#[cfg(context = "esp32")]
247define_uart_drivers!(UART0, UART1, UART2);
248#[cfg(context = "esp32c3")]
249define_uart_drivers!(UART0, UART1);
250#[cfg(context = "esp32c6")]
251define_uart_drivers!(UART0, UART1);
252#[cfg(context = "esp32s2")]
253define_uart_drivers!(UART0, UART1);
254#[cfg(context = "esp32s3")]
255define_uart_drivers!(UART0, UART1, UART2);
256
257#[doc(hidden)]
258pub fn init(peripherals: &mut crate::OptionalPeripherals) {
259 cfg_if::cfg_if! {
261 if #[cfg(context = "esp32")] {
262 let _ = peripherals.UART0.take().unwrap();
263 let _ = peripherals.UART1.take().unwrap();
264 let _ = peripherals.UART2.take().unwrap();
265 } else if #[cfg(context = "esp32c3")] {
266 let _ = peripherals.UART0.take().unwrap();
267 let _ = peripherals.UART1.take().unwrap();
268 } else if #[cfg(context = "esp32c6")] {
269 let _ = peripherals.UART0.take().unwrap();
270 let _ = peripherals.UART1.take().unwrap();
271 } else if #[cfg(context = "esp32s2")] {
272 let _ = peripherals.UART0.take().unwrap();
273 let _ = peripherals.UART1.take().unwrap();
274 } else if #[cfg(context = "esp32s3")] {
275 let _ = peripherals.UART0.take().unwrap();
276 let _ = peripherals.UART1.take().unwrap();
277 let _ = peripherals.UART2.take().unwrap();
278 } else {
279 compile_error!("this ESP32 chip is not supported");
280 }
281 }
282}