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}