Add RTT logging
This commit is contained in:
@ -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<u8>; HEAP_SIZE] = [MaybeUninit::uninit(); HEAP_SIZE];
|
||||
unsafe { HEAP.init(HEAP_MEM.as_ptr() as usize, HEAP_SIZE) }
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
0
src/defmt.rs
Normal file
0
src/defmt.rs
Normal file
@ -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;
|
||||
|
||||
60
src/logger.rs
Normal file
60
src/logger.rs
Normal file
@ -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<Logger> = 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(())
|
||||
}
|
||||
}
|
||||
@ -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<Executor> = 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(())
|
||||
}
|
||||
}
|
||||
|
||||
42
src/rtt.rs
Normal file
42
src/rtt.rs
Normal file
@ -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<RefCell<Option<UpChannel>>> = 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
|
||||
})
|
||||
}
|
||||
12
src/usb.rs
12
src/usb.rs
@ -21,16 +21,13 @@ static STATE: StaticCell<State> = 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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user