Skip to main content

ove/
uart.rs

1// Copyright (C) 2026 Kamil Lulko <kamil.lulko@gmail.com>
2//
3// SPDX-License-Identifier: GPL-3.0-or-later
4//
5// This file is part of oveRTOS.
6
7//! UART serial bus driver.
8//!
9//! [`Uart`] wraps an opaque `ove_uart_t` handle and exposes a method-shaped
10//! API.  `embedded_io::Read` / `embedded_io::Write` impls are provided when
11//! the `embedded-io` Cargo feature is enabled.
12
13use crate::bindings;
14use crate::error::{Error, Result};
15
16// SAFETY (module-wide contract for the `unsafe { bindings::ove_*(...) }` FFI
17// calls below): any handle passed to the C API is non-null and refers to a
18// live RTOS object — wrapper constructors establish validity via
19// `Error::from_code`, and `Drop` (or an explicit `deinit`) is the only place
20// a handle is released. Pointer and slice arguments reference caller-owned
21// memory valid for the duration of the call; the C side copies whatever it
22// retains and does not alias them past return (verified against the
23// signatures in `include/ove/*.h`). Blocks that deviate — `transmute`, raw
24// pointer casts from user data, slice reconstruction via `from_raw_parts`,
25// or storing a callback across the FFI boundary — carry their own
26// `// SAFETY:` comment.
27
28/// UART parity mode.
29#[repr(u32)]
30#[derive(Debug, Copy, Clone, PartialEq, Eq)]
31pub enum Parity {
32    None = 0,
33    Odd = 1,
34    Even = 2,
35}
36
37/// UART stop bits.
38#[repr(u32)]
39#[derive(Debug, Copy, Clone, PartialEq, Eq)]
40pub enum StopBits {
41    One = 0,
42    OnePointFive = 1,
43    Two = 2,
44}
45
46/// UART flow control.
47#[repr(u32)]
48#[derive(Debug, Copy, Clone, PartialEq, Eq)]
49pub enum FlowControl {
50    None = 0,
51    RtsCts = 1,
52}
53
54/// UART driver.
55///
56/// Wraps an opaque `ove_uart_t` handle provided by the board configuration.
57/// Construct via [`Uart::from_handle`].
58#[derive(Debug, Copy, Clone)]
59pub struct Uart {
60    handle: bindings::ove_uart_t,
61}
62
63impl Uart {
64    /// Wrap an existing `ove_uart_t` handle.
65    ///
66    /// # Safety
67    /// `handle` must be a valid UART handle returned by the substrate.
68    /// The caller is responsible for ensuring no other `Uart` wrapper
69    /// exists for the same handle concurrently.
70    #[inline]
71    pub const unsafe fn from_handle(handle: bindings::ove_uart_t) -> Self {
72        Self { handle }
73    }
74
75    /// Return the underlying handle.
76    #[inline]
77    pub fn raw(&self) -> bindings::ove_uart_t {
78        self.handle
79    }
80
81    /// Write data to the UART. Returns the number of bytes written.
82    pub fn write(&self, data: &[u8], timeout: core::time::Duration) -> Result<usize> {
83        let mut written: usize = 0;
84        let rc = unsafe {
85            bindings::ove_uart_write(
86                self.handle,
87                data.as_ptr().cast(),
88                data.len(),
89                crate::time::dur_to_ns(timeout),
90                &mut written,
91            )
92        };
93        Error::from_code(rc)?;
94        Ok(written)
95    }
96
97    /// Read data from the UART RX buffer. Returns the number of bytes read.
98    pub fn read(&self, buf: &mut [u8], timeout: core::time::Duration) -> Result<usize> {
99        let mut read_count: usize = 0;
100        let rc = unsafe {
101            bindings::ove_uart_read(
102                self.handle,
103                buf.as_mut_ptr().cast(),
104                buf.len(),
105                crate::time::dur_to_ns(timeout),
106                &mut read_count,
107            )
108        };
109        Error::from_code(rc)?;
110        Ok(read_count)
111    }
112
113    /// Query the number of bytes available in the RX buffer.
114    pub fn bytes_available(&self) -> usize {
115        unsafe { bindings::ove_uart_bytes_available(self.handle) }
116    }
117
118    /// Flush the TX hardware buffer.
119    pub fn flush(&self) -> Result<()> {
120        let rc = unsafe { bindings::ove_uart_flush(self.handle) };
121        Error::from_code(rc)
122    }
123
124    /// Register a notify callback fired after every received chunk.
125    /// Wraps the C-level `ove_uart_set_rx_notify`, which delegates to
126    /// `ove_stream_set_notify` on the UART's internal RX stream.
127    ///
128    /// # Safety
129    /// Same as [`crate::Stream::set_notify`]: `user_data` must outlive
130    /// the registration, and `cb` must be ISR-safe (UART RX
131    /// typically pushes from ISR context via
132    /// `ove_uart_rx_isr_push`).
133    #[cfg(has_async)]
134    #[inline]
135    pub unsafe fn set_rx_notify(
136        &self,
137        cb: Option<unsafe extern "C" fn(*mut core::ffi::c_void)>,
138        user_data: *mut core::ffi::c_void,
139    ) -> Result<()> {
140        let rc = unsafe { bindings::ove_uart_set_rx_notify(self.handle, cb, user_data) };
141        Error::from_code(rc)
142    }
143}