Skip to content

Commit

Permalink
uart: Rearrange functions for better documentation structure
Browse files Browse the repository at this point in the history
  • Loading branch information
chrysn committed Jan 7, 2025
1 parent 707cf17 commit dcfeff9
Showing 1 changed file with 97 additions and 99 deletions.
196 changes: 97 additions & 99 deletions src/uart.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<F>(
index: usize,
baud: u32,
user_callback: &'cb mut F,
) -> Result<Self, UartDeviceError>
where
F: FnMut(u8) + Send + 'cb,
{
let dev = macro_UART_DEV(index as c_uint);
uart_init(
dev,
baud,
Some(Self::new_data_callback::<F>),
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<RMain>` where `RMain` is the value returned by the scoped main function
/// or a `Err<UartDeviceStatus>` 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<F, Main, RMain>(
index: usize,
baud: u32,
user_callback: &mut F,
main: Main,
) -> Result<RMain, UartDeviceError>
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 <b>ONLY</b> send data.
///
/// Returns a Result with rather `Ok<Self>` if the UART was initialized successfully or a
Expand Down Expand Up @@ -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<UartDeviceStatus::UnsupportedConfig>
/// Returns a Result with rather `Ok<RMain>` where `RMain` is the value returned by the scoped main function
/// or a `Err<UartDeviceStatus>` 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<F, Main, RMain>(
index: usize,
baud: u32,
user_callback: &mut F,
main: Main,
) -> Result<RMain, UartDeviceError>
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<F>(
index: usize,
baud: u32,
user_callback: &'cb mut F,
) -> Result<Self, UartDeviceError>
where
F: FnMut(u8) + Send + 'cb,
{
let dev = macro_UART_DEV(index as c_uint);
uart_init(
dev,
baud,
Some(Self::new_data_callback::<F>),
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.
Expand Down Expand Up @@ -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<UartDeviceStatus::UnsupportedConfig>
///
/// # 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`
Expand Down

0 comments on commit dcfeff9

Please sign in to comment.