Fix uart interrupt printing when the buffer fills up

It almost managed to block the print until there was space in the
buffer, except it ended up blocking out interrupts so it just
deadlocked.

Change-Id: Ifa3ae0cd6bef22cc8521c9bd866a30f62cfbc76d
diff --git a/motors/fet12/fet12v2.cc b/motors/fet12/fet12v2.cc
index 01a6336..d95d4a2 100644
--- a/motors/fet12/fet12v2.cc
+++ b/motors/fet12/fet12v2.cc
@@ -111,8 +111,7 @@
   teensy::InterruptBufferedUart *const tty =
       global_stdout.load(::std::memory_order_acquire);
   if (tty != nullptr) {
-    DisableInterrupts disable_interrupts;
-    tty->Write(gsl::make_span(ptr, len), disable_interrupts);
+    tty->Write(gsl::make_span(ptr, len));
     return len;
   }
   return 0;
diff --git a/motors/peripheral/uart.cc b/motors/peripheral/uart.cc
index a901483..70eadf1 100644
--- a/motors/peripheral/uart.cc
+++ b/motors/peripheral/uart.cc
@@ -64,8 +64,8 @@
   uart_.Initialize(baud_rate);
 }
 
-void InterruptBufferedUart::Write(gsl::span<char> data,
-                                  const DisableInterrupts &disable_interrupts) {
+void InterruptBufferedUart::Write(gsl::span<char> data) {
+  DisableInterrupts disable_interrupts;
   uart_.EnableTransmitInterrupt();
   static_assert(buffer_.size() >= 8,
                 "Need enough space to not turn the interrupt off each time");
@@ -73,6 +73,7 @@
     const int bytes_written = buffer_.PushSpan(data);
     data = data.subspan(bytes_written);
     WriteCharacters(data.empty(), disable_interrupts);
+    ReenableInterrupts{&disable_interrupts};
   }
 }
 
diff --git a/motors/peripheral/uart.h b/motors/peripheral/uart.h
index cf79815..12b8523 100644
--- a/motors/peripheral/uart.h
+++ b/motors/peripheral/uart.h
@@ -56,7 +56,7 @@
 
   void Initialize(int baud_rate);
 
-  void Write(gsl::span<char> data, const DisableInterrupts &disable_interrupts);
+  void Write(gsl::span<char> data);
 
   // Should be called as the body of the interrupt handler.
   void HandleInterrupt(const DisableInterrupts &disable_interrupts) {
diff --git a/motors/util.h b/motors/util.h
index 110caed..0056089 100644
--- a/motors/util.h
+++ b/motors/util.h
@@ -240,6 +240,19 @@
   DisableInterrupts &operator=(const DisableInterrupts &) = delete;
 };
 
+class ReenableInterrupts {
+ public:
+  ReenableInterrupts(DisableInterrupts *) {
+    __enable_irq();
+    // Because we're on a Cortex-M4, we don't need an ISB here to ensure
+    // interrupts are processed.
+  }
+  ~ReenableInterrupts() { __disable_irq(); }
+
+  ReenableInterrupts(const ReenableInterrupts &) = delete;
+  ReenableInterrupts &operator=(const ReenableInterrupts &) = delete;
+};
+
 // constexpr log base 2, which fails to compile for non-power-of-2 inputs.
 // This is a silly implementation to use at runtime.
 template<typename T>