use rustmeter_beacon_core::{get_current_core_id, protocol::raw_writers::write_defmt_data};
use crate::ringbuffer::AtomicRingBuffer;
static mut PER_CORE_BUFFER: [AtomicRingBuffer<32>; 2] =
[AtomicRingBuffer::new(), AtomicRingBuffer::new()];
static mut PER_CORE_STATE: [u32; 2] = [0, 0];
static mut PER_CORE_ENCODER: [defmt::Encoder; 2] = [defmt::Encoder::new(), defmt::Encoder::new()];
#[defmt::global_logger]
pub struct Logger;
impl Logger {
pub fn flush_via_event() {
unsafe {
let core_id = get_current_core_id() as usize;
let mut buffer = [0u8; 32];
loop {
match PER_CORE_BUFFER[core_id].pop_slice(&mut buffer) {
0 => break,
n => {
let data = &buffer[..n];
write_defmt_data(data);
}
}
}
}
}
}
#[allow(static_mut_refs)]
unsafe impl defmt::Logger for Logger {
fn acquire() {
unsafe {
let core_id = get_current_core_id() as usize;
core::arch::asm!(
"mrs {}, PRIMASK", "cpsid i", out(reg) PER_CORE_STATE[core_id],
options(nomem, nostack, preserves_flags)
);
PER_CORE_ENCODER[core_id].start_frame(do_encoder_write)
}
}
unsafe fn release() {
unsafe {
let core_id = get_current_core_id() as usize;
PER_CORE_ENCODER[core_id].end_frame(do_encoder_write);
Self::flush();
core::arch::asm!(
"msr PRIMASK, {}",
in(reg) PER_CORE_STATE[core_id],
);
}
}
unsafe fn flush() {
Logger::flush_via_event();
}
unsafe fn write(bytes: &[u8]) {
unsafe {
let core_id = get_current_core_id() as usize;
PER_CORE_ENCODER[core_id].write(bytes, do_encoder_write);
}
}
}
fn do_encoder_write(bytes: &[u8]) {
unsafe {
let core_id = get_current_core_id() as usize;
let cap = PER_CORE_BUFFER[core_id].capacity();
let mut start = 0;
while start < bytes.len() {
let end = core::cmp::min(start + cap, bytes.len());
let chunk = &bytes[start..end];
while PER_CORE_BUFFER[core_id].push_slice_fast(chunk).is_none() {
Logger::flush_via_event();
}
start = end;
}
}
}