summaryrefslogtreecommitdiffstats
path: root/ble/src/logger.rs
blob: 07790cc57a61add272ffab8f23d39a3915bdb00d (plain)
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");
    }
}