Add Kinetis-K UART code

This was used for bringing up fet12v2 already, and seems to work nicely.

Need to either document how to use stty to configure a serial port to
interact with this or switch it to use Linux's defaults.

Change-Id: Id13bc733a53f5c723cce56b1c63c69070039fbcd
diff --git a/motors/peripheral/uart.cc b/motors/peripheral/uart.cc
new file mode 100644
index 0000000..f910651
--- /dev/null
+++ b/motors/peripheral/uart.cc
@@ -0,0 +1,97 @@
+#include "motors/peripheral/uart.h"
+
+#include <stdint.h>
+
+namespace frc971 {
+namespace teensy {
+
+// Currently hard-coded for 8-bit + odd parity + start bit + stop bit.
+void Uart::Initialize(int baud_rate) {
+  {
+    // UART baud rate = UART module clock / (16 * (SBR[12:0] + BRFD))
+    // BRFD = BRFA (bitfield) / 32
+    const int desired_receiver_clock = baud_rate * 16;
+    const int sbr_and_brfd32 =
+        ((static_cast<int64_t>(module_clock_frequency_) * UINT64_C(64) /
+          static_cast<int64_t>(desired_receiver_clock)) +
+         1) /
+        2;
+    const int sbr = sbr_and_brfd32 / 32;
+    const int brfa = sbr_and_brfd32 % 32;
+
+    module_->BDH = (sbr >> 8) & 0x1F;
+    module_->BDL = sbr & 0xFF;
+    module_->C1 = M_UART_M /* 9 data bits */ |
+                  M_UART_ILT /* only detect idle after stop bit */ |
+                  M_UART_PE /* enable parity */ | M_UART_PT /* odd parity */;
+    module_->C4 = V_UART_BRFA(brfa);
+  }
+  {
+    const uint8_t pfifo = module_->PFIFO;
+    tx_fifo_size_ = G_UART_TXFIFOSIZE(pfifo);
+    rx_fifo_size_ = G_UART_RXFIFOSIZE(pfifo);
+  }
+
+  // When C1[M] is set and C4[M10] is cleared, the UART is configured for 9-bit
+  // data characters. If C1[PE] is enabled, the ninth bit is either C3[T8/R8] or
+  // the internally generated parity bit
+
+  // TODO(Brian): M_UART_TIE /* Enable TX interrupt or DMA */ |
+  // M_UART_RIE /* Enable RX interrupt or DMA */
+  // Also set in C5: M_UART_TDMAS /* Do DMA for TX */ |
+  // M_UART_RDMAS /* Do DMA for RX */
+  c2_value_ = M_UART_TE;
+  module_->C2 = c2_value_;
+  module_->PFIFO =
+      M_UART_TXFE /* Enable TX FIFO */ | M_UART_RXFE /* Enable RX FIFO */;
+  module_->CFIFO =
+      M_UART_TXFLUSH /* Flush TX FIFO */ | M_UART_RXFLUSH /* Flush RX FIFO */;
+  // TODO(Brian): Adjust for DMA?
+  module_->TWFIFO = tx_fifo_size_ - 1;
+  module_->RWFIFO = rx_fifo_size_ - 1;
+}
+
+void Uart::DoWrite(gsl::span<char> data) {
+  for (int i = 0; i < data.size(); ++i) {
+    while (!SpaceAvailable()) {
+    }
+    WriteCharacter(data[i]);
+  }
+}
+
+Uart::~Uart() { DisableTransmitInterrupt(); }
+
+void InterruptBufferedUart::Initialize(int baud_rate) {
+  uart_.Initialize(baud_rate);
+}
+
+void InterruptBufferedUart::Write(gsl::span<char> data,
+                                  const DisableInterrupts &disable_interrupts) {
+  uart_.EnableTransmitInterrupt();
+  static_assert(buffer_.size() >= 8,
+                "Need enough space to not turn the interrupt off each time");
+  while (!data.empty()) {
+    const int bytes_written = buffer_.PushSpan(data);
+    data = data.subspan(bytes_written);
+    WriteCharacters(data.empty(), disable_interrupts);
+  }
+}
+
+void InterruptBufferedUart::WriteCharacters(bool disable_empty,
+                                            const DisableInterrupts &) {
+  while (true) {
+    if (buffer_.empty()) {
+      if (disable_empty) {
+        uart_.DisableTransmitInterrupt();
+      }
+      return;
+    }
+    if (!uart_.SpaceAvailable()) {
+      return;
+    }
+    uart_.WriteCharacter(buffer_.PopSingle());
+  }
+}
+
+}  // namespace teensy
+}  // namespace frc971