tartan_serial/lib.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
//! Support for Universal Asynchronous Receiver/Transmitter (UART) devices
#![no_std]
#![feature(doc_cfg)]
#![warn(missing_docs)]
#![warn(clippy::pedantic)]
#![allow(clippy::must_use_candidate)]
#![allow(clippy::upper_case_acronyms)]
pub mod model_pl011;
#[cfg(any(target_arch = "x86", target_arch = "x86_64", doc))]
#[doc(cfg(any(target_arch = "x86", target_arch = "x86_64")))]
pub mod model_16550;
/// High-level interface for UART drivers.
pub trait UART {
/// Stop transmission, clear buffers, and set the device to a sane state.
fn reset(&mut self);
/// Get the device's active line protocol mode.
fn line_mode(&mut self) -> LineMode;
/// Update the device's line protocol mode.
fn set_line_mode(&mut self, mode: LineMode);
/// Send the given data through the UART. Blocks until all data is set.
fn write(&mut self, data: &[u8]);
}
/// Newtype wrapper that allows a UART implementation to be used by [`core::fmt::write`].
pub struct UARTWriteAdapter<T: UART>(pub T);
impl<T: UART> core::fmt::Write for UARTWriteAdapter<T> {
fn write_str(&mut self, s: &str) -> core::fmt::Result {
// Transform "\n" into "\r\n" while writing
let bytes = s.as_bytes();
let mut first = true;
for chunk in bytes.split(|&c| c == b'\n') {
if first {
first = false;
} else {
self.0.write(b"\r\n");
}
self.0.write(chunk);
}
Ok(())
}
}
/// Speed and other line protocol settings.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct LineMode {
/// Bits per second (including non-data bits) of line protocol.
pub baud: u32,
/// Number of data bits per word in line protocol.
pub data_bits: u8,
/// Parity setting for line protocol.
pub parity: Parity,
/// Use 1.5 or 2 stop bits (depending on baud rate) if set. If clear, use 1 stop bit.
pub extended_stop: bool,
}
impl Default for LineMode {
fn default() -> LineMode {
LineMode {
baud: 9600,
data_bits: 8,
parity: Parity::default(),
extended_stop: false,
}
}
}
/// Parity setting for line protocol.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Parity {
/// No parity bit.
None,
/// Set parity so that there are an odd number of high bits in the word.
Odd,
/// Set parity so that there are an even number of high bits in the word.
Even,
/// Set parity bit high unconditionally (sticky).
High,
/// Set parity bit low unconditionally (sticky).
Low,
}
impl Parity {
fn from_flags(enabled: bool, even: bool, sticky: bool) -> Self {
if enabled {
match (sticky, even) {
(false, false) => Self::Odd,
(false, true) => Self::Even,
(true, false) => Self::High,
(true, true) => Self::Low,
}
} else {
Self::None
}
}
fn enabled_flag(self) -> bool {
self != Self::None
}
fn even_flag(self) -> bool {
self == Self::Even || self == Self::Low
}
fn sticky_flag(self) -> bool {
self == Self::High || self == Self::Low
}
}
impl Default for Parity {
fn default() -> Self {
Self::None
}
}
/// Dummy UART driver that drops outgoing data and never receives anything.
pub struct NullUART;
impl UART for NullUART {
fn reset(&mut self) {}
fn set_line_mode(&mut self, _: LineMode) {}
fn write(&mut self, _: &[u8]) {}
fn line_mode(&mut self) -> LineMode {
LineMode::default()
}
}
/// Common two-bit register encoding for setting the data word length.
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum WordLength {
Five,
Six,
Seven,
Eight,
}
impl WordLength {
pub fn bits(self) -> u8 {
match self {
Self::Five => 5,
Self::Six => 6,
Self::Seven => 7,
Self::Eight => 8,
}
}
pub fn from_bits(bits: u8) -> Option<WordLength> {
match bits {
5 => Some(Self::Five),
6 => Some(Self::Six),
7 => Some(Self::Seven),
8 => Some(Self::Eight),
_ => None,
}
}
}
impl From<u8> for WordLength {
fn from(value: u8) -> Self {
match value & 0b11 {
0 => Self::Five,
1 => Self::Six,
2 => Self::Seven,
3 => Self::Eight,
// For two bit values, the cases above are exhaustive
_ => unreachable!(),
}
}
}
impl From<WordLength> for u8 {
fn from(value: WordLength) -> Self {
value as u8
}
}
fn baud_from_divisor(max_baud: u32, divisor: u32) -> u32 {
if divisor == 0 {
0
} else {
max_baud / divisor
}
}
fn divisor_from_baud(max_baud: u32, baud: u32) -> u32 {
if baud == 0 || baud >= max_baud {
1
} else {
max_baud / baud
}
}