1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
use crate::rtc;
use core::cell::UnsafeCell;
use core::fmt::{self, Write};
use core::mem::MaybeUninit;
use log::{Metadata, Record};
use nrf52840_hal::{target::UARTE0, uarte, Uarte};
use starb::{Reader, RingBuffer, Writer};
static mut UARTE0: usize = 0;
struct JoinedRingBuffer<'a> {
lbr: Reader<'a, u8>,
lbw: Writer<'a, u8>,
}
impl<'a> JoinedRingBuffer<'a> {
const fn new(rb: &'a RingBuffer<u8>) -> Self {
let (lbr, lbw) = rb.split();
Self { lbr: lbr, lbw: lbw }
}
}
impl fmt::Write for JoinedRingBuffer<'_> {
fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
// Drop anything that couldn't fit on the ground so we don't
// back up.
self.lbw.unshift_from(s.as_bytes());
Ok(())
}
}
static mut LB: RingBuffer<u8> = RingBuffer::<u8>::new();
static mut JRB: JoinedRingBuffer = unsafe { JoinedRingBuffer::new(&LB) };
// The UART isn't necessarily Sync, so wrap it in something that
// is. As long as flush() is only called from one thread, we're fine,
// but this is a guarantee that the logger module doesn't make.
pub struct WriteWrapper<W> {
w: W,
}
impl<W> WriteWrapper<W> {
pub fn new(writer: W) -> Self {
Self { w: writer }
}
}
unsafe impl<W> Sync for WriteWrapper<W> {}
pub struct SerialLogger<W> {
writer: UnsafeCell<WriteWrapper<Uarte<W>>>,
}
impl<W> SerialLogger<W>
where
W: uarte::Instance,
{
pub fn new(writer: WriteWrapper<Uarte<W>>) -> Self {
// Stash this for unsafe usage in case there's an issue with
// the rest of the logging.
unsafe { UARTE0 = core::mem::transmute(&writer.w) };
Self {
writer: UnsafeCell::new(writer),
}
}
}
unsafe impl<W> Send for SerialLogger<W> {}
unsafe impl<W> Sync for SerialLogger<W> {}
impl<W> log::Log for SerialLogger<W>
where
W: uarte::Instance,
{
fn enabled(&self, metadata: &Metadata) -> bool {
metadata.level() <= log::max_level()
}
fn log(&self, record: &Record) {
if !self.enabled(record.metadata()) {
return;
}
let jrb = unsafe { &mut JRB };
if record.target() == "usb" {
write!(jrb, "{}", record.args()).ok();
} else {
write!(
jrb,
"[{}] {} {} -- {}\r\n",
rtc::millis(),
record.level(),
record.target(),
record.args()
)
.ok();
}
}
fn flush(&self) {
//let start = rtc::millis();
let jrb = unsafe { &mut JRB };
let writer = unsafe { &mut (*self.writer.get()) };
let mut buf: [u8; 256] = unsafe { MaybeUninit::<[u8; 256]>::uninit().assume_init() };
let len = jrb.lbr.shift_into(&mut buf);
if len > 0 {
writer.w.write(&buf[0..len]).expect("writing log");
/*
let end = rtc::millis();
writer
.w
.write(&[b' ', b'-', b' ', b'0' + (end as u8 - start as u8)])
.ok();
*/
}
}
}
// Write to the UART right now, instead of putting it on a ring
// buffer. This function is a huge hack, and only useful for debugging
// either before the main loop starts or if the ring buffer is broken.
pub unsafe fn write_fmt_now(args: fmt::Arguments, nl: bool) {
if UARTE0 == 0 {
return;
}
let uart: &mut Uarte<UARTE0> = core::mem::transmute(UARTE0);
fmt::write(uart, args).expect("writing fmt now to uart");
if nl {
uart.write_str("\r\n").expect("writing nl now to uart");
}
}
|