diff --git a/examples/embassy/src/bin/uart-echo-with-irq.rs b/examples/embassy/src/bin/uart-echo-with-irq.rs index cc8a599..94ba310 100644 --- a/examples/embassy/src/bin/uart-echo-with-irq.rs +++ b/examples/embassy/src/bin/uart-echo-with-irq.rs @@ -128,17 +128,14 @@ async fn blinky(mut led: Pin) { fn UART0_RX() { let mut buf: [u8; 16] = [0; 16]; let mut read_len: usize = 0; - let mut irq_error = None; + let mut errors = None; RX.lock(|static_rx| { let mut rx_borrow = static_rx.borrow_mut(); let rx_mut_ref = rx_borrow.as_mut().unwrap(); - match rx_mut_ref.irq_handler(&mut buf) { - Ok(result) => { - read_len = result.bytes_read; - } - Err(e) => { - irq_error = Some(e); - } + let result = rx_mut_ref.irq_handler(&mut buf); + read_len = result.bytes_read; + if result.errors.is_some() { + errors = result.errors; } }); let mut ringbuf_full = false; @@ -155,8 +152,8 @@ fn UART0_RX() { }); } - if irq_error.is_some() { - rprintln!("error in IRQ handler: {:?}", irq_error); + if errors.is_some() { + rprintln!("UART error: {:?}", errors); } if ringbuf_full { rprintln!("ringbuffer is full, deleted oldest data"); diff --git a/flashloader/src/main.rs b/flashloader/src/main.rs index 96d546d..f9746f6 100644 --- a/flashloader/src/main.rs +++ b/flashloader/src/main.rs @@ -293,8 +293,8 @@ mod app { .read_fixed_len_or_timeout_based_using_irq(cx.local.rx_context) .expect("read operation failed"); } - if result.error() { - log::warn!("UART error: {:?}", result.error()); + if result.has_errors() { + log::warn!("UART error: {:?}", result.errors.unwrap()); } } Err(e) => { diff --git a/va416xx-hal/src/gpio/reg.rs b/va416xx-hal/src/gpio/reg.rs index d8a9022..9fbf17a 100644 --- a/va416xx-hal/src/gpio/reg.rs +++ b/va416xx-hal/src/gpio/reg.rs @@ -113,14 +113,6 @@ pub(super) unsafe trait RegisterInterface { /// this type. fn id(&self) -> DynPinId; - const PORTA: *const PortRegisterBlock = Porta::ptr(); - const PORTB: *const PortRegisterBlock = Portb::ptr(); - const PORTC: *const PortRegisterBlock = Portc::ptr(); - const PORTD: *const PortRegisterBlock = Portd::ptr(); - const PORTE: *const PortRegisterBlock = Porte::ptr(); - const PORTF: *const PortRegisterBlock = Portf::ptr(); - const PORTG: *const PortRegisterBlock = Portg::ptr(); - /// Change the pin mode #[inline] fn change_mode(&mut self, mode: DynPinMode) { @@ -155,13 +147,13 @@ pub(super) unsafe trait RegisterInterface { #[inline] fn port_reg(&self) -> &PortRegisterBlock { match self.id().group { - DynGroup::A => unsafe { &(*Self::PORTA) }, - DynGroup::B => unsafe { &(*Self::PORTB) }, - DynGroup::C => unsafe { &(*Self::PORTC) }, - DynGroup::D => unsafe { &(*Self::PORTD) }, - DynGroup::E => unsafe { &(*Self::PORTE) }, - DynGroup::F => unsafe { &(*Self::PORTF) }, - DynGroup::G => unsafe { &(*Self::PORTG) }, + DynGroup::A => unsafe { &(*Porta::ptr()) }, + DynGroup::B => unsafe { &(*Portb::ptr()) }, + DynGroup::C => unsafe { &(*Portc::ptr()) }, + DynGroup::D => unsafe { &(*Portd::ptr()) }, + DynGroup::E => unsafe { &(*Porte::ptr()) }, + DynGroup::F => unsafe { &(*Portf::ptr()) }, + DynGroup::G => unsafe { &(*Portg::ptr()) }, } } diff --git a/va416xx-hal/src/uart.rs b/va416xx-hal/src/uart.rs index 15ab017..a08418c 100644 --- a/va416xx-hal/src/uart.rs +++ b/va416xx-hal/src/uart.rs @@ -70,6 +70,10 @@ impl RxPin for Pin {} // Regular Definitions //================================================================================================== +#[derive(Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct TransferPendingError; + #[derive(Debug, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum RxError { @@ -82,8 +86,6 @@ pub enum RxError { pub enum Error { Rx(RxError), BreakCondition, - TransferPending, - BufferTooShort, } impl From for Error { @@ -243,50 +245,47 @@ impl IrqContextTimeoutOrMaxSize { #[derive(Debug, Default)] pub struct IrqResult { pub bytes_read: usize, - pub errors: IrqUartError, + pub errors: Option, } /// This struct is used to return the default IRQ handler result to the user #[derive(Debug, Default)] -pub struct IrqResultMaxSizeTimeout { +pub struct IrqResultMaxSizeOrTimeout { complete: bool, timeout: bool, - pub errors: IrqUartError, + pub errors: Option, pub bytes_read: usize, } -impl IrqResultMaxSizeTimeout { +impl IrqResultMaxSizeOrTimeout { pub fn new() -> Self { - IrqResultMaxSizeTimeout { + IrqResultMaxSizeOrTimeout { complete: false, timeout: false, - errors: IrqUartError::default(), + errors: None, bytes_read: 0, } } } -impl IrqResultMaxSizeTimeout { +impl IrqResultMaxSizeOrTimeout { #[inline] - pub fn error(&self) -> bool { - if self.errors.overflow || self.errors.parity || self.errors.framing { - return true; - } - false + pub fn has_errors(&self) -> bool { + self.errors.is_some() } #[inline] pub fn overflow_error(&self) -> bool { - self.errors.overflow + self.errors.map_or(false, |e| e.overflow) } #[inline] pub fn framing_error(&self) -> bool { - self.errors.framing + self.errors.map_or(false, |e| e.framing) } #[inline] pub fn parity_error(&self) -> bool { - self.errors.parity + self.errors.map_or(false, |e| e.parity) } #[inline] @@ -747,7 +746,7 @@ impl Tx { } } -#[derive(Default, Debug)] +#[derive(Default, Debug, Copy, Clone)] pub struct IrqUartError { overflow: bool, framing: bool, @@ -784,10 +783,11 @@ impl IrqUartError { } } -#[derive(Debug)] -pub enum IrqError { - BufferTooShort { found: usize, expected: usize }, - Uart(IrqUartError), +#[derive(Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct BufferTooShortError { + found: usize, + expected: usize, } /// Serial receiver, using interrupts to offload reading to the hardware. @@ -833,9 +833,9 @@ impl RxWithIrq { pub fn read_fixed_len_or_timeout_based_using_irq( &mut self, context: &mut IrqContextTimeoutOrMaxSize, - ) -> Result<(), Error> { + ) -> Result<(), TransferPendingError> { if context.mode != IrqReceptionMode::Idle { - return Err(Error::TransferPending); + return Err(TransferPendingError); } context.mode = IrqReceptionMode::Pending; context.rx_idx = 0; @@ -874,8 +874,9 @@ impl RxWithIrq { /// result of the operation. /// /// This function will not disable the RX interrupts, so you don't need to call any other - /// API after calling this function to continue emptying the FIFO. - pub fn irq_handler(&mut self, buf: &mut [u8; 16]) -> Result { + /// API after calling this function to continue emptying the FIFO. RX errors are handled + /// as partial errors and are returned as part of the [IrqResult]. + pub fn irq_handler(&mut self, buf: &mut [u8; 16]) -> IrqResult { let mut result = IrqResult::default(); let irq_end = self.uart().irq_end().read(); @@ -917,7 +918,7 @@ impl RxWithIrq { self.uart() .irq_clr() .write(|w| unsafe { w.bits(irq_end.bits()) }); - Ok(result) + result } /// This function should be called in the user provided UART interrupt handler. @@ -930,19 +931,20 @@ impl RxWithIrq { /// [IrqContextTimeoutOrMaxSize] structure. /// /// If passed buffer is equal to or larger than the specified maximum length, an - /// [`Error::BufferTooShort`] will be returned + /// [BufferTooShortError] will be returned. Other RX errors are treated as partial errors + /// and returned inside the [IrqResultMaxSizeOrTimeout] structure. pub fn irq_handler_max_size_or_timeout_based( &mut self, context: &mut IrqContextTimeoutOrMaxSize, buf: &mut [u8], - ) -> Result { + ) -> Result { if buf.len() < context.max_len { - return Err(IrqError::BufferTooShort { + return Err(BufferTooShortError { found: buf.len(), expected: context.max_len, }); } - let mut result = IrqResultMaxSizeTimeout::default(); + let mut result = IrqResultMaxSizeOrTimeout::default(); let irq_end = self.uart().irq_end().read(); let enb_status = self.uart().enable().read(); @@ -1006,46 +1008,51 @@ impl RxWithIrq { fn read_handler( &self, - errors: &mut IrqUartError, + errors: &mut Option, read_res: &nb::Result, ) -> Option { match read_res { Ok(byte) => Some(*byte), Err(nb::Error::WouldBlock) => None, Err(nb::Error::Other(e)) => { + // Ensure `errors` is Some(IrqUartError), initializing if it's None + let err = errors.get_or_insert(IrqUartError::default()); + + // Now we can safely modify fields inside `err` match e { - RxError::Overrun => { - errors.overflow = true; - } - RxError::Framing => { - errors.framing = true; - } - RxError::Parity => { - errors.parity = true; - } + RxError::Overrun => err.overflow = true, + RxError::Framing => err.framing = true, + RxError::Parity => err.parity = true, } None } } } - fn check_for_errors(&self, errors: &mut IrqUartError) { - // Read status register again, might have changed since reading received data + fn check_for_errors(&self, errors: &mut Option) { let rx_status = self.uart().rxstatus().read(); - if rx_status.rxovr().bit_is_set() { - errors.overflow = true; - } - if rx_status.rxfrm().bit_is_set() { - errors.framing = true; - } - if rx_status.rxpar().bit_is_set() { - errors.parity = true; + + if rx_status.rxovr().bit_is_set() + || rx_status.rxfrm().bit_is_set() + || rx_status.rxpar().bit_is_set() + { + let err = errors.get_or_insert(IrqUartError::default()); + + if rx_status.rxovr().bit_is_set() { + err.overflow = true; + } + if rx_status.rxfrm().bit_is_set() { + err.framing = true; + } + if rx_status.rxpar().bit_is_set() { + err.parity = true; + } } } fn irq_completion_handler_max_size_timeout( &mut self, - res: &mut IrqResultMaxSizeTimeout, + res: &mut IrqResultMaxSizeOrTimeout, context: &mut IrqContextTimeoutOrMaxSize, ) { self.disable_rx_irq_sources();