Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

uart_bytes_available() missing #1481

Closed
joeatbayes opened this issue Apr 19, 2024 · 1 comment
Closed

uart_bytes_available() missing #1481

joeatbayes opened this issue Apr 19, 2024 · 1 comment
Labels
peripheral:uart UART peripheral

Comments

@joeatbayes
Copy link

In the Example: https://github.com/esp-rs/esp-hal/blob/main/examples/src/bin/advanced_serial.rs

There is a line: block!(serial1.read_byte()) When writing serial code we quite often want to use fast polling rather than spinning a thread or triggering an interrupt on next byte. In short we need the ability to query the Uart to see if there are characters pending in the RX buffer before we attempt the read. We also need the ability to query the Uart to determine if all characters submitted have been sent and the write buffer is empty.

It would be great to be able to write

  if (serial1.bytes_available() > 0) {
     block!(serial1.read_byte())
  }

Conversely when writing bytes sometimes it is necessary to know when the last of the bytes sent previously have
exited the uart buffer. I use this to determine when I can disable a proprietary RF transceiver running a custom protocol. So it would
be good to be able to write.

If (serial1.tx_bytes_pending() == 0) {
   transceiver_enable.set_low();
}

I know that we can do some of this with async & embassy but I write for some chips where we don't have the resources to run multiple threads and fast polling is a valid pattern in embedded word.

In ESP32 IDF they offer a function int uart_read_bytes(uart_port_t uart_num, void* buf, uint32_t length, TickType_t ticks_to_wait); which is OK since it returns after very short delay but it would be better to skip even that delay since I could have been using those CPU cycles to do other work. They also offer the following functions that allow avoiding the read uart_get_buffered_data_len

/**
 * @brief   UART get RX ring buffer cached data length
 *
 * @param   uart_num UART port number, the max port number is (UART_NUM_MAX -1).
 * @param   size Pointer of size_t to accept cached data length
 *
 * @return
 *     - ESP_OK Success
 *     - ESP_FAIL Parameter error
 */
esp_err_t uart_get_buffered_data_len(uart_port_t uart_num, size_t* size);

/**
 * @brief   UART get TX ring buffer free space size
 *
 * @param   uart_num UART port number, the max port number is (UART_NUM_MAX -1).
 * @param   size Pointer of size_t to accept the free space size
 *
 * @return
 *     - ESP_OK Success
 *     - ESP_ERR_INVALID_ARG Parameter error
 */
esp_err_t uart_get_tx_buffer_free_size(uart_port_t uart_num, size_t *size);

@jessebraham jessebraham added the peripheral:uart UART peripheral label Apr 24, 2024
@MabezDev
Copy link
Member

if (serial1.bytes_available() > 0) {
block!(serial1.read_byte())
}

This can be expressed as

while let Ok(byte) = serial1.read_byte() {
  // do stuff with byte, exits loop when none are available
}

or with proper error handling:

loop {
  let byte = serial1.read_byte();
  match byte {
    Ok(byte) => {} // do stuff with byte
    Err(Error::WouldBlock) => break, // nothing left
    Err(Error::Other(e)) => {} // handle e
  }
}

I know that we can do some of this with async & embassy but I write for some chips where we don't have the resources to run multiple threads and fast polling is a valid pattern in embedded word.

FYI using async will give you lower latency and probably better throughput than a busy polling super loop. Async doesn't require threads either.

In ESP32 IDF they offer a function int uart_read_bytes

Yeah, we have a write_bytes method, but not one for read_bytes, I'll open another issue for that.

I will close this for now, as I think I've addressed your points. If you have more general questions about approaching these problems in Rust you might be better served by our matrix channel .

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
peripheral:uart UART peripheral
Projects
Status: Done
Development

No branches or pull requests

3 participants