Skip to content
Merged
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed

- Update the `embedded-hal-*` packages to `1.0.0-rc.1` and implement traits from `embedded-io` and `embedded-io-async` (#747)

### Fixed

- Fix `psram` availability lookup in `esp-hal-common` build script (#718)
Expand Down
12 changes: 7 additions & 5 deletions esp-hal-common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@ critical-section = "1.1.2"
embedded-can = { version = "0.4.1", optional = true }
embedded-dma = "0.2.0"
embedded-hal = { version = "0.2.7", features = ["unproven"] }
embedded-hal-1 = { version = "=1.0.0-alpha.11", optional = true, package = "embedded-hal" }
embedded-hal-nb = { version = "=1.0.0-alpha.3", optional = true }
embedded-hal-1 = { version = "=1.0.0-rc.1", optional = true, package = "embedded-hal" }
embedded-hal-nb = { version = "=1.0.0-rc.1", optional = true }
embedded-io = "0.5.0"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't this be optional and only get included if we target eh1 / async?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The embedded_io trait implementations are not feature gated currently. Should they be? I didn't see any reason to, they're not really following the 1.0.0-xxx release cycle of the other packages. But I can change this if there's a reason to.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

well we pull an unused dependency this way 🤷‍♂️

Copy link
Member Author

@jessebraham jessebraham Aug 22, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

embedded-hal and embedded-dma should both be optional too then, right? I'm not really sure where we're drawing the line here. I'm not against feature gating it, I'd just like to come up with actual criteria for this I guess.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think code implementing embedded-hal and embedded-dma is not feature gated.
But embedded-hal-1 is and it's optional because of that.

esp-synopsys-usb-otg = { version = "0.3.2", optional = true, features = ["fs", "esp32sx"] }
fugit = "0.3.7"
log = "0.4.20"
Expand All @@ -33,9 +34,10 @@ void = { version = "1.0.2", default-features = false }
usb-device = { version = "0.2.9", optional = true }

# async
embedded-hal-async = { version = "=0.2.0-alpha.2", optional = true }
embedded-hal-async = { version = "=1.0.0-rc.1", optional = true }
embedded-io-async = { version = "0.5.0", optional = true }
embassy-sync = { version = "0.2.0", optional = true }
embassy-time = { version = "0.1.2", features = ["nightly"], optional = true }
embassy-time = { git = "https://github.com/embassy-rs/embassy", rev = "4f453d7", features = ["nightly"], optional = true }
embassy-futures = { version = "0.1.0", optional = true }

# RISC-V
Expand Down Expand Up @@ -97,7 +99,7 @@ ufmt = ["ufmt-write"]
vectored = ["procmacros/interrupt"]

# Implement the `embedded-hal-async==1.0.0-alpha.x` traits
async = ["embedded-hal-async", "eh1", "embassy-sync", "embassy-futures"]
async = ["embedded-hal-async", "eh1", "embassy-sync", "embassy-futures", "embedded-io-async"]
embassy = ["embassy-time"]

embassy-time-systick = []
Expand Down
141 changes: 116 additions & 25 deletions esp-hal-common/src/uart.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,19 @@ pub enum Error {
RxFifoOvf,
}

#[cfg(feature = "eh1")]
impl embedded_hal_nb::serial::Error for Error {
fn kind(&self) -> embedded_hal_nb::serial::ErrorKind {
embedded_hal_nb::serial::ErrorKind::Other
}
}

impl embedded_io::Error for Error {
fn kind(&self) -> embedded_io::ErrorKind {
embedded_io::ErrorKind::Other
}
}

/// UART configuration
pub mod config {
/// Number of data bits
Expand Down Expand Up @@ -289,13 +302,6 @@ impl<TX: OutputPin, RX: InputPin> UartPins for TxRxPins<'_, TX, RX> {
}
}

#[cfg(feature = "eh1")]
impl embedded_hal_1::serial::Error for Error {
fn kind(&self) -> embedded_hal_1::serial::ErrorKind {
embedded_hal_1::serial::ErrorKind::Other
}
}

/// UART driver
pub struct Uart<'d, T> {
uart: PeripheralRef<'d, T>,
Expand Down Expand Up @@ -363,9 +369,13 @@ where
}

/// Writes bytes
pub fn write_bytes(&mut self, data: &[u8]) -> Result<(), Error> {
pub fn write_bytes(&mut self, data: &[u8]) -> Result<usize, Error> {
let count = data.len();

data.iter()
.try_for_each(|c| nb::block!(self.write_byte(*c)))
.try_for_each(|c| nb::block!(self.write_byte(*c)))?;

Ok(count)
}

/// Configures the AT-CMD detection settings.
Expand Down Expand Up @@ -999,13 +1009,16 @@ where

#[inline]
fn write_str(&mut self, s: &str) -> Result<(), Self::Error> {
self.write_bytes(s.as_bytes())
self.write_bytes(s.as_bytes())?;
Ok(())
}

#[inline]
fn write_char(&mut self, ch: char) -> Result<(), Self::Error> {
let mut buffer = [0u8; 4];
self.write_bytes(ch.encode_utf8(&mut buffer).as_bytes())
self.write_bytes(ch.encode_utf8(&mut buffer).as_bytes())?;

Ok(())
}
}

Expand All @@ -1015,7 +1028,9 @@ where
{
#[inline]
fn write_str(&mut self, s: &str) -> core::fmt::Result {
self.write_bytes(s.as_bytes()).map_err(|_| core::fmt::Error)
self.write_bytes(s.as_bytes())
.map_err(|_| core::fmt::Error)?;
Ok(())
}
}

Expand Down Expand Up @@ -1046,7 +1061,7 @@ where
}

#[cfg(feature = "eh1")]
impl<T> embedded_hal_1::serial::ErrorType for Uart<'_, T> {
impl<T> embedded_hal_nb::serial::ErrorType for Uart<'_, T> {
type Error = Error;
}

Expand Down Expand Up @@ -1074,6 +1089,61 @@ where
}
}

impl<T> embedded_io::ErrorType for Uart<'_, T> {
type Error = Error;
}

impl<T> embedded_io::Read for Uart<'_, T>
where
T: Instance,
{
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
let mut count = 0;
loop {
if count >= buf.len() {
break;
}

match self.read_byte() {
Ok(byte) => {
buf[count] = byte;
count += 1;
}
Err(nb::Error::WouldBlock) => {
// Block until we have read at least one byte
if count > 0 {
break;
}
}
Err(nb::Error::Other(e)) => return Err(e),
}
}

Ok(count)
}
}

impl<T> embedded_io::Write for Uart<'_, T>
where
T: Instance,
{
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
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;
Expand Down Expand Up @@ -1222,8 +1292,7 @@ mod asynch {
/// # Ok
/// When succesfull, returns the number of bytes written to
/// buf

pub async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
async fn read_async(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
let mut read_bytes = 0;

if self.at_cmd_config.is_some() {
Expand Down Expand Up @@ -1259,62 +1328,81 @@ mod asynch {
Ok(read_bytes)
}

async fn write(&mut self, words: &[u8]) -> Result<(), Error> {
async fn write_async(&mut self, words: &[u8]) -> Result<usize, Error> {
let mut count = 0;
let mut offset: usize = 0;
loop {
let mut next_offset =
offset + (UART_FIFO_SIZE - self.uart.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

for byte in &words[offset..next_offset] {
self.write_byte(*byte).unwrap(); // should never fail
count += 1;
}
if next_offset == words.len() {

if next_offset >= words.len() {
break;
}

offset = next_offset;
UartFuture::new(Event::TxFiFoEmpty, self.inner()).await;
}
Ok(())

Ok(count)
}

async fn flush(&mut self) -> Result<(), Error> {
async fn flush_async(&mut self) -> Result<(), Error> {
let count = self.inner_mut().get_tx_fifo_count();
if count > 0 {
UartFuture::new(Event::TxDone, self.inner()).await;
}

Ok(())
}
}

impl<T> embedded_hal_async::serial::Write for Uart<'_, T>
impl<T> embedded_io_async::Read for Uart<'_, T>
where
T: Instance,
{
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
self.read_async(buf).await
}
}

impl<T> embedded_io_async::Write for Uart<'_, T>
where
T: Instance,
{
async fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
self.write(words).await
async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
self.write_async(buf).await
}

async fn flush(&mut self) -> Result<(), Self::Error> {
self.flush().await
self.flush_async().await
}
}

fn intr_handler(uart: &RegisterBlock) -> bool {
let int_ena_val = uart.int_ena.read();
let int_raw_val = uart.int_raw.read();

if int_ena_val.txfifo_empty_int_ena().bit_is_set()
&& int_raw_val.txfifo_empty_int_raw().bit_is_set()
{
uart.int_ena.write(|w| w.txfifo_empty_int_ena().clear_bit());
return true;
}

if int_ena_val.tx_done_int_ena().bit_is_set() && int_raw_val.tx_done_int_raw().bit_is_set()
{
uart.int_ena.write(|w| w.tx_done_int_ena().clear_bit());
return true;
}

if int_ena_val.at_cmd_char_det_int_ena().bit_is_set()
&& int_raw_val.at_cmd_char_det_int_raw().bit_is_set()
{
Expand All @@ -1324,20 +1412,23 @@ mod asynch {
.write(|w| w.at_cmd_char_det_int_ena().clear_bit());
return true;
}

if int_ena_val.rxfifo_full_int_ena().bit_is_set()
&& int_raw_val.rxfifo_full_int_raw().bit_is_set()
{
uart.int_clr.write(|w| w.rxfifo_full_int_clr().set_bit());
uart.int_ena.write(|w| w.rxfifo_full_int_ena().clear_bit());
return true;
}

if int_ena_val.rxfifo_ovf_int_ena().bit_is_set()
&& int_raw_val.rxfifo_ovf_int_raw().bit_is_set()
{
uart.int_clr.write(|w| w.rxfifo_ovf_int_clr().set_bit());
uart.int_ena.write(|w| w.rxfifo_ovf_int_ena().clear_bit());
return true;
}

false
}

Expand Down
Loading