diff --git a/src/logger.rs b/src/logger.rs new file mode 100644 index 00000000..7519f973 --- /dev/null +++ b/src/logger.rs @@ -0,0 +1,74 @@ +//! Booster NGFW logging utilities +//! +//! # Copyright +//! Copyright (C) 2020 QUARTIQ GmbH - All Rights Reserved +//! Unauthorized usage, editing, or copying is strictly prohibited. +//! Proprietary and confidential. +use heapless::{consts, String}; + +use super::SerialTerminal; +use core::fmt::Write; + +/// A logging buffer for storing serialized logs pending transmission. +/// +/// # Notes +/// The LoBufferedLog contains a character buffer of the log data waiting to be written. It is +/// intended to be consumed asynchronously. In the case of booster, this log data is consumed in the +/// USB task. +pub struct BufferedLog { + logs: heapless::mpmc::Q16>, +} + +impl BufferedLog { + /// Construct a new buffered log object. + pub const fn new() -> Self { + Self { + logs: heapless::mpmc::Q16::new(), + } + } + + /// Process all of the available log data. + /// + /// # Args + /// * `terminal` - The serial terminal to write log data into. + pub fn process(&self, terminal: &mut SerialTerminal) { + while let Some(log) = self.logs.dequeue() { + terminal.write(&log.as_bytes()); + } + } +} + +impl log::Log for BufferedLog { + fn enabled(&self, _metadata: &log::Metadata) -> bool { + true + } + + fn log(&self, record: &log::Record) { + let source_file = record.file().unwrap_or("Unknown"); + let source_line = record.line().unwrap_or(u32::MAX); + + // Print the record into the buffer. + let mut string: String = String::new(); + match write!( + &mut string, + "[{}] {}:{} - {}\n", + record.level(), + source_file, + source_line, + record.args() + ) { + // If we cannot encode the log entry, note this in the output log to indicate the log + // was dropped. + Err(_) => { + error!("Log entry overflow"); + return; + } + _ => {} + }; + + self.logs.enqueue(string).ok(); + } + + // The log is not capable of being flushed as it does not own the data consumer. + fn flush(&self) {} +} diff --git a/src/main.rs b/src/main.rs index d94af5aa..da2edd6a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -25,6 +25,7 @@ mod chassis_fans; mod delay; mod error; mod linear_transformation; +mod logger; mod mqtt_control; mod mutex; mod platform; @@ -37,6 +38,7 @@ use booster_channels::{BoosterChannels, Channel}; use chassis_fans::ChassisFans; use delay::AsmDelay; use error::Error; +use logger::BufferedLog; use rf_channel::{AdcPin, AnalogPins as AdcPins, ChannelPins as RfChannelPins, ChannelState}; use serial_terminal::SerialTerminal; use settings::BoosterSettings; @@ -138,6 +140,8 @@ macro_rules! channel_pins { // USB end-point memory. static mut USB_EP_MEMORY: [u32; 1024] = [0; 1024]; +static LOGGER: BufferedLog = BufferedLog::new(); + /// Container method for all devices on the main I2C bus. pub struct MainBus { pub channels: BoosterChannels, @@ -162,6 +166,11 @@ const APP: () = { static mut USB_BUS: Option> = None; static mut USB_SERIAL: Option> = None; + // Install the logger + log::set_logger(&LOGGER) + .map(|()| log::set_max_level(log::LevelFilter::Info)) + .unwrap(); + c.core.DWT.enable_cycle_counter(); c.core.DCB.enable_trace(); @@ -678,6 +687,10 @@ const APP: () = { .watchdog .lock(|watchdog| watchdog.check_in(WatchdogClient::UsbTask)); + // Process any log output. + LOGGER.process(&mut c.resources.usb_terminal); + + // Handle the USB serial terminal. c.resources.usb_terminal.process(); // TODO: Replace hard-coded CPU cycles here.