aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUlf Lilleengen <[email protected]>2024-08-02 13:50:32 +0000
committerGitHub <[email protected]>2024-08-02 13:50:32 +0000
commitf2c29ba9d89fb7128eecb71dac7159d91aae855d (patch)
tree251573437e8a9d927fec38cee1277ef9d27cd14c
parent2b031756c6d705f58de972de48f7300b4fdc673c (diff)
parent7c1ecae53f062b26e06850fd66f7acb754a0f680 (diff)
Merge pull request #3174 from JomerDev/add-count-to-read_to_break
RP2040: Add read_to_break_with_count
-rw-r--r--embassy-rp/src/uart/mod.rs255
1 files changed, 155 insertions, 100 deletions
diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs
index f546abe71..d50f5b4d5 100644
--- a/embassy-rp/src/uart/mod.rs
+++ b/embassy-rp/src/uart/mod.rs
@@ -490,6 +490,36 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
490 /// * The first call to `read_to_break()` will return `Ok(20)`. 490 /// * The first call to `read_to_break()` will return `Ok(20)`.
491 /// * The next call to `read_to_break()` will work as expected 491 /// * The next call to `read_to_break()` will work as expected
492 pub async fn read_to_break(&mut self, buffer: &mut [u8]) -> Result<usize, ReadToBreakError> { 492 pub async fn read_to_break(&mut self, buffer: &mut [u8]) -> Result<usize, ReadToBreakError> {
493 self.read_to_break_with_count(buffer, 0).await
494 }
495
496 /// Read from the UART, waiting for a line break as soon as at least `min_count` bytes have been read.
497 ///
498 /// We read until one of the following occurs:
499 ///
500 /// * We read `buffer.len()` bytes without a line break
501 /// * returns `Err(ReadToBreakError::MissingBreak(buffer.len()))`
502 /// * We read `n > min_count` bytes then a line break occurs
503 /// * returns `Ok(n)`
504 /// * We encounter some error OTHER than a line break
505 /// * returns `Err(ReadToBreakError::Other(error))`
506 ///
507 /// If a line break occurs before `min_count` bytes have been read, the break will be ignored and the read will continue
508 ///
509 /// **NOTE**: you MUST provide a buffer one byte larger than your largest expected
510 /// message to reliably detect the framing on one single call to `read_to_break()`.
511 ///
512 /// * If you expect a message of 20 bytes + line break, and provide a 20-byte buffer:
513 /// * The first call to `read_to_break()` will return `Err(ReadToBreakError::MissingBreak(20))`
514 /// * The next call to `read_to_break()` will immediately return `Ok(0)`, from the "stale" line break
515 /// * If you expect a message of 20 bytes + line break, and provide a 21-byte buffer:
516 /// * The first call to `read_to_break()` will return `Ok(20)`.
517 /// * The next call to `read_to_break()` will work as expected
518 pub async fn read_to_break_with_count(
519 &mut self,
520 buffer: &mut [u8],
521 min_count: usize,
522 ) -> Result<usize, ReadToBreakError> {
493 // clear error flags before we drain the fifo. errors that have accumulated 523 // clear error flags before we drain the fifo. errors that have accumulated
494 // in the flags will also be present in the fifo. 524 // in the flags will also be present in the fifo.
495 T::dma_state().rx_errs.store(0, Ordering::Relaxed); 525 T::dma_state().rx_errs.store(0, Ordering::Relaxed);
@@ -502,7 +532,7 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
502 532
503 // then drain the fifo. we need to read at most 32 bytes. errors that apply 533 // then drain the fifo. we need to read at most 32 bytes. errors that apply
504 // to fifo bytes will be reported directly. 534 // to fifo bytes will be reported directly.
505 let sbuffer = match { 535 let mut sbuffer = match {
506 let limit = buffer.len().min(32); 536 let limit = buffer.len().min(32);
507 self.drain_fifo(&mut buffer[0..limit]) 537 self.drain_fifo(&mut buffer[0..limit])
508 } { 538 } {
@@ -511,7 +541,13 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
511 // Drained (some/all of the fifo), no room left 541 // Drained (some/all of the fifo), no room left
512 Ok(len) => return Err(ReadToBreakError::MissingBreak(len)), 542 Ok(len) => return Err(ReadToBreakError::MissingBreak(len)),
513 // We got a break WHILE draining the FIFO, return what we did get before the break 543 // We got a break WHILE draining the FIFO, return what we did get before the break
514 Err((i, Error::Break)) => return Ok(i), 544 Err((len, Error::Break)) => {
545 if len < min_count && len < buffer.len() {
546 &mut buffer[len..]
547 } else {
548 return Ok(len);
549 }
550 }
515 // Some other error, just return the error 551 // Some other error, just return the error
516 Err((_i, e)) => return Err(ReadToBreakError::Other(e)), 552 Err((_i, e)) => return Err(ReadToBreakError::Other(e)),
517 }; 553 };
@@ -530,110 +566,118 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
530 reg.set_rxdmae(true); 566 reg.set_rxdmae(true);
531 reg.set_dmaonerr(true); 567 reg.set_dmaonerr(true);
532 }); 568 });
533 let transfer = unsafe {
534 // If we don't assign future to a variable, the data register pointer
535 // is held across an await and makes the future non-Send.
536 crate::dma::read(&mut ch, T::regs().uartdr().as_ptr() as *const _, sbuffer, T::RX_DREQ)
537 };
538 569
539 // wait for either the transfer to complete or an error to happen. 570 loop {
540 let transfer_result = select( 571 let transfer = unsafe {
541 transfer, 572 // If we don't assign future to a variable, the data register pointer
542 poll_fn(|cx| { 573 // is held across an await and makes the future non-Send.
543 T::dma_state().rx_err_waker.register(cx.waker()); 574 crate::dma::read(&mut ch, T::regs().uartdr().as_ptr() as *const _, sbuffer, T::RX_DREQ)
544 match T::dma_state().rx_errs.swap(0, Ordering::Relaxed) { 575 };
545 0 => Poll::Pending,
546 e => Poll::Ready(Uartris(e as u32)),
547 }
548 }),
549 )
550 .await;
551
552 // Figure out our error state
553 let errors = match transfer_result {
554 Either::First(()) => {
555 // We're here because the DMA finished, BUT if an error occurred on the LAST
556 // byte, then we may still need to grab the error state!
557 Uartris(T::dma_state().rx_errs.swap(0, Ordering::Relaxed) as u32)
558 }
559 Either::Second(e) => {
560 // We're here because we errored, which means this is the error that
561 // was problematic.
562 e
563 }
564 };
565
566 if errors.0 == 0 {
567 // No errors? That means we filled the buffer without a line break.
568 // For THIS function, that's a problem.
569 return Err(ReadToBreakError::MissingBreak(buffer.len()));
570 } else if errors.beris() {
571 // We got a Line Break! By this point, we've finished/aborted the DMA
572 // transaction, which means that we need to figure out where it left off
573 // by looking at the write_addr.
574 //
575 // First, we do a sanity check to make sure the write value is within the
576 // range of DMA we just did.
577 let sval = buffer.as_ptr() as usize;
578 let eval = sval + buffer.len();
579
580 // This is the address where the DMA would write to next
581 let next_addr = ch.regs().write_addr().read() as usize;
582
583 // If we DON'T end up inside the range, something has gone really wrong.
584 // Note that it's okay that `eval` is one past the end of the slice, as
585 // this is where the write pointer will end up at the end of a full
586 // transfer.
587 if (next_addr < sval) || (next_addr > eval) {
588 unreachable!("UART DMA reported invalid `write_addr`");
589 }
590 576
591 let regs = T::regs(); 577 // wait for either the transfer to complete or an error to happen.
592 let all_full = next_addr == eval; 578 let transfer_result = select(
593 579 transfer,
594 // NOTE: This is off label usage of RSR! See the issue below for 580 poll_fn(|cx| {
595 // why I am not checking if there is an "extra" FIFO byte, and why 581 T::dma_state().rx_err_waker.register(cx.waker());
596 // I am checking RSR directly (it seems to report the status of the LAST 582 match T::dma_state().rx_errs.swap(0, Ordering::Relaxed) {
597 // POPPED value, rather than the NEXT TO POP value like the datasheet 583 0 => Poll::Pending,
598 // suggests!) 584 e => Poll::Ready(Uartris(e as u32)),
599 // 585 }
600 // issue: https://github.com/raspberrypi/pico-feedback/issues/367 586 }),
601 let last_was_break = regs.uartrsr().read().be(); 587 )
602 588 .await;
603 return match (all_full, last_was_break) { 589
604 (true, true) | (false, _) => { 590 // Figure out our error state
605 // We got less than the full amount + a break, or the full amount 591 let errors = match transfer_result {
606 // and the last byte was a break. Subtract the break off by adding one to sval. 592 Either::First(()) => {
607 Ok(next_addr.saturating_sub(1 + sval)) 593 // We're here because the DMA finished, BUT if an error occurred on the LAST
594 // byte, then we may still need to grab the error state!
595 Uartris(T::dma_state().rx_errs.swap(0, Ordering::Relaxed) as u32)
608 } 596 }
609 (true, false) => { 597 Either::Second(e) => {
610 // We finished the whole DMA, and the last DMA'd byte was NOT a break 598 // We're here because we errored, which means this is the error that
611 // character. This is an error. 599 // was problematic.
612 // 600 e
613 // NOTE: we COULD potentially return Ok(buffer.len()) here, since we
614 // know a line break occured at SOME POINT after the DMA completed.
615 //
616 // However, we have no way of knowing if there was extra data BEFORE
617 // that line break, so instead return an Err to signal to the caller
618 // that there are "leftovers", and they'll catch the actual line break
619 // on the next call.
620 //
621 // Doing it like this also avoids racyness: now whether you finished
622 // the full read BEFORE the line break occurred or AFTER the line break
623 // occurs, you still get `MissingBreak(buffer.len())` instead of sometimes
624 // getting `Ok(buffer.len())` if you were "late enough" to observe the
625 // line break.
626 Err(ReadToBreakError::MissingBreak(buffer.len()))
627 } 601 }
628 }; 602 };
629 } else if errors.oeris() { 603
630 return Err(ReadToBreakError::Other(Error::Overrun)); 604 if errors.0 == 0 {
631 } else if errors.peris() { 605 // No errors? That means we filled the buffer without a line break.
632 return Err(ReadToBreakError::Other(Error::Parity)); 606 // For THIS function, that's a problem.
633 } else if errors.feris() { 607 return Err(ReadToBreakError::MissingBreak(buffer.len()));
634 return Err(ReadToBreakError::Other(Error::Framing)); 608 } else if errors.beris() {
609 // We got a Line Break! By this point, we've finished/aborted the DMA
610 // transaction, which means that we need to figure out where it left off
611 // by looking at the write_addr.
612 //
613 // First, we do a sanity check to make sure the write value is within the
614 // range of DMA we just did.
615 let sval = buffer.as_ptr() as usize;
616 let eval = sval + buffer.len();
617
618 // This is the address where the DMA would write to next
619 let next_addr = ch.regs().write_addr().read() as usize;
620
621 // If we DON'T end up inside the range, something has gone really wrong.
622 // Note that it's okay that `eval` is one past the end of the slice, as
623 // this is where the write pointer will end up at the end of a full
624 // transfer.
625 if (next_addr < sval) || (next_addr > eval) {
626 unreachable!("UART DMA reported invalid `write_addr`");
627 }
628
629 if (next_addr - sval) < min_count {
630 sbuffer = &mut buffer[(next_addr - sval)..];
631 continue;
632 }
633
634 let regs = T::regs();
635 let all_full = next_addr == eval;
636
637 // NOTE: This is off label usage of RSR! See the issue below for
638 // why I am not checking if there is an "extra" FIFO byte, and why
639 // I am checking RSR directly (it seems to report the status of the LAST
640 // POPPED value, rather than the NEXT TO POP value like the datasheet
641 // suggests!)
642 //
643 // issue: https://github.com/raspberrypi/pico-feedback/issues/367
644 let last_was_break = regs.uartrsr().read().be();
645
646 return match (all_full, last_was_break) {
647 (true, true) | (false, _) => {
648 // We got less than the full amount + a break, or the full amount
649 // and the last byte was a break. Subtract the break off by adding one to sval.
650 Ok(next_addr.saturating_sub(1 + sval))
651 }
652 (true, false) => {
653 // We finished the whole DMA, and the last DMA'd byte was NOT a break
654 // character. This is an error.
655 //
656 // NOTE: we COULD potentially return Ok(buffer.len()) here, since we
657 // know a line break occured at SOME POINT after the DMA completed.
658 //
659 // However, we have no way of knowing if there was extra data BEFORE
660 // that line break, so instead return an Err to signal to the caller
661 // that there are "leftovers", and they'll catch the actual line break
662 // on the next call.
663 //
664 // Doing it like this also avoids racyness: now whether you finished
665 // the full read BEFORE the line break occurred or AFTER the line break
666 // occurs, you still get `MissingBreak(buffer.len())` instead of sometimes
667 // getting `Ok(buffer.len())` if you were "late enough" to observe the
668 // line break.
669 Err(ReadToBreakError::MissingBreak(buffer.len()))
670 }
671 };
672 } else if errors.oeris() {
673 return Err(ReadToBreakError::Other(Error::Overrun));
674 } else if errors.peris() {
675 return Err(ReadToBreakError::Other(Error::Parity));
676 } else if errors.feris() {
677 return Err(ReadToBreakError::Other(Error::Framing));
678 }
679 unreachable!("unrecognized rx error");
635 } 680 }
636 unreachable!("unrecognized rx error");
637 } 681 }
638} 682}
639 683
@@ -997,6 +1041,17 @@ impl<'d, T: Instance> Uart<'d, T, Async> {
997 pub async fn read_to_break<'a>(&mut self, buf: &'a mut [u8]) -> Result<usize, ReadToBreakError> { 1041 pub async fn read_to_break<'a>(&mut self, buf: &'a mut [u8]) -> Result<usize, ReadToBreakError> {
998 self.rx.read_to_break(buf).await 1042 self.rx.read_to_break(buf).await
999 } 1043 }
1044
1045 /// Read until the buffer is full or a line break occurs after at least `min_count` bytes have been read.
1046 ///
1047 /// See [`UartRx::read_to_break_with_count()`] for more details
1048 pub async fn read_to_break_with_count<'a>(
1049 &mut self,
1050 buf: &'a mut [u8],
1051 min_count: usize,
1052 ) -> Result<usize, ReadToBreakError> {
1053 self.rx.read_to_break_with_count(buf, min_count).await
1054 }
1000} 1055}
1001 1056
1002impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Read<u8> for UartRx<'d, T, M> { 1057impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Read<u8> for UartRx<'d, T, M> {