Add RTT logging

This commit is contained in:
2023-05-21 10:18:26 +02:00
parent 8a14c13bf1
commit 481066a343
11 changed files with 182 additions and 28 deletions

21
Cargo.lock generated
View File

@ -1126,6 +1126,16 @@ dependencies = [
"crc-any", "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]] [[package]]
name = "rustc_version" name = "rustc_version"
version = "0.2.3" version = "0.2.3"
@ -1320,8 +1330,10 @@ dependencies = [
name = "tangentbord1" name = "tangentbord1"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"atomic-polyfill 1.0.2",
"cortex-m", "cortex-m",
"cortex-m-rt", "cortex-m-rt",
"critical-section",
"embassy-executor", "embassy-executor",
"embassy-futures", "embassy-futures",
"embassy-rp", "embassy-rp",
@ -1335,11 +1347,14 @@ dependencies = [
"embedded-io", "embedded-io",
"fixed", "fixed",
"futures", "futures",
"heapless",
"log", "log",
"once_cell",
"pio", "pio",
"pio-proc", "pio-proc",
"postcard", "postcard",
"ron", "ron",
"rtt-target",
"smart-leds", "smart-leds",
"static_cell", "static_cell",
"tgnt", "tgnt",
@ -1410,6 +1425,12 @@ version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
[[package]]
name = "ufmt-write"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e87a2ed6b42ec5e28cc3b94c09982969e9227600b2e3dcbc1db927a84c06bd69"
[[package]] [[package]]
name = "unicode-ident" name = "unicode-ident"
version = "1.0.8" version = "1.0.8"

View File

@ -31,6 +31,11 @@ smart-leds = "0.3.0"
embedded-alloc = "0.5.0" embedded-alloc = "0.5.0"
postcard = { version = "1.0.4", features = ["alloc"] } postcard = { version = "1.0.4", features = ["alloc"] }
fixed = "1.23.1" 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"] #[patch."https://git.nubo.sh/hulthe/tgnt.git"]
#tgnt = { path = "../tgnt" } #tgnt = { path = "../tgnt" }

View File

@ -4,11 +4,12 @@ use core::mem::MaybeUninit;
use embedded_alloc::Heap; use embedded_alloc::Heap;
pub const HEAP_SIZE: usize = 4096;
#[global_allocator] #[global_allocator]
static HEAP: Heap = Heap::empty(); static HEAP: Heap = Heap::empty();
pub fn init() { pub fn init() {
const HEAP_SIZE: usize = 4096;
static mut HEAP_MEM: [MaybeUninit<u8>; HEAP_SIZE] = [MaybeUninit::uninit(); HEAP_SIZE]; static mut HEAP_MEM: [MaybeUninit<u8>; HEAP_SIZE] = [MaybeUninit::uninit(); HEAP_SIZE];
unsafe { HEAP.init(HEAP_MEM.as_ptr() as usize, HEAP_SIZE) } unsafe { HEAP.init(HEAP_MEM.as_ptr() as usize, HEAP_SIZE) }
} }

View File

@ -14,21 +14,33 @@ use embassy_time::{Duration, Timer};
use log::error; use log::error;
use tangentbord1::board::Board; use tangentbord1::board::Board;
use tangentbord1::keyboard::{Half, KeyboardConfig}; use tangentbord1::keyboard::{Half, KeyboardConfig};
use tangentbord1::logger::Logger;
use tangentbord1::util::{stall, wheel}; use tangentbord1::util::{stall, wheel};
use tangentbord1::ws2812::{Rgb, Ws2812}; use tangentbord1::ws2812::{Rgb, Ws2812};
use tangentbord1::{allocator, uart, usb}; use tangentbord1::{allocator, rtt, uart, usb};
use tgnt::layer::Layer; use tgnt::layer::Layer;
#[embassy_executor::main] #[embassy_executor::main]
async fn main(_spawner: Spawner) { async fn main(_spawner: Spawner) {
let half = Half::Left; 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(); allocator::init();
let p = embassy_rp::init(Default::default()); let p = embassy_rp::init(Default::default());
let board = Board::from(p); let board = Board::from(p);
let _led = Output::new(board.d13, Level::High);
let _neopixel_power = Output::new(board.neopixel_power, Level::High); let _neopixel_power = Output::new(board.neopixel_power, Level::High);
let mut neopixel = Ws2812::new(board.PIO0, board.DMA_CH0, board.neopixel); let mut neopixel = Ws2812::new(board.PIO0, board.DMA_CH0, board.neopixel);

View File

@ -14,21 +14,33 @@ use embassy_time::{Duration, Timer};
use log::error; use log::error;
use tangentbord1::board::Board; use tangentbord1::board::Board;
use tangentbord1::keyboard::{Half, KeyboardConfig}; use tangentbord1::keyboard::{Half, KeyboardConfig};
use tangentbord1::logger::Logger;
use tangentbord1::util::{stall, wheel}; use tangentbord1::util::{stall, wheel};
use tangentbord1::ws2812::{Rgb, Ws2812}; use tangentbord1::ws2812::{Rgb, Ws2812};
use tangentbord1::{allocator, uart, usb}; use tangentbord1::{allocator, rtt, uart, usb};
use tgnt::layer::Layer; use tgnt::layer::Layer;
#[embassy_executor::main] #[embassy_executor::main]
async fn main(_spawner: Spawner) { async fn main(_spawner: Spawner) {
let half = Half::Right; 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(); allocator::init();
let p = embassy_rp::init(Default::default()); let p = embassy_rp::init(Default::default());
let board = Board::from(p); let board = Board::from(p);
let _led = Output::new(board.d13, Level::High);
let _neopixel_power = Output::new(board.neopixel_power, Level::High); let _neopixel_power = Output::new(board.neopixel_power, Level::High);
let mut neopixel = Ws2812::new(board.PIO0, board.DMA_CH0, board.neopixel); let mut neopixel = Ws2812::new(board.PIO0, board.DMA_CH0, board.neopixel);

0
src/defmt.rs Normal file
View File

View File

@ -12,8 +12,10 @@ pub mod allocator;
pub mod board; pub mod board;
pub mod keyboard; pub mod keyboard;
pub mod lights; pub mod lights;
pub mod logger;
pub mod neopixel; pub mod neopixel;
pub mod panic_handler; pub mod panic_handler;
pub mod rtt;
pub mod uart; pub mod uart;
pub mod usb; pub mod usb;
pub mod util; pub mod util;

60
src/logger.rs Normal file
View 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(())
}
}

View File

@ -1,28 +1,29 @@
use core::panic::PanicInfo; use core::{fmt::Write, panic::PanicInfo};
use embassy_executor::Executor; use cortex_m::asm;
use embassy_rp::gpio::{AnyPin, Level, Output, Pin}; use embassy_rp::gpio::{Level, Output};
use embassy_time::{Duration, Timer};
use static_cell::StaticCell; use crate::rtt::rtt_write;
#[panic_handler] #[panic_handler]
fn panic_blink(_info: &PanicInfo) -> ! { fn panic_blink(info: &PanicInfo) -> ! {
static EXECUTOR: StaticCell<Executor> = StaticCell::new(); cortex_m::interrupt::disable();
let _ = write!(&mut Writer, "{info}");
// SAFETY: we panicked, so no other code will be running. // SAFETY: we panicked, so no other code will be running.
let p = unsafe { embassy_rp::Peripherals::steal() }; let p = unsafe { embassy_rp::Peripherals::steal() };
let _led = Output::new(p.PIN_11, Level::High);
EXECUTOR.init(Executor::new()).run(|spawner| { asm::udf()
spawner.spawn(blink(p.PIN_11.degrade())).ok();
});
} }
#[embassy_executor::task] /// Write to RTT
async fn blink(led: AnyPin) { struct Writer;
let mut led = Output::new(led, Level::High);
loop { impl core::fmt::Write for Writer {
Timer::after(Duration::from_secs(1)).await; fn write_str(&mut self, s: &str) -> Result<(), core::fmt::Error> {
led.toggle(); rtt_write(s.as_bytes());
Ok(())
} }
} }

42
src/rtt.rs Normal file
View 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
})
}

View File

@ -21,16 +21,13 @@ static STATE: StaticCell<State> = StaticCell::new();
pub async fn setup_logger_and_keyboard(usb: USB, events: KbEvents) { pub async fn setup_logger_and_keyboard(usb: USB, events: KbEvents) {
let mut builder = builder(usb); let mut builder = builder(usb);
logger::setup(&mut builder).await; //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");
keyboard::setup(&mut builder, events).await; keyboard::setup(&mut builder, events).await;
log::info!("building usb device");
let usb = builder.build(); let usb = builder.build();
log::info!("spawning usb task");
Spawner::for_current_executor().await.must_spawn(run(usb)); 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] #[embassy_executor::task]
pub async fn run(mut device: UsbDevice<'static, Driver<'static, USB>>) { pub async fn run(mut device: UsbDevice<'static, Driver<'static, USB>>) {
log::info!("running usb device");
device.run().await device.run().await
} }