From 481066a3430fd89333469a49fd21d88022393d2c Mon Sep 17 00:00:00 2001 From: Joakim Hulthe Date: Sun, 21 May 2023 10:18:26 +0200 Subject: [PATCH] Add RTT logging --- Cargo.lock | 21 ++++++++++++++++ Cargo.toml | 5 ++++ src/allocator.rs | 3 ++- src/bin/left.rs | 16 ++++++++++-- src/bin/right.rs | 16 ++++++++++-- src/defmt.rs | 0 src/lib.rs | 2 ++ src/logger.rs | 60 ++++++++++++++++++++++++++++++++++++++++++++ src/panic_handler.rs | 33 ++++++++++++------------ src/rtt.rs | 42 +++++++++++++++++++++++++++++++ src/usb.rs | 12 ++++----- 11 files changed, 182 insertions(+), 28 deletions(-) create mode 100644 src/defmt.rs create mode 100644 src/logger.rs create mode 100644 src/rtt.rs diff --git a/Cargo.lock b/Cargo.lock index 528e3d6..8573492 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1126,6 +1126,16 @@ dependencies = [ "crc-any", ] +[[package]] +name = "rtt-target" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3afa12c77ba1b9bf560e4039a9b9a08bb9cde0e9e6923955eeb917dd8d5cf303" +dependencies = [ + "critical-section", + "ufmt-write", +] + [[package]] name = "rustc_version" version = "0.2.3" @@ -1320,8 +1330,10 @@ dependencies = [ name = "tangentbord1" version = "0.1.0" dependencies = [ + "atomic-polyfill 1.0.2", "cortex-m", "cortex-m-rt", + "critical-section", "embassy-executor", "embassy-futures", "embassy-rp", @@ -1335,11 +1347,14 @@ dependencies = [ "embedded-io", "fixed", "futures", + "heapless", "log", + "once_cell", "pio", "pio-proc", "postcard", "ron", + "rtt-target", "smart-leds", "static_cell", "tgnt", @@ -1410,6 +1425,12 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +[[package]] +name = "ufmt-write" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e87a2ed6b42ec5e28cc3b94c09982969e9227600b2e3dcbc1db927a84c06bd69" + [[package]] name = "unicode-ident" version = "1.0.8" diff --git a/Cargo.toml b/Cargo.toml index f892e70..a3e484d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,6 +31,11 @@ smart-leds = "0.3.0" embedded-alloc = "0.5.0" postcard = { version = "1.0.4", features = ["alloc"] } fixed = "1.23.1" +rtt-target = "0.4.0" +heapless = "0.7.16" +once_cell = { version = "1.17.1", default-features = false } +atomic-polyfill = "1.0.2" +critical-section = "1.1.1" #[patch."https://git.nubo.sh/hulthe/tgnt.git"] #tgnt = { path = "../tgnt" } diff --git a/src/allocator.rs b/src/allocator.rs index b3c3c42..981123b 100644 --- a/src/allocator.rs +++ b/src/allocator.rs @@ -4,11 +4,12 @@ use core::mem::MaybeUninit; use embedded_alloc::Heap; +pub const HEAP_SIZE: usize = 4096; + #[global_allocator] static HEAP: Heap = Heap::empty(); pub fn init() { - const HEAP_SIZE: usize = 4096; static mut HEAP_MEM: [MaybeUninit; HEAP_SIZE] = [MaybeUninit::uninit(); HEAP_SIZE]; unsafe { HEAP.init(HEAP_MEM.as_ptr() as usize, HEAP_SIZE) } } diff --git a/src/bin/left.rs b/src/bin/left.rs index 0948aad..bbbe2ad 100644 --- a/src/bin/left.rs +++ b/src/bin/left.rs @@ -14,21 +14,33 @@ use embassy_time::{Duration, Timer}; use log::error; use tangentbord1::board::Board; use tangentbord1::keyboard::{Half, KeyboardConfig}; +use tangentbord1::logger::Logger; use tangentbord1::util::{stall, wheel}; use tangentbord1::ws2812::{Rgb, Ws2812}; -use tangentbord1::{allocator, uart, usb}; +use tangentbord1::{allocator, rtt, uart, usb}; use tgnt::layer::Layer; #[embassy_executor::main] async fn main(_spawner: Spawner) { let half = Half::Left; + let rtt_write = rtt::init_rtt_logger(); + let logger = Logger { + outputs: [rtt_write], + }; + logger.init(); + + log::error!("log_level: error"); + log::warn!("log_level: warn"); + log::info!("log_level: info"); + log::debug!("log_level: debug"); + log::trace!("log_level: trace"); + allocator::init(); let p = embassy_rp::init(Default::default()); let board = Board::from(p); - let _led = Output::new(board.d13, Level::High); let _neopixel_power = Output::new(board.neopixel_power, Level::High); let mut neopixel = Ws2812::new(board.PIO0, board.DMA_CH0, board.neopixel); diff --git a/src/bin/right.rs b/src/bin/right.rs index 54f1629..2a46015 100644 --- a/src/bin/right.rs +++ b/src/bin/right.rs @@ -14,21 +14,33 @@ use embassy_time::{Duration, Timer}; use log::error; use tangentbord1::board::Board; use tangentbord1::keyboard::{Half, KeyboardConfig}; +use tangentbord1::logger::Logger; use tangentbord1::util::{stall, wheel}; use tangentbord1::ws2812::{Rgb, Ws2812}; -use tangentbord1::{allocator, uart, usb}; +use tangentbord1::{allocator, rtt, uart, usb}; use tgnt::layer::Layer; #[embassy_executor::main] async fn main(_spawner: Spawner) { let half = Half::Right; + let rtt_write = rtt::init_rtt_logger(); + let logger = Logger { + outputs: [rtt_write], + }; + logger.init(); + + log::error!("log_level: error"); + log::warn!("log_level: warn"); + log::info!("log_level: info"); + log::debug!("log_level: debug"); + log::trace!("log_level: trace"); + allocator::init(); let p = embassy_rp::init(Default::default()); let board = Board::from(p); - let _led = Output::new(board.d13, Level::High); let _neopixel_power = Output::new(board.neopixel_power, Level::High); let mut neopixel = Ws2812::new(board.PIO0, board.DMA_CH0, board.neopixel); diff --git a/src/defmt.rs b/src/defmt.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/lib.rs b/src/lib.rs index 372b00c..dfa6fd5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,8 +12,10 @@ pub mod allocator; pub mod board; pub mod keyboard; pub mod lights; +pub mod logger; pub mod neopixel; pub mod panic_handler; +pub mod rtt; pub mod uart; pub mod usb; pub mod util; diff --git a/src/logger.rs b/src/logger.rs new file mode 100644 index 0000000..260d6a5 --- /dev/null +++ b/src/logger.rs @@ -0,0 +1,60 @@ +use core::{fmt::Write, sync::atomic::Ordering}; + +use atomic_polyfill::AtomicBool; +use embassy_time::Instant; +use log::{Metadata, Record}; +use static_cell::StaticCell; + +pub const LOGGER_OUTPUTS: usize = 1; + +pub struct Logger { + pub outputs: [fn(&[u8]); LOGGER_OUTPUTS], +} + +impl Logger { + /// Set this as the global logger. + /// + /// Calling this function more than once does nothing. + pub fn init(self) { + // guard against calling this multiple times + static INITIALIZED: AtomicBool = AtomicBool::new(false); + if INITIALIZED.fetch_or(true, Ordering::SeqCst) { + return; + } + + static LOGGER: StaticCell = StaticCell::new(); + let logger = LOGGER.init(self); + unsafe { log::set_logger_racy(logger).unwrap() }; + log::set_max_level(log::LevelFilter::Debug); + } +} + +impl log::Log for Logger { + fn enabled(&self, _metadata: &Metadata) -> bool { + true + } + + fn log(&self, record: &Record) { + if self.enabled(record.metadata()) { + let now = Instant::now(); + let s = now.as_secs(); + let ms = now.as_millis() % 1000; + let level = record.metadata().level(); + let mut w = &mut Writer(self); + let _ = writeln!(&mut w, "[{s}.{ms:04}] ({level}) {}", record.args()); + } + } + + fn flush(&self) {} +} + +struct Writer<'a>(&'a Logger); + +impl Write for Writer<'_> { + fn write_str(&mut self, s: &str) -> Result<(), core::fmt::Error> { + for output in &self.0.outputs { + output(s.as_bytes()); + } + Ok(()) + } +} diff --git a/src/panic_handler.rs b/src/panic_handler.rs index beddd28..d80bfba 100644 --- a/src/panic_handler.rs +++ b/src/panic_handler.rs @@ -1,28 +1,29 @@ -use core::panic::PanicInfo; +use core::{fmt::Write, panic::PanicInfo}; -use embassy_executor::Executor; -use embassy_rp::gpio::{AnyPin, Level, Output, Pin}; -use embassy_time::{Duration, Timer}; -use static_cell::StaticCell; +use cortex_m::asm; +use embassy_rp::gpio::{Level, Output}; + +use crate::rtt::rtt_write; #[panic_handler] -fn panic_blink(_info: &PanicInfo) -> ! { - static EXECUTOR: StaticCell = StaticCell::new(); +fn panic_blink(info: &PanicInfo) -> ! { + cortex_m::interrupt::disable(); + + let _ = write!(&mut Writer, "{info}"); // SAFETY: we panicked, so no other code will be running. let p = unsafe { embassy_rp::Peripherals::steal() }; + let _led = Output::new(p.PIN_11, Level::High); - EXECUTOR.init(Executor::new()).run(|spawner| { - spawner.spawn(blink(p.PIN_11.degrade())).ok(); - }); + asm::udf() } -#[embassy_executor::task] -async fn blink(led: AnyPin) { - let mut led = Output::new(led, Level::High); +/// Write to RTT +struct Writer; - loop { - Timer::after(Duration::from_secs(1)).await; - led.toggle(); +impl core::fmt::Write for Writer { + fn write_str(&mut self, s: &str) -> Result<(), core::fmt::Error> { + rtt_write(s.as_bytes()); + Ok(()) } } diff --git a/src/rtt.rs b/src/rtt.rs new file mode 100644 index 0000000..770a364 --- /dev/null +++ b/src/rtt.rs @@ -0,0 +1,42 @@ +use core::cell::RefCell; + +use critical_section::Mutex; +use rtt_target::{rtt_init, UpChannel}; + +pub type RttWriteFn = fn(&[u8]); + +static CHANNEL: Mutex>> = Mutex::new(RefCell::new(None)); + +/// Write directly to the rtt output. Must call [init_rtt_logger] first. +pub fn rtt_write(bytes: &[u8]) { + critical_section::with(|cs| { + let mut slot = CHANNEL.borrow_ref_mut(cs); + if let Some(channel) = slot.as_mut() { + channel.write(bytes); + }; + }); +} + +pub fn init_rtt_logger() -> RttWriteFn { + let channels = rtt_init! { + up: { + 0: { + size: 1024 + mode: NoBlockSkip + name: "Terminal" + } + } + }; + + critical_section::with(|cs| { + let mut slot = CHANNEL.borrow_ref_mut(cs); + + if slot.is_some() { + return rtt_write; + } + + *slot = Some(channels.up.0); + + rtt_write + }) +} diff --git a/src/usb.rs b/src/usb.rs index 4cfde79..3297d2c 100644 --- a/src/usb.rs +++ b/src/usb.rs @@ -21,16 +21,13 @@ static STATE: StaticCell = StaticCell::new(); pub async fn setup_logger_and_keyboard(usb: USB, events: KbEvents) { let mut builder = builder(usb); - logger::setup(&mut builder).await; - - log::error!("log_level: error"); - log::warn!("log_level: warn"); - log::info!("log_level: info"); - log::debug!("log_level: debug"); - log::trace!("log_level: trace"); + //logger::setup(&mut builder).await; keyboard::setup(&mut builder, events).await; + + log::info!("building usb device"); let usb = builder.build(); + log::info!("spawning usb task"); Spawner::for_current_executor().await.must_spawn(run(usb)); } @@ -73,5 +70,6 @@ pub fn builder(usb: USB) -> Builder<'static, Driver<'static, USB>> { #[embassy_executor::task] pub async fn run(mut device: UsbDevice<'static, Driver<'static, USB>>) { + log::info!("running usb device"); device.run().await }