Clean up printing in MCU code and add new options

We now have four different ways of getting debug prints off of boards,
with varying tradeoffs. Split out the printing into dedicated libraries
that are easy to switch between to avoid duplicating even more code, and
also make using the new options easy.

USB is handy for testing the code on a Teensy.
Semihosting is nice in theory, but in practice it's super slow and
messes up the code's timing.
ITM works well, as long as you have a debugger attached.
Serial also works pretty well, but it means having another cable.

Change-Id: I7af5099d421c33f0324aeca92b46732e341848d4
diff --git a/motors/button_board.cc b/motors/button_board.cc
index 676331b..0c0050b 100644
--- a/motors/button_board.cc
+++ b/motors/button_board.cc
@@ -5,13 +5,14 @@
 #include <atomic>
 #include <cmath>
 
-#include "motors/core/time.h"
 #include "motors/core/kinetis.h"
+#include "motors/core/time.h"
 #include "motors/peripheral/adc.h"
 #include "motors/peripheral/can.h"
-#include "motors/usb/usb.h"
+#include "motors/print/print.h"
 #include "motors/usb/cdc.h"
 #include "motors/usb/hid.h"
+#include "motors/usb/usb.h"
 #include "motors/util.h"
 
 namespace frc971 {
@@ -58,8 +59,6 @@
   return r;
 }
 
-::std::atomic<teensy::AcmTty *> global_stdout{nullptr};
-
 // The HID report descriptor we use.
 constexpr char kReportDescriptor1[] = {
     0x05, 0x01,        // Usage Page (Generic Desktop),
@@ -224,17 +223,16 @@
 extern "C" {
 
 void *__stack_chk_guard = (void *)0x67111971;
-
-int _write(int /*file*/, char *ptr, int len) {
-  teensy::AcmTty *const tty = global_stdout.load(::std::memory_order_acquire);
-  if (tty != nullptr) {
-    return tty->Write(ptr, len);
+void __stack_chk_fail(void) {
+  while (true) {
+    GPIOC_PSOR = (1 << 5);
+    printf("Stack corruption detected\n");
+    delay(1000);
+    GPIOC_PCOR = (1 << 5);
+    delay(1000);
   }
-  return 0;
 }
 
-void __stack_chk_fail(void);
-
 }  // extern "C"
 
 extern "C" int main(void) {
@@ -370,8 +368,13 @@
       ::std::string(kReportDescriptor1, sizeof(kReportDescriptor1)));
 
   teensy::AcmTty tty1(&usb_device);
-  global_stdout.store(&tty1, ::std::memory_order_release);
+  PrintingParameters printing_parameters;
+  printing_parameters.stdout_tty = &tty1;
+
+  const ::std::unique_ptr<PrintingImplementation> printing =
+      CreatePrinting(printing_parameters);
   usb_device.Initialize();
+  printing->Initialize();
 
   can_init(0, 1);
   AdcInitJoystick();
@@ -397,15 +400,5 @@
   return 0;
 }
 
-void __stack_chk_fail(void) {
-  while (true) {
-    GPIOC_PSOR = (1 << 5);
-    printf("Stack corruption detected\n");
-    delay(1000);
-    GPIOC_PCOR = (1 << 5);
-    delay(1000);
-  }
-}
-
 }  // namespace motors
 }  // namespace frc971