omnitiles/hw/
usart.rs

1// SPDX-License-Identifier: MIT
2// © 2025–2026 Christopher Liu
3
4//! USART abstraction layer.
5//!
6//! Provides several printing helpers for hex, decimal, and ASCII strings to print to an attached
7//! debug terminal.
8//!
9//! Note: When using `writeln!`, be sure to include `\r` (CR) in the format string to ensure correct
10//! line endings on the terminal.
11//!
12//! To access the terminal on the host machine, connect to the debug USB port and use
13//! ```
14//! $ screen /dev/tty.usbmodem* <baud_rate>
15//! ```
16//!
17//! To close the debug terminal, press `Ctrl+A` then `Ctrl+\` then `y`.
18
19use core::fmt;
20use nb::block;
21
22use stm32f7xx_hal::{
23    prelude::*,
24    serial::{Instance, Pins, Serial, Tx},
25};
26
27pub struct Usart<U: Instance> {
28    tx: Tx<U>,
29}
30
31impl<U: Instance> Usart<U> {
32    pub fn new<PINS: Pins<U>>(serial: Serial<U, PINS>) -> Self {
33        let (tx, _rx) = serial.split();
34        Self { tx }
35    }
36
37    #[inline]
38    pub fn write_byte(&mut self, b: u8) {
39        let _ = block!(self.tx.write(b));
40    }
41
42    pub fn write_str(&mut self, s: &str) {
43        for &b in s.as_bytes() {
44            self.write_byte(b);
45        }
46    }
47
48    /// Write string and CRLF terminator.
49    #[inline]
50    pub fn println(&mut self, s: &str) {
51        self.write_str(s);
52        self.write_str("\r\n");
53    }
54
55    /// Block until the hardware TX FIFO/drain is flushed.
56    #[inline]
57    pub fn flush(&mut self) {
58        let _ = block!(self.tx.flush());
59    }
60
61    pub fn print_hex_u8(&mut self, n: u8) {
62        const HEX: &[u8; 16] = b"0123456789ABCDEF";
63        self.write_str("0x");
64        self.write_byte(HEX[((n >> 4) & 0xF) as usize]);
65        self.write_byte(HEX[(n & 0xF) as usize]);
66    }
67
68    pub fn print_hex_u16(&mut self, n: u16) {
69        const HEX: &[u8; 16] = b"0123456789ABCDEF";
70        self.write_str("0x");
71        for shift in (0..=12).rev().step_by(4) {
72            self.write_byte(HEX[((n >> shift) & 0xF) as usize]);
73        }
74    }
75
76    pub fn print_hex_u32(&mut self, n: u32) {
77        const HEX: &[u8; 16] = b"0123456789ABCDEF";
78        self.write_str("0x");
79        for (i, shift) in (0..=28).rev().step_by(4).enumerate() {
80            if i == 4 {
81                self.write_byte(b'_');
82            }
83            self.write_byte(HEX[((n >> shift) & 0xF) as usize]);
84        }
85    }
86
87    pub fn print_u32(&mut self, mut n: u32) {
88        let mut buf = [0u8; 10];
89        let mut i = buf.len();
90        if n == 0 {
91            self.write_byte(b'0');
92            return;
93        }
94        while n > 0 {
95            i -= 1;
96            buf[i] = b'0' + (n % 10) as u8;
97            n /= 10;
98        }
99        for &b in &buf[i..] {
100            self.write_byte(b);
101        }
102    }
103}
104
105// Implement `core::fmt::Write` so we can use `write!` / `writeln!` on `Usart`.
106impl<U: Instance> fmt::Write for Usart<U> {
107    fn write_str(&mut self, s: &str) -> fmt::Result {
108        Usart::write_str(self, s);
109        Ok(())
110    }
111}