aboutsummaryrefslogtreecommitdiffstats
path: root/app/src/log.rs
diff options
context:
space:
mode:
authorBrian Cully <bjc@kublai.com>2019-06-24 21:14:32 -0400
committerBrian Cully <bjc@kublai.com>2019-07-23 19:55:18 -0400
commit63d4ce8154eb8f6feb67986e98ea9b5007632460 (patch)
tree187e66104eb7c848dcf73a5ee067c5f27235360a /app/src/log.rs
downloadsamd21-demo-63d4ce8154eb8f6feb67986e98ea9b5007632460.tar.gz
samd21-demo-63d4ce8154eb8f6feb67986e98ea9b5007632460.zip
Initial commit.
Diffstat (limited to 'app/src/log.rs')
-rw-r--r--app/src/log.rs95
1 files changed, 95 insertions, 0 deletions
diff --git a/app/src/log.rs b/app/src/log.rs
new file mode 100644
index 0000000..6cfba8f
--- /dev/null
+++ b/app/src/log.rs
@@ -0,0 +1,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");
+ }
+ }
+}