use log::info; use nrf52840_hal::uarte::{self, Uarte}; use starb::{Reader, RingBuffer, Writer}; static mut RB: RingBuffer = RingBuffer::new(); const BUFLEN: usize = 255; struct DoubleBuffer { bank0: [u8; BUFLEN], bank1: [u8; BUFLEN], is_bank0: bool, } impl DoubleBuffer { const fn new() -> Self { Self { bank0: [0; BUFLEN], bank1: [0; BUFLEN], is_bank0: true, } } fn cur_ptr(&mut self) -> *mut u8 { if self.is_bank0 { self.bank0.as_mut_ptr() } else { self.bank1.as_mut_ptr() } } fn next_ptr(&mut self) -> *mut u8 { self.is_bank0 = !self.is_bank0; if self.is_bank0 { self.bank1.as_mut_ptr() } else { self.bank0.as_mut_ptr() } } } static mut DBL_BUFF: DoubleBuffer = DoubleBuffer::new(); pub fn setup(mut uarte: Uarte) -> (Reader<'static, u8>, impl FnMut()) where I: uarte::Instance, { uarte.0.intenset.write(|w| { w.endrx().set_bit(); w.error().set_bit(); w.rxto().set_bit(); w.rxstarted().set_bit() }); // Keep the transmission going constantly. uarte.0.shorts.write(|w| w.endrx_startrx().set_bit()); let ptr = unsafe { DBL_BUFF.next_ptr() }; info!("setting up dma: p: {:x}, maxcnt: {}", ptr as u32, BUFLEN); uarte.0.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as _) }); uarte .0 .rxd .maxcnt .write(|w| unsafe { w.maxcnt().bits(BUFLEN as _) }); uarte.0.tasks_startrx.write(|w| w.tasks_startrx().set_bit()); let (rbr, mut rbw) = unsafe { RB.split() }; // start rx into a buffer. it would be nice if we could do this // with rxrdy or something like i2c does. let cl = move || handler(&mut uarte, &mut rbw); (rbr, cl) } fn handler(uarte: &mut Uarte, writer: &mut Writer) where I: uarte::Instance, { if uarte.0.events_endrx.read().events_endrx().bit_is_set() { uarte.0.events_endrx.write(|w| w.events_endrx().clear_bit()); // Copy DMA buffer to ring buffer. let len = uarte.0.rxd.amount.read().amount().bits(); let ptr = unsafe { DBL_BUFF.cur_ptr() }; /* let optr = uarte.0.rxd.ptr.read().ptr().bits(); let mc = uarte.0.rxd.maxcnt.read().maxcnt().bits(); info!( "ENDRX optr: {:x}, mc: {}, ptr: {:x}, len: {}", optr, mc, ptr as u32, len, ); */ flush_buf(writer, ptr, len as usize); } else if uarte.0.events_error.read().events_error().bit_is_set() { uarte.0.events_error.write(|w| w.events_error().clear_bit()); let len = uarte.0.rxd.amount.read().amount().bits(); info!("ERROR {:b} {}b", uarte.0.errorsrc.read().bits(), len); } else if uarte.0.events_rxto.read().events_rxto().bit_is_set() { uarte.0.events_rxto.write(|w| w.events_rxto().clear_bit()); let len = uarte.0.rxd.amount.read().amount().bits(); info!("RXTO - {}", len); flush_buf(writer, unsafe { DBL_BUFF.cur_ptr() }, len as usize); uarte.0.tasks_flushrx.write(|w| w.tasks_flushrx().set_bit()); } else if uarte .0 .events_rxstarted .read() .events_rxstarted() .bit_is_set() { uarte .0 .events_rxstarted .write(|w| w.events_rxstarted().clear_bit()); //info!("RXSTARTED"); // Swap to the next buffer as soon as the transfer starts to // try and lose as little data as possible. let ptr = unsafe { DBL_BUFF.next_ptr() }; uarte.0.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as _) }); } } fn flush_buf(writer: &mut Writer, ptr: *mut u8, len: usize) { let buf = unsafe { core::slice::from_raw_parts(ptr, len) }; //info!("flush start"); writer.unshift_from(buf); //info!("flush end"); }