Skip to main content

rdif_serial/
types.rs

1use bitflags::bitflags;
2
3bitflags! {
4    /// Stable event classes exchanged between a UART and its runtime.
5    #[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
6    pub struct SerialEventSet: u32 {
7        const RX_DATA      = 1 << 0;
8        const RX_TIMEOUT   = 1 << 1;
9        const RX_STATUS    = 1 << 2;
10        const TX_SPACE     = 1 << 3;
11        const MODEM_STATUS = 1 << 4;
12        const BUSY_DETECT  = 1 << 5;
13        const FAULT        = 1 << 6;
14
15        const RX = Self::RX_DATA.bits() | Self::RX_TIMEOUT.bits() | Self::RX_STATUS.bits();
16    }
17}
18
19impl SerialEventSet {
20    /// Returns whether any receive-side source is present.
21    pub const fn has_rx(self) -> bool {
22        self.intersects(Self::RX)
23    }
24
25    /// Returns whether the transmitter-space source is present.
26    pub const fn has_tx(self) -> bool {
27        self.contains(Self::TX_SPACE)
28    }
29}
30
31bitflags! {
32    /// RX error state reported by the IRQ endpoint while buffering samples.
33    #[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
34    pub struct RxErrorFlags: u32 {
35        const BREAK   = 1 << 0;
36        const PARITY  = 1 << 1;
37        const FRAMING = 1 << 2;
38        const OVERRUN = 1 << 3;
39    }
40}
41
42/// Stable event produced by an IRQ-owned UART endpoint.
43#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
44pub struct SerialIrqEvent {
45    pub events: SerialEventSet,
46    pub rx_errors: RxErrorFlags,
47    /// Sources masked by the IRQ endpoint and awaiting task-side rearm.
48    pub rearm: SerialEventSet,
49}
50
51#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
52pub enum RxFlag {
53    #[default]
54    Normal,
55    Break,
56    Parity,
57    Framing,
58}
59
60/// One hardware receive sample. Runtime channel policy is intentionally absent.
61#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
62pub struct RxSample {
63    pub byte: Option<u8>,
64    pub flag: RxFlag,
65    pub overrun: bool,
66}
67
68/// Maximum number of normalized RX samples returned by one hard-IRQ pass.
69///
70/// A full batch leaves the device source pending or reasserted so a later IRQ
71/// can continue draining. Keeping the capacity in the portable value type makes
72/// the hard-IRQ work and stack footprint independent of runtime policy.
73pub const IRQ_RX_BATCH_CAPACITY: usize = 64;
74
75const EMPTY_RX_SAMPLE: RxSample = RxSample {
76    byte: None,
77    flag: RxFlag::Normal,
78    overrun: false,
79};
80
81/// Fixed-capacity RX data extracted by one UART hard-IRQ pass.
82///
83/// The driver owns construction and the runtime owns publication into its
84/// preallocated queue. No callback into OS code runs while the driver holds or
85/// reads device registers.
86#[derive(Clone, Copy, Debug, PartialEq, Eq)]
87pub struct IrqRxBatch {
88    samples: [RxSample; IRQ_RX_BATCH_CAPACITY],
89    len: usize,
90}
91
92impl IrqRxBatch {
93    /// Creates an empty fixed-capacity batch.
94    pub const fn new() -> Self {
95        Self {
96            samples: [EMPTY_RX_SAMPLE; IRQ_RX_BATCH_CAPACITY],
97            len: 0,
98        }
99    }
100
101    /// Appends one sample or returns it unchanged when the fixed batch is full.
102    pub fn try_push(&mut self, sample: RxSample) -> Result<(), RxSample> {
103        let Some(slot) = self.samples.get_mut(self.len) else {
104            return Err(sample);
105        };
106        *slot = sample;
107        self.len += 1;
108        Ok(())
109    }
110
111    /// Returns the number of buffered samples.
112    pub const fn len(&self) -> usize {
113        self.len
114    }
115
116    /// Returns whether the batch contains no samples.
117    pub const fn is_empty(&self) -> bool {
118        self.len == 0
119    }
120
121    /// Borrows the initialized prefix of the batch.
122    pub fn as_slice(&self) -> &[RxSample] {
123        &self.samples[..self.len]
124    }
125}
126
127impl Default for IrqRxBatch {
128    fn default() -> Self {
129        Self::new()
130    }
131}
132
133/// Complete value returned by one UART hard-IRQ pass.
134#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
135pub struct SerialIrqReport {
136    pub event: SerialIrqEvent,
137    pub rx: IrqRxBatch,
138}
139
140impl SerialIrqReport {
141    /// Combines one normalized IRQ event with its bounded receive batch.
142    pub const fn new(event: SerialIrqEvent, rx: IrqRxBatch) -> Self {
143        Self { event, rx }
144    }
145}
146
147#[cfg(test)]
148mod tests {
149    use super::*;
150
151    #[test]
152    fn irq_rx_batch_rejects_samples_beyond_its_fixed_capacity() {
153        let mut batch = IrqRxBatch::new();
154        let sample = RxSample {
155            byte: Some(b'x'),
156            ..RxSample::default()
157        };
158
159        for _ in 0..IRQ_RX_BATCH_CAPACITY {
160            assert_eq!(batch.try_push(sample), Ok(()));
161        }
162
163        assert_eq!(batch.try_push(sample), Err(sample));
164        assert_eq!(batch.len(), IRQ_RX_BATCH_CAPACITY);
165        assert_eq!(batch.as_slice(), &[sample; IRQ_RX_BATCH_CAPACITY]);
166    }
167}