Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 58 additions & 1 deletion embassy-rp/src/uart/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use core::task::Poll;
use embassy_futures::select::{Either, select};
use embassy_hal_internal::{Peri, PeripheralType};
use embassy_sync::waitqueue::AtomicWaker;
use embassy_time::{Delay, Timer};
use embassy_time::{Delay, Instant, Timer};
use pac::uart::regs::Uartris;

use crate::clocks::clk_peri_freq;
Expand Down Expand Up @@ -116,6 +116,10 @@ pub enum Error {
Parity,
/// Triggered when the received character didn't have a valid stop bit.
Framing,
/// Triggered when the timeout is hit.
Timeout(usize),
/// Triggered when buffer passed by the user is smaller then the byte amount received
BufferOverflow,
}

impl core::fmt::Display for Error {
Expand Down Expand Up @@ -336,6 +340,42 @@ impl<'d, M: Mode> UartRx<'d, M> {
}
Ok(buffer.len())
}
/// Returns True if the UART FIFO is not empty
pub fn has_rx_data(&mut self) -> bool {
!self.info.regs.uartfr().read().rxfe()
}
/// Returns Ok(len) if no errors occured, in case the target byte is not found on timeout Error::Timeout(len) is returned
/// if the bytes read are bigger than the size of the buffer the Error::BufferOverflow is returned
/// These method does not clean the fifo they read the fifo until the target is reached or until timeout is reached.
pub fn blocking_read_until(
&mut self,
buffer: &mut [u8],
target_byte: u8,
timeout_micros: u64,
) -> Result<usize, Error> {
let r = self.info.regs;
let start_time = Instant::now();
let mut bytes_copied = 0;
loop {
if bytes_copied >= buffer.len() {
return Err(Error::BufferOverflow);
}
while r.uartfr().read().rxfe() {
if start_time.elapsed().as_micros() > timeout_micros {
return Err(Error::Timeout(bytes_copied));
}
}

let byte = r.uartdr().read().data();

buffer[bytes_copied] = byte;
bytes_copied += 1;

if byte == target_byte {
return Ok(bytes_copied);
}
}
}
}

impl<'d, M: Mode> Drop for UartRx<'d, M> {
Expand Down Expand Up @@ -798,6 +838,21 @@ impl<'d> Uart<'d, Blocking> {
},
}
}
/// Returns True if the UART FIFO is not empty
pub fn has_rx_data(&mut self) -> bool {
self.rx.has_rx_data()
}
/// Returns Ok(len) if no errors occured, in case the target byte is not found on timeout Error::Timeout(len) is returned
/// if the bytes read are bigger than the size of the buffer the Error::BufferOverflow is returned
/// These method does not clean the fifo they read the fifo until the target is reached or until timeout is reached.
pub fn blocking_read_until(
&mut self,
buffer: &mut [u8],
target_byte: u8,
timeout_micros: u64,
) -> Result<usize, Error> {
self.rx.blocking_read_until(buffer, target_byte, timeout_micros)
}
}

impl<'d> Uart<'d, Async> {
Expand Down Expand Up @@ -1245,6 +1300,8 @@ impl embedded_hal_nb::serial::Error for Error {
Self::Break => embedded_hal_nb::serial::ErrorKind::Other,
Self::Overrun => embedded_hal_nb::serial::ErrorKind::Overrun,
Self::Parity => embedded_hal_nb::serial::ErrorKind::Parity,
Self::Timeout(_) => embedded_hal_nb::serial::ErrorKind::Other,
Self::BufferOverflow => embedded_hal_nb::serial::ErrorKind::Other,
}
}
}
Expand Down
38 changes: 38 additions & 0 deletions examples/rp/src/bin/uart_blocking_read_until.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//! UART read until example for RP2040

#![no_std]
#![no_main]

use embassy_executor::Spawner;
use embassy_rp::uart;
use {defmt_rtt as _, panic_probe as _};

#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let p = embassy_rp::init(Default::default());
let config = uart::Config::default();
let mut uart = uart::Uart::new_blocking(
p.UART0, p.PIN_0, // TX
p.PIN_1, // RX
config,
);
let mut buf = [0u8; 100];
loop {
match uart.blocking_read_until(&mut buf, b'\r', 5_000_000) {
Ok(n) => {
defmt::info!("Received {} bytes", n);
uart.blocking_write(&buf[..n]).unwrap();
}
Err(embassy_rp::uart::Error::Timeout(n)) => {
defmt::warn!("Timeout after {} bytes", n);
uart.blocking_write(&buf[..n]).unwrap();
}
Err(embassy_rp::uart::Error::BufferOverflow) => {
defmt::warn!("Buffer overflow");
}
Err(e) => {
defmt::error!("UART error: {:?}", e);
}
}
}
}
88 changes: 88 additions & 0 deletions tests/rp/src/bin/uart.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,94 @@ async fn main(_spawner: Spawner) {
assert_eq!(read1(&mut uart).unwrap(), [5]);
}

info!("test has_rx_data");
{
let config = Config::default();
let mut uart = Uart::new_blocking(uart.reborrow(), tx.reborrow(), rx.reborrow(), config);

// No byte was sent to the FIFO should return False
assert_eq!(uart.has_rx_data(), false);

// We can't send too many bytes, they have to fit in the FIFO.
// This is because we aren't sending+receiving at the same time.
let data = [0xC0];
uart.blocking_write(&data).unwrap();
while uart.busy() {}
assert_eq!(uart.has_rx_data(), true);
// Cleaning fifo for the next test
read::<1>(&mut uart).unwrap();
}

info!("Test blocking_read_until ");
{
let config = Config::default();
let mut uart = Uart::new_blocking(uart.reborrow(), tx.reborrow(), rx.reborrow(), config);
let mut buf = [0u8; 4];

let data = [0xC0, 0xDE, 0xAA, 0xBB];

uart.blocking_write(&data).unwrap();
assert_eq!(uart.blocking_read_until(&mut buf, 0xAA, 10_000_000).unwrap(), 3);
assert_eq!(buf, [0xC0, 0xDE, 0xAA, 0x00]);
//Cleaning fifo for the next test
read::<1>(&mut uart).unwrap();
}
info!("Test blocking_read_until buffer overflow buffer smaller than data");
{
let config = Config::default();

let mut uart = Uart::new_blocking(uart.reborrow(), tx.reborrow(), rx.reborrow(), config);
let mut buf = [0u8; 1];

let data = [0xC0, 0xDE, 0xAA, 0xBB, 0xDD];

uart.blocking_write(&data).unwrap();
match uart.blocking_read_until(&mut buf, 0x00, 10_000_000) {
Ok(n) => defmt::panic!("Expected BufferOverflow, got Ok({})", n),
Err(e) => {
assert_eq!(e, Error::BufferOverflow);
}
}
//Cleaning fifo for the next test
read::<4>(&mut uart).unwrap();
}
info!("Test blocking_read_until buffer overflow buffer same size");
{
let config = Config::default();

let mut uart = Uart::new_blocking(uart.reborrow(), tx.reborrow(), rx.reborrow(), config);
let mut buf = [0u8; 5];

let data = [0xC0, 0xDE, 0xAA, 0xBB, 0xDD];

uart.blocking_write(&data).unwrap();
match uart.blocking_read_until(&mut buf, 0x00, 10_000_000) {
Ok(n) => defmt::panic!("Expected BufferOverflow, got Ok({})", n),
Err(e) => {
assert_eq!(e, Error::BufferOverflow);
}
}
}
info!("Test blocking_read_until timeout");
{
let config = Config::default();

let mut uart = Uart::new_blocking(uart.reborrow(), tx.reborrow(), rx.reborrow(), config);
let mut buf = [0u8; 5];
let data = [0xC0, 0xDE, 0xAA, 0xBB];

uart.blocking_write(&data).unwrap();
match uart.blocking_read_until(&mut buf, 0x00, 1000) {
Ok(_) => defmt::panic!("Expected Timeout error"),
Err(Error::Timeout(n)) => {
defmt::assert_eq!(n, 4);
assert_eq!(buf[..4], data);
}
Err(e) => {
defmt::panic!("Expected Timeout error, got {:?}", e);
}
}
}
info!("Test OK");
cortex_m::asm::bkpt();
}