#![no_std]
mod channel;
mod consts;
use core::{
cell::UnsafeCell,
sync::atomic::{AtomicBool, AtomicU32, Ordering},
};
use crate::{channel::Channel, consts::BUF_SIZE};
const MODE_MASK: u32 = 0b11;
const MODE_BLOCK_IF_FULL: u32 = 2;
const MODE_NON_BLOCKING_TRIM: u32 = 1;
#[defmt::global_logger]
struct Logger;
static RTT_ENCODER: RttEncoder = RttEncoder::new();
#[no_mangle]
static _SEGGER_RTT: Header = Header {
id: *b"SEGGER RTT\0\0\0\0\0\0",
max_up_channels: 1,
max_down_channels: 0,
up_channel: Channel {
name: NAME.as_ptr(),
buffer: BUFFER.get(),
size: BUF_SIZE as u32,
write: AtomicU32::new(0),
read: AtomicU32::new(0),
flags: AtomicU32::new(MODE_NON_BLOCKING_TRIM),
},
};
pub fn in_blocking_mode() -> bool {
(_SEGGER_RTT.up_channel.flags.load(Ordering::Relaxed) & MODE_MASK) == MODE_BLOCK_IF_FULL
}
#[cfg_attr(target_os = "macos", link_section = ".uninit,defmt-rtt.BUFFER")]
#[cfg_attr(not(target_os = "macos"), link_section = ".uninit.defmt-rtt.BUFFER")]
static BUFFER: Buffer = Buffer::new();
#[cfg_attr(target_os = "macos", link_section = ".data,defmt-rtt.NAME")]
#[cfg_attr(not(target_os = "macos"), link_section = ".data.defmt-rtt.NAME")]
static NAME: [u8; 6] = *b"defmt\0";
struct RttEncoder {
taken: AtomicBool,
cs_restore: UnsafeCell<critical_section::RestoreState>,
encoder: UnsafeCell<defmt::Encoder>,
}
impl RttEncoder {
const fn new() -> RttEncoder {
RttEncoder {
taken: AtomicBool::new(false),
cs_restore: UnsafeCell::new(critical_section::RestoreState::invalid()),
encoder: UnsafeCell::new(defmt::Encoder::new()),
}
}
fn acquire(&self) {
let restore = unsafe { critical_section::acquire() };
if self.taken.load(Ordering::Relaxed) {
panic!("defmt logger taken reentrantly")
}
self.taken.store(true, Ordering::Relaxed);
unsafe {
self.cs_restore.get().write(restore);
let encoder: &mut defmt::Encoder = &mut *self.encoder.get();
encoder.start_frame(|b| {
_SEGGER_RTT.up_channel.write_all(b);
});
}
}
unsafe fn write(&self, bytes: &[u8]) {
unsafe {
let encoder: &mut defmt::Encoder = &mut *self.encoder.get();
encoder.write(bytes, |b| {
_SEGGER_RTT.up_channel.write_all(b);
});
}
}
unsafe fn flush(&self) {
_SEGGER_RTT.up_channel.flush();
}
unsafe fn release(&self) {
if !self.taken.load(Ordering::Relaxed) {
panic!("defmt release out of context")
}
unsafe {
let encoder: &mut defmt::Encoder = &mut *self.encoder.get();
encoder.end_frame(|b| {
_SEGGER_RTT.up_channel.write_all(b);
});
let restore = self.cs_restore.get().read();
self.taken.store(false, Ordering::Relaxed);
critical_section::release(restore);
}
}
}
unsafe impl Sync for RttEncoder {}
unsafe impl defmt::Logger for Logger {
fn acquire() {
RTT_ENCODER.acquire();
}
unsafe fn write(bytes: &[u8]) {
unsafe {
RTT_ENCODER.write(bytes);
}
}
unsafe fn flush() {
unsafe {
RTT_ENCODER.flush();
}
}
unsafe fn release() {
unsafe {
RTT_ENCODER.release();
}
}
}
#[repr(C)]
struct Header {
id: [u8; 16],
max_up_channels: u32,
max_down_channels: u32,
up_channel: Channel,
}
unsafe impl Sync for Header {}
struct Buffer {
inner: UnsafeCell<[u8; BUF_SIZE]>,
}
impl Buffer {
const fn new() -> Buffer {
Buffer {
inner: UnsafeCell::new([0; BUF_SIZE]),
}
}
const fn get(&self) -> *mut u8 {
self.inner.get() as _
}
}
unsafe impl Sync for Buffer {}