Skip to main content

ax_plat/
console.rs

1//! Console input and output.
2
3use core::fmt::{Arguments, Result, Write};
4
5use bitflags::bitflags;
6
7bitflags! {
8    /// Console input IRQ events returned by the platform.
9    #[derive(Clone, Copy, Debug, Eq, PartialEq)]
10    pub struct ConsoleIrqEvent: u32 {
11        /// Console input is ready to be drained.
12        const RX_READY = 1 << 0;
13        /// A receive-side error was reported.
14        const RX_ERROR = 1 << 1;
15        /// An overrun was reported.
16        const OVERRUN = 1 << 2;
17    }
18}
19
20/// Console input and output interface.
21#[def_plat_interface]
22pub trait ConsoleIf {
23    /// Writes given bytes to the console.
24    fn write_bytes(bytes: &[u8]);
25
26    /// Reads bytes from the console into the given mutable slice.
27    ///
28    /// Returns the number of bytes read.
29    fn read_bytes(bytes: &mut [u8]) -> usize;
30
31    /// Returns the IRQ number for the console input interrupt.
32    ///
33    /// Returns `None` if input interrupt is not supported.
34    #[cfg(feature = "irq")]
35    fn irq_num() -> Option<usize>;
36
37    /// Enables or disables device-side console input interrupts.
38    #[cfg(feature = "irq")]
39    fn set_input_irq_enabled(enabled: bool);
40
41    /// Handles a console input IRQ in interrupt context and returns the
42    /// corresponding device events.
43    #[cfg(feature = "irq")]
44    fn handle_irq() -> ConsoleIrqEvent;
45}
46
47struct EarlyConsole;
48
49impl Write for EarlyConsole {
50    fn write_str(&mut self, s: &str) -> Result {
51        write_text_bytes(s.as_bytes());
52        Ok(())
53    }
54}
55
56/// Writes text bytes to the console, expanding line feeds to CRLF.
57///
58/// This is intended for human-readable console output. Use [`write_bytes`] for
59/// raw byte transport.
60pub fn write_text_bytes(bytes: &[u8]) {
61    let mut start = 0;
62    for (i, &byte) in bytes.iter().enumerate() {
63        if byte == b'\n' {
64            if start < i {
65                write_bytes(&bytes[start..i]);
66            }
67            write_bytes(b"\r\n");
68            start = i + 1;
69        }
70    }
71    if start < bytes.len() {
72        write_bytes(&bytes[start..]);
73    }
74}
75
76/// Lock for console operations to prevent mixed output from concurrent execution
77pub static CONSOLE_LOCK: ax_kspin::SpinNoIrq<()> = ax_kspin::SpinNoIrq::new(());
78
79/// Simple console print operation.
80#[macro_export]
81macro_rules! console_print {
82    ($($arg:tt)*) => {
83        $crate::console::__simple_print(format_args!($($arg)*));
84    }
85}
86
87/// Simple console print operation, with a newline.
88#[macro_export]
89macro_rules! console_println {
90    () => { $crate::ax_print!("\n") };
91    ($($arg:tt)*) => {
92        $crate::console::__simple_print(format_args!("{}\n", format_args!($($arg)*)));
93    }
94}
95
96#[doc(hidden)]
97pub fn __simple_print(fmt: Arguments) {
98    let _guard = CONSOLE_LOCK.lock();
99    EarlyConsole.write_fmt(fmt).unwrap();
100    drop(_guard);
101}