aboutsummaryrefslogtreecommitdiffstats
path: root/app/src/log.rs
blob: 6cfba8f9f685b91ea19c379d34cbcbd5b9206a95 (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
use rb::{Reader, RingBuffer, Writer};

use core::fmt::{self, Write};
use embedded_hal::{digital::v2::OutputPin, serial};
use trinket_m0::{
    gpio::{Pa6, Pa7, PfD},
    sercom::{Sercom0Pad2, Sercom0Pad3, UART0},
};

static mut LB: RingBuffer<u8> = RingBuffer::<u8>::new(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 Write for JoinedRingBuffer<'_> {
    fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
        for b in s.bytes() {
            if let Err(_) = self.lbw.unshift(b) {
                // Ignore buffer full errors for logging.
                return Ok(());
            }
        }
        Ok(())
    }
}

static mut LOGBUF: JoinedRingBuffer = unsafe { JoinedRingBuffer::new(&LB) };
static mut UART0: usize = 0;

pub struct Processor<W, L> {
    uart: W,
    led: L,
}

impl<W, L> Processor<W, L>
where
    W: serial::Write<u8>,
    L: OutputPin,
{
    pub fn new(uart: W, led: L) -> Self {
        // Unsafe because we're creating a mutable alias.
        unsafe { UART0 = core::mem::transmute(&uart) };
        Self {
            uart: uart,
            led: led,
        }
    }

    pub fn task(&mut self) {
        // Unsafe due to mutable static.
        if unsafe { LOGBUF.lbr.is_empty() } {
            return;
        }
        self.led.set_high().ok();
        // Unsafe due to mutable static.
        while let Some(b) = unsafe { LOGBUF.lbr.shift() } {
            nb::block!(self.uart.write(b)).ok();
        }
        self.led.set_low().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 UART0 == 0 {
        return;
    }
    let uart: &mut UART0<Sercom0Pad3<Pa7<PfD>>, Sercom0Pad2<Pa6<PfD>>, (), ()> =
        core::mem::transmute(UART0);
    fmt::write(uart, args).expect("writing fmt now to uart");
    if nl {
        uart.write_str("\r\n").expect("writing nl now to uart");
    }
}

pub fn write_fmt(args: fmt::Arguments, nl: bool) {
    // Unsafe due to mutable static.
    unsafe {
        fmt::write(&mut LOGBUF, args).expect("writing fmt to log");
        if nl {
            LOGBUF.write_str("\r\n").expect("writing nl to log");
        }
    }
}