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 esp_hal::{
10 Async,
11 gpio::interconnect::{PeripheralInput, PeripheralOutput},
12 peripherals,
13 uart::Uart as EspUart,
14};
15
16#[derive(Debug, Copy, Clone, PartialEq, Eq)]
18#[cfg_attr(feature = "defmt", derive(defmt::Format))]
19#[non_exhaustive]
20pub struct Config {
21 pub baudrate: ariel_os_embassy_common::uart::Baudrate<Baudrate>,
23 pub data_bits: DataBits,
25 pub stop_bits: StopBits,
27 pub parity: Parity,
29}
30
31impl Default for Config {
32 fn default() -> Self {
33 Self {
34 baudrate: ariel_os_embassy_common::uart::Baudrate::_115200,
35 data_bits: DataBits::Data8,
36 stop_bits: StopBits::Stop1,
37 parity: Parity::None,
38 }
39 }
40}
41
42#[derive(Debug, Copy, Clone, PartialEq, Eq)]
44#[cfg_attr(feature = "defmt", derive(defmt::Format))]
45pub struct Baudrate {
46 baud: u32,
48}
49
50impl From<Baudrate> for u32 {
51 fn from(baud: Baudrate) -> u32 {
52 baud.baud
53 }
54}
55
56impl From<u32> for Baudrate {
57 fn from(baudrate: u32) -> Baudrate {
58 Baudrate { baud: baudrate }
59 }
60}
61
62impl From<ariel_os_embassy_common::uart::Baudrate<Self>> for Baudrate {
63 fn from(baud: ariel_os_embassy_common::uart::Baudrate<Self>) -> Baudrate {
64 match baud {
65 ariel_os_embassy_common::uart::Baudrate::Hal(baud) => baud,
66 ariel_os_embassy_common::uart::Baudrate::_2400 => Baudrate { baud: 2400 },
67 ariel_os_embassy_common::uart::Baudrate::_4800 => Baudrate { baud: 4800 },
68 ariel_os_embassy_common::uart::Baudrate::_9600 => Baudrate { baud: 9600 },
69 ariel_os_embassy_common::uart::Baudrate::_19200 => Baudrate { baud: 19_200 },
70 ariel_os_embassy_common::uart::Baudrate::_38400 => Baudrate { baud: 38_400 },
71 ariel_os_embassy_common::uart::Baudrate::_57600 => Baudrate { baud: 57_600 },
72 ariel_os_embassy_common::uart::Baudrate::_115200 => Baudrate { baud: 115_200 },
73 }
74 }
75}
76
77#[derive(Debug, Copy, Clone, PartialEq, Eq)]
79#[cfg_attr(feature = "defmt", derive(defmt::Format))]
80pub enum DataBits {
81 Data5,
83 Data6,
85 Data7,
87 Data8,
89}
90
91fn from_data_bits(databits: DataBits) -> esp_hal::uart::DataBits {
92 match databits {
93 DataBits::Data5 => esp_hal::uart::DataBits::_5,
94 DataBits::Data6 => esp_hal::uart::DataBits::_6,
95 DataBits::Data7 => esp_hal::uart::DataBits::_7,
96 DataBits::Data8 => esp_hal::uart::DataBits::_8,
97 }
98}
99
100impl From<ariel_os_embassy_common::uart::DataBits<Self>> for DataBits {
101 fn from(databits: ariel_os_embassy_common::uart::DataBits<Self>) -> DataBits {
102 match databits {
103 ariel_os_embassy_common::uart::DataBits::Hal(bits) => bits,
104 ariel_os_embassy_common::uart::DataBits::Data8 => DataBits::Data8,
105 }
106 }
107}
108
109#[derive(Debug, Copy, Clone, PartialEq, Eq)]
111#[cfg_attr(feature = "defmt", derive(defmt::Format))]
112pub enum Parity {
113 None,
115 Even,
117 Odd,
119}
120
121fn from_parity(parity: Parity) -> esp_hal::uart::Parity {
122 match parity {
123 Parity::None => esp_hal::uart::Parity::None,
124 Parity::Even => esp_hal::uart::Parity::Even,
125 Parity::Odd => esp_hal::uart::Parity::Odd,
126 }
127}
128
129impl From<ariel_os_embassy_common::uart::Parity<Self>> for Parity {
130 fn from(parity: ariel_os_embassy_common::uart::Parity<Self>) -> Self {
131 match parity {
132 ariel_os_embassy_common::uart::Parity::Hal(parity) => parity,
133 ariel_os_embassy_common::uart::Parity::None => Self::None,
134 ariel_os_embassy_common::uart::Parity::Even => Self::Even,
135 }
136 }
137}
138
139#[derive(Debug, Copy, Clone, PartialEq, Eq)]
141#[cfg_attr(feature = "defmt", derive(defmt::Format))]
142pub enum StopBits {
143 Stop1,
145 Stop1P5,
147 Stop2,
149}
150
151fn from_stop_bits(stop_bits: StopBits) -> esp_hal::uart::StopBits {
152 match stop_bits {
153 StopBits::Stop1 => esp_hal::uart::StopBits::_1,
154 StopBits::Stop1P5 => esp_hal::uart::StopBits::_1p5,
155 StopBits::Stop2 => esp_hal::uart::StopBits::_2,
156 }
157}
158
159impl From<ariel_os_embassy_common::uart::StopBits<Self>> for StopBits {
160 fn from(stopbits: ariel_os_embassy_common::uart::StopBits<Self>) -> Self {
161 match stopbits {
162 ariel_os_embassy_common::uart::StopBits::Hal(stopbits) => stopbits,
163 ariel_os_embassy_common::uart::StopBits::Stop1 => StopBits::Stop1,
164 }
165 }
166}
167
168fn convert_error(_err: esp_hal::uart::ConfigError) -> ConfigError {
169 ConfigError::ConfigurationNotSupported
170}
171
172macro_rules! define_uart_drivers {
173 ($( $peripheral:ident ),* $(,)?) => {
174 $(
175 pub struct $peripheral<'d> {
177 uart: EspUart<'d, Async>
178 }
179
180 paste::paste! {
183 #[allow(dead_code)]
184 static [<PREVENT_MULTIPLE_ $peripheral>]: () = ();
185 }
186
187 paste::paste! {
189 static [< ACTIVE_ $peripheral >]: AtomicBool = AtomicBool::new(false);
190 }
191
192 impl<'d> $peripheral<'d> {
193 #[expect(clippy::new_ret_no_self)]
204 pub fn new<RX: PeripheralInput<'d>, TX: PeripheralOutput<'d>>(
205 rx_pin: impl $crate::IntoPeripheral<'d, RX>,
206 tx_pin: impl $crate::IntoPeripheral<'d, TX>,
207 _rx_buf: &'d mut [u8],
208 _tx_buf: &'d mut [u8],
209 config: Config,
210 ) -> Result<Uart<'d>, ConfigError> {
211
212 let uart_config = esp_hal::uart::Config::default()
213 .with_baudrate(config.baudrate.into())
214 .with_data_bits(from_data_bits(config.data_bits))
215 .with_stop_bits(from_stop_bits(config.stop_bits))
216 .with_parity(from_parity(config.parity));
217
218 paste::paste! {
220 if [< ACTIVE_ $peripheral >].swap(true, Ordering::AcqRel) {
221 panic!("UART peripheral already initialized")
222 }
223 }
224
225 let uart_peripheral = unsafe { peripherals::$peripheral::steal() };
229
230 let uart = EspUart::new(
231 uart_peripheral,
232 uart_config
233 )
234 .map_err(|e| {
235 paste::paste! {
237 [< ACTIVE_ $peripheral >].store(false, Ordering::Release);
238 }
239 convert_error(e)
240 })?
241 .with_tx(tx_pin.into_hal_peripheral())
242 .with_rx(rx_pin.into_hal_peripheral())
243 .into_async();
244
245 Ok(Uart::$peripheral(Self { uart }))
246 }
247 }
248
249 impl<'d> Drop for $peripheral<'d> {
250 fn drop(&mut self) {
251 paste::paste! {
252 [< ACTIVE_ $peripheral >].store(false, Ordering::Release);
253 }
254 }
255 }
256 )*
257
258 pub enum Uart<'d> {
260 $(
261 #[doc = concat!(stringify!($peripheral), " peripheral.")]
262 $peripheral($peripheral<'d>)
263 ),*
264 }
265
266 impl embedded_io_async::ErrorType for Uart<'_> {
267 type Error = esp_hal::uart::IoError;
268 }
269
270 impl_async_uart_for_driver_enum!(Uart, $( $peripheral ),*);
271 }
272}
273
274#[cfg(context = "esp32")]
275define_uart_drivers!(UART0, UART1, UART2);
276#[cfg(context = "esp32c3")]
277define_uart_drivers!(UART0, UART1);
278#[cfg(context = "esp32c6")]
279define_uart_drivers!(UART0, UART1);
280#[cfg(context = "esp32s2")]
281define_uart_drivers!(UART0, UART1);
282#[cfg(context = "esp32s3")]
283define_uart_drivers!(UART0, UART1, UART2);
284
285#[doc(hidden)]
286pub fn init(peripherals: &mut crate::OptionalPeripherals) {
287 cfg_select! {
289 context = "esp32" => {
290 let _ = peripherals.UART0.take().unwrap();
291 let _ = peripherals.UART1.take().unwrap();
292 let _ = peripherals.UART2.take().unwrap();
293 }
294 context = "esp32c3" => {
295 let _ = peripherals.UART0.take().unwrap();
296 let _ = peripherals.UART1.take().unwrap();
297 }
298 context = "esp32c6" => {
299 let _ = peripherals.UART0.take().unwrap();
300 let _ = peripherals.UART1.take().unwrap();
301 }
302 context = "esp32s2" => {
303 let _ = peripherals.UART0.take().unwrap();
304 let _ = peripherals.UART1.take().unwrap();
305 }
306 context = "esp32s3" => {
307 let _ = peripherals.UART0.take().unwrap();
308 let _ = peripherals.UART1.take().unwrap();
309 let _ = peripherals.UART2.take().unwrap();
310 }
311 _ => {
312 compile_error!("this ESP32 chip is not supported");
313 }
314 }
315}