use core::cell::RefCell;
use core::future::poll_fn;
use core::task::{Poll, Waker};
use critical_section::Mutex;
use super::Uart;
use crate::pac::UART0;
static RX_WAKER: Mutex<RefCell<Option<Waker>>> = Mutex::new(RefCell::new(None));
static TX_WAKER: Mutex<RefCell<Option<Waker>>> = Mutex::new(RefCell::new(None));
pub fn on_irq() {
let uart0 = unsafe { UART0::steal() };
let status = uart0.mis().read();
let rx = status.rxmis().bit_is_set() || status.rtmis().bit_is_set();
let tx = status.txmis().bit_is_set();
if rx {
uart0
.imsc()
.modify(|_, w| w.rxim().clear_bit().rtim().clear_bit());
uart0.icr().write(|w| w.rxic().set_bit().rtic().set_bit());
}
if tx {
uart0.imsc().modify(|_, w| w.txim().clear_bit());
uart0.icr().write(|w| w.txic().set_bit());
}
critical_section::with(|cs| {
if rx {
if let Some(waker) = RX_WAKER.borrow_ref_mut(cs).take() {
waker.wake();
}
}
if tx {
if let Some(waker) = TX_WAKER.borrow_ref_mut(cs).take() {
waker.wake();
}
}
});
}
impl Uart {
async fn wait_rx(&mut self) {
poll_fn(|cx| {
if self.byte_available() {
return Poll::Ready(());
}
critical_section::with(|cs| {
*RX_WAKER.borrow_ref_mut(cs) = Some(cx.waker().clone());
});
self.enable_rx_irq();
if self.byte_available() {
self.disable_rx_irq();
Poll::Ready(())
} else {
Poll::Pending
}
})
.await;
}
async fn wait_tx(&mut self) {
poll_fn(|cx| {
if !self.tx_full() {
return Poll::Ready(());
}
critical_section::with(|cs| {
*TX_WAKER.borrow_ref_mut(cs) = Some(cx.waker().clone());
});
self.enable_tx_irq();
if !self.tx_full() {
self.disable_tx_irq();
Poll::Ready(())
} else {
Poll::Pending
}
})
.await;
}
}
impl embedded_io_async::Read for Uart {
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
if buf.is_empty() {
return Ok(0);
}
self.wait_rx().await;
let mut n = 0;
while n < buf.len() {
match self.try_read_byte() {
Some(byte) => {
buf[n] = byte;
n += 1;
}
None => break,
}
}
Ok(n)
}
}
impl embedded_io_async::Write for Uart {
async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
if buf.is_empty() {
return Ok(0);
}
self.wait_tx().await;
let mut n = 0;
while n < buf.len() && self.try_write_byte(buf[n]) {
n += 1;
}
Ok(n)
}
async fn flush(&mut self) -> Result<(), Self::Error> {
while self.tx_full() {
self.wait_tx().await;
}
self.wait_tx_idle();
Ok(())
}
}