diff --git a/src/uart.rs b/src/uart.rs index ce32a8b..3b2591a 100644 --- a/src/uart.rs +++ b/src/uart.rs @@ -104,82 +104,7 @@ pub struct UartDevice<'cb> { _phantom: core::marker::PhantomData<&'cb ()>, } -impl<'cb> UartDevice<'cb> { - /// Creates a UART with an arbitrary lifetime. - /// - /// # Unsafety - /// - /// To use this safely, the caller must ensure that the returned Self is reliably destructed before &'cb mut F becomes unavailable. - unsafe fn construct_uart( - index: usize, - baud: u32, - user_callback: &'cb mut F, - ) -> Result - where - F: FnMut(u8) + Send + 'cb, - { - let dev = macro_UART_DEV(index as c_uint); - uart_init( - dev, - baud, - Some(Self::new_data_callback::), - user_callback as *mut _ as *mut c_void, - ) - .negative_to_error()?; - Ok(Self { - dev, - _phantom: Default::default(), - }) - } -} - impl UartDevice<'static> { - /// Initializes the given `UART`, and runs a `main` function while it is configured. - /// - /// Returns a Result with rather `Ok` where `RMain` is the value returned by the scoped main function - /// or a `Err` containing the error. - /// - /// This is the scoped version of [`new_with_static_cb()`] that can be used if you want to use short-lived callbacks, such as - /// closures or anything containing references. The `UartDevice` is deconfigured when the internal main function - /// terminates. A common pattern around this kind of scoped functions is that `main` contains the application's - /// main loop, and never terminates (in which case the clean-up code is eliminated during compilation). - /// - /// # Arguments - /// - /// * `dev` – The index of the hardware device - /// * `baud` – The used baud rate - /// * `user_callback` – The user defined callback that gets called from the os whenever new data is received from the `UART` - /// * `main` – The main loop that is executed inside the wrapper - /// - /// # Examples - /// ``` - /// use riot_wrappers::uart::UartDevice; - /// let mut cb = |new_data| { - /// println!("Received {:02x}", new_data); - /// }; - /// let mut scoped_main = |self_: &mut UartDevice| loop { - /// self_.write(b"Hello from UART") - /// }; - /// let mut uart = UartDevice::new_scoped(0, 115200, &mut cb, scoped_main) - /// .unwrap_or_else(|e| panic!("Error initializing UART: {e:?}")); - /// ``` - pub fn new_scoped( - index: usize, - baud: u32, - user_callback: &mut F, - main: Main, - ) -> Result - where - F: FnMut(u8) + Send, - Main: for<'brand> FnOnce(&mut UartDevice<'brand>) -> RMain, - { - // This possibly relies on Rust code in RIOT to not unwind. - let mut self_ = unsafe { UartDevice::construct_uart(index, baud, user_callback) }?; - let result = (main)(&mut self_); - drop(self_); - Ok(result) - } - /// Initialize the given `UART`; as the name implies, the created `UART` device can ONLY send data. /// /// Returns a Result with rather `Ok` if the UART was initialized successfully or a @@ -249,38 +174,80 @@ impl UartDevice<'static> { { unsafe { Self::construct_uart(index, baud, user_callback) } } -} -impl<'cb> UartDevice<'cb> { - /// Sets the mode according to the given parameters. + /// Initializes the given `UART`, and runs a `main` function while it is configured. /// - /// Should the parameters be invalid, the function returns a Err + /// Returns a Result with rather `Ok` where `RMain` is the value returned by the scoped main function + /// or a `Err` containing the error. + /// + /// This is the scoped version of [`new_with_static_cb()`] that can be used if you want to use short-lived callbacks, such as + /// closures or anything containing references. The `UartDevice` is deconfigured when the internal main function + /// terminates. A common pattern around this kind of scoped functions is that `main` contains the application's + /// main loop, and never terminates (in which case the clean-up code is eliminated during compilation). /// /// # Arguments - /// * `data_bits` - Number of data bits in a UART frame - /// * `parity` - Parity mode - /// * `stop_bits` - Number of stop bits in a UART frame + /// + /// * `dev` – The index of the hardware device + /// * `baud` – The used baud rate + /// * `user_callback` – The user defined callback that gets called from the os whenever new data is received from the `UART` + /// * `main` – The main loop that is executed inside the wrapper /// /// # Examples /// ``` - /// use riot_wrappers::uart::{DataBits, Parity, StopBits, UartDevice}; - /// let mut uart = UartDevice::new_without_rx(0, 115200) - /// .unwrap_or_else(|e| panic!("Error initializing UART: {e:?}")); - /// uart.set_mode(DataBits::Eight, Parity::None, StopBits::One) - /// .unwrap_or_else(|e| panic!("Error setting UART mode: {e:?}")); + /// use riot_wrappers::uart::UartDevice; + /// let mut cb = |new_data| { + /// println!("Received {:02x}", new_data); + /// }; + /// let mut scoped_main = |self_: &mut UartDevice| loop { + /// self_.write(b"Hello from UART") + /// }; + /// let mut uart = UartDevice::new_scoped(0, 115200, &mut cb, scoped_main) + /// .unwrap_or_else(|e| panic!("Error initializing UART: {e:?}")); /// ``` - #[cfg(riot_module_periph_uart_modecfg)] - pub fn set_mode( - &mut self, - data_bits: DataBits, - parity: Parity, - stop_bits: StopBits, - ) -> Result<(), UartDeviceError> { - unsafe { - uart_mode(self.dev, data_bits.to_c(), parity.to_c(), stop_bits.to_c()) - .negative_to_error()?; - Ok(()) - } + pub fn new_scoped( + index: usize, + baud: u32, + user_callback: &mut F, + main: Main, + ) -> Result + where + F: FnMut(u8) + Send, + Main: for<'brand> FnOnce(&mut UartDevice<'brand>) -> RMain, + { + // This possibly relies on Rust code in RIOT to not unwind. + let mut self_ = unsafe { UartDevice::construct_uart(index, baud, user_callback) }?; + let result = (main)(&mut self_); + drop(self_); + Ok(result) + } +} + +impl<'cb> UartDevice<'cb> { + /// Creates a UART with an arbitrary lifetime. + /// + /// # Unsafety + /// + /// To use this safely, the caller must ensure that the returned Self is reliably destructed before &'cb mut F becomes unavailable. + unsafe fn construct_uart( + index: usize, + baud: u32, + user_callback: &'cb mut F, + ) -> Result + where + F: FnMut(u8) + Send + 'cb, + { + let dev = macro_UART_DEV(index as c_uint); + uart_init( + dev, + baud, + Some(Self::new_data_callback::), + user_callback as *mut _ as *mut c_void, + ) + .negative_to_error()?; + Ok(Self { + dev, + _phantom: Default::default(), + }) } /// Transmits the given data via the `UART`-device. @@ -308,6 +275,37 @@ impl<'cb> UartDevice<'cb> { unsafe { uart_poweroff(self.dev) }; } + /// Sets the mode according to the given parameters. + /// + /// Should the parameters be invalid, the function returns a Err + /// + /// # Arguments + /// * `data_bits` - Number of data bits in a UART frame + /// * `parity` - Parity mode + /// * `stop_bits` - Number of stop bits in a UART frame + /// + /// # Examples + /// ``` + /// use riot_wrappers::uart::{DataBits, Parity, StopBits, UartDevice}; + /// let mut uart = UartDevice::new_without_rx(0, 115200) + /// .unwrap_or_else(|e| panic!("Error initializing UART: {e:?}")); + /// uart.set_mode(DataBits::Eight, Parity::None, StopBits::One) + /// .unwrap_or_else(|e| panic!("Error setting UART mode: {e:?}")); + /// ``` + #[cfg(riot_module_periph_uart_modecfg)] + pub fn set_mode( + &mut self, + data_bits: DataBits, + parity: Parity, + stop_bits: StopBits, + ) -> Result<(), UartDeviceError> { + unsafe { + uart_mode(self.dev, data_bits.to_c(), parity.to_c(), stop_bits.to_c()) + .negative_to_error()?; + Ok(()) + } + } + /// Undoes the effects of [.deinit_pins()][Self::deinit_pins]. /// /// This function normally does not need to be called. But in some case, the pins on the `UART`