Skip to main content

rdif_serial/
lib.rs

1//! Portable interrupt-driven serial runtime primitives.
2//!
3//! The reusable stack is intentionally split by synchronization ownership:
4//! raw UART drivers expose only register-level operations, `TxQueue` and
5//! `RxQueue` own independent lock-free software queues, `SerialPort` owns the
6//! task/worker control path, and `SerialIrqHandler` is the IRQ-only endpoint.
7//!
8//! OS glue must route hardware IRQs and control/service calls to the configured
9//! owner CPU and pass an `OwnerLease`. Task context drains `RxItem`s and
10//! enqueues TX bytes through the queues, while worker context uses `SerialPort`
11//! for bounded soft service. Neither TX nor RX queues poll the shared UART
12//! IRQ/status register to rediscover readiness. This keeps the fast path bounded
13//! and leaves wakeups, wait queues, poll sets, and line discipline processing to
14//! OS-specific layers above this crate.
15
16#![no_std]
17
18extern crate alloc;
19
20use core::fmt::Display;
21
22use bitflags::bitflags;
23pub use rdif_base::{DriverGeneric, KError};
24
25mod queue;
26mod raw;
27#[path = "core.rs"]
28mod serial_core;
29mod types;
30
31pub use self::{queue::*, raw::*, serial_core::*, types::*};
32
33#[derive(Debug, Clone, Copy, PartialEq, Eq)]
34pub enum ConfigError {
35    InvalidBaudrate,
36    UnsupportedDataBits,
37    UnsupportedStopBits,
38    UnsupportedParity,
39    RegisterError,
40    Timeout,
41}
42
43#[derive(thiserror::Error, Debug, Clone, Copy, PartialEq, Eq)]
44pub struct TransBytesError {
45    pub bytes_transferred: usize,
46    pub kind: TransferError,
47}
48
49impl Display for TransBytesError {
50    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
51        write!(
52            f,
53            "Transfer error after transferring {} bytes: {}",
54            self.bytes_transferred, self.kind
55        )
56    }
57}
58
59#[derive(thiserror::Error, Debug, Clone, Copy, PartialEq, Eq)]
60pub enum TransferError {
61    #[error("Data overrun by `{0:#x}`")]
62    Overrun(u8),
63    #[error("Parity error")]
64    Parity,
65    #[error("Framing error")]
66    Framing,
67    #[error("Break condition")]
68    Break,
69    #[error("Serial closed")]
70    Closed,
71}
72
73#[derive(Debug, Clone, Copy, PartialEq, Eq)]
74#[repr(u8)]
75pub enum DataBits {
76    Five  = 5,
77    Six   = 6,
78    Seven = 7,
79    Eight = 8,
80}
81
82#[derive(Debug, Clone, Copy, PartialEq, Eq)]
83#[repr(u8)]
84pub enum StopBits {
85    One = 1,
86    Two = 2,
87}
88
89#[derive(Debug, Clone, Copy, PartialEq, Eq)]
90pub enum Parity {
91    None,
92    Even,
93    Odd,
94    Mark,
95    Space,
96}
97
98bitflags! {
99    /// Polling-only serial events for direct raw users such as someboot.
100    ///
101    /// Runtime `SerialIrqHandler` does not use this high-level snapshot type;
102    /// it uses `IrqSnapshot`, `RxSample`, and TX/RX software FIFOs instead.
103    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
104    pub struct SerialEvent: u32 {
105        const RX_READY = 0x01;
106        const TX_READY = 0x02;
107        const RX_ERROR = 0x04;
108        const TX_ERROR = 0x08;
109        const OVERRUN = 0x10;
110        const MODEM_STATUS = 0x20;
111        const IRQ_ACK = 0x40;
112    }
113}
114
115impl SerialEvent {
116    pub fn rx_ready(&self) -> bool {
117        self.contains(Self::RX_READY)
118    }
119
120    pub fn tx_ready(&self) -> bool {
121        self.contains(Self::TX_READY)
122    }
123
124    pub fn rx_error(&self) -> bool {
125        self.intersects(Self::RX_ERROR | Self::OVERRUN)
126    }
127}
128
129#[derive(Debug, Clone, Copy, PartialEq, Eq)]
130pub enum SerialDirection {
131    Input,
132    Output,
133}
134
135#[derive(Debug, Clone, Default)]
136pub struct Config {
137    pub baudrate: Option<u32>,
138    pub data_bits: Option<DataBits>,
139    pub stop_bits: Option<StopBits>,
140    pub parity: Option<Parity>,
141}
142
143impl Config {
144    pub fn new() -> Self {
145        Self::default()
146    }
147
148    pub fn baudrate(mut self, baudrate: u32) -> Self {
149        self.baudrate = Some(baudrate);
150        self
151    }
152
153    pub fn data_bits(mut self, data_bits: DataBits) -> Self {
154        self.data_bits = Some(data_bits);
155        self
156    }
157
158    pub fn stop_bits(mut self, stop_bits: StopBits) -> Self {
159        self.stop_bits = Some(stop_bits);
160        self
161    }
162
163    pub fn parity(mut self, parity: Parity) -> Self {
164        self.parity = Some(parity);
165        self
166    }
167}
168
169#[cfg(test)]
170mod tests {
171    use super::*;
172
173    #[test]
174    fn serial_event_reports_readiness_and_errors() {
175        let event = SerialEvent::RX_READY | SerialEvent::OVERRUN;
176
177        assert!(event.rx_ready());
178        assert!(!event.tx_ready());
179        assert!(event.rx_error());
180    }
181}