aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2024-01-19 16:01:02 +0100
committerGitHub <[email protected]>2024-01-19 16:01:02 +0100
commit1e16661e0a17cdb9ad044ef9a38dacbaf35c1d10 (patch)
treede77ef8c0c60d00808a761e74abcbbce3236332d
parent686069b4c97b201e4fd444785d784b9836ee2271 (diff)
parent5e08bb8bc3a7e0e308cbada03c9c363cdf5223b9 (diff)
Merge pull request #2311 from jamesmunns/james/read_to_break
Add a basic RP "read to break" function
-rw-r--r--embassy-rp/src/uart/mod.rs222
1 files changed, 211 insertions, 11 deletions
diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs
index 99fce0fc9..9f5ba4e8a 100644
--- a/embassy-rp/src/uart/mod.rs
+++ b/embassy-rp/src/uart/mod.rs
@@ -118,6 +118,17 @@ pub enum Error {
118 Framing, 118 Framing,
119} 119}
120 120
121/// Read To Break error
122#[derive(Debug, Eq, PartialEq, Copy, Clone)]
123#[cfg_attr(feature = "defmt", derive(defmt::Format))]
124#[non_exhaustive]
125pub enum ReadToBreakError {
126 /// Read this many bytes, but never received a line break.
127 MissingBreak(usize),
128 /// Other, standard issue with the serial request
129 Other(Error),
130}
131
121/// Internal DMA state of UART RX. 132/// Internal DMA state of UART RX.
122pub struct DmaState { 133pub struct DmaState {
123 rx_err_waker: AtomicWaker, 134 rx_err_waker: AtomicWaker,
@@ -274,14 +285,17 @@ impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> {
274 285
275 /// Read from UART RX blocking execution until done. 286 /// Read from UART RX blocking execution until done.
276 pub fn blocking_read(&mut self, mut buffer: &mut [u8]) -> Result<(), Error> { 287 pub fn blocking_read(&mut self, mut buffer: &mut [u8]) -> Result<(), Error> {
277 while buffer.len() > 0 { 288 while !buffer.is_empty() {
278 let received = self.drain_fifo(buffer)?; 289 let received = self.drain_fifo(buffer).map_err(|(_i, e)| e)?;
279 buffer = &mut buffer[received..]; 290 buffer = &mut buffer[received..];
280 } 291 }
281 Ok(()) 292 Ok(())
282 } 293 }
283 294
284 fn drain_fifo(&mut self, buffer: &mut [u8]) -> Result<usize, Error> { 295 /// Returns Ok(len) if no errors occurred. Returns Err((len, err)) if an error was
296 /// encountered. in both cases, `len` is the number of *good* bytes copied into
297 /// `buffer`.
298 fn drain_fifo(&mut self, buffer: &mut [u8]) -> Result<usize, (usize, Error)> {
285 let r = T::regs(); 299 let r = T::regs();
286 for (i, b) in buffer.iter_mut().enumerate() { 300 for (i, b) in buffer.iter_mut().enumerate() {
287 if r.uartfr().read().rxfe() { 301 if r.uartfr().read().rxfe() {
@@ -291,13 +305,13 @@ impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> {
291 let dr = r.uartdr().read(); 305 let dr = r.uartdr().read();
292 306
293 if dr.oe() { 307 if dr.oe() {
294 return Err(Error::Overrun); 308 return Err((i, Error::Overrun));
295 } else if dr.be() { 309 } else if dr.be() {
296 return Err(Error::Break); 310 return Err((i, Error::Break));
297 } else if dr.pe() { 311 } else if dr.pe() {
298 return Err(Error::Parity); 312 return Err((i, Error::Parity));
299 } else if dr.fe() { 313 } else if dr.fe() {
300 return Err(Error::Framing); 314 return Err((i, Error::Framing));
301 } else { 315 } else {
302 *b = dr.data(); 316 *b = dr.data();
303 } 317 }
@@ -389,7 +403,7 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
389 } { 403 } {
390 Ok(len) if len < buffer.len() => &mut buffer[len..], 404 Ok(len) if len < buffer.len() => &mut buffer[len..],
391 Ok(_) => return Ok(()), 405 Ok(_) => return Ok(()),
392 Err(e) => return Err(e), 406 Err((_i, e)) => return Err(e),
393 }; 407 };
394 408
395 // start a dma transfer. if errors have happened in the interim some error 409 // start a dma transfer. if errors have happened in the interim some error
@@ -426,13 +440,25 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
426 .await; 440 .await;
427 441
428 let errors = match transfer_result { 442 let errors = match transfer_result {
429 Either::First(()) => return Ok(()), 443 Either::First(()) => {
430 Either::Second(e) => e, 444 // We're here because the DMA finished, BUT if an error occurred on the LAST
445 // byte, then we may still need to grab the error state!
446 Uartris(T::dma_state().rx_errs.swap(0, Ordering::Relaxed) as u32)
447 }
448 Either::Second(e) => {
449 // We're here because we errored, which means this is the error that
450 // was problematic.
451 e
452 }
431 }; 453 };
432 454
455 // If we got no error, just return at this point
433 if errors.0 == 0 { 456 if errors.0 == 0 {
434 return Ok(()); 457 return Ok(());
435 } else if errors.oeris() { 458 }
459
460 // If we DID get an error, we need to figure out which one it was.
461 if errors.oeris() {
436 return Err(Error::Overrun); 462 return Err(Error::Overrun);
437 } else if errors.beris() { 463 } else if errors.beris() {
438 return Err(Error::Break); 464 return Err(Error::Break);
@@ -443,6 +469,173 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
443 } 469 }
444 unreachable!("unrecognized rx error"); 470 unreachable!("unrecognized rx error");
445 } 471 }
472
473 /// Read from the UART, waiting for a line break.
474 ///
475 /// We read until one of the following occurs:
476 ///
477 /// * We read `buffer.len()` bytes without a line break
478 /// * returns `Err(ReadToBreakError::MissingBreak(buffer.len()))`
479 /// * We read `n` bytes then a line break occurs
480 /// * returns `Ok(n)`
481 /// * We encounter some error OTHER than a line break
482 /// * returns `Err(ReadToBreakError::Other(error))`
483 ///
484 /// **NOTE**: you MUST provide a buffer one byte larger than your largest expected
485 /// message to reliably detect the framing on one single call to `read_to_break()`.
486 ///
487 /// * If you expect a message of 20 bytes + line break, and provide a 20-byte buffer:
488 /// * The first call to `read_to_break()` will return `Err(ReadToBreakError::MissingBreak(20))`
489 /// * The next call to `read_to_break()` will immediately return `Ok(0)`, from the "stale" line break
490 /// * If you expect a message of 20 bytes + line break, and provide a 21-byte buffer:
491 /// * The first call to `read_to_break()` will return `Ok(20)`.
492 /// * The next call to `read_to_break()` will work as expected
493 pub async fn read_to_break(&mut self, buffer: &mut [u8]) -> Result<usize, ReadToBreakError> {
494 // clear error flags before we drain the fifo. errors that have accumulated
495 // in the flags will also be present in the fifo.
496 T::dma_state().rx_errs.store(0, Ordering::Relaxed);
497 T::regs().uarticr().write(|w| {
498 w.set_oeic(true);
499 w.set_beic(true);
500 w.set_peic(true);
501 w.set_feic(true);
502 });
503
504 // then drain the fifo. we need to read at most 32 bytes. errors that apply
505 // to fifo bytes will be reported directly.
506 let sbuffer = match {
507 let limit = buffer.len().min(32);
508 self.drain_fifo(&mut buffer[0..limit])
509 } {
510 // Drained fifo, still some room left!
511 Ok(len) if len < buffer.len() => &mut buffer[len..],
512 // Drained (some/all of the fifo), no room left
513 Ok(len) => return Err(ReadToBreakError::MissingBreak(len)),
514 // We got a break WHILE draining the FIFO, return what we did get before the break
515 Err((i, Error::Break)) => return Ok(i),
516 // Some other error, just return the error
517 Err((_i, e)) => return Err(ReadToBreakError::Other(e)),
518 };
519
520 // start a dma transfer. if errors have happened in the interim some error
521 // interrupt flags will have been raised, and those will be picked up immediately
522 // by the interrupt handler.
523 let mut ch = self.rx_dma.as_mut().unwrap();
524 T::regs().uartimsc().write_set(|w| {
525 w.set_oeim(true);
526 w.set_beim(true);
527 w.set_peim(true);
528 w.set_feim(true);
529 });
530 T::regs().uartdmacr().write_set(|reg| {
531 reg.set_rxdmae(true);
532 reg.set_dmaonerr(true);
533 });
534 let transfer = unsafe {
535 // If we don't assign future to a variable, the data register pointer
536 // is held across an await and makes the future non-Send.
537 crate::dma::read(&mut ch, T::regs().uartdr().as_ptr() as *const _, sbuffer, T::RX_DREQ)
538 };
539
540 // wait for either the transfer to complete or an error to happen.
541 let transfer_result = select(
542 transfer,
543 poll_fn(|cx| {
544 T::dma_state().rx_err_waker.register(cx.waker());
545 match T::dma_state().rx_errs.swap(0, Ordering::Relaxed) {
546 0 => Poll::Pending,
547 e => Poll::Ready(Uartris(e as u32)),
548 }
549 }),
550 )
551 .await;
552
553 // Figure out our error state
554 let errors = match transfer_result {
555 Either::First(()) => {
556 // We're here because the DMA finished, BUT if an error occurred on the LAST
557 // byte, then we may still need to grab the error state!
558 Uartris(T::dma_state().rx_errs.swap(0, Ordering::Relaxed) as u32)
559 }
560 Either::Second(e) => {
561 // We're here because we errored, which means this is the error that
562 // was problematic.
563 e
564 }
565 };
566
567 if errors.0 == 0 {
568 // No errors? That means we filled the buffer without a line break.
569 // For THIS function, that's a problem.
570 return Err(ReadToBreakError::MissingBreak(buffer.len()));
571 } else if errors.beris() {
572 // We got a Line Break! By this point, we've finished/aborted the DMA
573 // transaction, which means that we need to figure out where it left off
574 // by looking at the write_addr.
575 //
576 // First, we do a sanity check to make sure the write value is within the
577 // range of DMA we just did.
578 let sval = buffer.as_ptr() as usize;
579 let eval = sval + buffer.len();
580
581 // This is the address where the DMA would write to next
582 let next_addr = ch.regs().write_addr().read() as usize;
583
584 // If we DON'T end up inside the range, something has gone really wrong.
585 // Note that it's okay that `eval` is one past the end of the slice, as
586 // this is where the write pointer will end up at the end of a full
587 // transfer.
588 if (next_addr < sval) || (next_addr > eval) {
589 unreachable!("UART DMA reported invalid `write_addr`");
590 }
591
592 let regs = T::regs();
593 let all_full = next_addr == eval;
594
595 // NOTE: This is off label usage of RSR! See the issue below for
596 // why I am not checking if there is an "extra" FIFO byte, and why
597 // I am checking RSR directly (it seems to report the status of the LAST
598 // POPPED value, rather than the NEXT TO POP value like the datasheet
599 // suggests!)
600 //
601 // issue: https://github.com/raspberrypi/pico-feedback/issues/367
602 let last_was_break = regs.uartrsr().read().be();
603
604 return match (all_full, last_was_break) {
605 (true, true) | (false, _) => {
606 // We got less than the full amount + a break, or the full amount
607 // and the last byte was a break. Subtract the break off.
608 Ok((next_addr - 1) - sval)
609 }
610 (true, false) => {
611 // We finished the whole DMA, and the last DMA'd byte was NOT a break
612 // character. This is an error.
613 //
614 // NOTE: we COULD potentially return Ok(buffer.len()) here, since we
615 // know a line break occured at SOME POINT after the DMA completed.
616 //
617 // However, we have no way of knowing if there was extra data BEFORE
618 // that line break, so instead return an Err to signal to the caller
619 // that there are "leftovers", and they'll catch the actual line break
620 // on the next call.
621 //
622 // Doing it like this also avoids racyness: now whether you finished
623 // the full read BEFORE the line break occurred or AFTER the line break
624 // occurs, you still get `MissingBreak(buffer.len())` instead of sometimes
625 // getting `Ok(buffer.len())` if you were "late enough" to observe the
626 // line break.
627 Err(ReadToBreakError::MissingBreak(buffer.len()))
628 }
629 };
630 } else if errors.oeris() {
631 return Err(ReadToBreakError::Other(Error::Overrun));
632 } else if errors.peris() {
633 return Err(ReadToBreakError::Other(Error::Parity));
634 } else if errors.feris() {
635 return Err(ReadToBreakError::Other(Error::Framing));
636 }
637 unreachable!("unrecognized rx error");
638 }
446} 639}
447 640
448impl<'d, T: Instance> Uart<'d, T, Blocking> { 641impl<'d, T: Instance> Uart<'d, T, Blocking> {
@@ -743,6 +936,13 @@ impl<'d, T: Instance> Uart<'d, T, Async> {
743 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { 936 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
744 self.rx.read(buffer).await 937 self.rx.read(buffer).await
745 } 938 }
939
940 /// Read until the buffer is full or a line break occurs.
941 ///
942 /// See [`UartRx::read_to_break()`] for more details
943 pub async fn read_to_break<'a>(&mut self, buf: &'a mut [u8]) -> Result<usize, ReadToBreakError> {
944 self.rx.read_to_break(buf).await
945 }
746} 946}
747 947
748impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Read<u8> for UartRx<'d, T, M> { 948impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Read<u8> for UartRx<'d, T, M> {