use core::task::Poll;
use enumset::{EnumSet, EnumSetType};
use portable_atomic::AtomicBool;
#[cfg(feature = "unstable")]
use super::BaudrateTolerance;
use super::{
AnyUart,
Config,
ConfigError,
DataBits,
HwFlowControl,
Parity,
RxError,
RxErrorKind,
StopBits,
SwFlowControl,
TxError,
UartInterrupt,
any,
};
#[cfg(sleep_driver_supported)]
use super::{WakeConfigError, WakeupConfig};
use crate::{
asynch::AtomicWaker,
gpio::{InputSignal, OutputSignal},
handler,
interrupt::InterruptHandler,
pac::uart0::RegisterBlock,
ram,
soc::clocks::{
self,
ClockTree,
UartBaudRateGeneratorConfig as BaudRateConfig,
UartFunctionClockConfig as ClockConfig,
},
};
#[cfg_attr(uart_version = "1", path = "v1.rs")]
#[cfg_attr(uart_version = "2", path = "v2.rs")]
mod version;
pub(super) use version::{enable_register_sync, sync_regs};
#[derive(Debug, EnumSetType)]
pub(super) enum TxEvent {
Done,
FiFoEmpty,
}
#[derive(Debug, EnumSetType)]
pub(super) enum RxEvent {
FifoFull,
CmdCharDetected,
FifoOvf,
FifoTout,
GlitchDetected,
FrameError,
ParityError,
BreakDetected,
}
pub(super) fn rx_event_check_for_error(
events: EnumSet<RxEvent>,
reported_errors: EnumSet<RxErrorKind>,
) -> Result<(), RxError> {
for event in events {
if let Some(error) = rx_error_kind(event)
&& reported_errors.contains(error)
{
return Err(error.into());
}
}
Ok(())
}
fn rx_error_kind(event: RxEvent) -> Option<RxErrorKind> {
match event {
RxEvent::FifoOvf => Some(RxErrorKind::FifoOverflowed),
RxEvent::GlitchDetected => Some(RxErrorKind::GlitchOccurred),
RxEvent::FrameError => Some(RxErrorKind::FrameFormatViolated),
RxEvent::ParityError => Some(RxErrorKind::ParityMismatch),
RxEvent::FifoFull
| RxEvent::CmdCharDetected
| RxEvent::FifoTout
| RxEvent::BreakDetected => None,
}
}
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub(super) struct UartRxFuture {
events: EnumSet<RxEvent>,
uart: &'static Info,
state: &'static State,
registered: bool,
}
impl UartRxFuture {
pub(super) fn new(uart: impl Instance, events: impl Into<EnumSet<RxEvent>>) -> Self {
Self {
events: events.into(),
uart: uart.info(),
state: uart.state(),
registered: false,
}
}
}
impl core::future::Future for UartRxFuture {
type Output = EnumSet<RxEvent>;
fn poll(
mut self: core::pin::Pin<&mut Self>,
cx: &mut core::task::Context<'_>,
) -> core::task::Poll<Self::Output> {
let events = self.uart.rx_events().intersection(self.events);
if !events.is_empty() {
self.uart.clear_rx_events(events);
Poll::Ready(events)
} else {
self.state.rx_waker.register(cx.waker());
if !self.registered {
self.uart.enable_listen_rx(self.events, true);
self.registered = true;
}
Poll::Pending
}
}
}
impl Drop for UartRxFuture {
fn drop(&mut self) {
self.uart.enable_listen_rx(self.events, false);
}
}
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub(super) struct UartTxFuture {
events: EnumSet<TxEvent>,
uart: &'static Info,
state: &'static State,
registered: bool,
}
impl UartTxFuture {
pub(super) fn new(uart: impl Instance, events: impl Into<EnumSet<TxEvent>>) -> Self {
Self {
events: events.into(),
uart: uart.info(),
state: uart.state(),
registered: false,
}
}
}
impl core::future::Future for UartTxFuture {
type Output = ();
fn poll(
mut self: core::pin::Pin<&mut Self>,
cx: &mut core::task::Context<'_>,
) -> core::task::Poll<Self::Output> {
let events = self.uart.tx_events().intersection(self.events);
if !events.is_empty() {
self.uart.clear_tx_events(events);
Poll::Ready(())
} else {
self.state.tx_waker.register(cx.waker());
if !self.registered {
self.uart.enable_listen_tx(self.events, true);
self.registered = true;
}
Poll::Pending
}
}
}
impl Drop for UartTxFuture {
fn drop(&mut self) {
self.uart.enable_listen_tx(self.events, false);
}
}
#[ram]
pub(super) fn intr_handler(uart: &Info, state: &State) {
let interrupts = uart.regs().int_st().read();
let interrupt_bits = interrupts.bits(); let rx_wake = interrupts.rxfifo_full().bit_is_set()
| interrupts.rxfifo_ovf().bit_is_set()
| interrupts.rxfifo_tout().bit_is_set()
| interrupts.at_cmd_char_det().bit_is_set()
| interrupts.glitch_det().bit_is_set()
| interrupts.frm_err().bit_is_set()
| interrupts.parity_err().bit_is_set()
| interrupts.brk_det().bit_is_set();
let tx_wake = interrupts.tx_done().bit_is_set() | interrupts.txfifo_empty().bit_is_set();
uart.regs()
.int_ena()
.modify(|r, w| unsafe { w.bits(r.bits() & !interrupt_bits) });
if tx_wake {
state.tx_waker.wake();
}
if rx_wake {
state.rx_waker.wake();
}
}
pub trait Instance: crate::private::Sealed + any::Degrade {
#[doc(hidden)]
fn parts(&self) -> (&'static Info, &'static State);
#[inline(always)]
#[doc(hidden)]
fn info(&self) -> &'static Info {
self.parts().0
}
#[inline(always)]
#[doc(hidden)]
fn state(&self) -> &'static State {
self.parts().1
}
}
#[doc(hidden)]
#[non_exhaustive]
#[allow(private_interfaces, reason = "Unstable details")]
pub struct Info {
pub register_block: *const RegisterBlock,
pub peripheral: crate::system::Peripheral,
pub clock_instance: clocks::UartInstance,
pub async_handler: InterruptHandler,
pub tx_signal: OutputSignal,
pub rx_signal: InputSignal,
pub cts_signal: InputSignal,
pub rts_signal: OutputSignal,
#[cfg(sleep_driver_supported)]
pub wakeup_source: Option<crate::rtc_cntl::WakeupSource>,
}
#[doc(hidden)]
#[non_exhaustive]
pub struct State {
pub rx_waker: AtomicWaker,
pub tx_waker: AtomicWaker,
pub is_rx_async: AtomicBool,
pub is_tx_async: AtomicBool,
}
impl Info {
pub(super) const UART_FIFO_SIZE: u16 = property!("uart.ram_size");
pub(super) const RX_FIFO_MAX_THRHD: u16 = Self::UART_FIFO_SIZE - 1;
pub(super) const TX_FIFO_MAX_THRHD: u16 = Self::RX_FIFO_MAX_THRHD;
pub fn regs(&self) -> &RegisterBlock {
unsafe { &*self.register_block }
}
pub(super) fn enable_listen(&self, interrupts: EnumSet<UartInterrupt>, enable: bool) {
let reg_block = self.regs();
reg_block.int_ena().modify(|_, w| {
for interrupt in interrupts {
match interrupt {
UartInterrupt::AtCmd => w.at_cmd_char_det().bit(enable),
UartInterrupt::TxDone => w.tx_done().bit(enable),
UartInterrupt::RxBreakDetected => w.brk_det().bit(enable),
UartInterrupt::RxFifoFull => w.rxfifo_full().bit(enable),
UartInterrupt::RxTimeout => w.rxfifo_tout().bit(enable),
};
}
w
});
}
pub(super) fn interrupts(&self) -> EnumSet<UartInterrupt> {
let mut res = EnumSet::new();
let reg_block = self.regs();
let ints = reg_block.int_raw().read();
if ints.at_cmd_char_det().bit_is_set() {
res.insert(UartInterrupt::AtCmd);
}
if ints.tx_done().bit_is_set() {
res.insert(UartInterrupt::TxDone);
}
if ints.brk_det().bit_is_set() {
res.insert(UartInterrupt::RxBreakDetected);
}
if ints.rxfifo_full().bit_is_set() {
res.insert(UartInterrupt::RxFifoFull);
}
if ints.rxfifo_tout().bit_is_set() {
res.insert(UartInterrupt::RxTimeout);
}
res
}
pub(super) fn clear_interrupts(&self, interrupts: EnumSet<UartInterrupt>) {
let reg_block = self.regs();
reg_block.int_clr().write(|w| {
for interrupt in interrupts {
match interrupt {
UartInterrupt::AtCmd => w.at_cmd_char_det().clear_bit_by_one(),
UartInterrupt::TxDone => w.tx_done().clear_bit_by_one(),
UartInterrupt::RxBreakDetected => w.brk_det().clear_bit_by_one(),
UartInterrupt::RxFifoFull => w.rxfifo_full().clear_bit_by_one(),
UartInterrupt::RxTimeout => w.rxfifo_tout().clear_bit_by_one(),
};
}
w
});
}
pub(super) fn apply_config(&self, config: &Config) -> Result<(), ConfigError> {
config.validate()?;
self.change_baud(config)?;
self.change_data_bits(config.data_bits);
self.change_parity(config.parity);
self.change_stop_bits(config.stop_bits);
self.change_flow_control(config.sw_flow_ctrl, config.hw_flow_ctrl);
self.regs().int_clr().write(|w| unsafe { w.bits(u32::MAX) });
Ok(())
}
pub(super) fn enable_listen_tx(&self, events: EnumSet<TxEvent>, enable: bool) {
self.regs().int_ena().modify(|_, w| {
for event in events {
match event {
TxEvent::Done => w.tx_done().bit(enable),
TxEvent::FiFoEmpty => w.txfifo_empty().bit(enable),
};
}
w
});
}
fn tx_events(&self) -> EnumSet<TxEvent> {
let pending_interrupts = self.regs().int_raw().read();
let mut active_events = EnumSet::new();
if pending_interrupts.tx_done().bit_is_set() {
active_events |= TxEvent::Done;
}
if pending_interrupts.txfifo_empty().bit_is_set() {
active_events |= TxEvent::FiFoEmpty;
}
active_events
}
fn clear_tx_events(&self, events: impl Into<EnumSet<TxEvent>>) {
let events = events.into();
self.regs().int_clr().write(|w| {
for event in events {
match event {
TxEvent::FiFoEmpty => w.txfifo_empty().clear_bit_by_one(),
TxEvent::Done => w.tx_done().clear_bit_by_one(),
};
}
w
});
}
pub(super) fn enable_listen_rx(&self, events: EnumSet<RxEvent>, enable: bool) {
self.regs().int_ena().modify(|_, w| {
for event in events {
match event {
RxEvent::FifoFull => w.rxfifo_full().bit(enable),
RxEvent::BreakDetected => w.brk_det().bit(enable),
RxEvent::CmdCharDetected => w.at_cmd_char_det().bit(enable),
RxEvent::FifoOvf => w.rxfifo_ovf().bit(enable),
RxEvent::FifoTout => w.rxfifo_tout().bit(enable),
RxEvent::GlitchDetected => w.glitch_det().bit(enable),
RxEvent::FrameError => w.frm_err().bit(enable),
RxEvent::ParityError => w.parity_err().bit(enable),
};
}
w
});
}
fn rx_events(&self) -> EnumSet<RxEvent> {
let pending_interrupts = self.regs().int_raw().read();
let mut active_events = EnumSet::new();
if pending_interrupts.rxfifo_full().bit_is_set() {
active_events |= RxEvent::FifoFull;
}
if pending_interrupts.brk_det().bit_is_set() {
active_events |= RxEvent::BreakDetected;
}
if pending_interrupts.at_cmd_char_det().bit_is_set() {
active_events |= RxEvent::CmdCharDetected;
}
if pending_interrupts.rxfifo_ovf().bit_is_set() {
active_events |= RxEvent::FifoOvf;
}
if pending_interrupts.rxfifo_tout().bit_is_set() {
active_events |= RxEvent::FifoTout;
}
if pending_interrupts.glitch_det().bit_is_set() {
active_events |= RxEvent::GlitchDetected;
}
if pending_interrupts.frm_err().bit_is_set() {
active_events |= RxEvent::FrameError;
}
if pending_interrupts.parity_err().bit_is_set() {
active_events |= RxEvent::ParityError;
}
active_events
}
fn clear_rx_events(&self, events: impl Into<EnumSet<RxEvent>>) {
let events = events.into();
self.regs().int_clr().write(|w| {
for event in events {
match event {
RxEvent::FifoFull => w.rxfifo_full().clear_bit_by_one(),
RxEvent::BreakDetected => w.brk_det().clear_bit_by_one(),
RxEvent::CmdCharDetected => w.at_cmd_char_det().clear_bit_by_one(),
RxEvent::FifoOvf => w.rxfifo_ovf().clear_bit_by_one(),
RxEvent::FifoTout => w.rxfifo_tout().clear_bit_by_one(),
RxEvent::GlitchDetected => w.glitch_det().clear_bit_by_one(),
RxEvent::FrameError => w.frm_err().clear_bit_by_one(),
RxEvent::ParityError => w.parity_err().clear_bit_by_one(),
};
}
w
});
}
pub(super) fn set_rx_fifo_full_threshold(&self, threshold: u16) -> Result<(), ConfigError> {
if threshold == 0 || threshold > Self::RX_FIFO_MAX_THRHD {
return Err(ConfigError::RxFifoThresholdNotSupported);
}
self.regs()
.conf1()
.modify(|_, w| unsafe { w.rxfifo_full_thrhd().bits(threshold as _) });
Ok(())
}
#[allow(clippy::useless_conversion)]
pub(super) fn rx_fifo_full_threshold(&self) -> u16 {
self.regs().conf1().read().rxfifo_full_thrhd().bits().into()
}
pub(super) fn set_tx_fifo_empty_threshold(&self, threshold: u16) -> Result<(), ConfigError> {
if threshold > Self::TX_FIFO_MAX_THRHD {
return Err(ConfigError::TxFifoThresholdNotSupported);
}
self.regs()
.conf1()
.modify(|_, w| unsafe { w.txfifo_empty_thrhd().bits(threshold as _) });
Ok(())
}
#[cfg(uart_has_sclk_enable)]
pub(super) fn set_at_cmd_clock_enabled(&self, enabled: bool) {
self.regs()
.clk_conf()
.modify(|_, w| w.sclk_en().bit(enabled));
}
#[procmacros::doc_replace(
"rx_timeout_limit" => {
cfg(esp32) => "- Symbol size is fixed to 8, do not pass a value > **0x7F**.",
_ => "- The value you pass times the symbol size must be <= **0x3FF**.",
}
)]
pub(super) fn set_rx_timeout(
&self,
timeout: Option<u8>,
symbol_len: u8,
) -> Result<(), ConfigError> {
version::set_rx_timeout(self, timeout, symbol_len)
}
pub(super) fn rx_timeout_enabled(&self) -> bool {
version::rx_timeout_enabled(self)
}
pub(super) fn set_discard_erroneous_bytes(&self, discard: bool) {
self.regs()
.conf0()
.modify(|_, w| w.err_wr_mask().bit(discard));
self.sync_regs();
}
pub(super) fn is_tx_idle(&self) -> bool {
version::is_tx_idle(self)
}
fn sync_regs(&self) {
sync_regs(self.regs());
}
fn change_baud(&self, config: &Config) -> Result<(), ConfigError> {
ClockTree::with(|clocks| {
let clock = self.clock_instance;
let clk = clocks::UartInstance::function_clock_source_frequency(config.clock_source);
const FRAC_BITS: u32 = const {
let largest_divider: u32 =
property!("clock_tree.uart.baud_rate_generator.fractional").1;
::core::assert!((largest_divider + 1).is_power_of_two());
largest_divider.count_ones()
};
const FRAC_MASK: u32 = (1 << FRAC_BITS) - 1;
cfg_select! {
any(uart_has_sclk_divider, soc_has_pcr, esp32p4, esp32s31) => {
const MAX_DIV: u32 =
property!("clock_tree.uart.baud_rate_generator.integral").1;
let clk_div = clk.div_ceil(MAX_DIV).div_ceil(config.baudrate);
debug!("SCLK: {} divider: {}", clk, clk_div);
let conf = ClockConfig::new(config.clock_source, clk_div - 1);
let divider = (clk << FRAC_BITS) / (config.baudrate * clk_div);
}
_ => {
debug!("SCLK: {}", clk);
let conf = ClockConfig::new(config.clock_source);
let divider = (clk << FRAC_BITS) / config.baudrate;
}
}
let divider_integer = divider >> FRAC_BITS;
let divider_frag = divider & FRAC_MASK;
debug!(
"UART CLK divider: {} + {}/16",
divider_integer, divider_frag
);
clock.configure_function_clock(clocks, conf);
clock.configure_baud_rate_generator(
clocks,
BaudRateConfig::new(divider_frag, divider_integer),
);
self.sync_regs();
#[cfg(feature = "unstable")]
{
let deviation_limit = match config.baudrate_tolerance {
BaudrateTolerance::Exact => 1, BaudrateTolerance::ErrorPercent(percent) => percent as u32,
_ => return Ok(()),
};
let actual_baud = clock.baud_rate_generator_frequency();
if actual_baud == 0 {
return Err(ConfigError::BaudrateNotAchievable);
}
let deviation = (config.baudrate.abs_diff(actual_baud) * 100) / actual_baud;
debug!(
"Nominal baud: {}, actual: {}, deviation: {}%",
config.baudrate, actual_baud, deviation
);
if deviation > deviation_limit {
return Err(ConfigError::BaudrateNotAchievable);
}
}
Ok(())
})
}
fn change_data_bits(&self, data_bits: DataBits) {
self.regs()
.conf0()
.modify(|_, w| unsafe { w.bit_num().bits(data_bits as u8) });
}
fn change_parity(&self, parity: Parity) {
self.regs().conf0().modify(|_, w| match parity {
Parity::None => w.parity_en().clear_bit(),
Parity::Even => w.parity_en().set_bit().parity().clear_bit(),
Parity::Odd => w.parity_en().set_bit().parity().set_bit(),
});
}
fn change_stop_bits(&self, stop_bits: StopBits) {
version::change_stop_bits(self, stop_bits);
}
fn change_flow_control(&self, sw_flow_ctrl: SwFlowControl, hw_flow_ctrl: HwFlowControl) {
version::change_flow_control(self, sw_flow_ctrl, hw_flow_ctrl);
}
pub(super) fn rxfifo_reset(&self) {
fn rxfifo_rst(reg_block: &RegisterBlock, enable: bool) {
reg_block.conf0().modify(|_, w| w.rxfifo_rst().bit(enable));
sync_regs(reg_block);
}
rxfifo_rst(self.regs(), true);
rxfifo_rst(self.regs(), false);
}
pub(super) fn txfifo_reset(&self) {
fn txfifo_rst(reg_block: &RegisterBlock, enable: bool) {
reg_block.conf0().modify(|_, w| w.txfifo_rst().bit(enable));
sync_regs(reg_block);
}
txfifo_rst(self.regs(), true);
txfifo_rst(self.regs(), false);
while !self.is_tx_idle() {}
}
pub(super) fn current_symbol_length(&self) -> u8 {
version::current_symbol_length(self)
}
pub(super) fn read_next_from_fifo(&self) -> u8 {
version::read_next_from_fifo(self)
}
#[allow(clippy::useless_conversion)]
pub(super) fn tx_fifo_count(&self) -> u16 {
u16::from(self.regs().status().read().txfifo_cnt().bits())
}
pub(super) fn write_byte(&self, byte: u8) {
self.regs()
.fifo()
.write(|w| unsafe { w.rxfifo_rd_byte().bits(byte) });
}
fn check_for_errors_and_reset_fifo(
&self,
reported_errors: EnumSet<RxErrorKind>,
) -> Result<bool, RxError> {
let errors =
RxEvent::FifoOvf | RxEvent::GlitchDetected | RxEvent::FrameError | RxEvent::ParityError;
let events = self.rx_events().intersection(errors);
let result = rx_event_check_for_error(events, reported_errors);
let fifo_overflowed = events.contains(RxEvent::FifoOvf);
if !events.is_empty() {
self.clear_rx_events(events);
if fifo_overflowed {
self.rxfifo_reset();
}
}
result.map(|()| fifo_overflowed)
}
pub(super) fn check_for_errors(
&self,
reported_errors: EnumSet<RxErrorKind>,
) -> Result<(), RxError> {
self.check_for_errors_and_reset_fifo(reported_errors)
.map(|_| ())
}
pub(super) fn check_rx_break_detected(&self) -> bool {
self.rx_events().contains(RxEvent::BreakDetected)
}
pub(super) fn clear_rx_break_detected(&self) {
self.clear_rx_events(RxEvent::BreakDetected);
}
pub(super) fn rx_fifo_count(&self) -> u16 {
version::rx_fifo_count(self)
}
pub(super) fn write(&self, data: &[u8]) -> Result<usize, TxError> {
if data.is_empty() {
return Ok(0);
}
while self.tx_fifo_count() >= Info::UART_FIFO_SIZE {}
let space = (Info::UART_FIFO_SIZE - self.tx_fifo_count()) as usize;
let to_write = space.min(data.len());
for &byte in &data[..to_write] {
self.write_byte(byte);
}
Ok(to_write)
}
pub(super) fn read(
&self,
buf: &mut [u8],
reported_errors: EnumSet<RxErrorKind>,
) -> Result<usize, RxError> {
if buf.is_empty() {
return Ok(0);
}
loop {
while self.rx_fifo_count() == 0 {
self.check_for_errors(reported_errors)?;
}
let read = self.read_buffered(buf, reported_errors)?;
if read > 0 {
break Ok(read);
}
}
}
pub(super) fn read_buffered(
&self,
buf: &mut [u8],
reported_errors: EnumSet<RxErrorKind>,
) -> Result<usize, RxError> {
let to_read = (self.rx_fifo_count() as usize).min(buf.len());
if self.check_for_errors_and_reset_fifo(reported_errors)? {
return Ok(0);
}
for byte_into in buf[..to_read].iter_mut() {
*byte_into = self.read_next_from_fifo();
}
self.clear_rx_events(RxEvent::FifoFull);
Ok(to_read)
}
#[cfg(sleep_driver_supported)]
pub(crate) fn suspend_for_sleep(&self) {
version::suspend(self, true);
version::wait_for_suspended(self);
}
#[cfg(sleep_driver_supported)]
pub(crate) fn resume_from_sleep(&self) {
version::suspend(self, false);
}
#[cfg(sleep_driver_supported)]
pub(crate) fn enable_wakeup(&self, config: &WakeupConfig) -> Result<(), WakeConfigError> {
let source = self
.wakeup_source
.ok_or(WakeConfigError::NotAWakeupSource)?;
let edges = config.rising_edges();
if !(super::MIN_WAKEUP_EDGES..=super::MAX_WAKEUP_EDGES).contains(&edges) {
return Err(WakeConfigError::EdgeCountUnsupported);
}
version::set_wakeup_edge_threshold(self, edges - super::WAKEUP_EDGE_OFFSET);
source.enable_with_hooks(Some(keep_peripherals_powered), None);
Ok(())
}
#[cfg(sleep_driver_supported)]
pub(crate) fn disable_wakeup(&self) {
if let Some(source) = self.wakeup_source {
source.disable();
}
}
}
#[cfg(sleep_driver_supported)]
#[crate::ram]
fn keep_peripherals_powered(config: &mut crate::rtc_cntl::sleep::WrappedSleepConfig<'_>) {
if !config.is_deep_sleep() {
config.keep_alive(crate::rtc_cntl::sleep::SleepResource::HpPeripherals);
}
}
impl PartialEq for Info {
fn eq(&self, other: &Self) -> bool {
core::ptr::eq(self.register_block, other.register_block)
}
}
unsafe impl Sync for Info {}
macro_rules! impl_instance {
($inst:ident, $peri:ident, $rxd:ident, $txd:ident, $cts:ident, $rts:ident, $wakeup_source:expr) => {
impl Instance for crate::peripherals::$inst<'_> {
fn parts(&self) -> (&'static Info, &'static State) {
#[handler]
#[ram]
pub(super) fn irq_handler() {
intr_handler(&PERIPHERAL, &STATE);
}
static STATE: State = State {
tx_waker: AtomicWaker::new(),
rx_waker: AtomicWaker::new(),
is_rx_async: AtomicBool::new(false),
is_tx_async: AtomicBool::new(false),
};
static PERIPHERAL: Info = Info {
register_block: crate::peripherals::$inst::ptr(),
peripheral: crate::system::Peripheral::$peri,
clock_instance: clocks::UartInstance::$peri,
async_handler: irq_handler,
tx_signal: OutputSignal::$txd,
rx_signal: InputSignal::$rxd,
cts_signal: InputSignal::$cts,
rts_signal: OutputSignal::$rts,
#[cfg(sleep_driver_supported)]
wakeup_source: $wakeup_source,
};
(&PERIPHERAL, &STATE)
}
}
};
}
for_each_uart! {
($id:literal, $inst:ident, $peri:ident, $rxd:ident, $txd:ident, $cts:ident, $rts:ident, wakeup_source = true) => {
impl_instance!($inst, $peri, $rxd, $txd, $cts, $rts, Some(crate::rtc_cntl::WakeupSource::$peri));
};
($id:literal, $inst:ident, $peri:ident, $rxd:ident, $txd:ident, $cts:ident, $rts:ident, wakeup_source = false) => {
impl_instance!($inst, $peri, $rxd, $txd, $cts, $rts, None);
};
}
pub(super) struct UartClockGuard<'t> {
uart: AnyUart<'t>,
}
impl<'t> UartClockGuard<'t> {
pub(super) fn new(uart: AnyUart<'t>) -> Self {
let this = Self::new_inner(uart, false);
crate::rom::ets_delay_us(100);
this
}
pub(super) fn new_inner(uart: AnyUart<'t>, clone: bool) -> Self {
ClockTree::with(|clocks| {
let clock = uart.info().clock_instance;
if !clone {
let sclk_config = ClockConfig::new(
Default::default(),
#[cfg(any(uart_has_sclk_divider, soc_has_pcr, esp32p4, esp32s31))]
0,
);
clock.configure_function_clock(clocks, sclk_config);
}
clock.request_function_clock(clocks);
clock.request_baud_rate_generator(clocks);
#[cfg(soc_has_clock_node_uart_mem_clock)]
clock.request_mem_clock(clocks);
});
Self { uart }
}
}
impl Clone for UartClockGuard<'_> {
fn clone(&self) -> Self {
Self::new_inner(unsafe { self.uart.clone_unchecked() }, true)
}
}
impl Drop for UartClockGuard<'_> {
fn drop(&mut self) {
ClockTree::with(|clocks| {
let clock = self.uart.info().clock_instance;
#[cfg(soc_has_clock_node_uart_mem_clock)]
clock.release_mem_clock(clocks);
clock.release_baud_rate_generator(clocks);
clock.release_function_clock(clocks);
});
}
}