Skip to content

Instantly share code, notes, and snippets.

@ryankurte
Created March 25, 2021 22:42
Show Gist options
  • Select an option

  • Save ryankurte/445c6b197a4214f6e5b3be064718c537 to your computer and use it in GitHub Desktop.

Select an option

Save ryankurte/445c6b197a4214f6e5b3be064718c537 to your computer and use it in GitHub Desktop.

Revisions

  1. ryankurte created this gist Mar 25, 2021.
    73 changes: 73 additions & 0 deletions static-log.rs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,73 @@


    use core::fmt::Write;
    use alloc::boxed::Box;

    use embedded_hal::serial::{Write as SerialWrite};
    use stm32f4xx_hal::serial;
    use log::{Log, Level, Metadata, Record};

    pub struct SerialLogger<E> {
    pub level: Level,
    pub writer: Option<Box<dyn SerialWrite<u8, Error=E>>>,
    }

    unsafe impl <E> Sync for SerialLogger<E> {}
    unsafe impl <E> Send for SerialLogger<E> {}


    static mut SERIAL_LOGGER: SerialLogger<serial::Error> = SerialLogger{level: Level::Info, writer: None};


    impl SerialLogger<serial::Error> {
    pub fn init(level: Level, w: Box<dyn SerialWrite<u8, Error=serial::Error>>) {
    unsafe {
    // Set global SERIAL_LOGGER log context
    SERIAL_LOGGER.level = level;
    SERIAL_LOGGER.writer = Some(w);

    // Attach to logger
    let _ = log::set_logger(&SERIAL_LOGGER);
    log::set_max_level(SERIAL_LOGGER.level.to_level_filter());
    }
    }
    }

    impl <E> Log for SerialLogger<E> {
    fn enabled(&self, metadata: &Metadata) -> bool {
    metadata.level() <= self.level
    }

    fn log(&self, record: &Record) {
    if self.enabled(record.metadata()) {
    let _ = unsafe {
    match record.module_path() {
    Some(p) => write!(SERIAL_LOGGER, "[{}] {} - {}\r\n", record.level(), p, record.args()),
    None => write!(SERIAL_LOGGER, "[{}] - {}\r\n", record.level(), record.args())
    }
    };
    }
    }

    fn flush(&self) { }
    }

    impl <E>core::fmt::Write for SerialLogger<E> {
    fn write_str(&mut self, s: &str) -> core::fmt::Result {
    // Fetch writer (if bound)
    let w = match &mut self.writer {
    Some(w) => w,
    None => return Err(core::fmt::Error),
    };

    // Output string as bytes
    for b in s.as_bytes() {
    block!(w.try_write(*b)).map_err(|_| core::fmt::Error)?;
    }

    // Flush output buffers
    block!(w.try_flush()).map_err(|_| core::fmt::Error)?;

    Ok(())
    }
    }