diff --git a/esp-hal/Cargo.toml b/esp-hal/Cargo.toml index 8aeb56bebce..b6d6cdd4c0b 100644 --- a/esp-hal/Cargo.toml +++ b/esp-hal/Cargo.toml @@ -44,10 +44,12 @@ esp-synopsys-usb-otg = { version = "0.4.2", optional = true, features = ["fs fugit = "0.3.7" instability = "0.3" log = { version = "0.4.22", optional = true } +nb = "1.1.0" paste = "1.0.15" portable-atomic = { version = "1.9.0", default-features = false } procmacros = { version = "0.15.0", package = "esp-hal-procmacros", path = "../esp-hal-procmacros" } strum = { version = "0.26.3", default-features = false, features = ["derive"] } +void = { version = "1.0.2", default-features = false } usb-device = { version = "0.3.2", optional = true } rand_core = "0.6.4" ufmt-write = "0.1.0" diff --git a/esp-hal/src/analog/adc/esp32.rs b/esp-hal/src/analog/adc/esp32.rs index b2a92f56517..93e003a0c7d 100644 --- a/esp-hal/src/analog/adc/esp32.rs +++ b/esp-hal/src/analog/adc/esp32.rs @@ -288,7 +288,7 @@ where /// This method takes an [AdcPin](super::AdcPin) reference, as it is /// expected that the ADC will be able to sample whatever channel /// underlies the pin. - pub fn read_oneshot(&mut self, _pin: &mut super::AdcPin) -> Option + pub fn read_oneshot(&mut self, _pin: &mut super::AdcPin) -> nb::Result where PIN: super::AdcChannel, { @@ -301,7 +301,7 @@ where // - if it's for a different channel try again later // - if it's for the given channel, go ahead and check progress if active_channel != PIN::CHANNEL { - return None; + return Err(nb::Error::WouldBlock); } } else { // If no conversions are in progress, start a new one for given channel @@ -316,7 +316,7 @@ where // Wait for ADC to finish conversion let conversion_finished = ADCI::read_done_sar(); if !conversion_finished { - return None; + return Err(nb::Error::WouldBlock); } // Get converted value @@ -325,7 +325,7 @@ where // Mark that no conversions are currently in progress self.active_channel = None; - Some(converted_value) + Ok(converted_value) } } diff --git a/esp-hal/src/analog/adc/mod.rs b/esp-hal/src/analog/adc/mod.rs index 730a7a747d5..2b899cfcbdd 100644 --- a/esp-hal/src/analog/adc/mod.rs +++ b/esp-hal/src/analog/adc/mod.rs @@ -43,11 +43,7 @@ //! let mut delay = Delay::new(); //! //! loop { -//! let pin_value: u16 = loop { -//! if let Some(value) = adc1.read_oneshot(&mut pin) { -//! break value; -//! } -//! }; +//! let pin_value: u16 = nb::block!(adc1.read_oneshot(&mut pin)).unwrap(); //! //! delay.delay_millis(1500); //! } diff --git a/esp-hal/src/analog/adc/riscv.rs b/esp-hal/src/analog/adc/riscv.rs index bacca94ef70..f4968cc5bb0 100644 --- a/esp-hal/src/analog/adc/riscv.rs +++ b/esp-hal/src/analog/adc/riscv.rs @@ -433,7 +433,10 @@ where /// This method takes an [AdcPin](super::AdcPin) reference, as it is /// expected that the ADC will be able to sample whatever channel /// underlies the pin. - pub fn read_oneshot(&mut self, pin: &mut super::AdcPin) -> Option + pub fn read_oneshot( + &mut self, + pin: &mut super::AdcPin, + ) -> nb::Result where PIN: super::AdcChannel, CS: super::AdcCalScheme, @@ -447,7 +450,7 @@ where // - if it's for a different channel try again later // - if it's for the given channel, go ahead and check progress if active_channel != PIN::CHANNEL { - return None; + return Err(nb::Error::WouldBlock); } } else { // If no conversions are in progress, start a new one for given channel @@ -473,7 +476,7 @@ where // Wait for ADC to finish conversion let conversion_finished = ADCI::is_done(); if !conversion_finished { - return None; + return Err(nb::Error::WouldBlock); } // Get converted value @@ -496,7 +499,7 @@ where // Mark that no conversions are currently in progress self.active_channel = None; - Some(converted_value) + Ok(converted_value) } } diff --git a/esp-hal/src/analog/adc/xtensa.rs b/esp-hal/src/analog/adc/xtensa.rs index 0b4c9637766..f92b7406f09 100644 --- a/esp-hal/src/analog/adc/xtensa.rs +++ b/esp-hal/src/analog/adc/xtensa.rs @@ -502,7 +502,10 @@ where /// This method takes an [AdcPin](super::AdcPin) reference, as it is /// expected that the ADC will be able to sample whatever channel /// underlies the pin. - pub fn read_oneshot(&mut self, pin: &mut super::AdcPin) -> Option + pub fn read_oneshot( + &mut self, + pin: &mut super::AdcPin, + ) -> nb::Result where PIN: super::AdcChannel, CS: super::AdcCalScheme, @@ -512,7 +515,7 @@ where // - if it's for a different channel try again later // - if it's for the given channel, go ahead and check progress if active_channel != PIN::CHANNEL { - return None; + return Err(nb::Error::WouldBlock); } } else { // If no conversions are in progress, start a new one for given channel @@ -524,7 +527,7 @@ where // Wait for ADC to finish conversion let conversion_finished = ADCI::is_done(); if !conversion_finished { - return None; + return Err(nb::Error::WouldBlock); } // Get converted value @@ -537,7 +540,7 @@ where // Mark that no conversions are currently in progress self.active_channel = None; - Some(converted_value) + Ok(converted_value) } fn start_sample(&mut self, pin: &mut AdcPin) diff --git a/esp-hal/src/hmac.rs b/esp-hal/src/hmac.rs index 1beb4758216..31a699248b6 100644 --- a/esp-hal/src/hmac.rs +++ b/esp-hal/src/hmac.rs @@ -34,6 +34,8 @@ //! //! [HMAC]: https://github.com/esp-rs/esp-hal/blob/main/examples/src/bin/hmac.rs +use core::convert::Infallible; + use crate::{ peripheral::{Peripheral, PeripheralRef}, peripherals::HMAC, @@ -131,7 +133,7 @@ impl<'d> Hmac<'d> { } /// Step 2. Configure HMAC keys and key purposes. - pub fn configure(&mut self, m: HmacPurpose, key_id: KeyId) -> Result<(), Error> { + pub fn configure(&mut self, m: HmacPurpose, key_id: KeyId) -> nb::Result<(), Error> { self.hmac .set_para_purpose() .write(|w| unsafe { w.purpose_set().bits(m as u8) }); @@ -143,33 +145,39 @@ impl<'d> Hmac<'d> { .write(|w| w.set_para_end().set_bit()); if self.hmac.query_error().read().query_check().bit_is_set() { - return Err(Error::KeyPurposeMismatch); + return Err(nb::Error::Other(Error::KeyPurposeMismatch)); } Ok(()) } /// Process the msg block after block - pub fn update<'a>(&mut self, msg: &'a [u8]) -> &'a [u8] { - while (*self).is_busy() {} + /// + /// Call this function as many times as necessary (msg.len() > 0) + pub fn update<'a>(&mut self, msg: &'a [u8]) -> nb::Result<&'a [u8], Infallible> { + if self.is_busy() { + return Err(nb::Error::WouldBlock); + } self.next_command(); - let remaining = self.write_data(msg); + let remaining = self.write_data(msg).unwrap(); - remaining + Ok(remaining) } /// Finalizes the HMAC computation and retrieves the resulting hash output. - pub fn finalize(&mut self, output: &mut [u8]) { - while (*self).is_busy() {} + pub fn finalize(&mut self, output: &mut [u8]) -> nb::Result<(), Infallible> { + if self.is_busy() { + return Err(nb::Error::WouldBlock); + } self.next_command(); let msg_len = self.byte_written as u64; - self.write_data(&[0x80]); - self.flush_data(); + nb::block!(self.write_data(&[0x80])).unwrap(); + nb::block!(self.flush_data()).unwrap(); self.next_command(); debug_assert!(self.byte_written % 4 == 0); @@ -196,6 +204,7 @@ impl<'d> Hmac<'d> { .write(|w| w.set_result_end().set_bit()); self.byte_written = 64; self.next_command = NextCommand::None; + Ok(()) } fn is_busy(&mut self) -> bool { @@ -219,7 +228,7 @@ impl<'d> Hmac<'d> { self.next_command = NextCommand::None; } - fn write_data<'a>(&mut self, incoming: &'a [u8]) -> &'a [u8] { + fn write_data<'a>(&mut self, incoming: &'a [u8]) -> nb::Result<&'a [u8], Infallible> { let mod_length = self.byte_written % 64; let (remaining, bound_reached) = self.alignment_helper.aligned_volatile_copy( @@ -248,11 +257,13 @@ impl<'d> Hmac<'d> { } } - remaining + Ok(remaining) } - fn flush_data(&mut self) { - while self.is_busy() {} + fn flush_data(&mut self) -> nb::Result<(), Infallible> { + if self.is_busy() { + return Err(nb::Error::WouldBlock); + } let flushed = self.alignment_helper.flush_to( #[cfg(esp32s2)] @@ -270,6 +281,8 @@ impl<'d> Hmac<'d> { while self.is_busy() {} self.next_command = NextCommand::MessagePad; } + + Ok(()) } fn padding(&mut self, msg_len: u64) { diff --git a/esp-hal/src/rng.rs b/esp-hal/src/rng.rs index 72167018148..2efa64fc13c 100644 --- a/esp-hal/src/rng.rs +++ b/esp-hal/src/rng.rs @@ -81,13 +81,10 @@ /// Attenuation::Attenuation11dB /// ); /// let mut adc1 = Adc::::new(peripherals.ADC1, adc1_config); -/// let pin_value: u16 = loop { -/// if let Some(value) = adc1.read_oneshot(&mut adc1_pin) { -/// break value; -/// } -/// }; +/// let pin_value: u16 = nb::block!(adc1.read_oneshot(&mut adc1_pin)).unwrap(); /// rng.read(&mut buf); /// true_rand = rng.random(); +/// let pin_value: u16 = nb::block!(adc1.read_oneshot(&mut adc1_pin)).unwrap(); /// # } /// ``` use core::marker::PhantomData; diff --git a/esp-hal/src/rsa/esp32.rs b/esp-hal/src/rsa/esp32.rs index e5070d60153..32a7490cd3a 100644 --- a/esp-hal/src/rsa/esp32.rs +++ b/esp-hal/src/rsa/esp32.rs @@ -1,3 +1,5 @@ +use core::convert::Infallible; + use crate::rsa::{ implement_op, Multi, @@ -12,8 +14,11 @@ impl Rsa<'_, Dm> { /// After the RSA Accelerator is released from reset, the memory blocks /// needs to be initialized, only after that peripheral should be used. /// This function would return without an error if the memory is initialized - pub fn ready(&mut self) { - while !self.rsa.clean().read().clean().bit_is_clear() {} + pub fn ready(&mut self) -> nb::Result<(), Infallible> { + if self.rsa.clean().read().clean().bit_is_clear() { + return Err(nb::Error::WouldBlock); + } + Ok(()) } /// Writes the multi-mode configuration to the RSA hardware. diff --git a/esp-hal/src/rsa/esp32cX.rs b/esp-hal/src/rsa/esp32cX.rs index a376e39622c..04316db36fa 100644 --- a/esp-hal/src/rsa/esp32cX.rs +++ b/esp-hal/src/rsa/esp32cX.rs @@ -1,3 +1,5 @@ +use core::convert::Infallible; + use crate::rsa::{ implement_op, Multi, @@ -12,8 +14,11 @@ impl Rsa<'_, Dm> { /// After the RSA Accelerator is released from reset, the memory blocks /// needs to be initialized, only after that peripheral should be used. /// This function would return without an error if the memory is initialized - pub fn ready(&mut self) { - while !self.rsa.query_clean().read().query_clean().bit_is_clear() {} + pub fn ready(&mut self) -> nb::Result<(), Infallible> { + if self.rsa.query_clean().read().query_clean().bit_is_clear() { + return Err(nb::Error::WouldBlock); + } + Ok(()) } /// Enables/disables rsa interrupt. diff --git a/esp-hal/src/rsa/esp32sX.rs b/esp-hal/src/rsa/esp32sX.rs index 4816d04a11e..ca39a295707 100644 --- a/esp-hal/src/rsa/esp32sX.rs +++ b/esp-hal/src/rsa/esp32sX.rs @@ -1,3 +1,5 @@ +use core::convert::Infallible; + use crate::rsa::{ implement_op, Multi, @@ -13,8 +15,11 @@ impl Rsa<'_, Dm> { /// needs to be initialized, only after that peripheral should be used. /// This function would return without an error if the memory is /// initialized. - pub fn ready(&mut self) { - while !self.rsa.clean().read().clean().bit_is_clear() {} + pub fn ready(&mut self) -> nb::Result<(), Infallible> { + if self.rsa.clean().read().clean().bit_is_clear() { + return Err(nb::Error::WouldBlock); + } + Ok(()) } /// Enables/disables rsa interrupt. diff --git a/esp-hal/src/sha.rs b/esp-hal/src/sha.rs index a2021ecbb85..41fdf6dce0a 100644 --- a/esp-hal/src/sha.rs +++ b/esp-hal/src/sha.rs @@ -33,6 +33,7 @@ #![doc = crate::before_snippet!()] //! # use esp_hal::sha::Sha; //! # use esp_hal::sha::Sha256; +//! # use nb::block; //! let mut source_data = "HELLO, ESPRESSIF!".as_bytes(); //! let mut sha = Sha::new(peripherals.SHA); //! let mut hasher = sha.start::(); @@ -41,18 +42,21 @@ //! let mut output = [0u8; 32]; //! //! while !source_data.is_empty() { -//! source_data = hasher.update(source_data); -//! }; +//! // All the HW Sha functions are infallible so unwrap is fine to use if +//! // you use block! +//! source_data = block!(hasher.update(source_data)).unwrap(); +//! } //! //! // Finish can be called as many times as desired to get multiple copies of //! // the output. -//! hasher.finish(output.as_mut_slice()); +//! block!(hasher.finish(output.as_mut_slice())).unwrap(); +//! //! # } //! ``` //! ## Implementation State //! - DMA-SHA Mode is not supported. -use core::{borrow::BorrowMut, marker::PhantomData, mem::size_of}; +use core::{borrow::BorrowMut, convert::Infallible, marker::PhantomData, mem::size_of}; /// Re-export digest for convenience #[cfg(feature = "digest")] @@ -204,7 +208,7 @@ impl<'d, A: ShaAlgorithm, S: BorrowMut>> ShaDigest<'d, A, S> { } /// Updates the SHA digest with the provided data buffer. - pub fn update<'a>(&mut self, incoming: &'a [u8]) -> &'a [u8] { + pub fn update<'a>(&mut self, incoming: &'a [u8]) -> nb::Result<&'a [u8], Infallible> { self.finished = false; self.write_data(incoming) @@ -217,11 +221,10 @@ impl<'d, A: ShaAlgorithm, S: BorrowMut>> ShaDigest<'d, A, S> { /// Typically, output is expected to be the size of /// [ShaAlgorithm::DIGEST_LENGTH], but smaller inputs can be given to /// get a "short hash" - pub fn finish(&mut self, output: &mut [u8]) { + pub fn finish(&mut self, output: &mut [u8]) -> nb::Result<(), Infallible> { // Store message length for padding let length = (self.cursor as u64 * 8).to_be_bytes(); - // Append "1" bit - self.update(&[0x80]); + nb::block!(self.update(&[0x80]))?; // Append "1" bit // Flush partial data, ensures aligned cursor { @@ -304,12 +307,16 @@ impl<'d, A: ShaAlgorithm, S: BorrowMut>> ShaDigest<'d, A, S> { self.first_run = true; self.cursor = 0; self.alignment_helper.reset(); + + Ok(()) } /// Save the current state of the digest for later continuation. #[cfg(not(esp32))] - pub fn save(&mut self, context: &mut Context) { - while self.is_busy() {} + pub fn save(&mut self, context: &mut Context) -> nb::Result<(), Infallible> { + if self.is_busy() { + return Err(nb::Error::WouldBlock); + } context.alignment_helper = self.alignment_helper.clone(); context.cursor = self.cursor; @@ -332,6 +339,8 @@ impl<'d, A: ShaAlgorithm, S: BorrowMut>> ShaDigest<'d, A, S> { 32, ); } + + Ok(()) } /// Discard the current digest and return the peripheral. @@ -371,18 +380,18 @@ impl<'d, A: ShaAlgorithm, S: BorrowMut>> ShaDigest<'d, A, S> { } } - fn write_data<'a>(&mut self, incoming: &'a [u8]) -> &'a [u8] { + fn write_data<'a>(&mut self, incoming: &'a [u8]) -> nb::Result<&'a [u8], Infallible> { if self.message_buffer_is_full { - while (*self).is_busy() { - // The message buffer is full and the hardware is still - // processing the previous message. There's - // nothing to be done besides wait for the hardware. + if self.is_busy() { + // The message buffer is full and the hardware is still processing the previous + // message. There's nothing to be done besides wait for the hardware. + return Err(nb::Error::WouldBlock); + } else { + // Submit the full buffer. + self.process_buffer(); + // The buffer is now free for filling. + self.message_buffer_is_full = false; } - - // Submit the full buffer. - self.process_buffer(); - // The buffer is now free for filling. - self.message_buffer_is_full = false; } let mod_cursor = self.cursor % A::CHUNK_LENGTH; @@ -410,7 +419,7 @@ impl<'d, A: ShaAlgorithm, S: BorrowMut>> ShaDigest<'d, A, S> { } } - remaining + Ok(remaining) } } @@ -529,7 +538,7 @@ impl<'d, A: ShaAlgorithm, S: BorrowMut>> digest::Update for ShaDigest<'d fn update(&mut self, data: &[u8]) { let mut remaining = data.as_ref(); while !remaining.is_empty() { - remaining = self.update(remaining); + remaining = nb::block!(Self::update(self, remaining)).unwrap(); } } } @@ -537,7 +546,7 @@ impl<'d, A: ShaAlgorithm, S: BorrowMut>> digest::Update for ShaDigest<'d #[cfg(feature = "digest")] impl<'d, A: ShaAlgorithm, S: BorrowMut>> digest::FixedOutput for ShaDigest<'d, A, S> { fn finalize_into(mut self, out: &mut digest::Output) { - self.finish(out); + nb::block!(self.finish(out)).unwrap(); } } diff --git a/esp-hal/src/twai/mod.rs b/esp-hal/src/twai/mod.rs index bbafc268090..884d2e70d31 100644 --- a/esp-hal/src/twai/mod.rs +++ b/esp-hal/src/twai/mod.rs @@ -31,6 +31,7 @@ //! # use esp_hal::twai::TwaiConfiguration; //! # use esp_hal::twai::BaudRate; //! # use esp_hal::twai::TwaiMode; +//! # use nb::block; //! // Use GPIO pins 2 and 3 to connect to the respective pins on the TWAI //! // transceiver. //! let twai_rx_pin = peripherals.GPIO3; @@ -61,14 +62,10 @@ //! //! loop { //! // Wait for a frame to be received. -//! let frame = loop { -//! if let Ok(frame) = twai.receive() { -//! break frame; -//! } -//! }; +//! let frame = block!(twai.receive()).unwrap(); //! //! // Transmit the frame back. -//! while twai.transmit(&frame).is_err() {} +//! let _result = block!(twai.transmit(&frame)).unwrap(); //! } //! # } //! ``` @@ -84,6 +81,7 @@ //! # use esp_hal::twai::EspTwaiFrame; //! # use esp_hal::twai::StandardId; //! # use esp_hal::twai::TwaiMode; +//! # use nb::block; //! // Use GPIO pins 2 and 3 to connect to the respective pins on the TWAI //! // transceiver. //! let can_rx_pin = peripherals.GPIO3; @@ -113,11 +111,7 @@ //! //! let frame = EspTwaiFrame::new_self_reception(StandardId::ZERO, //! &[1, 2, 3]).unwrap(); // Wait for a frame to be received. -//! let frame = loop { -//! if let Ok(frame) = can.receive() { -//! break frame; -//! } -//! }; +//! let frame = block!(can.receive()).unwrap(); //! //! # loop {} //! # } @@ -1185,12 +1179,12 @@ where } /// Sends the specified `EspTwaiFrame` over the TWAI bus. - pub fn transmit(&mut self, frame: &EspTwaiFrame) -> Result<(), EspTwaiError> { + pub fn transmit(&mut self, frame: &EspTwaiFrame) -> nb::Result<(), EspTwaiError> { self.tx.transmit(frame) } /// Receives a TWAI frame from the TWAI bus. - pub fn receive(&mut self) -> Result { + pub fn receive(&mut self) -> nb::Result { self.rx.receive() } @@ -1225,16 +1219,18 @@ where /// NOTE: TODO: This may not work if using the self reception/self test /// functionality. See notes 1 and 2 in the "Frame Identifier" section /// of the reference manual. - pub fn transmit(&mut self, frame: &EspTwaiFrame) -> Result<(), EspTwaiError> { + pub fn transmit(&mut self, frame: &EspTwaiFrame) -> nb::Result<(), EspTwaiError> { let register_block = self.twai.register_block(); let status = register_block.status().read(); // Check that the peripheral is not in a bus off state. if status.bus_off_st().bit_is_set() { - return Err(EspTwaiError::BusOff); + return nb::Result::Err(nb::Error::Other(EspTwaiError::BusOff)); } // Check that the peripheral is not already transmitting a packet. - while !status.tx_buf_st().bit_is_set() {} + if !status.tx_buf_st().bit_is_set() { + return nb::Result::Err(nb::Error::WouldBlock); + } write_frame(register_block, frame); @@ -1255,24 +1251,28 @@ where Dm: crate::DriverMode, { /// Receive a frame - pub fn receive(&mut self) -> Result { + pub fn receive(&mut self) -> nb::Result { let register_block = self.twai.register_block(); let status = register_block.status().read(); // Check that the peripheral is not in a bus off state. if status.bus_off_st().bit_is_set() { - return Err(EspTwaiError::BusOff); + return nb::Result::Err(nb::Error::Other(EspTwaiError::BusOff)); } // Check that we actually have packets to receive. - while !status.rx_buf_st().bit_is_set() {} + if !status.rx_buf_st().bit_is_set() { + return nb::Result::Err(nb::Error::WouldBlock); + } // Check if the packet in the receive buffer is valid or overrun. if status.miss_st().bit_is_set() { - return Err(EspTwaiError::EmbeddedHAL(ErrorKind::Overrun)); + return nb::Result::Err(nb::Error::Other(EspTwaiError::EmbeddedHAL( + ErrorKind::Overrun, + ))); } - read_frame(register_block) + Ok(read_frame(register_block)?) } } @@ -1344,21 +1344,18 @@ where type Error = EspTwaiError; /// Transmit a frame. - fn transmit( - &mut self, - frame: &Self::Frame, - ) -> embedded_hal_nb::nb::Result, Self::Error> { + fn transmit(&mut self, frame: &Self::Frame) -> nb::Result, Self::Error> { self.tx.transmit(frame)?; // Success in readying packet for transmit. No packets can be replaced in the // transmit buffer so return None in accordance with the // embedded-can/embedded-hal trait. - embedded_hal_nb::nb::Result::Ok(None) + nb::Result::Ok(None) } /// Return a received frame if there are any available. - fn receive(&mut self) -> embedded_hal_nb::nb::Result { - Ok(self.rx.receive()?) + fn receive(&mut self) -> nb::Result { + self.rx.receive() } } diff --git a/esp-hal/src/uart.rs b/esp-hal/src/uart.rs index 9dd0d0bb0c5..107aba62117 100644 --- a/esp-hal/src/uart.rs +++ b/esp-hal/src/uart.rs @@ -677,7 +677,7 @@ where /// Flush the transmit buffer of the UART pub fn flush(&mut self) { - while self.is_tx_idle() {} + while !self.is_tx_idle() {} } /// Checks if the TX line is idle for this UART instance. diff --git a/esp-hal/src/usb_serial_jtag.rs b/esp-hal/src/usb_serial_jtag.rs index b6d8682c073..a53f981c363 100644 --- a/esp-hal/src/usb_serial_jtag.rs +++ b/esp-hal/src/usb_serial_jtag.rs @@ -112,7 +112,7 @@ //! //! writeln!(usb_serial, "USB serial interrupt").unwrap(); //! -//! while let Some(c) = usb_serial.read_byte() { +//! while let nb::Result::Ok(c) = usb_serial.read_byte() { //! writeln!(usb_serial, "Read byte: {:02x}", c).unwrap(); //! } //! @@ -198,6 +198,28 @@ where Ok(()) } + /// Write data to the serial output in a non-blocking manner + /// Requires manual flushing (automatically flushed every 64 bytes) + pub fn write_byte_nb(&mut self, word: u8) -> nb::Result<(), Error> { + let reg_block = USB_DEVICE::register_block(); + + if reg_block + .ep1_conf() + .read() + .serial_in_ep_data_free() + .bit_is_set() + { + // the FIFO is not full + unsafe { + reg_block.ep1().write(|w| w.rdwr_byte().bits(word)); + } + + Ok(()) + } else { + Err(nb::Error::WouldBlock) + } + } + /// Flush the output FIFO and block until it has been sent pub fn flush_tx(&mut self) -> Result<(), Error> { let reg_block = USB_DEVICE::register_block(); @@ -209,6 +231,18 @@ where Ok(()) } + + /// Flush the output FIFO but don't block if it isn't ready immediately + pub fn flush_tx_nb(&mut self) -> nb::Result<(), Error> { + let reg_block = USB_DEVICE::register_block(); + reg_block.ep1_conf().modify(|_, w| w.wr_done().set_bit()); + + if reg_block.ep1_conf().read().bits() & 0b011 == 0b000 { + Err(nb::Error::WouldBlock) + } else { + Ok(()) + } + } } impl<'d, Dm> UsbSerialJtagRx<'d, Dm> @@ -224,7 +258,7 @@ where } /// Read a byte from the UART in a non-blocking manner - pub fn read_byte(&mut self) -> Option { + pub fn read_byte(&mut self) -> nb::Result { let reg_block = USB_DEVICE::register_block(); // Check if there are any bytes to read @@ -236,9 +270,9 @@ where { let value = reg_block.ep1().read().rdwr_byte().bits(); - Some(value) + Ok(value) } else { - None + Err(nb::Error::WouldBlock) } } @@ -247,7 +281,7 @@ where /// number of bytes in the FIFO is larger than `buf`. pub fn drain_rx_fifo(&mut self, buf: &mut [u8]) -> usize { let mut count = 0; - while let Some(value) = self.read_byte() { + while let Ok(value) = self.read_byte() { buf[count] = value; count += 1; if count == buf.len() { @@ -373,13 +407,24 @@ where self.tx.write_bytes(data) } + /// Write data to the serial output in a non-blocking manner + /// Requires manual flushing (automatically flushed every 64 bytes) + pub fn write_byte_nb(&mut self, word: u8) -> nb::Result<(), Error> { + self.tx.write_byte_nb(word) + } + /// Flush the output FIFO and block until it has been sent pub fn flush_tx(&mut self) -> Result<(), Error> { self.tx.flush_tx() } + /// Flush the output FIFO but don't block if it isn't ready immediately + pub fn flush_tx_nb(&mut self) -> nb::Result<(), Error> { + self.tx.flush_tx_nb() + } + /// Read a single byte but don't block if it isn't ready immediately - pub fn read_byte(&mut self) -> Option { + pub fn read_byte(&mut self) -> nb::Result { self.rx.read_byte() } @@ -498,6 +543,71 @@ where } } +impl embedded_hal_nb::serial::ErrorType for UsbSerialJtag<'_, Dm> +where + Dm: DriverMode, +{ + type Error = Error; +} + +impl embedded_hal_nb::serial::ErrorType for UsbSerialJtagTx<'_, Dm> +where + Dm: DriverMode, +{ + type Error = Error; +} + +impl embedded_hal_nb::serial::ErrorType for UsbSerialJtagRx<'_, Dm> +where + Dm: DriverMode, +{ + type Error = Error; +} + +impl embedded_hal_nb::serial::Read for UsbSerialJtag<'_, Dm> +where + Dm: DriverMode, +{ + fn read(&mut self) -> nb::Result { + embedded_hal_nb::serial::Read::read(&mut self.rx) + } +} + +impl embedded_hal_nb::serial::Read for UsbSerialJtagRx<'_, Dm> +where + Dm: DriverMode, +{ + fn read(&mut self) -> nb::Result { + self.read_byte() + } +} + +impl embedded_hal_nb::serial::Write for UsbSerialJtag<'_, Dm> +where + Dm: DriverMode, +{ + fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> { + embedded_hal_nb::serial::Write::write(&mut self.tx, word) + } + + fn flush(&mut self) -> nb::Result<(), Self::Error> { + embedded_hal_nb::serial::Write::flush(&mut self.tx) + } +} + +impl embedded_hal_nb::serial::Write for UsbSerialJtagTx<'_, Dm> +where + Dm: DriverMode, +{ + fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> { + self.write_byte_nb(word) + } + + fn flush(&mut self) -> nb::Result<(), Self::Error> { + self.flush_tx_nb() + } +} + #[cfg(any(doc, feature = "unstable"))] #[cfg_attr(docsrs, doc(cfg(feature = "unstable")))] impl embedded_io::ErrorType for UsbSerialJtag<'_, Dm> diff --git a/esp-lp-hal/src/uart.rs b/esp-lp-hal/src/uart.rs index 9ef7873867a..db09f0be2a7 100644 --- a/esp-lp-hal/src/uart.rs +++ b/esp-lp-hal/src/uart.rs @@ -46,13 +46,8 @@ pub unsafe fn conjure() -> LpUart { } /// UART Error -#[derive(Debug, Clone, Copy, PartialEq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[non_exhaustive] -pub enum Error { - /// This operation requires blocking behavior to complete - WouldBlock, -} +#[derive(Debug)] +pub enum Error {} #[cfg(feature = "embedded-hal")] impl embedded_hal_nb::serial::Error for Error { @@ -174,23 +169,24 @@ pub struct LpUart { impl LpUart { /// Read a single byte from the UART in a non-blocking manner. - pub fn read_byte(&mut self) -> Option { + pub fn read_byte(&mut self) -> nb::Result { if self.rx_fifo_count() > 0 { - Some(self.uart.fifo().read().rxfifo_rd_byte().bits()) + let byte = self.uart.fifo().read().rxfifo_rd_byte().bits(); + Ok(byte) } else { - None + Err(nb::Error::WouldBlock) } } /// Write a single byte to the UART in a non-blocking manner. - pub fn write_byte(&mut self, byte: u8) -> Option<()> { + pub fn write_byte(&mut self, byte: u8) -> nb::Result<(), Error> { if self.tx_fifo_count() < UART_FIFO_SIZE { self.uart .fifo() .write(|w| unsafe { w.rxfifo_rd_byte().bits(byte) }); - Some(()) + Ok(()) } else { - None + Err(nb::Error::WouldBlock) } } @@ -199,21 +195,18 @@ impl LpUart { pub fn write_bytes(&mut self, data: &[u8]) -> Result { let count = data.len(); - for &byte in data { - if self.write_byte(byte).is_none() { - return Err(Error::WouldBlock); - } - } + data.iter() + .try_for_each(|c| nb::block!(self.write_byte(*c)))?; Ok(count) } - /// Flush the transmit buffer of the UART - pub fn flush(&mut self) -> Option<()> { + /// Flush the UART's transmit buffer in a non-blocking manner. + pub fn flush_tx(&mut self) -> nb::Result<(), Error> { if self.is_tx_idle() { - Some(()) + Ok(()) } else { - None + Err(nb::Error::WouldBlock) } } @@ -245,21 +238,19 @@ impl embedded_hal_nb::serial::ErrorType for LpUart { #[cfg(feature = "embedded-hal")] impl embedded_hal_nb::serial::Read for LpUart { - fn read(&mut self) -> embedded_hal_nb::nb::Result { + fn read(&mut self) -> nb::Result { self.read_byte() - .ok_or(embedded_hal_nb::nb::Error::WouldBlock) } } #[cfg(feature = "embedded-hal")] impl embedded_hal_nb::serial::Write for LpUart { - fn write(&mut self, word: u8) -> embedded_hal_nb::nb::Result<(), Self::Error> { + fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> { self.write_byte(word) - .ok_or(embedded_hal_nb::nb::Error::WouldBlock) } - fn flush(&mut self) -> embedded_hal_nb::nb::Result<(), Self::Error> { - self.flush().ok_or(embedded_hal_nb::nb::Error::WouldBlock) + fn flush(&mut self) -> nb::Result<(), Self::Error> { + self.flush_tx() } } @@ -304,9 +295,11 @@ impl embedded_io::Write for LpUart { fn flush(&mut self) -> Result<(), Self::Error> { loop { - match self.flush() { - Some(_) => break, - None => { /* Wait */ } + match self.flush_tx() { + Ok(_) => break, + Err(nb::Error::WouldBlock) => { /* Wait */ } + #[allow(unreachable_patterns)] + Err(nb::Error::Other(e)) => return Err(e), } } diff --git a/examples/src/bin/hmac.rs b/examples/src/bin/hmac.rs index aacdcc8ef82..e9aba42642c 100644 --- a/examples/src/bin/hmac.rs +++ b/examples/src/bin/hmac.rs @@ -66,6 +66,7 @@ use esp_hal::{ }; use esp_println::println; use hmac::{Hmac as HmacSw, Mac}; +use nb::block; use sha2::Sha256; type HmacSha256 = HmacSw; @@ -92,14 +93,12 @@ fn main() -> ! { let (nsrc, _) = src.split_at(i); let mut remaining = nsrc; hw_hmac.init(); - hw_hmac - .configure(HmacPurpose::ToUser, KeyId::Key0) - .expect("Key purpose mismatch"); + block!(hw_hmac.configure(HmacPurpose::ToUser, KeyId::Key0)).expect("Key purpose mismatch"); let pre_hw_hmac = esp_hal::time::now(); while remaining.len() > 0 { - remaining = hw_hmac.update(remaining); + remaining = block!(hw_hmac.update(remaining)).unwrap(); } - hw_hmac.finalize(output.as_mut_slice()); + block!(hw_hmac.finalize(output.as_mut_slice())).unwrap(); let post_hw_hmac = esp_hal::time::now(); let hw_time = post_hw_hmac - pre_hw_hmac; let mut sw_hmac = HmacSha256::new_from_slice(key).expect("HMAC can take key of any size"); diff --git a/examples/src/bin/twai.rs b/examples/src/bin/twai.rs index 41970e88b3f..d2b3e490e5a 100644 --- a/examples/src/bin/twai.rs +++ b/examples/src/bin/twai.rs @@ -34,6 +34,7 @@ use esp_hal::{ twai::{self, filter::SingleStandardFilter, EspTwaiFrame, StandardId, TwaiMode}, }; use esp_println::println; +use nb::block; #[entry] fn main() -> ! { @@ -81,22 +82,21 @@ fn main() -> ! { // Send a frame to the other ESP // Use `new_self_reception` if you want to use self-testing. let frame = EspTwaiFrame::new(StandardId::ZERO, &[1, 2, 3]).unwrap(); - twai.transmit(&frame).unwrap(); - + block!(twai.transmit(&frame)).unwrap(); println!("Sent a frame"); } let delay = Delay::new(); loop { // Wait for a frame to be received. - let frame = twai.receive().unwrap(); + let frame = block!(twai.receive()).unwrap(); println!("Received a frame: {frame:?}"); delay.delay_millis(250); let frame = EspTwaiFrame::new(StandardId::ZERO, &[1, 2, 3]).unwrap(); // Transmit a new frame back to the other ESP - twai.transmit(&frame).unwrap(); + block!(twai.transmit(&frame)).unwrap(); println!("Sent a frame"); } } diff --git a/hil-test/Cargo.toml b/hil-test/Cargo.toml index 419ad853c7e..97204555d4e 100644 --- a/hil-test/Cargo.toml +++ b/hil-test/Cargo.toml @@ -223,6 +223,7 @@ embassy-executor = { version = "0.6.0", default-features = false } embedded-test = { version = "0.5.0", git = "https://github.com/probe-rs/embedded-test.git", rev = "7109473", default-features = false } fugit = "0.3.7" hex-literal = "0.4.1" +nb = "1.1.0" p192 = { version = "0.13.0", default-features = false, features = ["arithmetic"] } p256 = { version = "0.13.2", default-features = false, features = ["arithmetic"] } sha1 = { version = "0.10.6", default-features = false } diff --git a/hil-test/tests/rsa.rs b/hil-test/tests/rsa.rs index 70d8e8596e7..0b39046f6ce 100644 --- a/hil-test/tests/rsa.rs +++ b/hil-test/tests/rsa.rs @@ -56,7 +56,7 @@ mod tests { fn init() -> Context<'static> { let peripherals = esp_hal::init(esp_hal::Config::default()); let mut rsa = Rsa::new(peripherals.RSA); - rsa.ready(); + nb::block!(rsa.ready()).unwrap(); Context { rsa } } diff --git a/hil-test/tests/rsa_async.rs b/hil-test/tests/rsa_async.rs index 7edeb005b4d..21ba4d4e229 100644 --- a/hil-test/tests/rsa_async.rs +++ b/hil-test/tests/rsa_async.rs @@ -56,7 +56,7 @@ mod tests { fn init() -> Context<'static> { let peripherals = esp_hal::init(esp_hal::Config::default()); let mut rsa = Rsa::new(peripherals.RSA).into_async(); - rsa.ready(); + nb::block!(rsa.ready()).unwrap(); Context { rsa } } diff --git a/hil-test/tests/sha.rs b/hil-test/tests/sha.rs index 965b146013a..4f67c0573d6 100644 --- a/hil-test/tests/sha.rs +++ b/hil-test/tests/sha.rs @@ -18,6 +18,7 @@ use esp_hal::{ sha::{Sha, Sha1, Sha256, ShaAlgorithm, ShaDigest}, }; use hil_test as _; +use nb::block; /// Dummy data used to feed the hasher. const SOURCE_DATA: &[u8] = &[b'a'; 258]; @@ -34,9 +35,9 @@ fn assert_sw_hash(input: &[u8], expected_output: &[u8]) { fn hash_sha(sha: &mut Sha<'static>, mut input: &[u8], output: &mut [u8]) { let mut digest = sha.start::(); while !input.is_empty() { - input = digest.update(input); + input = block!(digest.update(input)).unwrap(); } - digest.finish(output); + block!(digest.finish(output)).unwrap(); } fn hash_digest<'a, S: ShaAlgorithm>(sha: &'a mut Sha<'static>, input: &[u8], output: &mut [u8]) { @@ -268,22 +269,22 @@ mod tests { let mut all_done = true; if !sha1_remaining.is_empty() { let mut digest = ShaDigest::restore(&mut ctx.sha, &mut sha1); - sha1_remaining = digest.update(sha1_remaining); - digest.save(&mut sha1); + sha1_remaining = block!(digest.update(sha1_remaining)).unwrap(); + block!(digest.save(&mut sha1)); all_done = false; } #[cfg(not(feature = "esp32"))] if !sha224_remaining.is_empty() { let mut digest = ShaDigest::restore(&mut ctx.sha, &mut sha224); - sha224_remaining = digest.update(sha224_remaining); - digest.save(&mut sha224); + sha224_remaining = block!(digest.update(sha224_remaining)).unwrap(); + block!(digest.save(&mut sha224)); all_done = false; } if !sha256_remaining.is_empty() { let mut digest = ShaDigest::restore(&mut ctx.sha, &mut sha256); - sha256_remaining = digest.update(sha256_remaining); - digest.save(&mut sha256); + sha256_remaining = block!(digest.update(sha256_remaining)).unwrap(); + block!(digest.save(&mut sha256)); all_done = false; } @@ -291,15 +292,15 @@ mod tests { { if !sha384_remaining.is_empty() { let mut digest = ShaDigest::restore(&mut ctx.sha, &mut sha384); - sha384_remaining = digest.update(sha384_remaining); - digest.save(&mut sha384); + sha384_remaining = block!(digest.update(sha384_remaining)).unwrap(); + block!(digest.save(&mut sha384)); all_done = false; } if !sha512_remaining.is_empty() { let mut digest = ShaDigest::restore(&mut ctx.sha, &mut sha512); - sha512_remaining = digest.update(sha512_remaining); - digest.save(&mut sha512); + sha512_remaining = block!(digest.update(sha512_remaining)).unwrap(); + block!(digest.save(&mut sha512)); all_done = false; } } @@ -310,17 +311,17 @@ mod tests { } let mut digest = ShaDigest::restore(&mut ctx.sha, &mut sha1); - digest.finish(sha1_p.1); + block!(digest.finish(sha1_p.1)).unwrap(); let mut digest = ShaDigest::restore(&mut ctx.sha, &mut sha224); - digest.finish(sha224_p.1); + block!(digest.finish(sha224_p.1)).unwrap(); let mut digest = ShaDigest::restore(&mut ctx.sha, &mut sha256); - digest.finish(sha256_p.1); + block!(digest.finish(sha256_p.1)).unwrap(); #[cfg(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3"))] { let mut digest = ShaDigest::restore(&mut ctx.sha, &mut sha384); - digest.finish(sha384_p.1); + block!(digest.finish(sha384_p.1)).unwrap(); let mut digest = ShaDigest::restore(&mut ctx.sha, &mut sha512); - digest.finish(sha512_p.1); + block!(digest.finish(sha512_p.1)).unwrap(); } }); } diff --git a/hil-test/tests/twai.rs b/hil-test/tests/twai.rs index 95efad208ca..b244dd8d289 100644 --- a/hil-test/tests/twai.rs +++ b/hil-test/tests/twai.rs @@ -11,6 +11,7 @@ use esp_hal::{ Blocking, }; use hil_test as _; +use nb::block; struct Context { twai: twai::Twai<'static, Blocking>, @@ -51,9 +52,9 @@ mod tests { #[test] fn test_send_receive(mut ctx: Context) { let frame = EspTwaiFrame::new_self_reception(StandardId::ZERO, &[1, 2, 3]).unwrap(); - ctx.twai.transmit(&frame).unwrap(); + block!(ctx.twai.transmit(&frame)).unwrap(); - let frame = ctx.twai.receive().unwrap(); + let frame = block!(ctx.twai.receive()).unwrap(); assert_eq!(frame.data(), &[1, 2, 3]) }