embassy icon indicating copy to clipboard operation
embassy copied to clipboard

Add efficient polling functions to BufferedUart (add them to traits too?)

Open DCNick3 opened this issue 3 years ago • 2 comments
trafficstars

It might be useful to read only the data that the BufferedUart accumulated, without waiting for any data to come in.

I have found the following way to do this:

let mut b_fut = uart.read_byte();

let waker = futures::task::noop_waker();
let mut context = Context::from_waker(&waker);

if let core::task::Poll::Ready(r) = b_fut.poll_unpin(&mut context) {
    let read = unwrap!(r);

    // read something!
} else {
    // nope, nothing available
}

It basically creates a no-op waker, polls the read_byte future one time and drops it afterwards, canceling the async operation. It works, but requires quite a lot of boilerplate and executor-agnostic feature of embassy, which ¿might? produce less efficient code.

It would be nice to have a function purposed for reading the buffer without actually touching the uart hardware

DCNick3 avatar Jan 06 '22 12:01 DCNick3

If you're in async context, you can reuse the "current" waker.

let buf: &[u8] = poll_fn(|cx| {
    Poll::Ready(match uart.poll_fill_buf(cx) {
       Poll::Ready(x) => x,
       Poll::Pending => &[],
    }
}).await;

If you're not in an async context yep, you have to "invent" a waker which requires executor-agnostic (which does increase code size a bit).

A fill_buf fn that's equivalent to poll_fill_buf but doesn't use wakers could be a nice addition, yes! Not sure if it should be a new method in embassy::io::AsyncBufRead, or a separate trait, or just inherent methods in the BufferedUart...

Dirbaio avatar Jan 06 '22 13:01 Dirbaio

I kinda lean towards separate trait, but maybe adding it to AsyncBufRead might be better. Not sure here

DCNick3 avatar Jan 06 '22 14:01 DCNick3