diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index 7ba209063..f7b2bf4b4 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs @@ -157,6 +157,7 @@ pub struct BufferedUartTx<'d> { tx: Option>, cts: Option>, de: Option>, + is_borrowed: bool, } /// Rx-only buffered UART @@ -168,6 +169,7 @@ pub struct BufferedUartRx<'d> { kernel_clock: Hertz, rx: Option>, rts: Option>, + is_borrowed: bool, } impl<'d> SetConfig for BufferedUart<'d> { @@ -341,6 +343,7 @@ impl<'d> BufferedUart<'d> { kernel_clock, rx, rts, + is_borrowed: false, }, tx: BufferedUartTx { info, @@ -349,6 +352,7 @@ impl<'d> BufferedUart<'d> { tx, cts, de, + is_borrowed: false, }, }; this.enable_and_configure(tx_buffer, rx_buffer, &config)?; @@ -396,6 +400,31 @@ impl<'d> BufferedUart<'d> { (self.tx, self.rx) } + /// Split the Uart into a transmitter and receiver, + /// which is particularly useful when having two tasks correlating to + /// transmitting and receiving. + pub fn split_ref(&mut self) -> (BufferedUartTx<'_>, BufferedUartRx<'_>) { + ( + BufferedUartTx { + info: self.tx.info, + state: self.tx.state, + kernel_clock: self.tx.kernel_clock, + tx: self.tx.tx.as_mut().map(PeripheralRef::reborrow), + cts: self.tx.cts.as_mut().map(PeripheralRef::reborrow), + de: self.tx.de.as_mut().map(PeripheralRef::reborrow), + is_borrowed: true, + }, + BufferedUartRx { + info: self.rx.info, + state: self.rx.state, + kernel_clock: self.rx.kernel_clock, + rx: self.rx.rx.as_mut().map(PeripheralRef::reborrow), + rts: self.rx.rts.as_mut().map(PeripheralRef::reborrow), + is_borrowed: true, + }, + ) + } + /// Reconfigure the driver pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { reconfigure(self.rx.info, self.rx.kernel_clock, config)?; @@ -600,40 +629,44 @@ impl<'d> BufferedUartTx<'d> { impl<'d> Drop for BufferedUartRx<'d> { fn drop(&mut self) { - let state = self.state; - unsafe { - state.rx_buf.deinit(); + if !self.is_borrowed { + let state = self.state; + unsafe { + state.rx_buf.deinit(); - // TX is inactive if the the buffer is not available. - // We can now unregister the interrupt handler - if state.tx_buf.len() == 0 { - self.info.interrupt.disable(); + // TX is inactive if the the buffer is not available. + // We can now unregister the interrupt handler + if state.tx_buf.len() == 0 { + self.info.interrupt.disable(); + } } - } - self.rx.as_ref().map(|x| x.set_as_disconnected()); - self.rts.as_ref().map(|x| x.set_as_disconnected()); - drop_tx_rx(self.info, state); + self.rx.as_ref().map(|x| x.set_as_disconnected()); + self.rts.as_ref().map(|x| x.set_as_disconnected()); + drop_tx_rx(self.info, state); + } } } impl<'d> Drop for BufferedUartTx<'d> { fn drop(&mut self) { - let state = self.state; - unsafe { - state.tx_buf.deinit(); + if !self.is_borrowed { + let state = self.state; + unsafe { + state.tx_buf.deinit(); - // RX is inactive if the the buffer is not available. - // We can now unregister the interrupt handler - if state.rx_buf.len() == 0 { - self.info.interrupt.disable(); + // RX is inactive if the the buffer is not available. + // We can now unregister the interrupt handler + if state.rx_buf.len() == 0 { + self.info.interrupt.disable(); + } } - } - self.tx.as_ref().map(|x| x.set_as_disconnected()); - self.cts.as_ref().map(|x| x.set_as_disconnected()); - self.de.as_ref().map(|x| x.set_as_disconnected()); - drop_tx_rx(self.info, state); + self.tx.as_ref().map(|x| x.set_as_disconnected()); + self.cts.as_ref().map(|x| x.set_as_disconnected()); + self.de.as_ref().map(|x| x.set_as_disconnected()); + drop_tx_rx(self.info, state); + } } } diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 333e01e36..8152fc560 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -1440,6 +1440,13 @@ impl<'d, M: Mode> Uart<'d, M> { (self.tx, self.rx) } + /// Split the Uart into a transmitter and receiver by mutable reference, + /// which is particularly useful when having two tasks correlating to + /// transmitting and receiving. + pub fn split_ref(&mut self) -> (&mut UartTx<'d, M>, &mut UartRx<'d, M>) { + (&mut self.tx, &mut self.rx) + } + /// Send break character pub fn send_break(&self) { self.tx.send_break();