this involved adding a lot of code from the develop branch step by step there are still some bugs, but at least i can get into the web interface and configure stuff again \o/ … measuring and pumping is working as well
109 lines
3.3 KiB
Rust
109 lines
3.3 KiB
Rust
use alloc::string::String;
|
|
use alloc::vec::Vec;
|
|
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
|
use embassy_sync::blocking_mutex::Mutex as BlockingMutex;
|
|
use log::{LevelFilter, Log, Metadata, Record};
|
|
|
|
const MAX_LIVE_LOG_ENTRIES: usize = 64;
|
|
|
|
struct LiveLogBuffer {
|
|
entries: Vec<(u64, String)>,
|
|
next_seq: u64,
|
|
}
|
|
|
|
impl LiveLogBuffer {
|
|
const fn new() -> Self {
|
|
Self {
|
|
entries: Vec::new(),
|
|
next_seq: 0,
|
|
}
|
|
}
|
|
|
|
fn push(&mut self, text: String) {
|
|
if self.entries.len() >= MAX_LIVE_LOG_ENTRIES {
|
|
self.entries.remove(0);
|
|
}
|
|
self.entries.push((self.next_seq, text));
|
|
self.next_seq += 1;
|
|
}
|
|
|
|
fn get_after(&self, after: Option<u64>) -> (Vec<(u64, String)>, bool, u64) {
|
|
let next_seq = self.next_seq;
|
|
match after {
|
|
None => (self.entries.clone(), false, next_seq),
|
|
Some(after_seq) => {
|
|
let result: Vec<_> = self.entries
|
|
.iter()
|
|
.filter(|(seq, _)| *seq > after_seq)
|
|
.cloned()
|
|
.collect();
|
|
|
|
// Dropped if there are entries that should exist (seq > after_seq) but
|
|
// the oldest retained entry has a higher seq than after_seq + 1.
|
|
let dropped = if next_seq > after_seq.saturating_add(1) {
|
|
if let Some((oldest_seq, _)) = self.entries.first() {
|
|
*oldest_seq > after_seq.saturating_add(1)
|
|
} else {
|
|
// Buffer empty but entries were written — all dropped
|
|
true
|
|
}
|
|
} else {
|
|
false
|
|
};
|
|
|
|
(result, dropped, next_seq)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pub struct InterceptorLogger {
|
|
live_log: BlockingMutex<CriticalSectionRawMutex, core::cell::RefCell<LiveLogBuffer>>,
|
|
}
|
|
|
|
impl InterceptorLogger {
|
|
pub const fn new() -> Self {
|
|
Self {
|
|
live_log: BlockingMutex::new(core::cell::RefCell::new(LiveLogBuffer::new())),
|
|
}
|
|
}
|
|
|
|
/// Returns (entries_after, dropped, next_seq).
|
|
/// Pass `after = None` to retrieve the entire current buffer.
|
|
/// Pass `after = Some(seq)` to retrieve only entries with seq > that value.
|
|
pub fn get_live_logs(&self, after: Option<u64>) -> (Vec<(u64, String)>, bool, u64) {
|
|
self.live_log.lock(|buf| buf.borrow().get_after(after))
|
|
}
|
|
|
|
pub fn init(&'static self) {
|
|
match log::set_logger(self).map(|()| log::set_max_level(LevelFilter::Info)) {
|
|
Ok(()) => {}
|
|
Err(_e) => {
|
|
esp_println::println!("ERROR: Logger already set");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Log for InterceptorLogger {
|
|
fn enabled(&self, metadata: &Metadata) -> bool {
|
|
metadata.level() <= log::Level::Info
|
|
}
|
|
|
|
fn log(&self, record: &Record) {
|
|
if self.enabled(record.metadata()) {
|
|
let message = alloc::format!("{}: {}", record.level(), record.args());
|
|
|
|
// Print to serial
|
|
esp_println::println!("{}", message);
|
|
|
|
// Store in live log ring buffer
|
|
self.live_log.lock(|buf| {
|
|
buf.borrow_mut().push(message);
|
|
});
|
|
}
|
|
}
|
|
|
|
fn flush(&self) {}
|
|
}
|