diff --git a/examples/uart_loopback.rs b/examples/uart_loopback.rs index 272d07ba0..c2d18bc8c 100644 --- a/examples/uart_loopback.rs +++ b/examples/uart_loopback.rs @@ -24,7 +24,7 @@ fn main() -> anyhow::Result<()> { println!("Starting UART loopback test"); let config = config::Config::new().baudrate(Hertz(115_200)); - let mut uart = UartDriver::new( + let uart = UartDriver::new( peripherals.uart1, tx, rx, diff --git a/src/uart.rs b/src/uart.rs index 6fae00781..bb1ca4191 100644 --- a/src/uart.rs +++ b/src/uart.rs @@ -38,7 +38,9 @@ //! - Address errata 3.17: UART fifo_cnt is inconsistent with FIFO pointer use core::marker::PhantomData; +use core::mem::ManuallyDrop; use core::ptr; +use core::sync::atomic::{AtomicU8, Ordering}; use crate::delay::NON_BLOCK; use crate::gpio::*; @@ -48,7 +50,7 @@ use esp_idf_sys::*; use crate::peripheral::Peripheral; -const UART_FIFO_SIZE: i32 = 128; +const UART_FIFO_SIZE: i32 = SOC_UART_FIFO_LEN as i32; pub type UartConfig = config::Config; @@ -189,6 +191,113 @@ pub mod config { } } + /// UART source clock + #[derive(PartialEq, Eq, Copy, Clone, Debug)] + pub enum SourceClock { + /// UART source clock from `APB` + #[cfg(any( + esp_idf_soc_uart_support_apb_clk, + esp_idf_soc_uart_support_pll_f40m_clk, + esp_idf_version_major = "4", + ))] + APB, + /// UART source clock from `RTC` + #[cfg(esp_idf_soc_uart_support_rtc_clk)] + RTC, + /// UART source clock from `XTAL` + #[cfg(esp_idf_soc_uart_support_xtal_clk)] + Crystal, + /// UART source clock from `REF_TICK` + #[cfg(esp_idf_soc_uart_support_ref_tick)] + RefTick, + } + + impl SourceClock { + #[cfg(not(esp_idf_version_major = "4"))] + pub fn frequency(self) -> Result { + let mut frequency: u32 = 0; + esp_result! { + unsafe { uart_get_sclk_freq(self.into(), &mut frequency) }, + Hertz(frequency) + } + } + } + + #[cfg(all(not(esp_idf_version_major = "4"), esp_idf_soc_uart_support_apb_clk))] + const APB_SCLK: uart_sclk_t = soc_periph_uart_clk_src_legacy_t_UART_SCLK_APB; + #[cfg(all( + not(esp_idf_version_major = "4"), + not(esp_idf_soc_uart_support_apb_clk), + esp_idf_soc_uart_support_pll_f40m_clk, + ))] + const APB_SCLK: uart_sclk_t = soc_periph_uart_clk_src_legacy_t_UART_SCLK_PLL_F40M; + #[cfg(esp_idf_version_major = "4")] + const APB_SCLK: uart_sclk_t = uart_sclk_t_UART_SCLK_APB; + + #[cfg(all(not(esp_idf_version_major = "4"), esp_idf_soc_uart_support_rtc_clk))] + const RTC_SCLK: uart_sclk_t = soc_periph_uart_clk_src_legacy_t_UART_SCLK_RTC; + #[cfg(all(esp_idf_version_major = "4", esp_idf_soc_uart_support_rtc_clk))] + const RTC_SCLK: uart_sclk_t = uart_sclk_t_UART_SCLK_RTC; + + #[cfg(all(not(esp_idf_version_major = "4"), esp_idf_soc_uart_support_xtal_clk))] + const XTAL_SCLK: uart_sclk_t = soc_periph_uart_clk_src_legacy_t_UART_SCLK_XTAL; + #[cfg(all(esp_idf_version_major = "4", esp_idf_soc_uart_support_xtal_clk))] + const XTAL_SCLK: uart_sclk_t = uart_sclk_t_UART_SCLK_XTAL; + + #[cfg(all(not(esp_idf_version_major = "4"), esp_idf_soc_uart_support_ref_tick))] + const REF_TICK_SCLK: uart_sclk_t = soc_periph_uart_clk_src_legacy_t_UART_SCLK_REF_TICK; + #[cfg(all(esp_idf_version_major = "4", esp_idf_soc_uart_support_ref_tick))] + const REF_TICK_SCLK: uart_sclk_t = uart_sclk_t_UART_SCLK_REF_TICK; + + impl Default for SourceClock { + fn default() -> Self { + #[cfg(not(esp_idf_version_major = "4"))] + const DEFAULT: uart_sclk_t = soc_periph_uart_clk_src_legacy_t_UART_SCLK_DEFAULT; + #[cfg(esp_idf_version_major = "4")] + const DEFAULT: uart_sclk_t = uart_sclk_t_UART_SCLK_APB; + Self::from(DEFAULT) + } + } + + impl From for uart_sclk_t { + fn from(source_clock: SourceClock) -> Self { + match source_clock { + #[cfg(any( + esp_idf_soc_uart_support_apb_clk, + esp_idf_soc_uart_support_pll_f40m_clk, + esp_idf_version_major = "4", + ))] + SourceClock::APB => APB_SCLK, + #[cfg(esp_idf_soc_uart_support_rtc_clk)] + SourceClock::RTC => RTC_SCLK, + #[cfg(esp_idf_soc_uart_support_xtal_clk)] + SourceClock::Crystal => XTAL_SCLK, + #[cfg(esp_idf_soc_uart_support_ref_tick)] + SourceClock::RefTick => REF_TICK_SCLK, + } + } + } + + impl From for SourceClock { + fn from(source_clock: uart_sclk_t) -> Self { + match source_clock { + #[cfg(any( + esp_idf_soc_uart_support_apb_clk, + esp_idf_soc_uart_support_pll_f40m_clk, + esp_idf_version_major = "4", + ))] + APB_SCLK => SourceClock::APB, + #[cfg(esp_idf_soc_uart_support_rtc_clk)] + RTC_SCLK => SourceClock::RTC, + #[cfg(esp_idf_soc_uart_support_xtal_clk)] + XTAL_SCLK => SourceClock::Crystal, + #[cfg(esp_idf_soc_uart_support_ref_tick)] + REF_TICK_SCLK => SourceClock::RefTick, + _ => unreachable!(), + } + } + } + /// UART configuration #[derive(Debug, Copy, Clone)] pub struct Config { @@ -198,6 +307,7 @@ pub mod config { pub stop_bits: StopBits, pub flow_control: FlowControl, pub flow_control_rts_threshold: u8, + pub source_clock: SourceClock, } impl Config { @@ -255,6 +365,12 @@ pub mod config { self.flow_control_rts_threshold = flow_control_rts_threshold; self } + + #[must_use] + pub fn source_clock(mut self, source_clock: SourceClock) -> Self { + self.source_clock = source_clock; + self + } } impl Default for Config { @@ -266,6 +382,7 @@ pub mod config { stop_bits: StopBits::STOP1, flow_control: FlowControl::None, flow_control_rts_threshold: 122, + source_clock: SourceClock::default(), } } } @@ -282,7 +399,6 @@ crate::embedded_hal_error!( ); /// Serial abstraction -/// pub struct UartDriver<'d> { port: u8, _p: PhantomData<&'d mut ()>, @@ -291,62 +407,28 @@ pub struct UartDriver<'d> { /// Serial receiver pub struct UartRxDriver<'d> { port: u8, + owner: Owner, _p: PhantomData<&'d mut ()>, } /// Serial transmitter pub struct UartTxDriver<'d> { port: u8, + owner: Owner, _p: PhantomData<&'d mut ()>, } impl<'d> UartDriver<'d> { /// Create a new serial driver pub fn new( - _uart: impl Peripheral

+ 'd, + uart: impl Peripheral

+ 'd, tx: impl Peripheral

+ 'd, rx: impl Peripheral

+ 'd, cts: Option + 'd>, rts: Option + 'd>, config: &config::Config, ) -> Result { - crate::into_ref!(tx, rx); - - let cts = cts.map(|cts| cts.into_ref()); - let rts = rts.map(|rts| rts.into_ref()); - - let uart_config = uart_config_t { - baud_rate: config.baudrate.0 as i32, - data_bits: config.data_bits.into(), - parity: config.parity.into(), - stop_bits: config.stop_bits.into(), - flow_ctrl: config.flow_control.into(), - rx_flow_ctrl_thresh: config.flow_control_rts_threshold, - ..Default::default() - }; - - esp!(unsafe { uart_param_config(UART::port(), &uart_config) })?; - - esp!(unsafe { - uart_set_pin( - UART::port(), - tx.pin(), - rx.pin(), - rts.as_ref().map_or(-1, |p| p.pin()), - cts.as_ref().map_or(-1, |p| p.pin()), - ) - })?; - - esp!(unsafe { - uart_driver_install( - UART::port(), - UART_FIFO_SIZE * 2, - UART_FIFO_SIZE * 2, - 0, - ptr::null_mut(), - 0, - ) - })?; + new_common(uart, Some(tx), Some(rx), cts, rts, config)?; Ok(Self { port: UART::port() as _, @@ -355,51 +437,33 @@ impl<'d> UartDriver<'d> { } /// Change the number of stop bits - pub fn change_stop_bits(&mut self, stop_bits: config::StopBits) -> Result<&mut Self, EspError> { - esp_result!( - unsafe { uart_set_stop_bits(self.port(), stop_bits.into()) }, - self - ) + pub fn change_stop_bits(&self, stop_bits: config::StopBits) -> Result<&Self, EspError> { + change_stop_bits(self.port(), stop_bits).map(|_| self) } - /// Retruns the current number of stop bits + /// Returns the current number of stop bits pub fn stop_bits(&self) -> Result { - let mut stop_bits: uart_stop_bits_t = 0; - esp_result!( - unsafe { uart_get_stop_bits(self.port(), &mut stop_bits) }, - stop_bits.into() - ) + stop_bits(self.port()) } /// Change the number of data bits - pub fn change_data_bits(&mut self, data_bits: config::DataBits) -> Result<&mut Self, EspError> { - esp_result!( - unsafe { uart_set_word_length(self.port(), data_bits.into()) }, - self - ) + pub fn change_data_bits(&self, data_bits: config::DataBits) -> Result<&Self, EspError> { + change_data_bits(self.port(), data_bits).map(|_| self) } /// Return the current number of data bits pub fn data_bits(&self) -> Result { - let mut data_bits: uart_word_length_t = 0; - esp_result!( - unsafe { uart_get_word_length(self.port(), &mut data_bits) }, - data_bits.into() - ) + data_bits(self.port()) } /// Change the type of parity checking - pub fn change_parity(&mut self, parity: config::Parity) -> Result<&mut Self, EspError> { - esp_result!(unsafe { uart_set_parity(self.port(), parity.into()) }, self) + pub fn change_parity(&self, parity: config::Parity) -> Result<&Self, EspError> { + change_parity(self.port(), parity).map(|_| self) } /// Returns the current type of parity checking pub fn parity(&self) -> Result { - let mut parity: uart_parity_t = 0; - esp_result!( - unsafe { uart_get_parity(self.port(), &mut parity) }, - parity.into() - ) + parity(self.port()) } /// Change the baudrate. @@ -409,54 +473,67 @@ impl<'d> UartDriver<'d> { /// However if one of the clock frequencies is below 10MHz or if the baudrate is above /// the reference clock or if the baudrate cannot be set within 1.5% /// then use the APB clock. - pub fn change_baudrate + Copy>( - &mut self, - baudrate: T, - ) -> Result<&mut Self, EspError> { - esp_result!( - unsafe { uart_set_baudrate(self.port(), baudrate.into().into()) }, - self - ) + pub fn change_baudrate + Copy>(&self, baudrate: T) -> Result<&Self, EspError> { + change_baudrate(self.port(), baudrate).map(|_| self) } /// Returns the current baudrate pub fn baudrate(&self) -> Result { - let mut baudrate: u32 = 0; - esp_result!( - unsafe { uart_get_baudrate(self.port(), &mut baudrate) }, - baudrate.into() - ) + baudrate(self.port()) } /// Split the serial driver in separate TX and RX drivers - pub fn split(&mut self) -> (UartTxDriver<'_>, UartRxDriver<'_>) { + pub fn split(&self) -> (UartTxDriver<'_>, UartRxDriver<'_>) { ( UartTxDriver { - port: self.port() as _, + port: self.port, + owner: Owner::Borrowed, _p: PhantomData, }, UartRxDriver { - port: self.port() as _, + port: self.port, + owner: Owner::Borrowed, + _p: PhantomData, + }, + ) + } + + /// Split the serial driver in separate TX and RX drivers. + /// + /// Unlike [`split`], the halves are owned and reference counted. + pub fn into_split(self) -> (UartTxDriver<'d>, UartRxDriver<'d>) { + let port = self.port; + let _ = ManuallyDrop::new(self); + REFS[port as usize].fetch_add(2, Ordering::SeqCst); + ( + UartTxDriver { + port, + owner: Owner::Shared, + _p: PhantomData, + }, + UartRxDriver { + port, + owner: Owner::Shared, _p: PhantomData, }, ) } /// Read multiple bytes into a slice - pub fn read(&mut self, buf: &mut [u8], delay: TickType_t) -> Result { + pub fn read(&self, buf: &mut [u8], delay: TickType_t) -> Result { self.rx().read(buf, delay) } /// Write multiple bytes from a slice - pub fn write(&mut self, buf: &[u8]) -> Result { + pub fn write(&self, buf: &[u8]) -> Result { self.tx().write(buf) } - pub fn flush_read(&mut self) -> Result<(), EspError> { + pub fn flush_read(&self) -> Result<(), EspError> { self.rx().flush() } - pub fn flush_write(&mut self) -> Result<(), EspError> { + pub fn flush_write(&self) -> Result<(), EspError> { self.tx().flush() } @@ -464,29 +541,39 @@ impl<'d> UartDriver<'d> { self.port as _ } - fn rx(&mut self) -> UartRxDriver<'_> { - UartRxDriver { - port: self.port() as _, - _p: PhantomData, - } + /// Get count of remaining bytes in the receive ring buffer + pub fn remaining_read(&self) -> Result { + remaining_unread_bytes(self.port()) } - fn tx(&mut self) -> UartTxDriver<'_> { - UartTxDriver { - port: self.port() as _, + /// Get count of remaining capacity in the transmit ring buffer + pub fn remaining_write(&self) -> Result { + remaining_write_capacity(self.port()) + } + + fn rx(&self) -> ManuallyDrop> { + ManuallyDrop::new(UartRxDriver { + port: self.port, + owner: Owner::Borrowed, _p: PhantomData, - } + }) + } + + fn tx(&self) -> ManuallyDrop> { + ManuallyDrop::new(UartTxDriver { + port: self.port, + owner: Owner::Borrowed, + _p: PhantomData, + }) } } impl<'d> Drop for UartDriver<'d> { fn drop(&mut self) { - esp!(unsafe { uart_driver_delete(self.port()) }).unwrap(); + delete_driver(self.port()).unwrap(); } } -unsafe impl<'d> Send for UartDriver<'d> {} - impl<'d> embedded_hal::serial::ErrorType for UartDriver<'d> { type Error = SerialError; } @@ -495,13 +582,13 @@ impl<'d> embedded_hal_0_2::serial::Read for UartDriver<'d> { type Error = SerialError; fn read(&mut self) -> nb::Result { - embedded_hal_0_2::serial::Read::read(&mut self.rx()) + embedded_hal_0_2::serial::Read::read(&mut *self.rx()) } } impl<'d> embedded_hal_nb::serial::Read for UartDriver<'d> { fn read(&mut self) -> nb::Result { - embedded_hal_nb::serial::Read::read(&mut self.rx()) + embedded_hal_nb::serial::Read::read(&mut *self.rx()) } } @@ -509,21 +596,21 @@ impl<'d> embedded_hal_0_2::serial::Write for UartDriver<'d> { type Error = SerialError; fn flush(&mut self) -> nb::Result<(), Self::Error> { - embedded_hal_0_2::serial::Write::flush(&mut self.tx()) + embedded_hal_0_2::serial::Write::flush(&mut *self.tx()) } fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> { - embedded_hal_0_2::serial::Write::write(&mut self.tx(), byte) + embedded_hal_0_2::serial::Write::write(&mut *self.tx(), byte) } } impl<'d> embedded_hal_nb::serial::Write for UartDriver<'d> { fn flush(&mut self) -> nb::Result<(), Self::Error> { - embedded_hal_nb::serial::Write::flush(&mut self.tx()) + embedded_hal_nb::serial::Write::flush(&mut *self.tx()) } fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> { - embedded_hal_nb::serial::Write::write(&mut self.tx(), byte) + embedded_hal_nb::serial::Write::write(&mut *self.tx(), byte) } } @@ -538,17 +625,71 @@ impl<'d> embedded_hal::serial::ErrorType for UartRxDriver<'d> { } impl<'d> UartRxDriver<'d> { - /// Get count of bytes in the receive FIFO - pub fn count(&self) -> Result { - let mut size = 0_u32; - esp_result!( - unsafe { uart_get_buffered_data_len(self.port(), &mut size) }, - size as u8 - ) + /// Create a new serial receiver + pub fn new( + uart: impl Peripheral

+ 'd, + rx: impl Peripheral

+ 'd, + cts: Option + 'd>, + rts: Option + 'd>, + config: &config::Config, + ) -> Result { + new_common(uart, None::, Some(rx), cts, rts, config)?; + + Ok(Self { + port: UART::port() as _, + owner: Owner::Owned, + _p: PhantomData, + }) + } + + /// Change the number of stop bits + pub fn change_stop_bits(&self, stop_bits: config::StopBits) -> Result<&Self, EspError> { + change_stop_bits(self.port(), stop_bits).map(|_| self) + } + + /// Returns the current number of stop bits + pub fn stop_bits(&self) -> Result { + stop_bits(self.port()) + } + + /// Change the number of data bits + pub fn change_data_bits(&self, data_bits: config::DataBits) -> Result<&Self, EspError> { + change_data_bits(self.port(), data_bits).map(|_| self) + } + + /// Return the current number of data bits + pub fn data_bits(&self) -> Result { + data_bits(self.port()) + } + + /// Change the type of parity checking + pub fn change_parity(&self, parity: config::Parity) -> Result<&Self, EspError> { + change_parity(self.port(), parity).map(|_| self) + } + + /// Returns the current type of parity checking + pub fn parity(&self) -> Result { + parity(self.port()) + } + + /// Change the baudrate. + /// + /// Will automatically select the clock source. When possible the reference clock (1MHz) will + /// be used, because this is constant when the clock source/frequency changes. + /// However if one of the clock frequencies is below 10MHz or if the baudrate is above + /// the reference clock or if the baudrate cannot be set within 1.5% + /// then use the APB clock. + pub fn change_baudrate + Copy>(&self, baudrate: T) -> Result<&Self, EspError> { + change_baudrate(self.port(), baudrate).map(|_| self) + } + + /// Returns the current baudrate + pub fn baudrate(&self) -> Result { + baudrate(self.port()) } /// Read multiple bytes into a slice; block until specified timeout - pub fn read(&mut self, buf: &mut [u8], delay: TickType_t) -> Result { + pub fn read(&self, buf: &mut [u8], delay: TickType_t) -> Result { // uart_read_bytes() returns error (-1) or how many bytes were read out // 0 means timeout and nothing is yet read out let len = unsafe { @@ -576,6 +717,17 @@ impl<'d> UartRxDriver<'d> { pub fn port(&self) -> uart_port_t { self.port as _ } + + /// Get count of remaining bytes in the receive ring buffer + pub fn count(&self) -> Result { + remaining_unread_bytes(self.port()) + } +} + +impl<'d> Drop for UartRxDriver<'d> { + fn drop(&mut self) { + self.owner.drop_impl(self.port()).unwrap() + } } impl<'d> embedded_hal_0_2::serial::Read for UartRxDriver<'d> { @@ -584,7 +736,7 @@ impl<'d> embedded_hal_0_2::serial::Read for UartRxDriver<'d> { fn read(&mut self) -> nb::Result { let mut buf = [0_u8]; - let result = self.read(&mut buf, NON_BLOCK); + let result = UartRxDriver::read(self, &mut buf, NON_BLOCK); check_nb(result, buf[0]) } @@ -594,13 +746,76 @@ impl<'d> embedded_hal_nb::serial::Read for UartRxDriver<'d> { fn read(&mut self) -> nb::Result { let mut buf = [0_u8]; - let result = self.read(&mut buf, NON_BLOCK); + let result = UartRxDriver::read(self, &mut buf, NON_BLOCK); check_nb(result, buf[0]) } } impl<'d> UartTxDriver<'d> { + /// Create a new serial transmitter + pub fn new( + uart: impl Peripheral

+ 'd, + tx: impl Peripheral

+ 'd, + cts: Option + 'd>, + rts: Option + 'd>, + config: &config::Config, + ) -> Result { + new_common(uart, Some(tx), None::, cts, rts, config)?; + + Ok(Self { + port: UART::port() as _, + owner: Owner::Owned, + _p: PhantomData, + }) + } + + /// Change the number of stop bits + pub fn change_stop_bits(&self, stop_bits: config::StopBits) -> Result<&Self, EspError> { + change_stop_bits(self.port(), stop_bits).map(|_| self) + } + + /// Returns the current number of stop bits + pub fn stop_bits(&self) -> Result { + stop_bits(self.port()) + } + + /// Change the number of data bits + pub fn change_data_bits(&self, data_bits: config::DataBits) -> Result<&Self, EspError> { + change_data_bits(self.port(), data_bits).map(|_| self) + } + + /// Return the current number of data bits + pub fn data_bits(&self) -> Result { + data_bits(self.port()) + } + + /// Change the type of parity checking + pub fn change_parity(&self, parity: config::Parity) -> Result<&Self, EspError> { + change_parity(self.port(), parity).map(|_| self) + } + + /// Returns the current type of parity checking + pub fn parity(&self) -> Result { + parity(self.port()) + } + + /// Change the baudrate. + /// + /// Will automatically select the clock source. When possible the reference clock (1MHz) will + /// be used, because this is constant when the clock source/frequency changes. + /// However if one of the clock frequencies is below 10MHz or if the baudrate is above + /// the reference clock or if the baudrate cannot be set within 1.5% + /// then use the APB clock. + pub fn change_baudrate + Copy>(&self, baudrate: T) -> Result<&Self, EspError> { + change_baudrate(self.port(), baudrate).map(|_| self) + } + + /// Returns the current baudrate + pub fn baudrate(&self) -> Result { + baudrate(self.port()) + } + /// Write multiple bytes from a slice pub fn write(&mut self, bytes: &[u8]) -> Result { // `uart_write_bytes()` returns error (-1) or how many bytes were written @@ -624,6 +839,17 @@ impl<'d> UartTxDriver<'d> { pub fn port(&self) -> uart_port_t { self.port as _ } + + /// Get count of remaining capacity in the transmit ring buffer + pub fn count(&self) -> Result { + remaining_write_capacity(self.port()) + } +} + +impl<'d> Drop for UartTxDriver<'d> { + fn drop(&mut self) { + self.owner.drop_impl(self.port()).unwrap() + } } impl<'d> embedded_hal::serial::ErrorType for UartTxDriver<'d> { @@ -638,7 +864,7 @@ impl<'d> embedded_hal_0_2::serial::Write for UartTxDriver<'d> { } fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> { - check_nb(self.write(&[byte]), ()) + check_nb(UartTxDriver::write(self, &[byte]), ()) } } @@ -648,7 +874,7 @@ impl<'d> embedded_hal_nb::serial::Write for UartTxDriver<'d> { } fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> { - check_nb(self.write(&[byte]), ()) + check_nb(UartTxDriver::write(self, &[byte]), ()) } } @@ -665,6 +891,141 @@ impl<'d> core::fmt::Write for UartTxDriver<'d> { } } +fn new_common( + _uart: impl Peripheral

, + tx: Option>, + rx: Option>, + cts: Option>, + rts: Option>, + config: &config::Config, +) -> Result<(), EspError> { + let tx = tx.map(|tx| tx.into_ref()); + let rx = rx.map(|rx| rx.into_ref()); + let cts = cts.map(|cts| cts.into_ref()); + let rts = rts.map(|rts| rts.into_ref()); + + #[allow(clippy::needless_update)] + let uart_config = uart_config_t { + baud_rate: config.baudrate.0 as i32, + data_bits: config.data_bits.into(), + parity: config.parity.into(), + stop_bits: config.stop_bits.into(), + flow_ctrl: config.flow_control.into(), + rx_flow_ctrl_thresh: config.flow_control_rts_threshold, + #[cfg(not(esp_idf_version_major = "4"))] + source_clk: config.source_clock.into(), + #[cfg(esp_idf_version_major = "4")] + __bindgen_anon_1: uart_config_t__bindgen_ty_1 { + source_clk: config.source_clock.into(), + }, + ..Default::default() + }; + + esp!(unsafe { uart_param_config(UART::port(), &uart_config) })?; + + esp!(unsafe { + uart_set_pin( + UART::port(), + tx.as_ref().map_or(-1, |p| p.pin()), + rx.as_ref().map_or(-1, |p| p.pin()), + rts.as_ref().map_or(-1, |p| p.pin()), + cts.as_ref().map_or(-1, |p| p.pin()), + ) + })?; + + esp!(unsafe { + uart_driver_install( + UART::port(), + UART_FIFO_SIZE * 2, + if tx.is_some() { UART_FIFO_SIZE * 2 } else { 0 }, + 0, + ptr::null_mut(), + 0, + ) + })?; + + Ok(()) +} + +fn stop_bits(port: uart_port_t) -> Result { + let mut stop_bits: uart_stop_bits_t = 0; + esp_result!( + unsafe { uart_get_stop_bits(port, &mut stop_bits) }, + stop_bits.into() + ) +} + +fn change_stop_bits(port: uart_port_t, stop_bits: config::StopBits) -> Result<(), EspError> { + esp!(unsafe { uart_set_stop_bits(port, stop_bits.into()) }) +} + +fn data_bits(port: uart_port_t) -> Result { + let mut data_bits: uart_word_length_t = 0; + esp_result!( + unsafe { uart_get_word_length(port, &mut data_bits) }, + data_bits.into() + ) +} + +fn change_data_bits(port: uart_port_t, data_bits: config::DataBits) -> Result<(), EspError> { + esp!(unsafe { uart_set_word_length(port, data_bits.into()) }) +} + +fn parity(port: uart_port_t) -> Result { + let mut parity: uart_parity_t = 0; + esp_result!(unsafe { uart_get_parity(port, &mut parity) }, parity.into()) +} + +fn change_parity(port: uart_port_t, parity: config::Parity) -> Result<(), EspError> { + esp!(unsafe { uart_set_parity(port, parity.into()) }) +} + +fn baudrate(port: uart_port_t) -> Result { + let mut baudrate: u32 = 0; + esp_result!( + unsafe { uart_get_baudrate(port, &mut baudrate) }, + baudrate.into() + ) +} + +fn change_baudrate + Copy>(port: uart_port_t, baudrate: T) -> Result<(), EspError> { + esp!(unsafe { uart_set_baudrate(port, baudrate.into().into()) }) +} + +fn delete_driver(port: uart_port_t) -> Result<(), EspError> { + esp!(unsafe { uart_driver_delete(port) }) +} + +pub fn remaining_unread_bytes(port: uart_port_t) -> Result { + let mut size = 0_u32; + esp_result!(unsafe { uart_get_buffered_data_len(port, &mut size) }, size) +} + +pub fn remaining_write_capacity(port: uart_port_t) -> Result { + let mut size = 0_u32; + esp_result!( + unsafe { uart_get_tx_buffer_free_size(port, &mut size) }, + size + ) +} + +enum Owner { + Owned, + Borrowed, + Shared, +} + +impl Owner { + fn drop_impl(&self, port: uart_port_t) -> Result<(), EspError> { + let needs_drop = match self { + Owner::Owned => true, + Owner::Borrowed => false, + Owner::Shared => REFS[port as usize].fetch_sub(1, Ordering::SeqCst) == 0, + }; + needs_drop.then(|| delete_driver(port)).unwrap_or(Ok(())) + } +} + macro_rules! impl_uart { ($uart:ident: $port:expr) => { crate::impl_peripheral!($uart); @@ -698,3 +1059,7 @@ impl_uart!(UART0: 0); impl_uart!(UART1: 1); #[cfg(any(esp32, esp32s3))] impl_uart!(UART2: 2); + +#[allow(clippy::declare_interior_mutable_const)] +const NO_REFS: AtomicU8 = AtomicU8::new(0); +static REFS: [AtomicU8; UART_NUM_MAX as usize] = [NO_REFS; UART_NUM_MAX as usize];