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
//! Integration with [log](https://docs.rs/crate/log) //! //! As embedded development implies `#[no_st]` we cannot box //! our logger so instead simplest approach would be to declare our logger static //! //! ```rust //! extern crate cortex_m_log; //! extern crate log; //! //! use cortex_m_log::log::{Logger, init}; //! use cortex_m_log::printer::Dummy; //! //! static LOGGER: Logger<Dummy> = Logger { //! inner: Dummy, //! level: log::LevelFilter::Off //! }; //! //! fn main() { //! init(&LOGGER).expect("To set logger"); //! } //! ``` //! //! Of course since there is no `const-fn` and some printers require //! Initialization function we need some better way. //! //! One way to do it would be to trick compiler by changing lifetime of stack //! allocated logger to static, obviously unsafe. //! //! ```rust,no_run //! extern crate cortex_m_log; //! extern crate log; //! extern crate cortex_m_semihosting; //! //! use std::mem; //! //! use cortex_m_log::log::{Logger, trick_init}; //! use cortex_m_log::printer::semihosting; //! use cortex_m_log::modes::InterruptOk; //! //! fn main() { //! let logger = Logger { //! inner: semihosting::InterruptOk::<_>::stdout().expect("Get Semihosting stdout"), //! level: log::LevelFilter::Info //! }; //! //Haha trust me, it is safe ;) //! //As long as logger is not dropped.... //! unsafe { //! let _ = trick_init(&logger); //! } //! } //! ``` //! //! Obviously it is UB to drop logger after that and use any of log's macros extern crate log; extern crate cortex_m_semihosting as sh; use core::mem; use core::marker; use ::printer::Printer; ///Simple Logger implementation pub struct Logger<P: Printer + marker::Send + marker::Sync> { ///Printer implementation pub inner: P, ///Log level pub level: log::LevelFilter, } impl<P: Printer + marker::Send + marker::Sync> log::Log for Logger<P> { fn enabled(&self, metadata: &log::Metadata) -> bool { metadata.level() <= self.level } fn log(&self, record: &log::Record) { if self.enabled(record.metadata()) { //Pretend we're the Cell let inner = &self.inner as *const P as *mut P; let inner = unsafe { &mut *inner }; inner.print(format_args!("{:<5} {}:{} - {}\n", record.level(), record.file().unwrap_or("UNKNOWN"), record.line().unwrap_or(0), record.args())) } } fn flush(&self) { } } ///Initialize logging facilities. /// ///Currently lacks a nice way to set global logger so user ///must himself guarantee static lifetime pub fn init<P: Printer + marker::Send + marker::Sync>(logger: &'static Logger<P>) -> Result<(), log::SetLoggerError> { log::set_max_level(logger.level.clone()); log::set_logger(logger) } #[inline] ///Performs init by tricking compiler into beliving that `&mut` is static. /// ///This is unsafe and it is up to you to ensure that reference ///will live longer that any attempts to access it pub unsafe fn trick_init<P: Printer + marker::Send + marker::Sync + 'static>(logger: &Logger<P>) -> Result<(), log::SetLoggerError> { let logger: &'static Logger<P> = mem::transmute(logger); init(logger) }