crate::unstable_driver! {
#[cfg(uhci_driver_supported)]
pub mod uhci;
#[cfg(lp_uart_driver_supported)]
pub mod lp_uart;
}
#[cfg_attr(uart_version = "1", path = "clocks/v1.rs")]
#[cfg_attr(soc_has_pcr, path = "clocks/v2_pcr.rs")]
#[cfg_attr(esp32p4, path = "clocks/v2_esp32p4.rs")]
#[cfg_attr(esp32s31, path = "clocks/v2_esp32s31.rs")]
mod clocks;
mod compat;
mod low_level;
use core::{marker::PhantomData, sync::atomic::Ordering};
use embedded_hal_async::delay::DelayNs;
use enumset::{EnumSet, EnumSetType};
pub use low_level::Instance;
use low_level::{
Info,
RxEvent,
State,
TxEvent,
UartClockGuard,
UartRxFuture,
UartTxFuture,
enable_register_sync,
rx_event_check_for_error,
sync_regs,
};
use crate::{
Async,
Blocking,
DriverMode,
gpio::{
InputConfig,
OutputConfig,
PinGuard,
Pull,
interconnect::{PeripheralInput, PeripheralOutput},
},
interrupt::InterruptHandler,
pac::uart0::RegisterBlock,
private::DropGuard,
rtc_cntl::WakeLock,
system::PeripheralGuard,
};
crate::any_peripheral! {
pub peripheral AnyUart<'d> {
#[cfg(soc_has_uart0)]
Uart0(crate::peripherals::UART0<'d>),
#[cfg(soc_has_uart1)]
Uart1(crate::peripherals::UART1<'d>),
#[cfg(soc_has_uart2)]
Uart2(crate::peripherals::UART2<'d>),
#[cfg(soc_has_uart3)]
Uart3(crate::peripherals::UART3<'d>),
#[cfg(soc_has_uart4)]
Uart4(crate::peripherals::UART4<'d>),
}
}
impl Instance for AnyUart<'_> {
#[inline]
fn parts(&self) -> (&'static Info, &'static State) {
any::delegate!(self, uart => { uart.parts() })
}
}
impl AnyUart<'_> {
pub(super) fn bind_peri_interrupt(&self, handler: InterruptHandler) {
any::delegate!(self, uart => { uart.bind_peri_interrupt(handler) })
}
pub(super) fn disable_peri_interrupt_on_all_cores(&self) {
any::delegate!(self, uart => { uart.disable_peri_interrupt_on_all_cores() })
}
pub(super) fn set_interrupt_handler(&self, handler: InterruptHandler) {
self.disable_peri_interrupt_on_all_cores();
self.info().enable_listen(EnumSet::all(), false);
self.info().clear_interrupts(EnumSet::all());
self.bind_peri_interrupt(handler);
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive]
pub enum RxError {
FifoOverflowed,
GlitchOccurred,
FrameFormatViolated,
ParityMismatch,
}
impl core::error::Error for RxError {}
#[derive(Debug, EnumSetType)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[instability::unstable]
#[non_exhaustive]
pub enum RxErrorKind {
FifoOverflowed,
GlitchOccurred,
FrameFormatViolated,
ParityMismatch,
}
impl From<RxErrorKind> for RxError {
fn from(value: RxErrorKind) -> Self {
match value {
RxErrorKind::FifoOverflowed => RxError::FifoOverflowed,
RxErrorKind::GlitchOccurred => RxError::GlitchOccurred,
RxErrorKind::FrameFormatViolated => RxError::FrameFormatViolated,
RxErrorKind::ParityMismatch => RxError::ParityMismatch,
}
}
}
impl core::fmt::Display for RxError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
RxError::FifoOverflowed => write!(f, "The RX FIFO overflowed"),
RxError::GlitchOccurred => write!(f, "A glitch was detected on the RX line"),
RxError::FrameFormatViolated => {
write!(f, "A framing error was detected on the RX line")
}
RxError::ParityMismatch => write!(f, "A parity error was detected on the RX line"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive]
pub enum TxError {}
impl core::fmt::Display for TxError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "Tx error")
}
}
impl core::error::Error for TxError {}
#[instability::unstable]
pub use crate::soc::clocks::UartFunctionClockSclk as ClockSource;
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum DataBits {
_5,
_6,
_7,
#[default]
_8,
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Parity {
#[default]
None,
Even,
Odd,
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum StopBits {
#[default]
_1,
_1p5,
_2,
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[instability::unstable]
pub enum SwFlowControl {
#[default]
Disabled,
Enabled {
xon_char: u8,
xoff_char: u8,
xon_threshold: u8,
xoff_threshold: u8,
},
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[instability::unstable]
pub enum CtsConfig {
Enabled,
#[default]
Disabled,
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[instability::unstable]
pub enum RtsConfig {
Enabled(u8),
#[default]
Disabled,
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[instability::unstable]
pub struct HwFlowControl {
pub cts: CtsConfig,
pub rts: RtsConfig,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[instability::unstable]
pub enum BaudrateTolerance {
#[default]
Closest,
Exact,
ErrorPercent(u8),
}
#[derive(Debug, Clone, Copy, procmacros::BuilderLite)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive]
pub struct Config {
baudrate: u32,
#[builder_lite(unstable)]
baudrate_tolerance: BaudrateTolerance,
data_bits: DataBits,
parity: Parity,
stop_bits: StopBits,
#[builder_lite(unstable)]
sw_flow_ctrl: SwFlowControl,
#[builder_lite(unstable)]
hw_flow_ctrl: HwFlowControl,
#[builder_lite(unstable)]
clock_source: ClockSource,
rx: RxConfig,
tx: TxConfig,
}
impl Default for Config {
fn default() -> Config {
Config {
rx: RxConfig::default(),
tx: TxConfig::default(),
baudrate: 115_200,
baudrate_tolerance: BaudrateTolerance::default(),
data_bits: Default::default(),
parity: Default::default(),
stop_bits: Default::default(),
sw_flow_ctrl: Default::default(),
hw_flow_ctrl: Default::default(),
clock_source: Default::default(),
}
}
}
impl Config {
fn validate(&self) -> Result<(), ConfigError> {
if let BaudrateTolerance::ErrorPercent(percentage) = self.baudrate_tolerance {
assert!(percentage > 0 && percentage <= 100);
}
if self.baudrate == 0 || self.baudrate > 5_000_000 {
return Err(ConfigError::BaudrateNotSupported);
}
Ok(())
}
}
#[derive(Debug, Clone, Copy, procmacros::BuilderLite)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive]
pub struct RxConfig {
fifo_full_threshold: u16,
timeout: Option<u8>,
#[builder_lite(unstable, into)]
reported_errors: EnumSet<RxErrorKind>,
#[builder_lite(unstable)]
discard_erroneous_bytes: bool,
}
impl Default for RxConfig {
fn default() -> RxConfig {
RxConfig {
fifo_full_threshold: 120,
timeout: Some(10),
reported_errors: EnumSet::all(),
discard_erroneous_bytes: true,
}
}
}
#[derive(Debug, Clone, Copy, procmacros::BuilderLite)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive]
pub struct TxConfig {
fifo_empty_threshold: u16,
}
impl Default for TxConfig {
fn default() -> TxConfig {
TxConfig {
fifo_empty_threshold: 10,
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, procmacros::BuilderLite)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[instability::unstable]
#[non_exhaustive]
pub struct AtCmdConfig {
pre_idle_count: Option<u16>,
post_idle_count: Option<u16>,
gap_timeout: Option<u16>,
cmd_char: u8,
char_num: u8,
}
impl Default for AtCmdConfig {
fn default() -> Self {
Self {
pre_idle_count: None,
post_idle_count: None,
gap_timeout: None,
cmd_char: b'+',
char_num: 1,
}
}
}
#[cfg(sleep_driver_supported)]
const WAKEUP_EDGE_OFFSET: u16 = cfg_select! {
esp32 => 2,
esp32p4 => 6,
_ => 3,
};
#[cfg(sleep_driver_supported)]
const MIN_WAKEUP_EDGES: u16 = cfg_select! {
esp32 => WAKEUP_EDGE_OFFSET + 1,
_ => WAKEUP_EDGE_OFFSET,
};
#[cfg(sleep_driver_supported)]
const MAX_WAKEUP_EDGES: u16 = WAKEUP_EDGE_OFFSET + 0x3FF;
#[cfg(sleep_driver_supported)]
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, procmacros::BuilderLite)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[instability::unstable]
#[non_exhaustive]
pub struct WakeupConfig {
#[cfg_attr(esp32, doc = "`3..=1025`.")]
#[cfg_attr(esp32p4, doc = "`6..=1029`.")]
#[cfg_attr(not(any(esp32, esp32p4)), doc = "`3..=1026`.")]
rising_edges: u16,
}
#[cfg(sleep_driver_supported)]
impl Default for WakeupConfig {
fn default() -> Self {
Self {
rising_edges: MIN_WAKEUP_EDGES,
}
}
}
#[cfg(sleep_driver_supported)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[instability::unstable]
#[non_exhaustive]
pub enum WakeConfigError {
NotAWakeupSource,
EdgeCountUnsupported,
}
#[cfg(sleep_driver_supported)]
#[instability::unstable]
impl core::error::Error for WakeConfigError {}
#[cfg(sleep_driver_supported)]
#[instability::unstable]
impl core::fmt::Display for WakeConfigError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
WakeConfigError::NotAWakeupSource => {
write!(f, "This UART instance cannot wake the chip")
}
WakeConfigError::EdgeCountUnsupported => {
write!(
f,
"The requested number of rising edges is not supported, it must be {MIN_WAKEUP_EDGES}..={MAX_WAKEUP_EDGES}"
)
}
}
}
}
struct UartBuilder<'d, Dm: DriverMode> {
uart: AnyUart<'d>,
phantom: PhantomData<Dm>,
}
impl<'d, Dm> UartBuilder<'d, Dm>
where
Dm: DriverMode,
{
fn new(uart: impl Instance + 'd) -> Self {
let uart = uart.degrade();
uart.info().rx_signal.connect_to(&crate::gpio::Level::High);
uart.info().cts_signal.connect_to(&crate::gpio::Level::Low);
Self {
uart,
phantom: PhantomData,
}
}
fn init(self, config: Config) -> Result<Uart<'d, Dm>, ConfigError> {
let rx_guard = PeripheralGuard::new(self.uart.info().peripheral);
let tx_guard = PeripheralGuard::new(self.uart.info().peripheral);
let peri_clock_guard = UartClockGuard::new(unsafe { self.uart.clone_unchecked() });
let rts_pin = PinGuard::new_unconnected();
let tx_pin = PinGuard::new_unconnected();
let mut serial = Uart {
rx: UartRx {
uart: unsafe { self.uart.clone_unchecked() },
phantom: PhantomData,
guard: rx_guard,
peri_clock_guard: peri_clock_guard.clone(),
_wake_lock: WakeLock::new(),
reported_errors: config.rx.reported_errors,
},
tx: UartTx {
uart: self.uart,
phantom: PhantomData,
guard: tx_guard,
peri_clock_guard,
rts_pin,
tx_pin,
baudrate: config.baudrate,
},
};
serial.init(config)?;
Ok(serial)
}
}
#[procmacros::doc_replace]
pub struct Uart<'d, Dm: DriverMode> {
rx: UartRx<'d, Dm>,
tx: UartTx<'d, Dm>,
}
#[instability::unstable]
pub struct UartTx<'d, Dm: DriverMode> {
uart: AnyUart<'d>,
phantom: PhantomData<Dm>,
guard: PeripheralGuard,
peri_clock_guard: UartClockGuard<'d>,
rts_pin: PinGuard,
tx_pin: PinGuard,
baudrate: u32,
}
#[instability::unstable]
pub struct UartRx<'d, Dm: DriverMode> {
uart: AnyUart<'d>,
phantom: PhantomData<Dm>,
guard: PeripheralGuard,
peri_clock_guard: UartClockGuard<'d>,
_wake_lock: WakeLock,
reported_errors: EnumSet<RxErrorKind>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive]
pub enum ConfigError {
#[cfg(feature = "unstable")]
#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
BaudrateNotAchievable,
BaudrateNotSupported,
#[cfg_attr(esp32, doc = "127")]
#[cfg_attr(not(esp32), doc = "1023")]
TimeoutTooLong,
RxFifoThresholdNotSupported,
TxFifoThresholdNotSupported,
}
impl core::error::Error for ConfigError {}
impl core::fmt::Display for ConfigError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
#[cfg(feature = "unstable")]
ConfigError::BaudrateNotAchievable => {
write!(f, "The requested baud rate is not achievable")
}
ConfigError::BaudrateNotSupported => {
write!(f, "The requested baud rate is not supported")
}
ConfigError::TimeoutTooLong => write!(f, "The requested timeout is not supported"),
ConfigError::RxFifoThresholdNotSupported => {
write!(f, "The requested RX FIFO threshold is not supported")
}
ConfigError::TxFifoThresholdNotSupported => {
write!(f, "The requested TX FIFO threshold is not supported")
}
}
}
}
impl<'d> UartTx<'d, Blocking> {
#[procmacros::doc_replace(
"note" => {
cfg(esp32) => "**esp32-specific ⚠️**: `UART2` is not recommended for use.",
_ => ""
}
)]
#[instability::unstable]
pub fn new(uart: impl Instance + 'd, config: Config) -> Result<Self, ConfigError> {
let (_, uart_tx) = UartBuilder::new(uart).init(config)?.split();
Ok(uart_tx)
}
#[instability::unstable]
pub fn into_async(self) -> UartTx<'d, Async> {
if !self.uart.state().is_rx_async.load(Ordering::Acquire) {
self.uart
.set_interrupt_handler(self.uart.info().async_handler);
}
self.uart.state().is_tx_async.store(true, Ordering::Release);
UartTx {
uart: self.uart,
phantom: PhantomData,
guard: self.guard,
peri_clock_guard: self.peri_clock_guard,
rts_pin: self.rts_pin,
tx_pin: self.tx_pin,
baudrate: self.baudrate,
}
}
}
impl<'d> UartTx<'d, Async> {
#[instability::unstable]
pub fn into_blocking(self) -> UartTx<'d, Blocking> {
self.uart
.state()
.is_tx_async
.store(false, Ordering::Release);
if !self.uart.state().is_rx_async.load(Ordering::Acquire) {
self.uart.disable_peri_interrupt_on_all_cores();
}
UartTx {
uart: self.uart,
phantom: PhantomData,
guard: self.guard,
peri_clock_guard: self.peri_clock_guard,
rts_pin: self.rts_pin,
tx_pin: self.tx_pin,
baudrate: self.baudrate,
}
}
pub async fn write_async(&mut self, bytes: &[u8]) -> Result<usize, TxError> {
let space = loop {
let tx_fifo_count = self.uart.info().tx_fifo_count();
let space = Info::UART_FIFO_SIZE - tx_fifo_count;
if space != 0 {
break space;
}
UartTxFuture::new(self.uart.reborrow(), TxEvent::FiFoEmpty).await;
};
let free = (space as usize).min(bytes.len());
for &byte in &bytes[..free] {
self.uart
.info()
.regs()
.fifo()
.write(|w| unsafe { w.rxfifo_rd_byte().bits(byte) });
}
Ok(free)
}
pub async fn flush_async(&mut self) -> Result<(), TxError> {
while self.uart.info().tx_fifo_count() > 0 {
UartTxFuture::new(self.uart.reborrow(), TxEvent::Done).await;
}
self.flush_last_byte();
Ok(())
}
#[instability::unstable]
pub async fn send_break_async<D: DelayNs>(&mut self, delay: &mut D, bits: u32) {
let total_delay_us = (bits as u64 * 1_000_000) / self.baudrate as u64;
let delay_us = (total_delay_us as u32).max(1);
let break_guard = self.start_break();
delay.delay_us(delay_us).await;
core::mem::drop(break_guard);
}
}
impl<'d, Dm> UartTx<'d, Dm>
where
Dm: DriverMode,
{
#[instability::unstable]
pub fn with_rts(mut self, rts: impl PeripheralOutput<'d>) -> Self {
let rts = rts.into();
rts.apply_output_config(&OutputConfig::default());
rts.set_output_enable(true);
self.rts_pin = rts.connect_with_guard(self.uart.info().rts_signal);
self
}
#[instability::unstable]
pub fn with_tx(mut self, tx: impl PeripheralOutput<'d>) -> Self {
let tx = tx.into();
tx.set_output_high(true);
tx.apply_output_config(&OutputConfig::default());
tx.set_output_enable(true);
self.tx_pin = tx.connect_with_guard(self.uart.info().tx_signal);
self
}
#[instability::unstable]
pub fn apply_config(&mut self, config: &Config) -> Result<(), ConfigError> {
self.uart
.info()
.set_tx_fifo_empty_threshold(config.tx.fifo_empty_threshold)?;
self.uart.info().txfifo_reset();
Ok(())
}
#[instability::unstable]
pub fn write_ready(&self) -> bool {
self.uart.info().tx_fifo_count() < Info::UART_FIFO_SIZE
}
#[instability::unstable]
pub fn write(&mut self, data: &[u8]) -> Result<usize, TxError> {
self.uart.info().write(data)
}
fn write_all(&mut self, mut data: &[u8]) -> Result<(), TxError> {
while !data.is_empty() {
let bytes_written = self.write(data)?;
data = &data[bytes_written..];
}
Ok(())
}
#[instability::unstable]
pub fn flush(&mut self) -> Result<(), TxError> {
while self.uart.info().tx_fifo_count() > 0 {}
self.flush_last_byte();
Ok(())
}
fn flush_last_byte(&mut self) {
crate::rom::ets_delay_us(10);
while !self.is_tx_idle() {}
}
#[instability::unstable]
pub fn send_break(&mut self, bits: u32) {
let total_delay_us = (bits as u64 * 1_000_000) / self.baudrate as u64;
let delay_us = (total_delay_us as u32).max(1);
let break_guard = self.start_break();
crate::rom::ets_delay_us(delay_us);
core::mem::drop(break_guard);
}
fn start_break(&mut self) -> impl Drop + '_ {
let original_conf0 = self.uart.info().regs().conf0().read();
let original_txd_inv = original_conf0.txd_inv().bit();
self.uart
.info()
.regs()
.conf0()
.modify(|_, w| w.txd_inv().bit(!original_txd_inv));
sync_regs(self.uart.info().regs());
DropGuard::new(self, move |this| {
this.uart
.info()
.regs()
.conf0()
.write(|w| unsafe { w.bits(original_conf0.bits()) });
sync_regs(this.uart.info().regs());
})
}
fn is_tx_idle(&self) -> bool {
self.uart.info().is_tx_idle()
}
fn disable_tx_interrupts(&self) {
self.regs().int_clr().write(|w| {
w.txfifo_empty().clear_bit_by_one();
w.tx_brk_done().clear_bit_by_one();
w.tx_brk_idle_done().clear_bit_by_one();
w.tx_done().clear_bit_by_one()
});
self.regs().int_ena().write(|w| {
w.txfifo_empty().clear_bit();
w.tx_brk_done().clear_bit();
w.tx_brk_idle_done().clear_bit();
w.tx_done().clear_bit()
});
}
fn regs(&self) -> &RegisterBlock {
self.uart.info().regs()
}
}
impl<'d> UartRx<'d, Blocking> {
#[procmacros::doc_replace(
"note" => {
cfg(esp32) => "**esp32-specific ⚠️**: `UART2` is not recommended for use.",
_ => ""
}
)]
#[instability::unstable]
pub fn new(uart: impl Instance + 'd, config: Config) -> Result<Self, ConfigError> {
let (uart_rx, _) = UartBuilder::new(uart).init(config)?.split();
Ok(uart_rx)
}
#[instability::unstable]
pub fn wait_for_break(&mut self) {
while !self.is_break_detected() {
}
self.clear_break_detected();
}
#[instability::unstable]
pub fn wait_for_break_with_timeout(&mut self, timeout: crate::time::Duration) -> bool {
let start = crate::time::Instant::now();
while !self.is_break_detected() {
if crate::time::Instant::now() - start >= timeout {
return false;
}
}
self.clear_break_detected();
true
}
#[instability::unstable]
pub fn into_async(self) -> UartRx<'d, Async> {
if !self.uart.state().is_tx_async.load(Ordering::Acquire) {
self.uart
.set_interrupt_handler(self.uart.info().async_handler);
}
self.uart.state().is_rx_async.store(true, Ordering::Release);
UartRx {
uart: self.uart,
phantom: PhantomData,
guard: self.guard,
peri_clock_guard: self.peri_clock_guard,
_wake_lock: self._wake_lock,
reported_errors: self.reported_errors,
}
}
}
impl<'d> UartRx<'d, Async> {
#[instability::unstable]
pub fn into_blocking(self) -> UartRx<'d, Blocking> {
self.uart
.state()
.is_rx_async
.store(false, Ordering::Release);
if !self.uart.state().is_tx_async.load(Ordering::Acquire) {
self.uart.disable_peri_interrupt_on_all_cores();
}
UartRx {
uart: self.uart,
phantom: PhantomData,
guard: self.guard,
peri_clock_guard: self.peri_clock_guard,
_wake_lock: self._wake_lock,
reported_errors: self.reported_errors,
}
}
async fn wait_for_buffered_data(
&mut self,
minimum: usize,
max_threshold: usize,
listen_for_timeout: bool,
) -> Result<(), RxError> {
let current_threshold = self.uart.info().rx_fifo_full_threshold();
let max_threshold = max_threshold.min(current_threshold as usize) as u16;
let minimum = minimum.min(Info::RX_FIFO_MAX_THRHD as usize) as u16;
let minimum = minimum.min(max_threshold);
while self.uart.info().rx_fifo_count() < minimum {
let info = self.uart.info();
unwrap!(info.set_rx_fifo_full_threshold(max_threshold));
let _guard = DropGuard::new((), |_| {
unwrap!(info.set_rx_fifo_full_threshold(current_threshold));
});
let mut events = RxEvent::FifoFull
| RxEvent::FifoOvf
| RxEvent::FrameError
| RxEvent::GlitchDetected
| RxEvent::ParityError;
if self.regs().at_cmd_char().read().char_num().bits() > 0 {
events |= RxEvent::CmdCharDetected;
}
if listen_for_timeout && self.uart.info().rx_timeout_enabled() {
events |= RxEvent::FifoTout;
}
let events = UartRxFuture::new(self.uart.reborrow(), events).await;
if events.contains(RxEvent::FifoOvf) {
self.uart.info().rxfifo_reset();
}
rx_event_check_for_error(events, self.reported_errors)?;
}
Ok(())
}
pub async fn read_async(&mut self, buf: &mut [u8]) -> Result<usize, RxError> {
if buf.is_empty() {
return Ok(0);
}
self.wait_for_buffered_data(1, buf.len(), true).await?;
self.read_buffered(buf)
}
pub async fn read_exact_async(&mut self, mut buf: &mut [u8]) -> Result<(), RxError> {
if buf.is_empty() {
return Ok(());
}
let read = self.read_buffered(buf)?;
buf = &mut buf[read..];
while !buf.is_empty() {
self.wait_for_buffered_data(buf.len(), buf.len(), false)
.await?;
let read = self.read_buffered(buf)?;
buf = &mut buf[read..];
}
Ok(())
}
#[instability::unstable]
pub async fn wait_for_break_async(&mut self) {
UartRxFuture::new(self.uart.reborrow(), RxEvent::BreakDetected).await;
}
}
impl<'d, Dm> UartRx<'d, Dm>
where
Dm: DriverMode,
{
fn regs(&self) -> &RegisterBlock {
self.uart.info().regs()
}
#[instability::unstable]
pub fn with_cts(self, cts: impl PeripheralInput<'d>) -> Self {
let cts = cts.into();
cts.apply_input_config(&InputConfig::default());
cts.set_input_enable(true);
self.uart.info().cts_signal.connect_to(&cts);
self
}
#[instability::unstable]
pub fn with_rx(self, rx: impl PeripheralInput<'d>) -> Self {
let rx = rx.into();
rx.apply_input_config(&InputConfig::default().with_pull(Pull::Up));
rx.set_input_enable(true);
self.uart.info().rx_signal.connect_to(&rx);
self
}
#[instability::unstable]
pub fn is_break_detected(&self) -> bool {
self.uart.info().check_rx_break_detected()
}
#[instability::unstable]
pub fn clear_break_detected(&mut self) {
self.uart.info().clear_rx_break_detected();
}
#[instability::unstable]
pub fn apply_config(&mut self, config: &Config) -> Result<(), ConfigError> {
self.uart
.info()
.set_rx_fifo_full_threshold(config.rx.fifo_full_threshold)?;
self.uart
.info()
.set_rx_timeout(config.rx.timeout, self.uart.info().current_symbol_length())?;
self.uart
.info()
.set_discard_erroneous_bytes(config.rx.discard_erroneous_bytes);
self.reported_errors = config.rx.reported_errors;
self.uart.info().rxfifo_reset();
Ok(())
}
#[cfg(sleep_driver_supported)]
#[instability::unstable]
pub fn enable_wakeup(&mut self, config: &WakeupConfig) -> Result<(), WakeConfigError> {
self.uart.info().enable_wakeup(config)
}
#[cfg(sleep_driver_supported)]
#[instability::unstable]
pub fn disable_wakeup(&mut self) {
self.uart.info().disable_wakeup();
}
#[instability::unstable]
pub fn check_for_errors(&mut self) -> Result<(), RxError> {
self.uart.info().check_for_errors(self.reported_errors)
}
#[instability::unstable]
pub fn read_ready(&self) -> bool {
self.uart.info().rx_fifo_count() > 0
}
#[instability::unstable]
pub fn read(&mut self, buf: &mut [u8]) -> Result<usize, RxError> {
self.uart.info().read(buf, self.reported_errors)
}
#[instability::unstable]
pub fn read_buffered(&mut self, buf: &mut [u8]) -> Result<usize, RxError> {
self.uart.info().read_buffered(buf, self.reported_errors)
}
fn disable_rx_interrupts(&self) {
self.regs().int_clr().write(|w| {
w.rxfifo_full().clear_bit_by_one();
w.rxfifo_ovf().clear_bit_by_one();
w.rxfifo_tout().clear_bit_by_one();
w.at_cmd_char_det().clear_bit_by_one()
});
self.regs().int_ena().write(|w| {
w.rxfifo_full().clear_bit();
w.rxfifo_ovf().clear_bit();
w.rxfifo_tout().clear_bit();
w.at_cmd_char_det().clear_bit()
});
}
}
impl<'d> Uart<'d, Blocking> {
#[procmacros::doc_replace(
"note" => {
cfg(esp32) => "**esp32-specific ⚠️**: `UART2` is not recommended for use.",
_ => ""
}
)]
pub fn new(uart: impl Instance + 'd, config: Config) -> Result<Self, ConfigError> {
UartBuilder::new(uart).init(config)
}
pub fn into_async(self) -> Uart<'d, Async> {
Uart {
rx: self.rx.into_async(),
tx: self.tx.into_async(),
}
}
#[cfg_attr(
not(multi_core),
doc = "Registers an interrupt handler for the peripheral."
)]
#[cfg_attr(
multi_core,
doc = "Registers an interrupt handler for the peripheral on the current core."
)]
#[doc = ""]
#[instability::unstable]
pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
self.tx.uart.set_interrupt_handler(handler);
}
#[procmacros::doc_replace]
#[instability::unstable]
pub fn listen(&mut self, interrupts: impl Into<EnumSet<UartInterrupt>>) {
self.tx.uart.info().enable_listen(interrupts.into(), true)
}
#[instability::unstable]
pub fn unlisten(&mut self, interrupts: impl Into<EnumSet<UartInterrupt>>) {
self.tx.uart.info().enable_listen(interrupts.into(), false)
}
#[instability::unstable]
pub fn interrupts(&mut self) -> EnumSet<UartInterrupt> {
self.tx.uart.info().interrupts()
}
#[instability::unstable]
pub fn clear_interrupts(&mut self, interrupts: EnumSet<UartInterrupt>) {
self.tx.uart.info().clear_interrupts(interrupts)
}
#[instability::unstable]
pub fn wait_for_break(&mut self) {
self.rx.wait_for_break()
}
#[instability::unstable]
pub fn wait_for_break_with_timeout(&mut self, timeout: crate::time::Duration) -> bool {
self.rx.wait_for_break_with_timeout(timeout)
}
}
impl<'d> Uart<'d, Async> {
pub fn into_blocking(self) -> Uart<'d, Blocking> {
Uart {
rx: self.rx.into_blocking(),
tx: self.tx.into_blocking(),
}
}
#[procmacros::doc_replace]
pub async fn write_async(&mut self, words: &[u8]) -> Result<usize, TxError> {
self.tx.write_async(words).await
}
#[procmacros::doc_replace]
pub async fn flush_async(&mut self) -> Result<(), TxError> {
self.tx.flush_async().await
}
#[procmacros::doc_replace]
pub async fn read_async(&mut self, buf: &mut [u8]) -> Result<usize, RxError> {
self.rx.read_async(buf).await
}
#[instability::unstable]
pub async fn read_exact_async(&mut self, buf: &mut [u8]) -> Result<(), RxError> {
self.rx.read_exact_async(buf).await
}
#[instability::unstable]
pub async fn wait_for_break_async(&mut self) {
self.rx.wait_for_break_async().await
}
#[instability::unstable]
pub async fn send_break_async<D: DelayNs>(&mut self, delay: &mut D, bits: u32) {
self.tx.send_break_async(delay, bits).await
}
}
#[derive(Debug, EnumSetType)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive]
#[instability::unstable]
pub enum UartInterrupt {
AtCmd,
TxDone,
RxBreakDetected,
RxFifoFull,
RxTimeout,
}
impl<'d, Dm> Uart<'d, Dm>
where
Dm: DriverMode,
{
#[procmacros::doc_replace]
pub fn with_rx(mut self, rx: impl PeripheralInput<'d>) -> Self {
self.rx = self.rx.with_rx(rx);
self
}
#[procmacros::doc_replace]
pub fn with_tx(mut self, tx: impl PeripheralOutput<'d>) -> Self {
self.tx = self.tx.with_tx(tx);
self
}
#[procmacros::doc_replace]
pub fn with_cts(mut self, cts: impl PeripheralInput<'d>) -> Self {
self.rx = self.rx.with_cts(cts);
self
}
#[procmacros::doc_replace]
pub fn with_rts(mut self, rts: impl PeripheralOutput<'d>) -> Self {
self.tx = self.tx.with_rts(rts);
self
}
fn regs(&self) -> &RegisterBlock {
self.tx.uart.info().regs()
}
#[procmacros::doc_replace]
pub fn write_ready(&self) -> bool {
self.tx.write_ready()
}
#[procmacros::doc_replace]
pub fn write(&mut self, data: &[u8]) -> Result<usize, TxError> {
self.tx.write(data)
}
#[procmacros::doc_replace]
pub fn flush(&mut self) -> Result<(), TxError> {
self.tx.flush()
}
#[instability::unstable]
pub fn send_break(&mut self, bits: u32) {
self.tx.send_break(bits)
}
#[procmacros::doc_replace]
pub fn read_ready(&self) -> bool {
self.rx.read_ready()
}
#[instability::unstable]
pub fn is_break_detected(&self) -> bool {
self.rx.is_break_detected()
}
#[instability::unstable]
pub fn clear_break_detected(&mut self) {
self.rx.clear_break_detected();
}
#[procmacros::doc_replace]
pub fn read(&mut self, buf: &mut [u8]) -> Result<usize, RxError> {
self.rx.read(buf)
}
#[procmacros::doc_replace]
pub fn apply_config(&mut self, config: &Config) -> Result<(), ConfigError> {
self.rx.uart.info().apply_config(config)?;
self.rx.apply_config(config)?;
self.tx.apply_config(config)?;
Ok(())
}
#[cfg(sleep_driver_supported)]
#[instability::unstable]
pub fn enable_wakeup(&mut self, config: &WakeupConfig) -> Result<(), WakeConfigError> {
self.rx.enable_wakeup(config)
}
#[cfg(sleep_driver_supported)]
#[instability::unstable]
pub fn disable_wakeup(&mut self) {
self.rx.disable_wakeup();
}
#[procmacros::doc_replace]
#[instability::unstable]
pub fn split(self) -> (UartRx<'d, Dm>, UartTx<'d, Dm>) {
(self.rx, self.tx)
}
#[procmacros::doc_replace]
#[instability::unstable]
pub fn split_mut(&mut self) -> (&mut UartRx<'d, Dm>, &mut UartTx<'d, Dm>) {
(&mut self.rx, &mut self.tx)
}
#[instability::unstable]
pub fn check_for_rx_errors(&mut self) -> Result<(), RxError> {
self.rx.check_for_errors()
}
#[instability::unstable]
pub fn read_buffered(&mut self, buf: &mut [u8]) -> Result<usize, RxError> {
self.rx.read_buffered(buf)
}
#[instability::unstable]
pub fn set_at_cmd(&mut self, config: AtCmdConfig) {
#[cfg(uart_has_sclk_enable)]
self.rx.uart.info().set_at_cmd_clock_enabled(false);
self.regs().at_cmd_char().write(|w| unsafe {
w.at_cmd_char().bits(config.cmd_char);
w.char_num().bits(config.char_num)
});
if let Some(pre_idle_count) = config.pre_idle_count {
self.regs()
.at_cmd_precnt()
.write(|w| unsafe { w.pre_idle_num().bits(pre_idle_count as _) });
}
if let Some(post_idle_count) = config.post_idle_count {
self.regs()
.at_cmd_postcnt()
.write(|w| unsafe { w.post_idle_num().bits(post_idle_count as _) });
}
if let Some(gap_timeout) = config.gap_timeout {
self.regs()
.at_cmd_gaptout()
.write(|w| unsafe { w.rx_gap_tout().bits(gap_timeout as _) });
}
#[cfg(uart_has_sclk_enable)]
self.rx.uart.info().set_at_cmd_clock_enabled(true);
sync_regs(self.regs());
}
#[inline(always)]
fn init(&mut self, config: Config) -> Result<(), ConfigError> {
self.rx.disable_rx_interrupts();
self.tx.disable_tx_interrupts();
enable_register_sync(self.regs());
self.apply_config(&config)?;
self.regs()
.idle_conf()
.modify(|_, w| unsafe { w.tx_idle_num().bits(0) });
sync_regs(self.regs());
crate::rom::ets_delay_us(15);
self.regs().int_clr().write(|w| unsafe { w.bits(u32::MAX) });
Ok(())
}
}
#[instability::unstable]
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive]
pub enum IoError {
Tx(TxError),
Rx(RxError),
}
#[instability::unstable]
impl core::error::Error for IoError {}
#[instability::unstable]
impl core::fmt::Display for IoError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
IoError::Tx(e) => e.fmt(f),
IoError::Rx(e) => e.fmt(f),
}
}
}
#[instability::unstable]
impl From<RxError> for IoError {
fn from(e: RxError) -> Self {
IoError::Rx(e)
}
}
#[instability::unstable]
impl From<TxError> for IoError {
fn from(e: TxError) -> Self {
IoError::Tx(e)
}
}