defmt_brtt/
lib.rs

1#![no_std]
2
3mod consts;
4
5#[cfg(feature = "bbq")]
6mod bbq;
7#[cfg(feature = "bbq")]
8pub use bbq::{init, Consumer, DefmtConsumer, Error as BBQError, GrantR, SplitGrantR};
9
10#[cfg(feature = "rtt")]
11mod rtt;
12#[cfg(feature = "rtt")]
13use rtt::handle;
14
15#[cfg(feature = "async-await")]
16mod csec_waker;
17
18use core::sync::atomic::{AtomicBool, Ordering};
19
20#[cfg(not(any(feature = "rtt", feature = "bbq")))]
21compile_error!("You must select at least one of the `rtt` or `bbq` features (or both).");
22
23#[defmt::global_logger]
24struct Logger;
25
26/// Global logger lock.
27static TAKEN: AtomicBool = AtomicBool::new(false);
28static mut CS_RESTORE: critical_section::RestoreState = critical_section::RestoreState::invalid();
29static mut ENCODER: defmt::Encoder = defmt::Encoder::new();
30
31fn combined_write(_data: &[u8]) {
32    #[cfg(feature = "rtt")]
33    rtt::do_write(_data);
34    #[cfg(feature = "bbq")]
35    bbq::do_write(_data);
36}
37
38unsafe impl defmt::Logger for Logger {
39    fn acquire() {
40        // safety: Must be paired with corresponding call to release(), see below
41        let restore = unsafe { critical_section::acquire() };
42
43        // safety: accessing the `static mut` is OK because we have acquired a critical section.
44        if TAKEN.load(Ordering::Relaxed) {
45            panic!("defmt logger taken reentrantly")
46        }
47
48        #[cfg(feature = "bbq")]
49        if bbq::should_bail() {
50            // safety: we have acquired a critical section and are releasing it
51            // again, without modifying the TAKEN variable.
52            unsafe { critical_section::release(restore) };
53            return;
54        }
55
56        // safety: accessing the `static mut` is OK because we have acquired a critical section.
57        TAKEN.store(true, Ordering::Relaxed);
58
59        // safety: accessing the `static mut` is OK because we have acquired a critical section.
60        unsafe { CS_RESTORE = restore };
61
62        // safety: accessing the `static mut` is OK because we have acquired a critical section.
63        unsafe { ENCODER.start_frame(combined_write) }
64    }
65
66    unsafe fn flush() {
67        #[cfg(feature = "rtt")]
68        // safety: accessing the `&'static _` is OK because we have acquired a critical section.
69        handle().flush();
70    }
71
72    unsafe fn release() {
73        // safety: accessing the `static mut` is OK because we have acquired a critical section.
74        ENCODER.end_frame(combined_write);
75
76        #[cfg(feature = "bbq")]
77        bbq::commit_w_grant();
78
79        // safety: accessing the `static mut` is OK because we have acquired a critical section.
80        TAKEN.store(false, Ordering::Relaxed);
81
82        // safety: accessing the `static mut` is OK because we have acquired a critical section.
83        let restore = CS_RESTORE;
84
85        // safety: Must be paired with corresponding call to acquire(), see above
86        critical_section::release(restore);
87
88        // Wake the defmt consumer's waker
89        #[cfg(feature = "async-await")]
90        bbq::DefmtConsumer::waker().wake();
91    }
92
93    unsafe fn write(bytes: &[u8]) {
94        #[cfg(all(feature = "bbq", not(feature = "rtt")))]
95        // Return early to avoid the encoder having to encode bytes we are going to throw away
96        if bbq::check_latch(Ordering::Relaxed).is_err() {
97            return;
98        }
99
100        // safety: accessing the `static mut` is OK because we have acquired a critical section.
101        ENCODER.write(bytes, combined_write);
102    }
103}