Merge pull request #2956 from tact1m4n3/uart-fix

Fix drop implementation of `BufferedUartRx` and `BufferedUartTx` in `embassy-rp`
This commit is contained in:
Dario Nieuwenhuis 2024-05-20 08:44:01 +00:00 committed by GitHub
commit a266948a7a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 87 additions and 72 deletions

View File

@ -123,6 +123,11 @@ impl RingBuffer {
Some(Writer(self))
}
/// Return if buffer is available.
pub fn is_available(&self) -> bool {
!self.buf.load(Ordering::Relaxed).is_null() && self.len.load(Ordering::Relaxed) != 0
}
/// Return length of buffer.
pub fn len(&self) -> usize {
self.len.load(Ordering::Relaxed)

View File

@ -51,14 +51,20 @@ pub struct BufferedUartTx<'d, T: Instance> {
pub(crate) fn init_buffers<'d, T: Instance + 'd>(
_irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
tx_buffer: &'d mut [u8],
rx_buffer: &'d mut [u8],
tx_buffer: Option<&'d mut [u8]>,
rx_buffer: Option<&'d mut [u8]>,
) {
let state = T::buffered_state();
if let Some(tx_buffer) = tx_buffer {
let len = tx_buffer.len();
unsafe { state.tx_buf.init(tx_buffer.as_mut_ptr(), len) };
}
if let Some(rx_buffer) = rx_buffer {
let len = rx_buffer.len();
unsafe { state.rx_buf.init(rx_buffer.as_mut_ptr(), len) };
}
// From the datasheet:
// "The transmit interrupt is based on a transition through a level, rather
@ -95,7 +101,7 @@ impl<'d, T: Instance> BufferedUart<'d, T> {
into_ref!(tx, rx);
super::Uart::<'d, T, Async>::init(Some(tx.map_into()), Some(rx.map_into()), None, None, config);
init_buffers::<T>(irq, tx_buffer, rx_buffer);
init_buffers::<T>(irq, Some(tx_buffer), Some(rx_buffer));
Self {
rx: BufferedUartRx { phantom: PhantomData },
@ -124,7 +130,7 @@ impl<'d, T: Instance> BufferedUart<'d, T> {
Some(cts.map_into()),
config,
);
init_buffers::<T>(irq, tx_buffer, rx_buffer);
init_buffers::<T>(irq, Some(tx_buffer), Some(rx_buffer));
Self {
rx: BufferedUartRx { phantom: PhantomData },
@ -175,7 +181,7 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
into_ref!(rx);
super::Uart::<'d, T, Async>::init(None, Some(rx.map_into()), None, None, config);
init_buffers::<T>(irq, &mut [], rx_buffer);
init_buffers::<T>(irq, None, Some(rx_buffer));
Self { phantom: PhantomData }
}
@ -192,7 +198,7 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
into_ref!(rx, rts);
super::Uart::<'d, T, Async>::init(None, Some(rx.map_into()), Some(rts.map_into()), None, config);
init_buffers::<T>(irq, &mut [], rx_buffer);
init_buffers::<T>(irq, None, Some(rx_buffer));
Self { phantom: PhantomData }
}
@ -323,7 +329,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
into_ref!(tx);
super::Uart::<'d, T, Async>::init(Some(tx.map_into()), None, None, None, config);
init_buffers::<T>(irq, tx_buffer, &mut []);
init_buffers::<T>(irq, Some(tx_buffer), None);
Self { phantom: PhantomData }
}
@ -340,12 +346,12 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
into_ref!(tx, cts);
super::Uart::<'d, T, Async>::init(Some(tx.map_into()), None, None, Some(cts.map_into()), config);
init_buffers::<T>(irq, tx_buffer, &mut []);
init_buffers::<T>(irq, Some(tx_buffer), None);
Self { phantom: PhantomData }
}
fn write<'a>(buf: &'a [u8]) -> impl Future<Output = Result<usize, Error>> + 'a {
fn write(buf: &[u8]) -> impl Future<Output = Result<usize, Error>> + '_ {
poll_fn(move |cx| {
if buf.is_empty() {
return Poll::Ready(Ok(0));
@ -459,9 +465,9 @@ impl<'d, T: Instance> Drop for BufferedUartRx<'d, T> {
let state = T::buffered_state();
unsafe { state.rx_buf.deinit() }
// TX is inactive if the the buffer is not available.
// TX is inactive if the buffer is not available.
// We can now unregister the interrupt handler
if state.tx_buf.is_empty() {
if !state.tx_buf.is_available() {
T::Interrupt::disable();
}
}
@ -472,9 +478,9 @@ impl<'d, T: Instance> Drop for BufferedUartTx<'d, T> {
let state = T::buffered_state();
unsafe { state.tx_buf.deinit() }
// RX is inactive if the the buffer is not available.
// RX is inactive if the buffer is not available.
// We can now unregister the interrupt handler
if state.rx_buf.is_empty() {
if !state.rx_buf.is_available() {
T::Interrupt::disable();
}
}
@ -520,6 +526,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for BufferedInterr
}
// RX
if s.rx_buf.is_available() {
let mut rx_writer = unsafe { s.rx_buf.writer() };
let rx_buf = rx_writer.push_slice();
let mut n_read = 0;
@ -559,8 +566,10 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for BufferedInterr
w.set_rtim(true);
});
}
}
// TX
if s.tx_buf.is_available() {
let mut tx_reader = unsafe { s.tx_buf.reader() };
let tx_buf = tx_reader.pop_slice();
let mut n_written = 0;
@ -579,6 +588,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for BufferedInterr
// crossed. No need to disable it when the buffer becomes empty
// as it does re-trigger anymore once we have cleared it.
}
}
}
impl embedded_io::Error for Error {

View File

@ -231,7 +231,7 @@ impl<'d, T: Instance> UartTx<'d, T, Blocking> {
irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
tx_buffer: &'d mut [u8],
) -> BufferedUartTx<'d, T> {
buffered::init_buffers::<T>(irq, tx_buffer, &mut []);
buffered::init_buffers::<T>(irq, Some(tx_buffer), None);
BufferedUartTx { phantom: PhantomData }
}
@ -352,7 +352,7 @@ impl<'d, T: Instance> UartRx<'d, T, Blocking> {
irq: impl Binding<T::Interrupt, BufferedInterruptHandler<T>>,
rx_buffer: &'d mut [u8],
) -> BufferedUartRx<'d, T> {
buffered::init_buffers::<T>(irq, &mut [], rx_buffer);
buffered::init_buffers::<T>(irq, None, Some(rx_buffer));
BufferedUartRx { phantom: PhantomData }
}
@ -690,7 +690,7 @@ impl<'d, T: Instance> Uart<'d, T, Blocking> {
tx_buffer: &'d mut [u8],
rx_buffer: &'d mut [u8],
) -> BufferedUart<'d, T> {
buffered::init_buffers::<T>(irq, tx_buffer, rx_buffer);
buffered::init_buffers::<T>(irq, Some(tx_buffer), Some(rx_buffer));
BufferedUart {
rx: BufferedUartRx { phantom: PhantomData },