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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
// Copyright 2021 Jacob Alexander
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

#![no_std]

pub use log;

#[cfg(feature = "semihosting")]
pub use cortex_m_semihosting;

#[cfg(feature = "rtt")]
pub use rtt_target;

/// Logger Structure
///
/// Example RTT Usage
/// ```
/// use kiibohd_log::{log, Logger};
///
/// static LOGGER: Logger = Logger::new(log::LevelFilter::Info);
///
/// fn main() {
///     // Setup RTT logging
///     let mut channels = rtt_target::rtt_init_default!();
///
///     // cortex-m or riscv
///     //rtt_target::set_print_channel(channels.up.0);
///     // otherwise use set_print_channel_cs
///     log::set_logger(&LOGGER).unwrap();
///
///     // Example usage
///     log::trace!("Trace message");
///     log::debug!("Debug message");
///     log::info!("Info message");
///     log::warn!("Warn message");
///     log::error!("Error message");
///
///     // Read downchannel
///     let mut buf = [0u8; 16];
///     channels.down.0.read(&mut buf[..]);
///     log::trace!("{:?}", buf);
/// }
/// ```
///
/// Example Semihosting Usage
/// ```
/// use kiibohd_log::{log, Logger};
///
/// static LOGGER: Logger = Logger::new(log::LevelFilter::Info);
///
/// fn main() {
///     log::set_logger(&LOGGER).unwrap();
///
///     // Example usage
///     log::trace!("Trace message");
///     log::debug!("Debug message");
///     log::info!("Info message");
///     log::warn!("Warn message");
///     log::error!("Error message");
/// }
/// ```
pub struct Logger {
    level_filter: log::LevelFilter,
}

impl Logger {
    pub const fn new(level_filter: log::LevelFilter) -> Self {
        Self { level_filter }
    }
}

impl log::Log for Logger {
    fn enabled(&self, metadata: &log::Metadata) -> bool {
        self.level_filter.ge(&metadata.level())
    }

    // Handle entry prefixes
    fn log(&self, record: &log::Record) {
        if self.enabled(record.metadata()) {
            #[cfg(any(feature = "rtt", feature = "semihosting"))]
            let color = match record.level() {
                log::Level::Error => "1;5;31",
                log::Level::Warn => "1;33",
                log::Level::Info => "1;32",
                log::Level::Debug => "1;35",
                log::Level::Trace => "1;90",
            };
            #[cfg(any(feature = "rtt", feature = "semihosting"))]
            let dwt = unsafe { &*cortex_m::peripheral::DWT::ptr() };
            #[cfg(feature = "rtt")]
            rtt_target::rprintln!(
                "{:10}:\x1b[{}m{:5}\x1b[0m:{}",
                dwt.get_cycle_count(),
                color,
                record.level(),
                record.args()
            );
            #[cfg(feature = "semihosting")]
            cortex_m_semihosting::hprintln!(
                "{:10}:\x1b[{}m{:5}\x1b[0m:{}",
                dwt.get_cycle_count(),
                color,
                record.level(),
                record.args()
            )
            .ok();
            /* TODO (HaaTa) Add itm support
            #[cfg(feature = "itm")]
            {
                let itm = unsafe { &mut *cortex_m::peripheral::ITM::ptr() };
                let stim = &mut itm.stim[0];
                cortex_m::iprintln!(stim,
                    "{}:\x1b[{}m{}\x1b[0m - {}",
                    dwt.cyccnt.read(),
                    color,
                    record.level(),
                    record.args()
                );
            }
            */
        }
    }

    fn flush(&self) {}
}