Skip to content

Commit

Permalink
Add core::fmt UART based logger for log package
Browse files Browse the repository at this point in the history
We can not use `ufmt` for formatting because there is no `ufmt` support for the required (sub) arguments of functions
in the `Log` trait.
  • Loading branch information
lmbollen committed Aug 6, 2024
1 parent 467bfe1 commit 26e40ed
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 0 deletions.
7 changes: 7 additions & 0 deletions firmware-binaries/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions firmware-support/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions firmware-support/bittide-sys/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ default = []
[dependencies]
fdt = "0.1.0"
ufmt = "0.2.0"
log = "0.4.21"

[dev-dependencies]
proptest = "1.0"
Expand Down
10 changes: 10 additions & 0 deletions firmware-support/bittide-sys/src/uart.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
//
// SPDX-License-Identifier: Apache-2.0

pub mod log;
pub struct UartStatus {
pub receive_buffer_empty: bool,
pub transmit_buffer_full: bool,
Expand Down Expand Up @@ -107,3 +108,12 @@ impl ufmt::uWrite for Uart {

type Error = ();
}

impl core::fmt::Write for Uart {
fn write_str(&mut self, s: &str) -> core::fmt::Result {
for b in s.bytes() {
self.send(b);
}
Ok(())
}
}
67 changes: 67 additions & 0 deletions firmware-support/bittide-sys/src/uart/log.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// SPDX-FileCopyrightText: 2024 Google LLC
//
// SPDX-License-Identifier: Apache-2.0
use crate::uart;

// The logger utilizes core::fmt to format the log messages because ufmt formatting is not
// compatible with (dependencies of) the log crate.
use core::fmt::Write;

/// A global logger instance to be used with the `log` crate.
///
/// Use `set_logger` to set the `Uart` instance to be used for logging.
/// # Safety
/// Using this logger is only safe if there is only one thread of execution.
/// Even though `UartLogger` is `Send` and `Sync`, The underlying `Uart` is not `Send` or `Sync`.
pub static mut LOGGER: UartLogger = UartLogger { uart: None };

/// Wrapper for `Uart` to be used as a logger with the `log` crate
/// Instead of making a new logger, use the `set_logger` method of the `LOGGER` instance.
/// # Safety
/// Using this logger is only safe if there is only one thread of execution.
/// Even though `UartLogger` is `Send` and `Sync`, The underlying `Uart` is not `Send` or `Sync`.
pub struct UartLogger {
uart: Option<uart::Uart>,
}

impl UartLogger {
/// Set the logger to use the given UART.
/// # Safety
/// Using this function and logger is only safe if there is only one thread of execution.
/// This function is used to assign the `Uart` instance to a global (`static mut`), but `Uart` is not `Send` or `Sync`.
pub unsafe fn set_logger(&mut self, uart: uart::Uart) {
self.uart = Some(uart);
}
}

impl log::Log for UartLogger {
fn enabled(&self, metadata: &log::Metadata) -> bool {
log::Level::Info <= metadata.level()
}

fn log(&self, record: &log::Record) {
if self.enabled(record.metadata()) {
unsafe {
match &mut LOGGER.uart {
Some(l) => {
writeln!(
l,
"{} | {}:{} - {}",
record.level(),
record.file().unwrap(),
record.line().unwrap(),
record.args()
)
.ok();
}
None => panic!("Logger not set"),
}
}
}
}

fn flush(&self) {}
}

unsafe impl core::marker::Send for UartLogger {}
unsafe impl core::marker::Sync for UartLogger {}
7 changes: 7 additions & 0 deletions host-tools/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 26e40ed

Please sign in to comment.