//! # Universal Asynchronous Receiver/Transmitter (UART) //! //! ## Overview //! The UART is a hardware peripheral which handles communication using serial //! communication interfaces, such as RS232 and RS485. This peripheral provides //! a cheap and ubiquitous method for full- and half-duplex communication //! between devices. //! //! Depending on your device, two or more UART controllers are available for //! use, all of which can be configured and used in the same way. All UART //! controllers are compatible with UART-enabled devices from various //! manufacturers, and can also support Infrared Data Association (IrDA) //! protocols. //! //! ## Configuration //! Each UART controller is individually configurable, and the usual setting //! such as baud rate, data bits, parity, and stop bits can easily be //! configured. Additionally, the transmit (TX) and receive (RX) pins need to //! be specified. //! //! ```rust, no_run #![doc = crate::before_snippet!()] //! # use core::option::Option::Some; //! # use esp_hal::uart::{config::Config, Uart}; //! use esp_hal::gpio::Io; //! let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); //! //! let mut uart1 = Uart::new(peripherals.UART1, &clocks, io.pins.gpio1, //! io.pins.gpio2).unwrap(); //! # } //! ``` //! //! The UART controller can be configured to invert the polarity of the pins. //! This is achived by inverting the desired pins, and then constucting the //! UART instance using the inverted pins. //! //! ## Usage //! The UART driver implements a number of third-party traits, with the //! intention of making the HAL inter-compatible with various device drivers //! from the community. This includes, but is not limited to, the [embedded-hal] //! and [embedded-io] blocking traits, and the [embedded-hal-async] and //! [embedded-io-async] asynchronous traits. //! //! In addition to the interfaces provided by these traits, native APIs are also //! available. See the examples below for more information on how to interact //! with this driver. //! //! ## Examples //! ### Sending and Receiving Data //! ```rust, no_run #![doc = crate::before_snippet!()] //! # use esp_hal::uart::{config::Config, Uart}; //! use esp_hal::gpio::Io; //! # let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); //! # let mut uart1 = Uart::new_with_config( //! # peripherals.UART1, //! # Config::default(), //! # &clocks, //! # io.pins.gpio1, //! # io.pins.gpio2, //! # ).unwrap(); //! // Write bytes out over the UART: //! uart1.write_bytes("Hello, world!".as_bytes()).expect("write error!"); //! # } //! ``` //! //! ### Splitting the UART into TX and RX Components //! ```rust, no_run #![doc = crate::before_snippet!()] //! # use esp_hal::uart::{config::Config, Uart}; //! use esp_hal::gpio::Io; //! # let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); //! # let mut uart1 = Uart::new_with_config( //! # peripherals.UART1, //! # Config::default(), //! # &clocks, //! # io.pins.gpio1, //! # io.pins.gpio2, //! # ).unwrap(); //! // The UART can be split into separate Transmit and Receive components: //! let (mut tx, mut rx) = uart1.split(); //! //! // Each component can be used individually to interact with the UART: //! tx.write_bytes(&[42u8]).expect("write error!"); //! let byte = rx.read_byte().expect("read error!"); //! # } //! ``` //! //! ### Inverting TX and RX Pins //! ```rust, no_run #![doc = crate::before_snippet!()] //! # use esp_hal::uart::{config::Config, Uart}; //! use esp_hal::gpio::{Io, any_pin::AnyPin}; //! let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); //! //! let tx = AnyPin::new_inverted(io.pins.gpio1); //! let rx = AnyPin::new_inverted(io.pins.gpio2); //! let mut uart1 = Uart::new(peripherals.UART1, &clocks, tx, rx).unwrap(); //! # } //! ``` //! //! ### Constructing TX and RX Components //! ```rust, no_run #![doc = crate::before_snippet!()] //! # use esp_hal::uart::{config::Config, UartTx, UartRx}; //! use esp_hal::gpio::{Io, any_pin::AnyPin}; //! let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); //! //! let tx = UartTx::new(peripherals.UART0, &clocks, //! io.pins.gpio1).unwrap(); //! let rx = UartRx::new(peripherals.UART1, &clocks, //! io.pins.gpio2).unwrap(); //! # } //! ``` //! //! [embedded-hal]: https://docs.rs/embedded-hal/latest/embedded_hal/ //! [embedded-io]: https://docs.rs/embedded-io/latest/embedded_io/ //! [embedded-hal-async]: https://docs.rs/embedded-hal-async/latest/embedded_hal_async/ //! [embedded-io-async]: https://docs.rs/embedded-io-async/latest/embedded_io_async/ use core::marker::PhantomData; use self::config::Config; use crate::{ clock::Clocks, gpio::{InputPin, InputSignal, OutputPin, OutputSignal}, interrupt::InterruptHandler, peripheral::Peripheral, peripherals::{ uart0::{fifo::FIFO_SPEC, RegisterBlock}, Interrupt, }, private::Internal, system::PeripheralClockControl, Blocking, InterruptConfigurable, Mode, }; const CONSOLE_UART_NUM: usize = 0; const UART_FIFO_SIZE: u16 = 128; #[cfg(not(any(esp32, esp32s2)))] use crate::soc::constants::RC_FAST_CLK; #[cfg(any(esp32, esp32s2))] use crate::soc::constants::REF_TICK; // Default TX and RX pins for Uart/Serial communication (UART0) cfg_if::cfg_if! { if #[cfg(esp32)] { pub type DefaultTxPin = crate::gpio::Gpio1; pub type DefaultRxPin = crate::gpio::Gpio3; } else if #[cfg(esp32c2)] { pub type DefaultTxPin = crate::gpio::Gpio20; pub type DefaultRxPin = crate::gpio::Gpio19; } else if #[cfg(esp32c3)] { pub type DefaultTxPin = crate::gpio::Gpio21; pub type DefaultRxPin = crate::gpio::Gpio20; }else if #[cfg(esp32c6)] { pub type DefaultTxPin = crate::gpio::Gpio16; pub type DefaultRxPin = crate::gpio::Gpio17; }else if #[cfg(esp32h2)] { pub type DefaultTxPin = crate::gpio::Gpio24; pub type DefaultRxPin = crate::gpio::Gpio23; } else if #[cfg(esp32s2)] { pub type DefaultTxPin = crate::gpio::Gpio43; pub type DefaultRxPin = crate::gpio::Gpio44; } else if #[cfg(esp32s3)] { pub type DefaultTxPin = crate::gpio::Gpio43; pub type DefaultRxPin = crate::gpio::Gpio44; } } /// UART Error #[derive(Debug, Clone, Copy, PartialEq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Error { /// An invalid configuration argument was provided InvalidArgument, /// The RX FIFO overflowed #[cfg(feature = "async")] RxFifoOvf, #[cfg(feature = "async")] RxGlitchDetected, #[cfg(feature = "async")] RxFrameError, #[cfg(feature = "async")] RxParityError, } #[cfg(feature = "embedded-hal")] impl embedded_hal_nb::serial::Error for Error { fn kind(&self) -> embedded_hal_nb::serial::ErrorKind { embedded_hal_nb::serial::ErrorKind::Other } } #[cfg(feature = "embedded-io")] impl embedded_io::Error for Error { fn kind(&self) -> embedded_io::ErrorKind { embedded_io::ErrorKind::Other } } // (outside of `config` module in order not to "use" it an extra time) /// UART clock source #[derive(PartialEq, Eq, Copy, Clone, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum ClockSource { /// APB_CLK clock source (default for UART on all the chips except of /// esp32c6 and esp32h2) Apb, #[cfg(not(any(esp32, esp32s2)))] /// RC_FAST_CLK clock source (17.5 MHz) RcFast, #[cfg(not(any(esp32, esp32s2)))] /// XTAL_CLK clock source (default for UART on esp32c6 and esp32h2 and /// LP_UART) Xtal, #[cfg(any(esp32, esp32s2))] /// REF_TICK clock source (derived from XTAL or RC_FAST, 1MHz) RefTick, } /// UART Configuration pub mod config { // see const UART_FULL_THRESH_DEFAULT: u16 = 120; // see const UART_TOUT_THRESH_DEFAULT: u8 = 10; /// Number of data bits #[derive(PartialEq, Eq, Copy, Clone, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum DataBits { DataBits5 = 0, DataBits6 = 1, DataBits7 = 2, DataBits8 = 3, } /// Parity check #[derive(PartialEq, Eq, Copy, Clone, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Parity { ParityNone, ParityEven, ParityOdd, } /// Number of stop bits #[derive(PartialEq, Eq, Copy, Clone, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum StopBits { /// 1 stop bit STOP1 = 1, /// 1.5 stop bits STOP1P5 = 2, /// 2 stop bits STOP2 = 3, } /// UART Configuration #[derive(Debug, Copy, Clone)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct Config { pub baudrate: u32, pub data_bits: DataBits, pub parity: Parity, pub stop_bits: StopBits, pub clock_source: super::ClockSource, pub rx_fifo_full_threshold: u16, pub rx_timeout: Option, } impl Config { pub fn baudrate(mut self, baudrate: u32) -> Self { self.baudrate = baudrate; self } pub fn parity_none(mut self) -> Self { self.parity = Parity::ParityNone; self } pub fn parity_even(mut self) -> Self { self.parity = Parity::ParityEven; self } pub fn parity_odd(mut self) -> Self { self.parity = Parity::ParityOdd; self } pub fn data_bits(mut self, data_bits: DataBits) -> Self { self.data_bits = data_bits; self } pub fn stop_bits(mut self, stop_bits: StopBits) -> Self { self.stop_bits = stop_bits; self } pub fn clock_source(mut self, source: super::ClockSource) -> Self { self.clock_source = source; self } pub fn symbol_length(&self) -> u8 { let mut length: u8 = 1; // start bit length += match self.data_bits { DataBits::DataBits5 => 5, DataBits::DataBits6 => 6, DataBits::DataBits7 => 7, DataBits::DataBits8 => 8, }; length += match self.parity { Parity::ParityNone => 0, _ => 1, }; length += match self.stop_bits { StopBits::STOP1 => 1, _ => 2, // esp-idf also counts 2 bits for settings 1.5 and 2 stop bits }; length } pub fn rx_fifo_full_threshold(mut self, threshold: u16) -> Self { self.rx_fifo_full_threshold = threshold; self } pub fn rx_timeout(mut self, timeout: Option) -> Self { self.rx_timeout = timeout; self } } impl Default for Config { fn default() -> Config { Config { baudrate: 115_200, data_bits: DataBits::DataBits8, parity: Parity::ParityNone, stop_bits: StopBits::STOP1, #[cfg(any(esp32c6, esp32h2, lp_uart))] clock_source: super::ClockSource::Xtal, #[cfg(not(any(esp32c6, esp32h2, lp_uart)))] clock_source: super::ClockSource::Apb, rx_fifo_full_threshold: UART_FULL_THRESH_DEFAULT, rx_timeout: Some(UART_TOUT_THRESH_DEFAULT), } } } /// Configuration for the AT-CMD detection functionality pub struct AtCmdConfig { pub pre_idle_count: Option, pub post_idle_count: Option, pub gap_timeout: Option, pub cmd_char: u8, pub char_num: Option, } impl AtCmdConfig { pub fn new( pre_idle_count: Option, post_idle_count: Option, gap_timeout: Option, cmd_char: u8, char_num: Option, ) -> AtCmdConfig { Self { pre_idle_count, post_idle_count, gap_timeout, cmd_char, char_num, } } } } /// UART (Full-duplex) pub struct Uart<'d, T, M> { tx: UartTx<'d, T, M>, rx: UartRx<'d, T, M>, } /// UART (Transmit) pub struct UartTx<'d, T, M> { phantom: PhantomData<(&'d mut T, M)>, } /// UART (Receive) pub struct UartRx<'d, T, M> { phantom: PhantomData<(&'d mut T, M)>, at_cmd_config: Option, rx_timeout_config: Option, internal_buf: [u8; 1024], // Buffer as part of the struct #[cfg(not(esp32))] symbol_len: u8, } impl<'d, T, M> UartTx<'d, T, M> where T: Instance, M: Mode, { fn new_inner() -> Self { Self { phantom: PhantomData, } } /// Configure RTS pin pub fn with_rts(self, rts: impl Peripheral

+ 'd) -> Self { crate::into_ref!(rts); rts.set_to_push_pull_output(Internal); rts.connect_peripheral_to_output(T::rts_signal(), Internal); self } /// Writes bytes pub fn write_bytes(&mut self, data: &[u8]) -> Result { let count = data.len(); data.iter() .try_for_each(|c| nb::block!(self.write_byte(*c)))?; Ok(count) } fn write_byte(&mut self, word: u8) -> nb::Result<(), Error> { if T::get_tx_fifo_count() < UART_FIFO_SIZE { T::register_block() .fifo() .write(|w| unsafe { w.rxfifo_rd_byte().bits(word) }); Ok(()) } else { Err(nb::Error::WouldBlock) } } /// Flush the transmit buffer of the UART pub fn flush_tx(&mut self) -> nb::Result<(), Error> { if T::is_tx_idle() { Ok(()) } else { Err(nb::Error::WouldBlock) } } } impl<'d, T> UartTx<'d, T, Blocking> where T: Instance + 'd, { /// Create a new UART TX instance in [`Blocking`] mode. pub fn new( uart: impl Peripheral

+ 'd, clocks: &Clocks, tx: impl Peripheral

+ 'd, ) -> Result { Self::new_with_config(uart, Default::default(), clocks, tx) } /// Create a new UART TX instance with configuration options in /// [`Blocking`] mode. pub fn new_with_config( uart: impl Peripheral

+ 'd, config: Config, clocks: &Clocks, tx: impl Peripheral

+ 'd, ) -> Result { crate::into_ref!(tx); tx.set_to_push_pull_output(Internal); tx.connect_peripheral_to_output(T::tx_signal(), Internal); let (uart_tx, _) = Uart::<'d, T, Blocking>::new_with_config_inner(uart, config, clocks)?.split(); Ok(uart_tx) } } impl<'d, T, M> UartRx<'d, T, M> where T: Instance, M: Mode, { fn new_inner(#[cfg(not(esp32))] symbol_len: u8) -> Self { Self { phantom: PhantomData, at_cmd_config: None, rx_timeout_config: None, internal_buf: [0; 1024], // Buffer as part of the struct #[cfg(not(esp32))] symbol_len, } } /// Configure CTS pin pub fn with_cts(self, cts: impl Peripheral

+ 'd) -> Self { crate::into_ref!(cts); cts.set_to_input(Internal); cts.connect_input_to_peripheral(T::cts_signal(), Internal); self } /// Fill a buffer with received bytes pub fn read_bytes(&mut self, mut buf: &mut [u8]) -> Result<(), Error> { if buf.is_empty() { return Ok(()); } let cap = buf.len(); let mut total = 0; loop { while T::get_rx_fifo_count() == 0 { // Block until we received at least one byte } let read = self.drain_fifo(buf); total += read; // drain_fifo only drains bytes that will fit in buf, // so we will always have an exact total if total == cap { break; } // update the buffer position based on the bytes read buf = &mut buf[read..]; } Ok(()) } /// Read a byte from the UART pub fn read_byte(&mut self) -> nb::Result { // On the ESP32-S2 we need to use PeriBus2 to read the FIFO: let offset = if cfg!(esp32s2) { 0x20C00000 } else { 0 }; if T::get_rx_fifo_count() > 0 { let value = unsafe { let fifo = (T::register_block().fifo().as_ptr() as *mut u8).offset(offset) as *mut crate::peripherals::generic::Reg; (*fifo).read().rxfifo_rd_byte().bits() }; Ok(value) } else { Err(nb::Error::WouldBlock) } } /// Read all available bytes from the RX FIFO into the provided buffer and /// returns the number of read bytes. Never blocks pub fn drain_fifo(&mut self, buf: &mut [u8]) -> usize { // On the ESP32-S2 we need to use PeriBus2 to read the FIFO: let offset = if cfg!(esp32s2) { 0x20C00000 } else { 0 }; let mut count = 0; while T::get_rx_fifo_count() > 0 && count < buf.len() { let value = unsafe { let fifo = (T::register_block().fifo().as_ptr() as *mut u8).offset(offset) as *mut crate::peripherals::generic::Reg; (*fifo).read().rxfifo_rd_byte().bits() }; buf[count] = value; count += 1; } count } /// Configures the RX-FIFO threshold /// /// # Errors /// `Err(Error::InvalidArgument)` if provided value exceeds maximum value /// for SOC : /// - `esp32` **0x7F** /// - `esp32c6`, `esp32h2` **0xFF** /// - `esp32c3`, `esp32c2`, `esp32s2` **0x1FF** /// - `esp32s3` **0x3FF** fn set_rx_fifo_full_threshold(&mut self, threshold: u16) -> Result<(), Error> { #[cfg(esp32)] const MAX_THRHD: u16 = 0x7F; #[cfg(any(esp32c6, esp32h2))] const MAX_THRHD: u16 = 0xFF; #[cfg(any(esp32c3, esp32c2, esp32s2))] const MAX_THRHD: u16 = 0x1FF; #[cfg(esp32s3)] const MAX_THRHD: u16 = 0x3FF; if threshold > MAX_THRHD { return Err(Error::InvalidArgument); } #[cfg(any(esp32, esp32c6, esp32h2))] let threshold: u8 = threshold as u8; T::register_block() .conf1() .modify(|_, w| unsafe { w.rxfifo_full_thrhd().bits(threshold) }); Ok(()) } /// Configures the Receive Timeout detection setting /// /// # Arguments /// `timeout` - the number of symbols ("bytes") to wait for before /// triggering a timeout. Pass None to disable the timeout. /// /// # Errors /// `Err(Error::InvalidArgument)` if the provided value exceeds the maximum /// value for SOC : /// - `esp32`: Symbol size is fixed to 8, do not pass a value > **0x7F**. /// - `esp32c2`, `esp32c3`, `esp32c6`, `esp32h2`, esp32s2`, esp32s3`: The /// value you pass times the symbol size must be <= **0x3FF** fn set_rx_timeout(&mut self, timeout: Option) -> Result<(), Error> { #[cfg(esp32)] const MAX_THRHD: u8 = 0x7F; // 7 bits #[cfg(any(esp32c2, esp32c3, esp32c6, esp32h2, esp32s2, esp32s3))] const MAX_THRHD: u16 = 0x3FF; // 10 bits #[cfg(esp32)] let reg_thrhd = &T::register_block().conf1(); #[cfg(any(esp32c6, esp32h2))] let reg_thrhd = &T::register_block().tout_conf(); #[cfg(any(esp32c2, esp32c3, esp32s2, esp32s3))] let reg_thrhd = &T::register_block().mem_conf(); #[cfg(any(esp32c6, esp32h2))] let reg_en = &T::register_block().tout_conf(); #[cfg(any(esp32, esp32c2, esp32c3, esp32s2, esp32s3))] let reg_en = &T::register_block().conf1(); match timeout { None => { reg_en.modify(|_, w| w.rx_tout_en().clear_bit()); } Some(timeout) => { // the esp32 counts directly in number of symbols (symbol len fixed to 8) #[cfg(esp32)] let timeout_reg = timeout; // all other count in bits, so we need to multiply by the symbol len. #[cfg(not(esp32))] let timeout_reg = timeout as u16 * self.symbol_len as u16; if timeout_reg > MAX_THRHD { return Err(Error::InvalidArgument); } reg_thrhd.modify(|_, w| unsafe { w.rx_tout_thrhd().bits(timeout_reg) }); reg_en.modify(|_, w| w.rx_tout_en().set_bit()); } } self.rx_timeout_config = timeout; Uart::<'d, T, M>::sync_regs(); Ok(()) } } impl<'d, T> UartRx<'d, T, Blocking> where T: Instance + 'd, { /// Create a new UART RX instance in [`Blocking`] mode. pub fn new( uart: impl Peripheral

+ 'd, clocks: &Clocks, rx: impl Peripheral

+ 'd, ) -> Result { Self::new_with_config(uart, Default::default(), clocks, rx) } /// Create a new UART RX instance with configuration options in /// [`Blocking`] mode. pub fn new_with_config( uart: impl Peripheral

+ 'd, config: Config, clocks: &Clocks, rx: impl Peripheral

+ 'd, ) -> Result { crate::into_ref!(rx); rx.set_to_input(Internal); rx.connect_input_to_peripheral(T::rx_signal(), Internal); let (_, uart_rx) = Uart::<'d, T, Blocking>::new_with_config_inner(uart, config, clocks)?.split(); Ok(uart_rx) } } impl<'d, T> Uart<'d, T, Blocking> where T: Instance + 'd, { /// Create a new UART instance with configuration options in [`Blocking`] /// mode. pub fn new_with_config( uart: impl Peripheral

+ 'd, config: Config, clocks: &Clocks, tx: impl Peripheral

+ 'd, rx: impl Peripheral

+ 'd, ) -> Result { crate::into_ref!(tx); crate::into_ref!(rx); tx.set_to_push_pull_output(Internal); tx.connect_peripheral_to_output(T::tx_signal(), Internal); rx.set_to_input(Internal); rx.connect_input_to_peripheral(T::rx_signal(), Internal); Self::new_with_config_inner(uart, config, clocks) } /// Create a new UART instance with defaults in [`Blocking`] mode. pub fn new( uart: impl Peripheral

+ 'd, clocks: &Clocks, tx: impl Peripheral

+ 'd, rx: impl Peripheral

+ 'd, ) -> Result { crate::into_ref!(tx); crate::into_ref!(rx); tx.set_to_push_pull_output(Internal); tx.connect_peripheral_to_output(T::tx_signal(), Internal); rx.set_to_input(Internal); rx.connect_input_to_peripheral(T::rx_signal(), Internal); Self::new_inner(uart, clocks) } /// Create a new UART instance with defaults in [`Blocking`] mode. /// Verify that the default pins (DefaultTxPin and DefaultRxPin) are used. pub fn new_with_default_pins( uart: impl Peripheral

+ 'd, clocks: &Clocks, tx: &mut DefaultTxPin, rx: &mut DefaultRxPin, ) -> Result { tx.set_to_push_pull_output(Internal); tx.connect_peripheral_to_output(T::tx_signal(), Internal); rx.set_to_input(Internal); rx.connect_input_to_peripheral(T::rx_signal(), Internal); Self::new_inner(uart, clocks) } } impl<'d, T, M> Uart<'d, T, M> where T: Instance + 'd, M: Mode, { pub(crate) fn new_with_config_inner( _uart: impl Peripheral

+ 'd, config: Config, clocks: &Clocks, ) -> Result { Self::init(); let mut serial = Uart { tx: UartTx::new_inner(), rx: UartRx::new_inner( #[cfg(not(esp32))] config.symbol_length(), ), }; serial .rx .set_rx_fifo_full_threshold(config.rx_fifo_full_threshold)?; serial.rx.set_rx_timeout(config.rx_timeout)?; serial.change_baud_internal(config.baudrate, config.clock_source, clocks); serial.change_data_bits(config.data_bits); serial.change_parity(config.parity); serial.change_stop_bits(config.stop_bits); // Setting err_wr_mask stops uart from storing data when data is wrong according // to reference manual T::register_block() .conf0() .modify(|_, w| w.err_wr_mask().set_bit()); // Reset Tx/Rx FIFOs serial.rxfifo_reset(); serial.txfifo_reset(); crate::rom::ets_delay_us(15); // Make sure we are starting in a "clean state" - previous operations might have // run into error conditions T::register_block() .int_clr() .write(|w| unsafe { w.bits(u32::MAX) }); Ok(serial) } fn inner_set_interrupt_handler(&mut self, handler: InterruptHandler) { unsafe { crate::interrupt::bind_interrupt(T::interrupt(), handler.handler()); crate::interrupt::enable(T::interrupt(), handler.priority()).unwrap(); } } fn new_inner(uart: impl Peripheral

+ 'd, clocks: &Clocks) -> Result { Self::new_with_config_inner(uart, Default::default(), clocks) } /// Configure CTS pin pub fn with_cts(self, cts: impl Peripheral

+ 'd) -> Self { crate::into_ref!(cts); cts.set_to_input(Internal); cts.connect_input_to_peripheral(T::cts_signal(), Internal); self } /// Configure RTS pin pub fn with_rts(self, rts: impl Peripheral

+ 'd) -> Self { crate::into_ref!(rts); rts.set_to_push_pull_output(Internal); rts.connect_peripheral_to_output(T::rts_signal(), Internal); self } /// Split the UART into a transmitter and receiver /// /// This is particularly useful when having two tasks correlating to /// transmitting and receiving. pub fn split(self) -> (UartTx<'d, T, M>, UartRx<'d, T, M>) { (self.tx, self.rx) } /// Write bytes out over the UART pub fn write_bytes(&mut self, data: &[u8]) -> Result { self.tx.write_bytes(data) } /// Fill a buffer with received bytes pub fn read_bytes(&mut self, buf: &mut [u8]) -> Result<(), Error> { self.rx.read_bytes(buf) } /// Configures the AT-CMD detection settings #[allow(clippy::useless_conversion)] pub fn set_at_cmd(&mut self, config: config::AtCmdConfig) { #[cfg(not(any(esp32, esp32s2)))] T::register_block() .clk_conf() .modify(|_, w| w.sclk_en().clear_bit()); T::register_block().at_cmd_char().write(|w| unsafe { w.at_cmd_char() .bits(config.cmd_char) .char_num() .bits(config.char_num.unwrap_or(1)) }); if let Some(pre_idle_count) = config.pre_idle_count { T::register_block() .at_cmd_precnt() .write(|w| unsafe { w.pre_idle_num().bits(pre_idle_count.into()) }); } if let Some(post_idle_count) = config.post_idle_count { T::register_block() .at_cmd_postcnt() .write(|w| unsafe { w.post_idle_num().bits(post_idle_count.into()) }); } if let Some(gap_timeout) = config.gap_timeout { T::register_block() .at_cmd_gaptout() .write(|w| unsafe { w.rx_gap_tout().bits(gap_timeout.into()) }); } #[cfg(not(any(esp32, esp32s2)))] T::register_block() .clk_conf() .modify(|_, w| w.sclk_en().set_bit()); Self::sync_regs(); self.rx.at_cmd_config = Some(config); } /// Listen for AT-CMD interrupts pub fn listen_at_cmd(&mut self) { T::register_block() .int_ena() .modify(|_, w| w.at_cmd_char_det().set_bit()); } /// Stop listening for AT-CMD interrupts pub fn unlisten_at_cmd(&mut self) { T::register_block() .int_ena() .modify(|_, w| w.at_cmd_char_det().clear_bit()); } /// Listen for TX-DONE interrupts pub fn listen_tx_done(&mut self) { T::register_block() .int_ena() .modify(|_, w| w.tx_done().set_bit()); } /// Stop listening for TX-DONE interrupts pub fn unlisten_tx_done(&mut self) { T::register_block() .int_ena() .modify(|_, w| w.tx_done().clear_bit()); } /// Listen for RX-FIFO-FULL interrupts pub fn listen_rx_fifo_full(&mut self) { T::register_block() .int_ena() .modify(|_, w| w.rxfifo_full().set_bit()); } /// Stop listening for RX-FIFO-FULL interrupts pub fn unlisten_rx_fifo_full(&mut self) { T::register_block() .int_ena() .modify(|_, w| w.rxfifo_full().clear_bit()); } /// Checks if AT-CMD interrupt is set pub fn at_cmd_interrupt_set(&self) -> bool { T::register_block() .int_raw() .read() .at_cmd_char_det() .bit_is_set() } /// Checks if TX-DONE interrupt is set pub fn tx_done_interrupt_set(&self) -> bool { T::register_block().int_raw().read().tx_done().bit_is_set() } /// Checks if RX-FIFO-FULL interrupt is set pub fn rx_fifo_full_interrupt_set(&self) -> bool { T::register_block() .int_raw() .read() .rxfifo_full() .bit_is_set() } /// Reset AT-CMD interrupt pub fn reset_at_cmd_interrupt(&self) { T::register_block() .int_clr() .write(|w| w.at_cmd_char_det().clear_bit_by_one()); } /// Reset TX-DONE interrupt pub fn reset_tx_done_interrupt(&self) { T::register_block() .int_clr() .write(|w| w.tx_done().clear_bit_by_one()); } /// Reset RX-FIFO-FULL interrupt pub fn reset_rx_fifo_full_interrupt(&self) { T::register_block() .int_clr() .write(|w| w.rxfifo_full().clear_bit_by_one()); } /// Write a byte out over the UART pub fn write_byte(&mut self, word: u8) -> nb::Result<(), Error> { self.tx.write_byte(word) } /// Flush the transmit buffer of the UART pub fn flush_tx(&mut self) -> nb::Result<(), Error> { self.tx.flush_tx() } /// Read a byte from the UART pub fn read_byte(&mut self) -> nb::Result { self.rx.read_byte() } /// Change the number of stop bits pub fn change_stop_bits(&mut self, stop_bits: config::StopBits) -> &mut Self { // workaround for hardware issue, when UART stop bit set as 2-bit mode. #[cfg(esp32)] if stop_bits == config::StopBits::STOP2 { T::register_block() .rs485_conf() .modify(|_, w| w.dl1_en().bit(true)); T::register_block() .conf0() .modify(|_, w| unsafe { w.stop_bit_num().bits(1) }); } else { T::register_block() .rs485_conf() .modify(|_, w| w.dl1_en().bit(false)); T::register_block() .conf0() .modify(|_, w| unsafe { w.stop_bit_num().bits(stop_bits as u8) }); } #[cfg(not(esp32))] T::register_block() .conf0() .modify(|_, w| unsafe { w.stop_bit_num().bits(stop_bits as u8) }); self } fn change_data_bits(&mut self, data_bits: config::DataBits) -> &mut Self { T::register_block() .conf0() .modify(|_, w| unsafe { w.bit_num().bits(data_bits as u8) }); self } fn change_parity(&mut self, parity: config::Parity) -> &mut Self { T::register_block().conf0().modify(|_, w| match parity { config::Parity::ParityNone => w.parity_en().clear_bit(), config::Parity::ParityEven => w.parity_en().set_bit().parity().clear_bit(), config::Parity::ParityOdd => w.parity_en().set_bit().parity().set_bit(), }); self } #[cfg(any(esp32c2, esp32c3, esp32s3))] fn change_baud_internal(&self, baudrate: u32, clock_source: ClockSource, clocks: &Clocks) { let clk = match clock_source { ClockSource::Apb => clocks.apb_clock.to_Hz(), ClockSource::Xtal => clocks.xtal_clock.to_Hz(), ClockSource::RcFast => RC_FAST_CLK.to_Hz(), }; let max_div = 0b1111_1111_1111 - 1; let clk_div = ((clk) + (max_div * baudrate) - 1) / (max_div * baudrate); T::register_block().clk_conf().write(|w| unsafe { w.sclk_sel() .bits(match clock_source { ClockSource::Apb => 1, ClockSource::RcFast => 2, ClockSource::Xtal => 3, }) .sclk_div_a() .bits(0) .sclk_div_b() .bits(0) .sclk_div_num() .bits(clk_div as u8 - 1) .rx_sclk_en() .bit(true) .tx_sclk_en() .bit(true) }); let divider = (clk << 4) / (baudrate * clk_div); let divider_integer = (divider >> 4) as u16; let divider_frag = (divider & 0xf) as u8; T::register_block() .clkdiv() .write(|w| unsafe { w.clkdiv().bits(divider_integer).frag().bits(divider_frag) }); } #[cfg(any(esp32c6, esp32h2))] fn change_baud_internal(&self, baudrate: u32, clock_source: ClockSource, clocks: &Clocks) { let clk = match clock_source { ClockSource::Apb => clocks.apb_clock.to_Hz(), ClockSource::Xtal => clocks.xtal_clock.to_Hz(), ClockSource::RcFast => RC_FAST_CLK.to_Hz(), }; let max_div = 0b1111_1111_1111 - 1; let clk_div = ((clk) + (max_div * baudrate) - 1) / (max_div * baudrate); // UART clocks are configured via PCR let pcr = unsafe { &*crate::peripherals::PCR::PTR }; match T::uart_number() { 0 => { pcr.uart0_conf() .modify(|_, w| w.uart0_rst_en().clear_bit().uart0_clk_en().set_bit()); pcr.uart0_sclk_conf().modify(|_, w| unsafe { w.uart0_sclk_div_a() .bits(0) .uart0_sclk_div_b() .bits(0) .uart0_sclk_div_num() .bits(clk_div as u8 - 1) .uart0_sclk_sel() .bits(match clock_source { ClockSource::Apb => 1, ClockSource::RcFast => 2, ClockSource::Xtal => 3, }) .uart0_sclk_en() .set_bit() }); } 1 => { pcr.uart1_conf() .modify(|_, w| w.uart1_rst_en().clear_bit().uart1_clk_en().set_bit()); pcr.uart1_sclk_conf().modify(|_, w| unsafe { w.uart1_sclk_div_a() .bits(0) .uart1_sclk_div_b() .bits(0) .uart1_sclk_div_num() .bits(clk_div as u8 - 1) .uart1_sclk_sel() .bits(match clock_source { ClockSource::Apb => 1, ClockSource::RcFast => 2, ClockSource::Xtal => 3, }) .uart1_sclk_en() .set_bit() }); } _ => unreachable!(), // ESP32-C6 only has 2 UART instances } let clk = clk / clk_div; let divider = clk / baudrate; let divider = divider as u16; T::register_block() .clkdiv() .write(|w| unsafe { w.clkdiv().bits(divider).frag().bits(0) }); Self::sync_regs(); } #[cfg(any(esp32, esp32s2))] fn change_baud_internal(&self, baudrate: u32, clock_source: ClockSource, clocks: &Clocks) { let clk = match clock_source { ClockSource::Apb => clocks.apb_clock.to_Hz(), ClockSource::RefTick => REF_TICK.to_Hz(), /* ESP32(/-S2) TRM, section 3.2.4.2 * (6.2.4.2 for S2) */ }; T::register_block().conf0().modify(|_, w| { w.tick_ref_always_on().bit(match clock_source { ClockSource::Apb => true, ClockSource::RefTick => false, }) }); let divider = clk / baudrate; T::register_block() .clkdiv() .write(|w| unsafe { w.clkdiv().bits(divider).frag().bits(0) }); } #[cfg(any(esp32c2, esp32c3, esp32s3))] #[inline(always)] fn init() { let system = unsafe { crate::peripherals::SYSTEM::steal() }; if !system.perip_clk_en0().read().uart_mem_clk_en().bit() { system .perip_clk_en0() .modify(|_, w| w.uart_mem_clk_en().set_bit()); } // initialize peripheral by setting clk_enable and clearing uart_reset bits T::enable_peripheral(); Self::uart_peripheral_reset(); T::disable_rx_interrupts(); T::disable_tx_interrupts(); } /// Modify UART baud rate and reset TX/RX fifo. pub fn change_baud(&mut self, baudrate: u32, clock_source: ClockSource, clocks: &Clocks) { self.change_baud_internal(baudrate, clock_source, clocks); self.txfifo_reset(); self.rxfifo_reset(); } #[cfg(any(esp32c6, esp32h2))] #[inline(always)] fn init() { T::register_block() .conf0() .modify(|_, w| w.mem_clk_en().set_bit()); // initialize peripheral by setting clk_enable and clearing uart_reset bits T::enable_peripheral(); Self::uart_peripheral_reset(); T::disable_rx_interrupts(); T::disable_tx_interrupts(); } #[cfg(any(esp32, esp32s2))] #[inline(always)] fn init() { T::enable_peripheral(); Self::uart_peripheral_reset(); T::disable_rx_interrupts(); T::disable_tx_interrupts(); } #[inline(always)] fn uart_peripheral_reset() { // don't reset the console UART - this will cause trouble (i.e. the UART will // start to transmit garbage) // // We should only reset the console UART if it was absolutely unused before. // Apparently the bootloader (and maybe the ROM code) writing to the UART is // already enough to make this a no-go. (i.e. one needs to mute the ROM // code via efuse / strapping pin AND use a silent bootloader) // // Ideally this should be configurable once we have a solution for https://github.com/esp-rs/esp-hal/issues/1111 // see https://github.com/espressif/esp-idf/blob/5f4249357372f209fdd57288265741aaba21a2b1/components/esp_driver_uart/src/uart.c#L179 if T::uart_number() != CONSOLE_UART_NUM { #[cfg(not(any(esp32, esp32s2)))] T::register_block() .clk_conf() .modify(|_, w| w.rst_core().set_bit()); // reset peripheral T::reset_peripheral(); #[cfg(not(any(esp32, esp32s2)))] T::register_block() .clk_conf() .modify(|_, w| w.rst_core().clear_bit()); } } #[cfg(any(esp32c3, esp32c6, esp32h2, esp32s3))] // TODO introduce a cfg symbol for this #[inline(always)] fn sync_regs() { #[cfg(any(esp32c6, esp32h2))] let update_reg = T::register_block().reg_update(); #[cfg(any(esp32c3, esp32s3))] let update_reg = T::register_block().id(); update_reg.modify(|_, w| w.reg_update().set_bit()); while update_reg.read().reg_update().bit_is_set() { // wait } } #[cfg(not(any(esp32c3, esp32c6, esp32h2, esp32s3)))] #[inline(always)] fn sync_regs() {} fn rxfifo_reset(&mut self) { T::register_block() .conf0() .modify(|_, w| w.rxfifo_rst().set_bit()); Self::sync_regs(); T::register_block() .conf0() .modify(|_, w| w.rxfifo_rst().clear_bit()); Self::sync_regs(); } fn txfifo_reset(&mut self) { T::register_block() .conf0() .modify(|_, w| w.txfifo_rst().set_bit()); Self::sync_regs(); T::register_block() .conf0() .modify(|_, w| w.txfifo_rst().clear_bit()); Self::sync_regs(); } } impl<'d, T> crate::private::Sealed for Uart<'d, T, Blocking> where T: Instance + 'd {} impl<'d, T> InterruptConfigurable for Uart<'d, T, Blocking> where T: Instance + 'd, { fn set_interrupt_handler(&mut self, handler: crate::interrupt::InterruptHandler) { self.inner_set_interrupt_handler(handler); } } /// UART Peripheral Instance pub trait Instance: crate::private::Sealed { fn register_block() -> &'static RegisterBlock; fn uart_number() -> usize; fn interrupt() -> Interrupt; fn disable_tx_interrupts() { Self::register_block().int_clr().write(|w| { w.txfifo_empty() .clear_bit_by_one() .tx_brk_done() .clear_bit_by_one() .tx_brk_idle_done() .clear_bit_by_one() .tx_done() .clear_bit_by_one() }); Self::register_block().int_ena().write(|w| { w.txfifo_empty() .clear_bit() .tx_brk_done() .clear_bit() .tx_brk_idle_done() .clear_bit() .tx_done() .clear_bit() }); } fn disable_rx_interrupts() { Self::register_block().int_clr().write(|w| { w.rxfifo_full() .clear_bit_by_one() .rxfifo_ovf() .clear_bit_by_one() .rxfifo_tout() .clear_bit_by_one() .at_cmd_char_det() .clear_bit_by_one() }); Self::register_block().int_ena().write(|w| { w.rxfifo_full() .clear_bit() .rxfifo_ovf() .clear_bit() .rxfifo_tout() .clear_bit() .at_cmd_char_det() .clear_bit() }); } #[allow(clippy::useless_conversion)] fn get_tx_fifo_count() -> u16 { Self::register_block() .status() .read() .txfifo_cnt() .bits() .into() } #[allow(clippy::useless_conversion)] fn get_rx_fifo_count() -> u16 { let fifo_cnt: u16 = Self::register_block() .status() .read() .rxfifo_cnt() .bits() .into(); // Calculate the real count based on the FIFO read and write offset address: // https://www.espressif.com/sites/default/files/documentation/esp32_errata_en.pdf // section 3.17 #[cfg(esp32)] { let rd_addr = Self::register_block() .mem_rx_status() .read() .mem_rx_rd_addr() .bits(); let wr_addr = Self::register_block() .mem_rx_status() .read() .mem_rx_wr_addr() .bits(); if wr_addr > rd_addr { wr_addr - rd_addr } else if wr_addr < rd_addr { (wr_addr + UART_FIFO_SIZE) - rd_addr } else if fifo_cnt > 0 { UART_FIFO_SIZE } else { 0 } } #[cfg(not(esp32))] fifo_cnt } fn is_tx_idle() -> bool { #[cfg(esp32)] let idle = Self::register_block().status().read().st_utx_out().bits() == 0x0u8; #[cfg(not(esp32))] let idle = Self::register_block() .fsm_status() .read() .st_utx_out() .bits() == 0x0u8; idle } fn is_rx_idle() -> bool { #[cfg(esp32)] let idle = Self::register_block().status().read().st_urx_out().bits() == 0x0u8; #[cfg(not(esp32))] let idle = Self::register_block() .fsm_status() .read() .st_urx_out() .bits() == 0x0u8; idle } fn tx_signal() -> OutputSignal; fn rx_signal() -> InputSignal; fn cts_signal() -> InputSignal; fn rts_signal() -> OutputSignal; fn enable_peripheral(); fn reset_peripheral(); } macro_rules! impl_instance { ($inst:ident, $num:expr, $txd:ident, $rxd:ident, $cts:ident, $rts:ident, $peri:ident) => { impl Instance for crate::peripherals::$inst { #[inline(always)] fn register_block() -> &'static RegisterBlock { unsafe { &*crate::peripherals::$inst::PTR } } #[inline(always)] fn uart_number() -> usize { $num } #[inline(always)] fn interrupt() -> Interrupt { Interrupt::$inst } fn tx_signal() -> OutputSignal { OutputSignal::$txd } fn rx_signal() -> InputSignal { InputSignal::$rxd } fn cts_signal() -> InputSignal { InputSignal::$cts } fn rts_signal() -> OutputSignal { OutputSignal::$rts } fn enable_peripheral() { PeripheralClockControl::enable(crate::system::Peripheral::$peri); } fn reset_peripheral() { PeripheralClockControl::reset(crate::system::Peripheral::$peri); } } }; } impl_instance!(UART0, 0, U0TXD, U0RXD, U0CTS, U0RTS, Uart0); impl_instance!(UART1, 1, U1TXD, U1RXD, U1CTS, U1RTS, Uart1); #[cfg(uart2)] impl_instance!(UART2, 2, U2TXD, U2RXD, U2CTS, U2RTS, Uart2); #[cfg(feature = "ufmt")] impl ufmt_write::uWrite for Uart<'_, T, M> where T: Instance, M: Mode, { type Error = Error; #[inline] fn write_str(&mut self, s: &str) -> Result<(), Self::Error> { self.tx.write_str(s) } #[inline] fn write_char(&mut self, ch: char) -> Result<(), Self::Error> { self.tx.write_char(ch) } } #[cfg(feature = "ufmt")] impl ufmt_write::uWrite for UartTx<'_, T, M> where T: Instance, M: Mode, { type Error = Error; #[inline] fn write_str(&mut self, s: &str) -> Result<(), Self::Error> { self.write_bytes(s.as_bytes())?; Ok(()) } } impl core::fmt::Write for Uart<'_, T, M> where T: Instance, M: Mode, { #[inline] fn write_str(&mut self, s: &str) -> core::fmt::Result { self.tx.write_str(s) } } impl core::fmt::Write for UartTx<'_, T, M> where T: Instance, M: Mode, { #[inline] fn write_str(&mut self, s: &str) -> core::fmt::Result { self.write_bytes(s.as_bytes()) .map_err(|_| core::fmt::Error)?; Ok(()) } } #[cfg(feature = "embedded-hal-02")] impl embedded_hal_02::serial::Write for Uart<'_, T, M> where T: Instance, M: Mode, { type Error = Error; fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> { self.tx.write(word) } fn flush(&mut self) -> nb::Result<(), Self::Error> { self.tx.flush() } } #[cfg(feature = "embedded-hal-02")] impl embedded_hal_02::serial::Write for UartTx<'_, T, M> where T: Instance, M: Mode, { type Error = Error; fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> { self.write_byte(word) } fn flush(&mut self) -> nb::Result<(), Self::Error> { self.flush_tx() } } #[cfg(feature = "embedded-hal-02")] impl embedded_hal_02::serial::Read for Uart<'_, T, M> where T: Instance, M: Mode, { type Error = Error; fn read(&mut self) -> nb::Result { self.rx.read() } } #[cfg(feature = "embedded-hal-02")] impl embedded_hal_02::serial::Read for UartRx<'_, T, M> where T: Instance, M: Mode, { type Error = Error; fn read(&mut self) -> nb::Result { self.read_byte() } } #[cfg(feature = "embedded-hal")] impl embedded_hal_nb::serial::ErrorType for Uart<'_, T, M> { type Error = Error; } #[cfg(feature = "embedded-hal")] impl embedded_hal_nb::serial::ErrorType for UartTx<'_, T, M> { type Error = Error; } #[cfg(feature = "embedded-hal")] impl embedded_hal_nb::serial::ErrorType for UartRx<'_, T, M> { type Error = Error; } #[cfg(feature = "embedded-hal")] impl embedded_hal_nb::serial::Read for Uart<'_, T, M> where T: Instance, M: Mode, { fn read(&mut self) -> nb::Result { self.read_byte() } } #[cfg(feature = "embedded-hal")] impl embedded_hal_nb::serial::Read for UartRx<'_, T, M> where T: Instance, M: Mode, { fn read(&mut self) -> nb::Result { self.read_byte() } } #[cfg(feature = "embedded-hal")] impl embedded_hal_nb::serial::Write for Uart<'_, T, M> where T: Instance, M: Mode, { fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> { self.write_byte(word) } fn flush(&mut self) -> nb::Result<(), Self::Error> { self.flush_tx() } } #[cfg(feature = "embedded-hal")] impl embedded_hal_nb::serial::Write for UartTx<'_, T, M> where T: Instance, M: Mode, { fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> { self.write_byte(word) } fn flush(&mut self) -> nb::Result<(), Self::Error> { self.flush_tx() } } #[cfg(feature = "embedded-io")] impl embedded_io::ErrorType for Uart<'_, T, M> { type Error = Error; } #[cfg(feature = "embedded-io")] impl embedded_io::ErrorType for UartTx<'_, T, M> { type Error = Error; } #[cfg(feature = "embedded-io")] impl embedded_io::ErrorType for UartRx<'_, T, M> { type Error = Error; } #[cfg(feature = "embedded-io")] impl embedded_io::Read for Uart<'_, T, M> where T: Instance, M: Mode, { fn read(&mut self, buf: &mut [u8]) -> Result { self.rx.read(buf) } } #[cfg(feature = "embedded-io")] impl embedded_io::Read for UartRx<'_, T, M> where T: Instance, M: Mode, { fn read(&mut self, buf: &mut [u8]) -> Result { if buf.is_empty() { return Ok(0); } while T::get_rx_fifo_count() == 0 { // Block until we received at least one byte } Ok(self.drain_fifo(buf)) } } #[cfg(feature = "embedded-io")] impl embedded_io::ReadReady for Uart<'_, T, M> where T: Instance, M: Mode, { fn read_ready(&mut self) -> Result { self.rx.read_ready() } } #[cfg(feature = "embedded-io")] impl embedded_io::ReadReady for UartRx<'_, T, M> where T: Instance, M: Mode, { fn read_ready(&mut self) -> Result { Ok(T::get_rx_fifo_count() > 0) } } #[cfg(feature = "embedded-io")] impl embedded_io::Write for Uart<'_, T, M> where T: Instance, M: Mode, { fn write(&mut self, buf: &[u8]) -> Result { self.tx.write(buf) } fn flush(&mut self) -> Result<(), Self::Error> { self.tx.flush() } } #[cfg(feature = "embedded-io")] impl embedded_io::Write for UartTx<'_, T, M> where T: Instance, M: Mode, { fn write(&mut self, buf: &[u8]) -> Result { self.write_bytes(buf) } fn flush(&mut self) -> Result<(), Self::Error> { loop { match self.flush_tx() { Ok(_) => break, Err(nb::Error::WouldBlock) => { /* Wait */ } Err(nb::Error::Other(e)) => return Err(e), } } Ok(()) } } #[cfg(feature = "async")] mod asynch { use core::task::Poll; use cfg_if::cfg_if; use embassy_sync::waitqueue::AtomicWaker; use enumset::{EnumSet, EnumSetType}; use procmacros::handler; use super::*; use crate::Async; cfg_if! { if #[cfg(all(uart0, uart1, uart2))] { const NUM_UART: usize = 3; } else if #[cfg(all(uart0, uart1))] { const NUM_UART: usize = 2; } else if #[cfg(uart0)] { const NUM_UART: usize = 1; } } const INIT: AtomicWaker = AtomicWaker::new(); static TX_WAKERS: [AtomicWaker; NUM_UART] = [INIT; NUM_UART]; static RX_WAKERS: [AtomicWaker; NUM_UART] = [INIT; NUM_UART]; #[derive(EnumSetType, Debug)] pub(crate) enum TxEvent { TxDone, TxFiFoEmpty, } #[derive(EnumSetType, Debug)] pub(crate) enum RxEvent { RxFifoFull, RxCmdCharDetected, RxFifoOvf, RxFifoTout, RxGlitchDetected, RxFrameError, RxParityError, } /// A future that resolves when the passed interrupt is triggered, /// or has been triggered in the meantime (flag set in INT_RAW). /// Upon construction the future enables the passed interrupt and when it /// is dropped it disables the interrupt again. The future returns the event /// that was initially passed, when it resolves. pub(crate) struct UartRxFuture<'d, T: Instance> { events: EnumSet, phantom: PhantomData<&'d mut T>, registered: bool, internal_buf: [u8; 1024], // Buffer as part of the struct } pub(crate) struct UartTxFuture<'d, T: Instance> { events: EnumSet, phantom: PhantomData<&'d mut T>, registered: bool, // internal_buf: [u8; 1024], // Buffer as part of the struct } impl<'d, T: Instance> UartRxFuture<'d, T> { pub fn new(events: EnumSet) -> Self { Self { events, phantom: PhantomData, registered: false, internal_buf: [0; 1024], // Initialize buffer } } fn get_triggered_events(&self) -> EnumSet { let interrupts_enabled = T::register_block().int_ena().read(); let mut events_triggered = EnumSet::new(); for event in self.events { let event_triggered = match event { RxEvent::RxFifoFull => interrupts_enabled.rxfifo_full().bit_is_clear(), RxEvent::RxCmdCharDetected => { interrupts_enabled.at_cmd_char_det().bit_is_clear() } RxEvent::RxFifoOvf => interrupts_enabled.rxfifo_ovf().bit_is_clear(), RxEvent::RxFifoTout => interrupts_enabled.rxfifo_tout().bit_is_clear(), RxEvent::RxGlitchDetected => interrupts_enabled.glitch_det().bit_is_clear(), RxEvent::RxFrameError => interrupts_enabled.frm_err().bit_is_clear(), RxEvent::RxParityError => interrupts_enabled.parity_err().bit_is_clear(), }; if event_triggered { events_triggered |= event; } } events_triggered } } impl<'d, T: Instance> core::future::Future for UartRxFuture<'d, T> { type Output = EnumSet; fn poll( mut self: core::pin::Pin<&mut Self>, cx: &mut core::task::Context<'_>, ) -> core::task::Poll { if !self.registered { RX_WAKERS[T::uart_number()].register(cx.waker()); T::register_block().int_ena().modify(|_, w| { for event in self.events { match event { RxEvent::RxFifoFull => w.rxfifo_full().set_bit(), RxEvent::RxCmdCharDetected => w.at_cmd_char_det().set_bit(), RxEvent::RxFifoOvf => w.rxfifo_ovf().set_bit(), RxEvent::RxFifoTout => w.rxfifo_tout().set_bit(), RxEvent::RxGlitchDetected => w.glitch_det().set_bit(), RxEvent::RxFrameError => w.frm_err().set_bit(), RxEvent::RxParityError => w.parity_err().set_bit(), }; } w }); self.registered = true; } let events = self.get_triggered_events(); if !events.is_empty() { Poll::Ready(events) } else { Poll::Pending } } } impl<'d, T: Instance> Drop for UartRxFuture<'d, T> { fn drop(&mut self) { // Although the isr disables the interrupt that occurred directly, we need to // disable the other interrupts (= the ones that did not occur), as // soon as this future goes out of scope. let int_ena = &T::register_block().int_ena(); for event in self.events { match event { RxEvent::RxFifoFull => int_ena.modify(|_, w| w.rxfifo_full().clear_bit()), RxEvent::RxCmdCharDetected => { int_ena.modify(|_, w| w.at_cmd_char_det().clear_bit()) } RxEvent::RxGlitchDetected => int_ena.modify(|_, w| w.glitch_det().clear_bit()), RxEvent::RxFrameError => int_ena.modify(|_, w| w.frm_err().clear_bit()), RxEvent::RxParityError => int_ena.modify(|_, w| w.parity_err().clear_bit()), RxEvent::RxFifoOvf => int_ena.modify(|_, w| w.rxfifo_ovf().clear_bit()), RxEvent::RxFifoTout => int_ena.modify(|_, w| w.rxfifo_tout().clear_bit()), } } } } impl<'d, T: Instance> UartTxFuture<'d, T> { pub fn new(events: EnumSet) -> Self { Self { events, phantom: PhantomData, registered: false, // internal_buf: [0; 1024], // Initialize buffer } } fn get_triggered_events(&self) -> bool { let interrupts_enabled = T::register_block().int_ena().read(); let mut event_triggered = false; for event in self.events { event_triggered |= match event { TxEvent::TxDone => interrupts_enabled.tx_done().bit_is_clear(), TxEvent::TxFiFoEmpty => interrupts_enabled.txfifo_empty().bit_is_clear(), } } event_triggered } } impl<'d, T: Instance> core::future::Future for UartTxFuture<'d, T> { type Output = (); fn poll( mut self: core::pin::Pin<&mut Self>, cx: &mut core::task::Context<'_>, ) -> core::task::Poll { if !self.registered { TX_WAKERS[T::uart_number()].register(cx.waker()); T::register_block().int_ena().modify(|_, w| { for event in self.events { match event { TxEvent::TxDone => w.tx_done().set_bit(), TxEvent::TxFiFoEmpty => w.txfifo_empty().set_bit(), }; } w }); self.registered = true; } if self.get_triggered_events() { Poll::Ready(()) } else { Poll::Pending } } } impl<'d, T: Instance> Drop for UartTxFuture<'d, T> { fn drop(&mut self) { // Although the isr disables the interrupt that occurred directly, we need to // disable the other interrupts (= the ones that did not occur), as // soon as this future goes out of scope. let int_ena = &T::register_block().int_ena(); for event in self.events { match event { TxEvent::TxDone => int_ena.modify(|_, w| w.tx_done().clear_bit()), TxEvent::TxFiFoEmpty => int_ena.modify(|_, w| w.txfifo_empty().clear_bit()), } } } } impl<'d, T> Uart<'d, T, Async> where T: Instance + 'd, { /// Create a new UART instance with configuration options in [`Async`] /// mode. pub fn new_async_with_config( uart: impl Peripheral

+ 'd, config: Config, clocks: &Clocks, tx: impl Peripheral

+ 'd, rx: impl Peripheral

+ 'd, ) -> Result { crate::into_ref!(tx); crate::into_ref!(rx); tx.set_to_push_pull_output(Internal); tx.connect_peripheral_to_output(T::tx_signal(), Internal); rx.set_to_input(Internal); rx.connect_input_to_peripheral(T::rx_signal(), Internal); let mut this = Self::new_with_config_inner(uart, config, clocks)?; this.inner_set_interrupt_handler(match T::uart_number() { #[cfg(uart0)] 0 => uart0, #[cfg(uart1)] 1 => uart1, #[cfg(uart2)] 2 => uart2, _ => unreachable!(), }); Ok(this) } /// Create a new UART instance with defaults in [`Async`] mode. pub fn new_async( uart: impl Peripheral

+ 'd, clocks: &Clocks, tx: impl Peripheral

+ 'd, rx: impl Peripheral

+ 'd, ) -> Result { Self::new_async_with_config(uart, Default::default(), clocks, tx, rx) } /// Create a new UART instance with defaults in [`Async`] mode. pub fn new_async_with_default_pins( uart: impl Peripheral

+ 'd, clocks: &Clocks, tx: DefaultTxPin, rx: DefaultRxPin, ) -> Result { Self::new_async_with_config(uart, Default::default(), clocks, tx, rx) } } impl Uart<'_, T, Async> where T: Instance, { /// See [`UartRx::read_async`] pub async fn read_async(&mut self, buf: &mut [u8]) -> Result { self.rx.read_async(buf).await } // pub async fn fill_buf(&mut self, buf: &mut [u8]) -> Result { // self.rx.fill_buf_async().await // } pub async fn write_async(&mut self, words: &[u8]) -> Result { self.tx.write_async(words).await } pub async fn flush_async(&mut self) -> Result<(), Error> { self.tx.flush_async().await } } impl<'d, T> UartTx<'d, T, Async> where T: Instance + 'd, { /// Create a new UART TX instance in [`Async`] mode. pub fn new_async( uart: impl Peripheral

+ 'd, clocks: &Clocks, tx: impl Peripheral

+ 'd, ) -> Result { Self::new_async_with_config(uart, Default::default(), clocks, tx) } /// Create a new UART TX instance with configuration options in /// [`Async`] mode. pub fn new_async_with_config( uart: impl Peripheral

+ 'd, config: Config, clocks: &Clocks, tx: impl Peripheral

+ 'd, ) -> Result { crate::into_ref!(tx); tx.set_to_push_pull_output(Internal); tx.connect_peripheral_to_output(T::tx_signal(), Internal); let mut uart = Uart::<'d, T, Async>::new_with_config_inner(uart, config, clocks)?; uart.inner_set_interrupt_handler(match T::uart_number() { #[cfg(uart0)] 0 => uart0, #[cfg(uart1)] 1 => uart1, #[cfg(uart2)] 2 => uart2, _ => unreachable!(), }); let (uart_tx, _) = uart.split(); Ok(uart_tx) } pub async fn write_async(&mut self, words: &[u8]) -> Result { let mut count = 0; let mut offset: usize = 0; loop { let mut next_offset = offset + (UART_FIFO_SIZE - T::get_tx_fifo_count()) as usize; if next_offset > words.len() { next_offset = words.len(); } for byte in &words[offset..next_offset] { self.write_byte(*byte).unwrap(); // should never fail count += 1; } if next_offset >= words.len() { break; } offset = next_offset; UartTxFuture::::new(TxEvent::TxFiFoEmpty.into()).await; } Ok(count) } pub async fn flush_async(&mut self) -> Result<(), Error> { let count = T::get_tx_fifo_count(); if count > 0 { UartTxFuture::::new(TxEvent::TxDone.into()).await; } Ok(()) } } impl<'d, T> UartRx<'d, T, Async> where T: Instance + 'd, { /// Create a new UART RX instance in [`Async`] mode. pub fn new_async( uart: impl Peripheral

+ 'd, clocks: &Clocks, rx: impl Peripheral

+ 'd, ) -> Result { Self::new_async_with_config(uart, Default::default(), clocks, rx) } /// Create a new UART RX instance with configuration options in /// [`Async`] mode. pub fn new_async_with_config( uart: impl Peripheral

+ 'd, config: Config, clocks: &Clocks, rx: impl Peripheral

+ 'd, ) -> Result { crate::into_ref!(rx); rx.set_to_input(Internal); rx.connect_input_to_peripheral(T::rx_signal(), Internal); let mut uart = Uart::<'d, T, Async>::new_with_config_inner(uart, config, clocks)?; uart.inner_set_interrupt_handler(match T::uart_number() { #[cfg(uart0)] 0 => uart0, #[cfg(uart1)] 1 => uart1, #[cfg(uart2)] 2 => uart2, _ => unreachable!(), }); let (_, uart_rx) = uart.split(); Ok(uart_rx) } /// Read async to buffer slice `buf`. /// Waits until at least one byte is in the Rx FiFo /// and one of the following interrupts occurs: /// - `RXFIFO_FULL` /// - `RXFIFO_OVF` /// - `AT_CMD_CHAR_DET` (only if `set_at_cmd` was called) /// - `RXFIFO_TOUT` (only if `set_rx_timeout was called) /// /// The interrupts in question are enabled during the body of this /// function. The method immediately returns when the interrupt /// has already occurred before calling this method (e.g. status /// bit set, but interrupt not enabled) /// /// # Params /// - `buf` buffer slice to write the bytes into /// /// /// # Ok /// When successful, returns the number of bytes written to buf. /// This method will never return Ok(0) pub async fn read_async(&mut self, buf: &mut [u8]) -> Result { if buf.len() == 0 { return Err(Error::InvalidArgument); } loop { let mut events = RxEvent::RxFifoFull | RxEvent::RxFifoOvf | RxEvent::RxFrameError | RxEvent::RxGlitchDetected | RxEvent::RxParityError; if self.at_cmd_config.is_some() { events |= RxEvent::RxCmdCharDetected; } if self.rx_timeout_config.is_some() { events |= RxEvent::RxFifoTout; } let events_happened = UartRxFuture::::new(events).await; // always drain the fifo, if an error has occurred the data is lost let read_bytes = self.drain_fifo(buf); // check error events for event_happened in events_happened { match event_happened { RxEvent::RxFifoOvf => return Err(Error::RxFifoOvf), RxEvent::RxGlitchDetected => return Err(Error::RxGlitchDetected), RxEvent::RxFrameError => return Err(Error::RxFrameError), RxEvent::RxParityError => return Err(Error::RxParityError), RxEvent::RxFifoFull | RxEvent::RxCmdCharDetected | RxEvent::RxFifoTout => { continue } } } // Unfortunately, the uart's rx-timeout counter counts up whenever there is // data in the fifo, even if the interrupt is disabled and the status bit // cleared. Since we do not drain the fifo in the interrupt handler, we need to // reset the counter here, after draining the fifo. T::register_block() .int_clr() .write(|w| w.rxfifo_tout().clear_bit_by_one()); if read_bytes > 0 { return Ok(read_bytes); } } } pub async fn fill_buf_async(&mut self) -> Result<&[u8], Error> { let mut total_read = 0; let mut internal_buf = [0u8; 1024]; // Adjust size as necessary loop { let mut events = RxEvent::RxFifoFull | RxEvent::RxFifoOvf | RxEvent::RxFrameError | RxEvent::RxGlitchDetected | RxEvent::RxParityError; if self.at_cmd_config.is_some() { events |= RxEvent::RxCmdCharDetected; } if self.rx_timeout_config.is_some() { events |= RxEvent::RxFifoTout; } let events_happened = UartRxFuture::::new(events).await; // Drain data into the temporary buffer let read_bytes = self.drain_fifo(&mut internal_buf); if read_bytes > 0 { // Copy read data to self.internal_buf self.internal_buf[..read_bytes].copy_from_slice(&internal_buf[..read_bytes]); total_read += read_bytes; // Check for errors for event_happened in events_happened { match event_happened { RxEvent::RxFifoOvf => return Err(Error::RxFifoOvf), RxEvent::RxGlitchDetected => return Err(Error::RxGlitchDetected), RxEvent::RxFrameError => return Err(Error::RxFrameError), RxEvent::RxParityError => return Err(Error::RxParityError), RxEvent::RxFifoFull | RxEvent::RxCmdCharDetected | RxEvent::RxFifoTout => { continue } } } // Reset RX timeout counter T::register_block() .int_clr() .write(|w| w.rxfifo_tout().clear_bit_by_one()); return Ok(&self.internal_buf[..total_read]); } } } pub fn consume_async(&self, amt: usize) { // Implement buffer consumption logic // Assuming the presence of an internal buffer management // Mocked function to represent internal buffer handling } } impl embedded_io_async::Read for Uart<'_, T, Async> where T: Instance, { /// In contrast to the documentation of embedded_io_async::Read, this /// method blocks until an uart interrupt occurs. /// See UartRx::read_async for more details. async fn read(&mut self, buf: &mut [u8]) -> Result { self.read_async(buf).await } } impl embedded_io_async::Read for UartRx<'_, T, Async> where T: Instance, { /// In contrast to the documentation of embedded_io_async::Read, this /// method blocks until an uart interrupt occurs. /// See UartRx::read_async for more details. async fn read(&mut self, buf: &mut [u8]) -> Result { self.read_async(buf).await } } impl embedded_io_async::BufRead for UartRx<'_, T, Async> where T: Instance, { async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> { self.fill_buf_async().await } fn consume(&mut self, amt: usize) { self.consume_async(amt) } } impl embedded_io_async::BufRead for Uart<'_, T, Async> where T: Instance, { async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> { self.rx.fill_buf_async().await } fn consume(&mut self, amt: usize) { self.rx.consume_async(amt) } } impl embedded_io_async::Write for Uart<'_, T, Async> where T: Instance, { async fn write(&mut self, buf: &[u8]) -> Result { self.write_async(buf).await } async fn flush(&mut self) -> Result<(), Self::Error> { self.flush_async().await } } impl embedded_io_async::Write for UartTx<'_, T, Async> where T: Instance, { async fn write(&mut self, buf: &[u8]) -> Result { self.write_async(buf).await } async fn flush(&mut self) -> Result<(), Self::Error> { self.flush_async().await } } /// Interrupt handler for all UART instances /// Clears and disables interrupts that have occurred and have their enable /// bit set. The fact that an interrupt has been disabled is used by the /// futures to detect that they should indeed resolve after being woken up fn intr_handler(uart: &RegisterBlock) -> (bool, bool) { let interrupts = uart.int_st().read(); let interrupt_bits = interrupts.bits(); // = int_raw & int_ena if interrupt_bits == 0 { return (false, false); } 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(); let tx_wake = interrupts.tx_done().bit_is_set() || interrupts.txfifo_empty().bit_is_set(); uart.int_clr().write(|w| unsafe { w.bits(interrupt_bits) }); uart.int_ena() .modify(|r, w| unsafe { w.bits(r.bits() & !interrupt_bits) }); (rx_wake, tx_wake) } #[cfg(uart0)] #[handler] fn uart0() { let uart = unsafe { &*crate::peripherals::UART0::ptr() }; let (rx, tx) = intr_handler(uart); if rx { RX_WAKERS[0].wake(); } if tx { TX_WAKERS[0].wake(); } } #[cfg(uart1)] #[handler] fn uart1() { let uart = unsafe { &*crate::peripherals::UART1::ptr() }; let (rx, tx) = intr_handler(uart); if rx { RX_WAKERS[1].wake(); } if tx { TX_WAKERS[1].wake(); } } #[cfg(uart2)] #[handler] fn uart2() { let uart = unsafe { &*crate::peripherals::UART2::ptr() }; let (rx, tx) = intr_handler(uart); if rx { RX_WAKERS[2].wake(); } if tx { TX_WAKERS[2].wake(); } } } /// Low-power UART #[cfg(lp_uart)] pub mod lp_uart { use crate::{ gpio::lp_io::{LowPowerInput, LowPowerOutput}, peripherals::{LP_CLKRST, LP_UART}, uart::config::{self, Config}, }; /// LP-UART driver /// /// The driver uses XTAL as clock source. pub struct LpUart { uart: LP_UART, } impl LpUart { /// Initialize the UART driver using the default configuration // TODO: CTS and RTS pins pub fn new(uart: LP_UART, _tx: LowPowerOutput<5>, _rx: LowPowerInput<4>) -> Self { let lp_io = unsafe { &*crate::peripherals::LP_IO::PTR }; let lp_aon = unsafe { &*crate::peripherals::LP_AON::PTR }; lp_aon .gpio_mux() .modify(|r, w| unsafe { w.sel().bits(r.sel().bits() | 1 << 4) }); lp_aon .gpio_mux() .modify(|r, w| unsafe { w.sel().bits(r.sel().bits() | 1 << 5) }); lp_io.gpio4().modify(|_, w| unsafe { w.mcu_sel().bits(1) }); lp_io.gpio5().modify(|_, w| unsafe { w.mcu_sel().bits(1) }); Self::new_with_config(uart, Config::default()) } /// Initialize the UART driver using the provided configuration pub fn new_with_config(uart: LP_UART, config: Config) -> Self { let mut me = Self { uart }; // Set UART mode - do nothing for LP // Disable UART parity // 8-bit world // 1-bit stop bit me.uart.conf0().modify(|_, w| unsafe { w.parity() .clear_bit() .parity_en() .clear_bit() .bit_num() .bits(0x3) .stop_bit_num() .bits(0x1) }); // Set tx idle me.uart .idle_conf() .modify(|_, w| unsafe { w.tx_idle_num().bits(0) }); // Disable hw-flow control me.uart .hwfc_conf() .modify(|_, w| w.rx_flow_en().clear_bit()); // Get source clock frequency // default == SOC_MOD_CLK_RTC_FAST == 2 // LP_CLKRST.lpperi.lp_uart_clk_sel = 0; unsafe { &*LP_CLKRST::PTR } .lpperi() .modify(|_, w| w.lp_uart_clk_sel().clear_bit()); // Override protocol parameters from the configuration // uart_hal_set_baudrate(&hal, cfg->uart_proto_cfg.baud_rate, sclk_freq); me.change_baud_internal(config.baudrate, config.clock_source); // uart_hal_set_parity(&hal, cfg->uart_proto_cfg.parity); me.change_parity(config.parity); // uart_hal_set_data_bit_num(&hal, cfg->uart_proto_cfg.data_bits); me.change_data_bits(config.data_bits); // uart_hal_set_stop_bits(&hal, cfg->uart_proto_cfg.stop_bits); me.change_stop_bits(config.stop_bits); // uart_hal_set_tx_idle_num(&hal, LP_UART_TX_IDLE_NUM_DEFAULT); me.change_tx_idle(0); // LP_UART_TX_IDLE_NUM_DEFAULT == 0 // Reset Tx/Rx FIFOs me.rxfifo_reset(); me.txfifo_reset(); me } fn rxfifo_reset(&mut self) { self.uart.conf0().modify(|_, w| w.rxfifo_rst().set_bit()); self.update(); self.uart.conf0().modify(|_, w| w.rxfifo_rst().clear_bit()); self.update(); } fn txfifo_reset(&mut self) { self.uart.conf0().modify(|_, w| w.txfifo_rst().set_bit()); self.update(); self.uart.conf0().modify(|_, w| w.txfifo_rst().clear_bit()); self.update(); } fn update(&mut self) { self.uart .reg_update() .modify(|_, w| w.reg_update().set_bit()); while self.uart.reg_update().read().reg_update().bit_is_set() { // wait } } fn change_baud_internal(&mut self, baudrate: u32, clock_source: super::ClockSource) { // TODO: Currently it's not possible to use XtalD2Clk let clk = 16_000_000; let max_div = 0b1111_1111_1111 - 1; let clk_div = ((clk) + (max_div * baudrate) - 1) / (max_div * baudrate); self.uart.clk_conf().modify(|_, w| unsafe { w.sclk_div_a() .bits(0) .sclk_div_b() .bits(0) .sclk_div_num() .bits(clk_div as u8 - 1) .sclk_sel() .bits(match clock_source { super::ClockSource::Xtal => 3, super::ClockSource::RcFast => 2, super::ClockSource::Apb => panic!("Wrong clock source for LP_UART"), }) .sclk_en() .set_bit() }); let clk = clk / clk_div; let divider = clk / baudrate; let divider = divider as u16; self.uart .clkdiv() .write(|w| unsafe { w.clkdiv().bits(divider).frag().bits(0) }); self.update(); } /// Modify UART baud rate and reset TX/RX fifo. pub fn change_baud(&mut self, baudrate: u32, clock_source: super::ClockSource) { self.change_baud_internal(baudrate, clock_source); self.txfifo_reset(); self.rxfifo_reset(); } fn change_parity(&mut self, parity: config::Parity) -> &mut Self { if parity != config::Parity::ParityNone { self.uart .conf0() .modify(|_, w| w.parity().bit((parity as u8 & 0x1) != 0)); } self.uart.conf0().modify(|_, w| match parity { config::Parity::ParityNone => w.parity_en().clear_bit(), config::Parity::ParityEven => w.parity_en().set_bit().parity().clear_bit(), config::Parity::ParityOdd => w.parity_en().set_bit().parity().set_bit(), }); self } fn change_data_bits(&mut self, data_bits: config::DataBits) -> &mut Self { self.uart .conf0() .modify(|_, w| unsafe { w.bit_num().bits(data_bits as u8) }); self.update(); self } fn change_stop_bits(&mut self, stop_bits: config::StopBits) -> &mut Self { self.uart .conf0() .modify(|_, w| unsafe { w.stop_bit_num().bits(stop_bits as u8) }); self.update(); self } fn change_tx_idle(&mut self, idle_num: u16) -> &mut Self { self.uart .idle_conf() .modify(|_, w| unsafe { w.tx_idle_num().bits(idle_num) }); self.update(); self } } }