merging in the most recent version of everything else
diff --git a/aos/atom_code/camera/Buffers.cpp b/aos/atom_code/camera/Buffers.cpp
index 9cd1a7d..d0d20f5 100644
--- a/aos/atom_code/camera/Buffers.cpp
+++ b/aos/atom_code/camera/Buffers.cpp
@@ -23,18 +23,15 @@
   } addr;
   const int r = socket(AF_UNIX, SOCK_STREAM, 0);
   if (r == -1) {
-    LOG(ERROR, "socket(AF_UNIX, SOCK_STREAM, 0) failed with %d: %s\n",
+    LOG(FATAL, "socket(AF_UNIX, SOCK_STREAM, 0) failed with %d: %s\n",
         errno, strerror(errno));
-    return -1;
   }
   addr.un.sun_family = AF_UNIX;
   memset(addr.un.sun_path, 0, sizeof(addr.un.sun_path));
   strcpy(addr.un.sun_path, kFDServerName.c_str());
   if (bind_connect(r, &addr.addr, sizeof(addr.un)) == -1) {
-    LOG(ERROR, "bind_connect(=%p)(%d, %p, %zd) failed with %d: %s\n",
+    LOG(FATAL, "bind_connect(=%p)(%d, %p, %zd) failed with %d: %s\n",
         bind_connect, r, &addr.addr, sizeof(addr.un), errno, strerror(errno));
-    close(r); // what are we going to do about an error?
-    return -1;
   }
   return r;
 }
diff --git a/aos/atom_code/camera/Reader.cpp b/aos/atom_code/camera/Reader.cpp
index 95f6128..125fde1 100644
--- a/aos/atom_code/camera/Reader.cpp
+++ b/aos/atom_code/camera/Reader.cpp
@@ -391,7 +391,7 @@
       }
 
       if (FD_ISSET(fd_, &fds)) {
-        LOG(INFO, "Got a frame\n");
+        LOG(DEBUG, "Got a frame\n");
         ReadFrame();
       }
       if (FD_ISSET(server_fd_, &fds)) {
diff --git a/aos/atom_code/configuration.cc b/aos/atom_code/configuration.cc
index a5dd4ee..2d6dab8 100644
--- a/aos/atom_code/configuration.cc
+++ b/aos/atom_code/configuration.cc
@@ -35,7 +35,8 @@
     if (addrs->ifa_addr->sa_family == AF_INET) {
       if (strcmp(kAtomNetInterface, addrs->ifa_name) == 0) {
         static const in_addr r =
-            reinterpret_cast<sockaddr_in *>(addrs->ifa_addr)->sin_addr;
+            reinterpret_cast<sockaddr_in *>(__builtin_assume_aligned(
+                addrs->ifa_addr, alignof(sockaddr_in)))->sin_addr;
         return &r;
       }
     }
diff --git a/aos/atom_code/core/LogFileCommon.h b/aos/atom_code/core/LogFileCommon.h
index 3798b06..8c1bd7b 100644
--- a/aos/atom_code/core/LogFileCommon.h
+++ b/aos/atom_code/core/LogFileCommon.h
@@ -132,15 +132,18 @@
         sizeof(mutex) > kPageSize) {
       char *const temp = current_;
       MapNextPage();
-      if (futex_set_value(reinterpret_cast<mutex *>(&temp[position_]), 2) == -1) {
-        fprintf(stderr, "LogFileCommon: futex_set_value(%p, 2) failed with %d: %s."
-                " readers will hang\n", &temp[position_], errno, strerror(errno));
+      if (futex_set_value(static_cast<mutex *>(static_cast<void *>(
+                      &temp[position_])), 2) == -1) {
+        fprintf(stderr,
+                "LogFileCommon: futex_set_value(%p, 2) failed with %d: %s."
+                " readers will hang\n",
+                &temp[position_], errno, strerror(errno));
       }
       Unmap(temp);
       position_ = 0;
     }
-    LogFileMessageHeader *const r = reinterpret_cast<LogFileMessageHeader *>(
-        &current_[position_]);
+    LogFileMessageHeader *const r = static_cast<LogFileMessageHeader *>(
+        static_cast<void *>(&current_[position_]));
     position_ += message_size;
     // keep it aligned for next time
     position_ += kAlignment - (position_ % kAlignment);
@@ -150,7 +153,8 @@
   const LogFileMessageHeader *ReadNextMessage(bool wait) {
     LogFileMessageHeader *r;
     do {
-      r = reinterpret_cast<LogFileMessageHeader *>(&current_[position_]);
+      r = static_cast<LogFileMessageHeader *>(
+          static_cast<void *>(&current_[position_]));
       if (wait) {
         if (futex_wait(&r->marker) != 0) continue;
       }
@@ -158,7 +162,7 @@
         Unmap(current_);
         MapNextPage();
         position_ = 0;
-        r = reinterpret_cast<LogFileMessageHeader *>(current_);
+        r = static_cast<LogFileMessageHeader *>(static_cast<void *>(current_));
       }
     } while (wait && r->marker == 0);
     if (r->marker == 0) {
diff --git a/aos/atom_code/init.cc b/aos/atom_code/init.cc
index c4e6d44..033a206 100644
--- a/aos/atom_code/init.cc
+++ b/aos/atom_code/init.cc
@@ -30,9 +30,9 @@
     }
     rlim.rlim_cur = soft;
     if (setrlimit64(resource, &rlim) == -1) {
-      Die("%s-init: setrlimit64(%d, {cur=%jd,max=%jd})"
+      Die("%s-init: setrlimit64(%d, {cur=%ju,max=%ju})"
           " failed with %d (%s)\n", program_invocation_short_name,
-          resource, (intmax_t)rlim.rlim_cur, (intmax_t)rlim.rlim_max,
+          resource, (uintmax_t)rlim.rlim_cur, (uintmax_t)rlim.rlim_max,
           errno, strerror(errno));
     }
   }
@@ -81,7 +81,7 @@
 
 void InitNRT() { DoInitNRT(aos_core_create::reference); }
 void InitCreate() { DoInitNRT(aos_core_create::create); }
-void Init() {
+void Init(int relative_priority) {
   if (getenv(kNoRealtimeEnvironmentVariable) == NULL) {  // if nobody set it
     LockAllMemory();
     // Only let rt processes run for 1 second straight.
@@ -90,7 +90,7 @@
     SetSoftRLimit(RLIMIT_RTPRIO, 40, false);
     // Set our process to priority 40.
     struct sched_param param;
-    param.sched_priority = 40;
+    param.sched_priority = 30 + relative_priority;
     if (sched_setscheduler(0, SCHED_FIFO, &param) != 0) {
       Die("%s-init: setting SCHED_FIFO failed with %d (%s)\n",
           program_invocation_short_name, errno, strerror(errno));
diff --git a/aos/atom_code/init.h b/aos/atom_code/init.h
index ffb7afc..b35a3b8 100644
--- a/aos/atom_code/init.h
+++ b/aos/atom_code/init.h
@@ -6,7 +6,9 @@
 // Does the non-realtime parts of the initialization process.
 void InitNRT();
 // Initializes everything, including the realtime stuff.
-void Init();
+// relative_priority adjusts the priority of this process relative to all of the
+// other ones (positive for higher priority).
+void Init(int relative_priority = 0);
 // Same as InitNRT, except will remove an existing shared memory file and create
 // a new one.
 void InitCreate();
diff --git a/aos/atom_code/input/JoystickInput.cpp b/aos/atom_code/input/JoystickInput.cpp
deleted file mode 100644
index 2c3b3b9..0000000
--- a/aos/atom_code/input/JoystickInput.cpp
+++ /dev/null
@@ -1,73 +0,0 @@
-#include "aos/atom_code/input/JoystickInput.h"
-
-#include "aos/common/Configuration.h"
-#include "aos/common/network/ReceiveSocket.h"
-#include "aos/common/messages/RobotState.q.h"
-
-namespace aos {
-
-void JoystickInput::SetupButtons() {
-  for (int i = 0; i < 4; ++i) {
-    old_buttons[i] = buttons[i];
-  }
-  buttons[0] = control_data_.stick0Buttons;
-  buttons[1] = control_data_.stick1Buttons;
-  buttons[2] = control_data_.stick2Buttons;
-  buttons[3] = control_data_.stick3Buttons;
-
-  // Put the ENABLED, AUTONOMOUS, and FMS_ATTACHED values into unused bits in
-  // the values for joystick 0 so that PosEdge and NegEdge can be used with
-  // them.
-  // Windows only supports 12 buttons, so we know there will never be any more.
-  // Not using MASK because it doesn't make it any cleaner.
-  buttons[0] |= (control_data_.enabled << (ENABLED - 9)) |
-      (control_data_.autonomous << (AUTONOMOUS - 9)) |
-      (control_data_.fmsAttached << (FMS_ATTACHED - 9));
-
-  for (int j = 0; j < 4; ++j) {
-    for (int k = 1; k <= 12; ++k) {
-      if (PosEdge(j, k)) {
-        LOG(INFO, "PosEdge(%d, %d)\n", j, k);
-      }
-      if (NegEdge(j, k)) {
-        LOG(INFO, "NegEdge(%d, %d)\n", j, k);
-      }
-    }
-  }
-  if (PosEdge(0, ENABLED)) LOG(INFO, "PosEdge(ENABLED)\n");
-  if (NegEdge(0, ENABLED)) LOG(INFO, "NegEdge(ENABLED)\n");
-  if (PosEdge(0, AUTONOMOUS)) LOG(INFO, "PosEdge(AUTONOMOUS)\n");
-  if (NegEdge(0, AUTONOMOUS)) LOG(INFO, "NegEdge(AUTONOMOUS)\n");
-  if (PosEdge(0, FMS_ATTACHED)) LOG(INFO, "PosEdge(FMS_ATTACHED)\n");
-  if (NegEdge(0, FMS_ATTACHED)) LOG(INFO, "NegEdge(FMS_ATTACHED)\n");
-}
-
-void JoystickInput::Run() {
-  ReceiveSocket sock(NetworkPort::kDS);
-  while (true) {
-    if (sock.Receive(&control_data_, sizeof(control_data_)) !=
-        sizeof(control_data_)) {
-      LOG(WARNING, "socket receive failed\n");
-      continue;
-    }
-    SetupButtons();
-    if (!robot_state.MakeWithBuilder()
-        .enabled(Pressed(0, ENABLED))
-        .autonomous(Pressed(0, AUTONOMOUS))
-        .team_id(ntohs(control_data_.teamID))
-        .Send()) {
-			LOG(WARNING, "sending robot_state failed\n");
-		}
-		if (robot_state.FetchLatest()) {
-    	char state[1024];
-    	robot_state->Print(state, sizeof(state));
-    	LOG(DEBUG, "robot_state={%s}\n", state);
-		} else {
-			LOG(WARNING, "fetching robot_state failed\n");
-		}
-    RunIteration();
-  }
-}
-
-}  // namespace aos
-
diff --git a/aos/atom_code/input/JoystickInput.h b/aos/atom_code/input/JoystickInput.h
deleted file mode 100644
index 313ad0a..0000000
--- a/aos/atom_code/input/JoystickInput.h
+++ /dev/null
@@ -1,46 +0,0 @@
-#ifndef AOS_INPUT_JOYSTICK_INPUT_H_
-#define AOS_INPUT_JOYSTICK_INPUT_H_
-
-#include "FRCComm.h"
-
-namespace aos {
-
-// Class for implementing atom code that reads the joystick values from the
-// cRIO.
-// Designed for a subclass that implements RunIteration to be instantiated and
-// Runed.
-// TODO(brians): rewrite this with OO buttons/fms state etc
-class JoystickInput {
- private:
-  uint16_t buttons[4], old_buttons[4];
-  inline uint16_t MASK(int button) {
-    return 1 << ((button > 8) ? (button - 9) : (button + 7));
-  }
-  void SetupButtons();
- protected:
-  FRCCommonControlData control_data_;
-
-  // Constants that retrieve data when used with joystick 0.
-  static const int ENABLED = 13;
-  static const int AUTONOMOUS = 14;
-  static const int FMS_ATTACHED = 15;
-  bool Pressed(int stick, int button) {
-	  return buttons[stick] & MASK(button);
-  }
-  bool PosEdge(int stick, int button) {
-	  return !(old_buttons[stick] & MASK(button)) && (buttons[stick] & MASK(button));
-  }
-  bool NegEdge(int stick, int button) {
-	  return (old_buttons[stick] & MASK(button)) && !(buttons[stick] & MASK(button));
-  }
-
-  virtual void RunIteration() = 0;
- public:
-  // Enters an infinite loop that reads values and calls RunIteration.
-  void Run();
-};
-
-} // namespace aos
-
-#endif
-
diff --git a/aos/atom_code/input/joystick_input.cc b/aos/atom_code/input/joystick_input.cc
index 28618ed..97b2c95 100644
--- a/aos/atom_code/input/joystick_input.cc
+++ b/aos/atom_code/input/joystick_input.cc
@@ -62,6 +62,26 @@
           }
         }
       }
+
+      using driver_station::ControlBit;
+      if (data.PosEdge(ControlBit::kFmsAttached)) {
+        LOG(INFO, "PosEdge(kFmsAttached)\n");
+      }
+      if (data.NegEdge(ControlBit::kFmsAttached)) {
+        LOG(INFO, "NegEdge(kFmsAttached)\n");
+      }
+      if (data.PosEdge(ControlBit::kAutonomous)) {
+        LOG(INFO, "PosEdge(kAutonomous)\n");
+      }
+      if (data.NegEdge(ControlBit::kAutonomous)) {
+        LOG(INFO, "NegEdge(kAutonomous)\n");
+      }
+      if (data.PosEdge(ControlBit::kEnabled)) {
+        LOG(INFO, "PosEdge(kEnabled)\n");
+      }
+      if (data.NegEdge(ControlBit::kEnabled)) {
+        LOG(INFO, "NegEdge(kEnabled)\n");
+      }
     }
 
     RunIteration(data);
diff --git a/aos/atom_code/ipc_lib/aos_sync.c b/aos/atom_code/ipc_lib/aos_sync.c
index 1980a4d..18e65a7 100644
--- a/aos/atom_code/ipc_lib/aos_sync.c
+++ b/aos/atom_code/ipc_lib/aos_sync.c
@@ -10,7 +10,13 @@
 #include <string.h>
 #include <inttypes.h>
 
-#include "cmpxchg.h"
+// TODO(brians): Inline these in the new PI version.
+#define cmpxchg(ptr, o, n) __sync_val_compare_and_swap(ptr, o, n)
+static inline uint32_t xchg(mutex *pointer, uint32_t value) {
+  uint32_t result;
+  __atomic_exchange(pointer, &value, &result, __ATOMIC_SEQ_CST);
+  return result;
+}
 
 // this code is based on something that appears to be based on <http://www.akkadia.org/drepper/futex.pdf>, which also has a lot of useful information
 // should probably use <http://lxr.linux.no/linux+v2.6.34/Documentation/robust-futexes.txt> once it becomes available
diff --git a/aos/atom_code/ipc_lib/cmpxchg.h b/aos/atom_code/ipc_lib/cmpxchg.h
deleted file mode 100644
index 715c57d..0000000
--- a/aos/atom_code/ipc_lib/cmpxchg.h
+++ /dev/null
@@ -1,153 +0,0 @@
-#ifndef __ASM_CMPXCHG_H
-#define __ASM_CMPXCHG_H
-
-#include <stdint.h>
-
-//TODO implement xchg using gcc's atomic builtins (http://gcc.gnu.org/onlinedocs/gcc-4.1.1/gcc/Atomic-Builtins.html)
-//or maybe http://gcc.gnu.org/onlinedocs/gcc/_005f_005fatomic-Builtins.html
-//__atomic_fetch_sub looks promising
-
-#define cmpxchg(ptr, o, n) __sync_val_compare_and_swap(ptr, o, n)
-/*#define xchg(ptr, n) ({typeof(*ptr) r; \
-    do{ \
-      r = *ptr; \
-    }while(!__sync_bool_compare_and_swap(ptr, r, n)); \
-    r; \
-})*/
-
-#  define LOCK "lock;"
-#  define LOCK_PREFIX "lock;"
-
-#define xchg(ptr,v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v),(ptr),sizeof(*(ptr))))
-
-#define __xg(x) ((volatile long long *)(x))
-
-/*static inline void set_64bit(volatile unsigned long *ptr, unsigned long val)
-{
-  *ptr = val;
-}
-
-#define _set_64bit set_64bit*/
-
-/*
- * Note: no "lock" prefix even on SMP: xchg always implies lock anyway
- * Note 2: xchg has side effect, so that attribute volatile is necessary,
- *    but generally the primitive is invalid, *ptr is output argument. --ANK
- */
-static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
-{
-  switch (size) {
-    case 1:
-      __asm__ __volatile__("xchgb %b0,%1"
-          :"=q" (x)
-          :"m" (*__xg(ptr)), "0" (x)
-          :"memory");
-      break;
-    case 2:
-      __asm__ __volatile__("xchgw %w0,%1"
-          :"=r" (x)
-          :"m" (*__xg(ptr)), "0" (x)
-          :"memory");
-      break;
-    case 4:
-      __asm__ __volatile__("xchgl %k0,%1"
-          :"=r" (x)
-          :"m" (*__xg(ptr)), "0" (x)
-          :"memory");
-      break;
-    case 8:
-      __asm__ __volatile__("xchg %0,%1"
-          :"=r" (x)
-          :"m" (*__xg(ptr)), "0" (x)
-          :"memory");
-      break;
-  }
-  return x;
-}
-
-/*
- * Atomic compare and exchange.  Compare OLD with MEM, if identical,
- * store NEW in MEM.  Return the initial value in MEM.  Success is
- * indicated by comparing RETURN with OLD.
- */
-
-#if 0
-
-#define __HAVE_ARCH_CMPXCHG 1
-
-static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
-    unsigned long new, int size)
-{
-  int32_t prev;
-  switch (size) {
-    case 1:
-      __asm__ __volatile__(LOCK_PREFIX "cmpxchgb %b1,%2"
-            : "=a"(prev)
-            : "q"(new), "m"(*__xg(ptr)), "0"(old)
-            : "memory");
-      return prev;
-    case 2:
-      __asm__ __volatile__(LOCK_PREFIX "cmpxchgw %w1,%2"
-            : "=a"(prev)
-            : "r"(new), "m"(*__xg(ptr)), "0"(old)
-            : "memory");
-      return prev;
-    case 4:
-      __asm__ __volatile__(LOCK_PREFIX "cmpxchgl %k1,%2"
-            : "=a"(prev)
-            : "r"(new), "m"(*__xg(ptr)), "0"(old)
-            : "memory");
-      return prev;
-    case 8:
-      __asm__ __volatile__("lock; cmpxchg %1,%2"
-            : "=a"(prev)
-            : "q"(new), "m"(*__xg(ptr)), "0"(old)
-            : "memory");
-      return prev;
-  }
-  return old;
-}
-
-/*
-static inline unsigned long __cmpxchg_local(volatile void *ptr,
-      unsigned long old, unsigned long new, int size)
-{
-  unsigned long prev;
-  switch (size) {
-  case 1:
-    __asm__ __volatile__("cmpxchgb %b1,%2"
-             : "=a"(prev)
-             : "q"(new), "m"(*__xg(ptr)), "0"(old)
-             : "memory");
-    return prev;
-  case 2:
-    __asm__ __volatile__("cmpxchgw %w1,%2"
-             : "=a"(prev)
-             : "r"(new), "m"(*__xg(ptr)), "0"(old)
-             : "memory");
-    return prev;
-  case 4:
-    __asm__ __volatile__("cmpxchgl %k1,%2"
-             : "=a"(prev)
-             : "r"(new), "m"(*__xg(ptr)), "0"(old)
-             : "memory");
-    return prev;
-  case 8:
-    __asm__ __volatile__("cmpxchgq %1,%2"
-             : "=a"(prev)
-             : "r"(new), "m"(*__xg(ptr)), "0"(old)
-             : "memory");
-    return prev;
-  }
-  return old;
-}*/
-
-#define cmpxchg(ptr,o,n)\
-  ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
-          (unsigned long)(n),sizeof(*(ptr))))
-/*#define cmpxchg_local(ptr,o,n)\
-  ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
-          (unsigned long)(n),sizeof(*(ptr))))*/
-#endif
-
-#endif
diff --git a/aos/atom_code/ipc_lib/core_lib.c b/aos/atom_code/ipc_lib/core_lib.c
index bbd2f5b..c83dbe4 100644
--- a/aos/atom_code/ipc_lib/core_lib.c
+++ b/aos/atom_code/ipc_lib/core_lib.c
@@ -9,7 +9,8 @@
   return (l > r) ? l : r;
 }
 void *shm_malloc_aligned(size_t length, uint8_t alignment) {
-  // minimum alignments from <http://software.intel.com/en-us/articles/data-alignment-when-migrating-to-64-bit-intel-architecture/>
+  // minimum alignments from
+  // <http://software.intel.com/en-us/articles/data-alignment-when-migrating-to-64-bit-intel-architecture/>
   if (length <= 1) {
     alignment = aos_8max(alignment, 1);
   } else if (length <= 2) {
diff --git a/aos/atom_code/ipc_lib/queue.cc b/aos/atom_code/ipc_lib/queue.cc
index 7ab7b6c..018f03a 100644
--- a/aos/atom_code/ipc_lib/queue.cc
+++ b/aos/atom_code/ipc_lib/queue.cc
@@ -39,9 +39,9 @@
   int ref_count;
   int index;  // in pool_
   static MessageHeader *Get(const void *msg) {
-    return reinterpret_cast<MessageHeader *>(
-        static_cast<uint8_t *>(const_cast<void *>(msg)) -
-        sizeof(MessageHeader));
+    return reinterpret_cast<MessageHeader *>(__builtin_assume_aligned(
+        static_cast<uint8_t *>(const_cast<void *>(msg)) - sizeof(MessageHeader),
+        alignof(MessageHeader)));
   }
   void Swap(MessageHeader *other) {
     MessageHeader temp;
diff --git a/aos/atom_code/ipc_lib/shared_mem.c b/aos/atom_code/ipc_lib/shared_mem.c
index e2c2c9e..5b1231c 100644
--- a/aos/atom_code/ipc_lib/shared_mem.c
+++ b/aos/atom_code/ipc_lib/shared_mem.c
@@ -13,8 +13,10 @@
 // the path for the shared memory segment. see shm_open(3) for restrictions
 #define AOS_SHM_NAME "/aos_shared_mem"
 // Size of the shared mem segment.
-// set to the maximum number that worked
-#define SIZEOFSHMSEG (4096 * 27813)
+// Set to the maximum number that worked. Any bigger than this and the kernel
+// thinks you should be able to access all of it but it doesn't work with the
+// ARM kernel Brian was using on 2013-12-20.
+#define SIZEOFSHMSEG (4096 * 25074)
 
 void init_shared_mem_core(aos_shm_core *shm_core) {
   clock_gettime(CLOCK_REALTIME, &shm_core->identifier);
diff --git a/aos/atom_code/output/motor_output.cc b/aos/atom_code/output/motor_output.cc
index b68dcad..48acc38 100644
--- a/aos/atom_code/output/motor_output.cc
+++ b/aos/atom_code/output/motor_output.cc
@@ -17,13 +17,19 @@
 
 uint8_t MotorOutput::MotorControllerBounds::Map(double value) const {
   if (value == 0.0) return kCenter;
+  if (value > 12.0) return Map(12.0);
+  if (value < -12.0) return Map(-12.0);
+  uint8_t r;
   if (value > 0.0) {
-    return static_cast<uint8_t>(kDeadbandMax + (value * (kMax - kDeadbandMax)) +
-                                0.5);
+    r = static_cast<uint8_t>(kDeadbandMax + (value * (kMax - kDeadbandMax)) +
+                             0.5);
   } else {
-    return static_cast<uint8_t>(kDeadbandMin + (value * (kDeadbandMin - kMin)) +
-                                0.5);
+    r = static_cast<uint8_t>(kDeadbandMin + (value * (kDeadbandMin - kMin)) +
+                             0.5);
   }
+  if (r < kMin) return kMin;
+  if (r > kMax) return kMax;
+  return r;
 }
 
 MotorOutput::MotorOutput()
diff --git a/aos/atom_code/queue-tmpl.h b/aos/atom_code/queue-tmpl.h
index 0cc9392..15b8608 100644
--- a/aos/atom_code/queue-tmpl.h
+++ b/aos/atom_code/queue-tmpl.h
@@ -23,7 +23,7 @@
 template <class T>
 void ScopedMessagePtr<T>::reset(T *msg) {
   if (queue_ != NULL && msg_ != NULL) {
-    queue_->FreeMessage(msg);
+    queue_->FreeMessage(msg_);
   }
   msg_ = msg;
 }
diff --git a/aos/atom_code/starter/starter.cc b/aos/atom_code/starter/starter.cc
index 4534ebc..bef4e73 100644
--- a/aos/atom_code/starter/starter.cc
+++ b/aos/atom_code/starter/starter.cc
@@ -198,8 +198,9 @@
       }
 
       notifyevt = reinterpret_cast<inotify_event *>(
-          reinterpret_cast<char *>(notifyevt) +
-          sizeof(*notifyevt) + notifyevt->len);
+          __builtin_assume_aligned(reinterpret_cast<char *>(notifyevt) +
+                                       sizeof(*notifyevt) + notifyevt->len,
+                                   alignof(notifyevt)));
     }
   }
 
diff --git a/aos/build/aos.gypi b/aos/build/aos.gypi
index 9eeba08..f27361b 100644
--- a/aos/build/aos.gypi
+++ b/aos/build/aos.gypi
@@ -23,17 +23,17 @@
   'conditions': [
     ['OS=="crio"', {
         'make_global_settings': [
-          ['CC', '<!(which powerpc-wrs-vxworks-gcc)'],
-          ['CXX', '<!(which powerpc-wrs-vxworks-g++)'],
-          ['LD', '<!(readlink -f <(AOS)/build/crio_link_out)'],
-          #['LD', 'powerpc-wrs-vxworks-ld'],
-          #['AR', '<!(which powerpc-wrs-vxworks-ar)'],
-          #['NM', '<!(which powerpc-wrs-vxworks-nm)'],
+          ['CC', '<!(readlink -f <(AOS)/build/crio_cc)'],
+          ['CXX', '<!(readlink -f <(AOS)/build/crio_cxx)'],
         ],
         'variables': {
           'aos_target': 'static_library',
         },
       }, {
+        'make_global_settings': [
+          ['CC', '<!(which arm-linux-gnueabihf-gcc-4.7)'],
+          ['CXX', '<!(which arm-linux-gnueabihf-g++-4.7)'],
+        ],
         'variables': {
           'aos_target': 'executable',
         },
@@ -103,8 +103,8 @@
               ],
             }, {
               'cflags': [
-                '-march=atom',
-                '-mfpmath=sse',
+                '-mcpu=cortex-a8',
+                '-mfpu=neon',
 
                 '-fstack-protector-all',
               ],
@@ -134,10 +134,10 @@
             '-mcpu=603e',
             '-mstrict-align',
             '-mlongcall',
-            '-isystem', '<(aos_abs)/externals/gccdist/WindRiver/gnu/3.4.4-vxworks-6.3/x86-win32/lib/gcc/powerpc-wrs-vxworks/3.4.4/include/',
-            '-isystem', '<(aos_abs)/externals/gccdist/WindRiver/vxworks-6.3/target/h/',
-            '-isystem', '<(aos_abs)/externals/gccdist/WindRiver/gnu/3.4.4-vxworks-6.3/x86-win32/include/c++/3.4.4/',
-            '-isystem', '<(aos_abs)/externals/gccdist/WindRiver/gnu/3.4.4-vxworks-6.3/x86-win32/include/c++/3.4.4/powerpc-wrs-vxworks/',
+            '-isystem', '<(aos_abs)/../output/downloaded/gccdist/WindRiver/gnu/3.4.4-vxworks-6.3/x86-win32/lib/gcc/powerpc-wrs-vxworks/3.4.4/include/',
+            '-isystem', '<(aos_abs)/../output/downloaded/gccdist/WindRiver/vxworks-6.3/target/h/',
+            '-isystem', '<(aos_abs)/../output/downloaded/gccdist/WindRiver/gnu/3.4.4-vxworks-6.3/x86-win32/include/c++/3.4.4/',
+            '-isystem', '<(aos_abs)/../output/downloaded/gccdist/WindRiver/gnu/3.4.4-vxworks-6.3/x86-win32/include/c++/3.4.4/powerpc-wrs-vxworks/',
             '-isystem', '<(WIND_BASE)/target/h',
             '-isystem', '<(WIND_BASE)/target/h/wrn/coreip',
           ],
@@ -179,19 +179,17 @@
           ],
           'ldflags': [
             '-pthread',
-            '-m32',
-          ],
-          'library_dirs': [
-            '/usr/lib32',
           ],
           'cflags': [
             '-pthread',
-            '-m32',
 
             '-Wunused-local-typedefs',
 
             # Give macro stack traces when they blow up.
-            '-ftrack-macro-expansion',
+            # TODO(brians): Re-enable this once they fix the bug where it
+            # sometimes doesn't show you the top-most (aka most useful)
+            # line of code.
+            #'-ftrack-macro-expansion',
           ],
           'cflags_cc': [
             '-std=gnu++11',
diff --git a/aos/build/aos_all.gyp b/aos/build/aos_all.gyp
index e4a9b6f..0629be5 100644
--- a/aos/build/aos_all.gyp
+++ b/aos/build/aos_all.gyp
@@ -20,10 +20,10 @@
         '../common/common.gyp:queue_test',
         '../common/common.gyp:die_test',
         '../common/util/util.gyp:trapezoid_profile_test',
-        '../common/sensors/sensors.gyp:sensor_receiver_test',
+        '../common/util/util.gyp:wrapping_counter_test',
+        '<(DEPTH)/bbb_cape/src/bbb/bbb.gyp:cows_test',
+        '<(DEPTH)/bbb_cape/src/bbb/bbb.gyp:packet_finder_test',
         'Common',
-        # TODO(brians): move this to Common
-        '<(AOS)/common/sensors/sensors.gyp:sensors_test',
       ],
     },
     {
diff --git a/aos/build/build.sh b/aos/build/build.sh
index 2bf6982..09fe83c 100755
--- a/aos/build/build.sh
+++ b/aos/build/build.sh
@@ -1,50 +1,56 @@
-#!/bin/bash -e
+#!/bin/bash
 #set -x
 
+set -e
+
 # This file should be called to build the code.
-# Usage: build.sh platform main_file.gyp debug [action]
+# Usage: build.sh platform main_file.gyp debug [action]...
 
 PLATFORM=$1
 GYP_MAIN=$2
 DEBUG=$3
 ACTION=$4
 
+shift 3
+shift || true # We might not have a 4th argument if ACTION is empty.
+
 export WIND_BASE=${WIND_BASE:-"/usr/local/powerpc-wrs-vxworks/wind_base"}
 
-[ ${PLATFORM} == "crio" -o ${PLATFORM} == "atom" ] || ( echo Platform "(${PLATFORM})" must be '"crio" or "atom"'. ; exit 1 )
-[ ${DEBUG} == "yes" -o ${DEBUG} == "no" ] || ( echo Debug "(${DEBUG})" must be '"yes" or "no"'. ; exit 1 )
+[ "${PLATFORM}" == "crio" -o "${PLATFORM}" == "atom" ] || ( echo Platform "(${PLATFORM})" must be '"crio" or "atom"'. ; exit 1 )
+[ "${DEBUG}" == "yes" -o "${DEBUG}" == "no" ] || ( echo Debug "(${DEBUG})" must be '"yes" or "no"'. ; exit 1 )
 
 AOS=`dirname $0`/..
-NINJA_DIR=${AOS}/externals/ninja
-NINJA=${NINJA_DIR}/ninja
-# From chromium@154360:trunk/src/DEPS.
-GYP_REVISION=1488
-GYP_DIR=${AOS}/externals/gyp-${GYP_REVISION}
-GYP=${GYP_DIR}/gyp
 
-OUTDIR=${AOS}/../out_${PLATFORM}
-BUILD_NINJA=${OUTDIR}/Default/build.ninja
+OUTDIR=${AOS}/../output/${PLATFORM}
+BUILD_NINJA=${OUTDIR}/build.ninja
 
-[ -d ${NINJA_DIR} ] || git clone --branch release https://github.com/martine/ninja.git ${NINJA_DIR}
-[ -x ${NINJA} ] || ${NINJA_DIR}/bootstrap.py
-[ -d ${GYP_DIR} ] || ( svn co http://gyp.googlecode.com/svn/trunk -r ${GYP_REVISION} ${GYP_DIR} && patch -p1 -d ${GYP_DIR} < ${AOS}/externals/gyp.patch )
 ${AOS}/build/download_externals.sh
+. $(dirname $0)/tools_config
 
 # The exciting quoting is so that it ends up with -DWHATEVER='"'`a command`'"'.
 # The '"' at either end is so that it creates a string constant when expanded
 #   in the C/C++ code.
 COMMONFLAGS='-DLOG_SOURCENAME='"'\"'"'`basename $in`'"'\"' "
-if [ ${PLATFORM} == crio ]; then
-  COMMONFLAGS+='-DAOS_INITNAME=aos_init_function_`readlink -f $out | sed \"s/[\/.]/_/g\"` '
-fi
 
 if [[ "${ACTION}" != "clean" && ( ! -d ${OUTDIR} || -n \
   			"`find ${AOS}/.. -newer ${BUILD_NINJA} \( -name '*.gyp' -or -name '*.gypi' \)`" ) ]]; then
-  ${GYP} \
-    --check --depth=${AOS}/.. --no-circular-check -f ninja \
-    -I${AOS}/build/aos.gypi -Goutput_dir=out_${PLATFORM} \
-    -DOS=${PLATFORM} -DWIND_BASE=${WIND_BASE} -DDEBUG=${DEBUG} \
-    ${GYP_MAIN}
+  # This is a gyp "file" that we pipe into gyp so that it will put the output
+  # in a directory named what we want where we want it.
+  GYP_INCLUDE=$(cat <<END
+{
+  'target_defaults': {
+    'configurations': {
+	  '${PLATFORM}': {}
+    }
+  }
+}
+END
+)
+  echo "${GYP_INCLUDE}" | ${GYP} \
+      --check --depth=${AOS}/.. --no-circular-check -f ninja \
+      -I${AOS}/build/aos.gypi -I/dev/stdin -Goutput_dir=output \
+      -DOS=${PLATFORM} -DWIND_BASE=${WIND_BASE} -DDEBUG=${DEBUG} \
+      ${GYP_MAIN}
   # Have to substitute "command = $compiler" so that it doesn't try to
   #   substitute them in the linker commands, where it doesn't work.
   sed -i "s:command = \$cc:\\0 ${COMMONFLAGS}:g ; \
@@ -56,34 +62,35 @@
 fi
 
 if [ "${ACTION}" == "clean" ]; then
-  rm -r ${OUTDIR}
+  rm -r ${OUTDIR} || true
 else
   if [ "${ACTION}" != "deploy" -a "${ACTION}" != "tests" -a "${ACTION}" != "redeploy" ]; then
-    GYP_ACTION=${ACTION}
+    NINJA_ACTION=${ACTION}
   else
-    GYP_ACTION=
+    NINJA_ACTION=
   fi
-  ${NINJA} -C ${OUTDIR}/Default ${GYP_ACTION}
+  ${NINJA} -C ${OUTDIR} ${NINJA_ACTION} "$@"
   if [[ ${ACTION} == deploy || ${ACTION} == redeploy ]]; then
     [ ${PLATFORM} == atom ] && \
       rsync --progress -c -r \
-      ${OUTDIR}/Default/outputs/* \
-      driver@`${AOS}/build/get_ip fitpc`:/home/driver/robot_code/bin
+        ${OUTDIR}/outputs/* \
+        driver@`${AOS}/build/get_ip fitpc`:/home/driver/robot_code/bin
+	  ssh driver@`${AOS}/build/get_ip fitpc` "sync; sync; sync"
     [ ${PLATFORM} == crio ] && \
       ncftpput `${AOS}/build/get_ip robot` / \
-      ${OUTDIR}/Default/lib/FRC_UserProgram.out
+      ${OUTDIR}/lib/FRC_UserProgram.out
   fi
   if [[ ${ACTION} == redeploy ]]; then
     if [[ ${PLATFORM} != crio ]]; then
       echo "Platform ${PLATFORM} does not support redeploy." 1>&2
       exit 1
     fi
-    ${OUTDIR}/../out_atom/Default/outputs/netconsole <<"END"
+    ${OUTDIR}/../out_atom/outputs/netconsole <<"END"
 unld "FRC_UserProgram.out"
 ld < FRC_UserProgram.out
 END
   fi
   if [[ ${ACTION} == tests ]]; then
-    find ${OUTDIR}/Default/tests -executable -exec ${AOS}/build/run_test.sh {} \;
+    find ${OUTDIR}/tests -executable -exec ${AOS}/build/run_test.sh {} \;
   fi
 fi
diff --git a/aos/build/crio_cc b/aos/build/crio_cc
new file mode 100755
index 0000000..442d3fe
--- /dev/null
+++ b/aos/build/crio_cc
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+# This is a helper script that gets called as a replacement for gcc. It just
+# passes all arguments on unless it is being called as a shared linker.
+
+[ $1 != '-shared' ] && exec powerpc-wrs-vxworks-gcc "$@"
+exec $(dirname $0)/crio_link_out "$@"
diff --git a/aos/build/crio_cxx b/aos/build/crio_cxx
new file mode 100755
index 0000000..ea68e58
--- /dev/null
+++ b/aos/build/crio_cxx
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+# This is a helper script that gets called as a replacement for g++. It just
+# passes all arguments on unless it is being called as a shared linker.
+
+[ $1 != '-shared' ] && exec powerpc-wrs-vxworks-g++ "$@"
+exec $(dirname $0)/crio_link_out "$@"
diff --git a/aos/build/crio_link_out b/aos/build/crio_link_out
index e5a66e7..0630341 100755
--- a/aos/build/crio_link_out
+++ b/aos/build/crio_link_out
@@ -1,7 +1,11 @@
-#!/bin/bash -e
+#!/bin/bash
+#set -x
 
-# This is a helper script that compiles .out files for the cRIO. It is designed
-# to be called as a replacement for g++ being used as a linker.
+set -e
+
+# This is a helper script that compiles .out files for the cRIO. It gets called
+# by the gcc and g++ wrapper scripts if they detect that the tool is being used
+# as a shared linker.
 
 # All the flags except -shared.
 INPUTS_FLAGS=`echo "$@" | sed 's/-shared//g'`
@@ -9,7 +13,6 @@
 OUTPUT=`echo ${INPUTS_FLAGS} | awk \
   'BEGIN { RS=" " }; output { print ; output = 0 }; /-o/ { output = 1 }'`
 # All arguments that don't start with a - and aren't ${OUTPUT}.
-#INPUTS=`echo ${INPUTS_FLAGS} | sed "s:-[^ ]*::g; s:${OUTPUT}::g;"`
 INPUTS=`echo ${INPUTS_FLAGS} | awk \
   'BEGIN { RS=" " }; /-Wl,--no-whole-archive/ { output = 0 }; \
   output { print }; \
@@ -17,7 +20,8 @@
 TEMPDIR=`dirname ${OUTPUT}`
 AOS=`dirname $0`/..
 powerpc-wrs-vxworks-nm ${INPUTS} | \
-  tclsh ${WIND_BASE}/host/resource/hutils/tcl/munch.tcl -c ppc > ${TEMPDIR}/ctdt.c
+  tclsh ${WIND_BASE}/host/resource/hutils/tcl/munch.tcl -c ppc > \
+    ${TEMPDIR}/ctdt.c
 powerpc-wrs-vxworks-gcc -I${AOS}/.. -c ${TEMPDIR}/ctdt.c -o ${TEMPDIR}/ctdt.o
 powerpc-wrs-vxworks-g++ ${INPUTS_FLAGS} ${TEMPDIR}/ctdt.o
 ln -f ${OUTPUT} `echo ${OUTPUT} | sed 's/lib\([A-Za-z0-9_]*\)\.so$/\1.out/'`
diff --git a/aos/build/download_externals.sh b/aos/build/download_externals.sh
index 70b3685..5868637 100755
--- a/aos/build/download_externals.sh
+++ b/aos/build/download_externals.sh
@@ -2,8 +2,32 @@
 
 set -e
 
-AOS=`dirname $0`/..
-EXTERNALS=${AOS}/externals
+AOS=$(readlink -f $(dirname $0)/..)
+. $(dirname $0)/tools_config
+COMPILED=${EXTERNALS}/../compiled-arm
+
+CROSS_COMPILE=arm-linux-gnueabihf-
+
+export CC=${CROSS_COMPILE}gcc-4.7
+export CXX=${CROSS_COMPILE}g++-4.7
+export CFLAGS="-mcpu=cortex-a8 -mfpu=neon"
+export CXXFLAGS="-mcpu=cortex-a8 -mfpu=neon"
+export OBJDUMP=${CROSS_COMPLIE}objdump
+# Flags that should get passed to all configure scripts.
+# Some of them need to set LDFLAGS separately to work around stupid configure
+# scripts, so we can't just set that here.
+CONFIGURE_FLAGS="--host=arm-linux-gnueabihf CC=${CC} CXX=${CXX} CFLAGS=\"${CFLAGS}\" CXXFLAGS=\"${CXXFLAGS}\" OBJDUMP=${OBJDUMP}"
+
+TMPDIR=/tmp/$$-aos-tmpdir
+mkdir -p ${EXTERNALS}
+mkdir -p ${COMPILED}
+
+# get and build ninja
+[ -d ${NINJA_DIR} ] || git clone --branch ${NINJA_RELEASE} https://github.com/martine/ninja.git ${NINJA_DIR}
+[ -x ${NINJA} ] || env -i "PATH=$PATH" ${NINJA_DIR}/bootstrap.py
+
+# get gyp
+[ -d ${GYP_DIR} ] || ( svn co http://gyp.googlecode.com/svn/trunk -r ${GYP_REVISION} ${GYP_DIR} && patch -p1 -d ${GYP_DIR} < ${AOS}/externals/gyp.patch )
 
 # get gccdist
 GCCDIST=${EXTERNALS}/gccdist
@@ -30,75 +54,78 @@
 
 # get and build libjpeg
 LIBJPEG_VERSION=8d
-LIBJPEG_DIR=${EXTERNALS}/jpeg-${LIBJPEG_VERSION}
+LIBJPEG_DIR=${COMPILED}/jpeg-${LIBJPEG_VERSION}
 # NOTE: this directory ends up in #include names
-LIBJPEG_PREFIX=${EXTERNALS}/libjpeg
+LIBJPEG_PREFIX=${COMPILED}/libjpeg
 LIBJPEG_LIB=${LIBJPEG_PREFIX}/lib/libjpeg.a
 LIBJPEG_TAR=${EXTERNALS}/jpegsrc.v${LIBJPEG_VERSION}.tar.gz
 [ -f ${LIBJPEG_TAR} ] || wget http://www.ijg.org/files/jpegsrc.v${LIBJPEG_VERSION}.tar.gz -O ${LIBJPEG_TAR}
 [ -d ${LIBJPEG_DIR} ] || ( mkdir ${LIBJPEG_DIR} && tar --strip-components=1 -C ${LIBJPEG_DIR} -xf ${LIBJPEG_TAR} )
-[ -f ${LIBJPEG_LIB} ] || env -i PATH="${PATH}" bash -c "cd ${LIBJPEG_DIR} && CFLAGS='-m32' ./configure --disable-shared --prefix=`readlink -f ${LIBJPEG_PREFIX}` && make && make install"
+[ -f ${LIBJPEG_LIB} ] || bash -c \
+	"cd ${LIBJPEG_DIR} && ./configure --disable-shared \
+	${CONFIGURE_FLAGS} --prefix=`readlink -f ${LIBJPEG_PREFIX}` \
+	&& make && make install"
 
 # get gtest
 GTEST_VERSION=1.6.0
-GTEST_DIR=${EXTERNALS}/gtest-${GTEST_VERSION}-p2
+GTEST_DIR=${EXTERNALS}/gtest-${GTEST_VERSION}-p1
 GTEST_ZIP=${EXTERNALS}/gtest-${GTEST_VERSION}.zip
-TMPDIR=/tmp/$$-aos-tmpdir
 [ -f ${GTEST_ZIP} ] || wget http://googletest.googlecode.com/files/gtest-${GTEST_VERSION}.zip -O ${GTEST_ZIP}
-[ -d ${GTEST_DIR} ] || ( unzip ${GTEST_ZIP} -d ${TMPDIR} && mv ${TMPDIR}/gtest-${GTEST_VERSION} ${GTEST_DIR} && cd ${GTEST_DIR} && patch -p1 < ../gtest.patch )
+[ -d ${GTEST_DIR} ] || ( unzip ${GTEST_ZIP} -d ${TMPDIR} && mv ${TMPDIR}/gtest-${GTEST_VERSION} ${GTEST_DIR} && cd ${GTEST_DIR} && patch -p1 < ${AOS}/externals/gtest.patch )
 
 # get and build ctemplate
 # This is the next revision after the 2.2 release and it only adds spaces to
 # make gcc 4.7 with --std=c++11 happy (user-defined string literals...).
 CTEMPLATE_VERSION=129
-CTEMPLATE_DIR=${EXTERNALS}/ctemplate-${CTEMPLATE_VERSION}
+CTEMPLATE_TAR=${EXTERNALS}/ctemplate-${CTEMPLATE_VERSION}.tar.gz
+CTEMPLATE_DIR=${COMPILED}/ctemplate-${CTEMPLATE_VERSION}
 CTEMPLATE_PREFIX=${CTEMPLATE_DIR}-prefix
 CTEMPLATE_LIB=${CTEMPLATE_PREFIX}/lib/libctemplate.a
 CTEMPLATE_URL=http://ctemplate.googlecode.com
 if [[ "${CTEMPLATE_VERSION}" =~ /\./ ]]; then
 	CTEMPLATE_URL=${CTEMPLATE_URL}/files/ctemplate-${CTEMPLATE_VERSION}.tar.gz
-	[ -f ${CTEMPLATE_DIR}.tar.gz ] || \
-		wget ${CTEMPLATE_URL} -O ${CTEMPLATE_DIR}.tar.gz
+	[ -f ${CTEMPLATE_TAR} ] || \
+		wget ${CTEMPLATE_URL} -O ${CTEMPLATE_TAR}
 	[ -d ${CTEMPLATE_DIR} ] || ( mkdir ${CTEMPLATE_DIR} && tar \
-		--strip-components=1 -C ${CTEMPLATE_DIR} -xf ${CTEMPLATE_DIR}.tar.gz )
+		--strip-components=1 -C ${CTEMPLATE_DIR} -xf ${CTEMPLATE_TAR} )
 else
 	CTEMPLATE_URL=${CTEMPLATE_URL}/svn/trunk
 	[ -d ${CTEMPLATE_DIR} ] || \
 		svn checkout ${CTEMPLATE_URL} -r ${CTEMPLATE_VERSION} ${CTEMPLATE_DIR}
 fi
-[ -f ${CTEMPLATE_LIB} ] || env -i PATH="${PATH}" \
-	CFLAGS='-m32' CXXFLAGS='-m32' LDFLAGS='-m32' \
-	bash -c "cd ${CTEMPLATE_DIR} && ./configure --disable-shared \
-	--prefix=`readlink -f ${CTEMPLATE_PREFIX}` && make && make install"
+[ -f ${CTEMPLATE_LIB} ] || bash -c "cd ${CTEMPLATE_DIR} && \
+	./configure --disable-shared \
+	${CONFIGURE_FLAGS} --prefix=`readlink -f ${CTEMPLATE_PREFIX}` \
+	&& make && make install"
 
 # get and build gflags
 GFLAGS_VERSION=2.0
-GFLAGS_DIR=${EXTERNALS}/gflags-${GFLAGS_VERSION}
+GFLAGS_TAR=${EXTERNALS}/gflags-${GFLAGS_VERSION}.tar.gz
+GFLAGS_DIR=${COMPILED}/gflags-${GFLAGS_VERSION}
 GFLAGS_PREFIX=${GFLAGS_DIR}-prefix
 GFLAGS_LIB=${GFLAGS_PREFIX}/lib/libgflags.a
 GFLAGS_URL=https://gflags.googlecode.com/files/gflags-${GFLAGS_VERSION}.tar.gz
-[ -f ${GFLAGS_DIR}.tar.gz ] || wget ${GFLAGS_URL} -O ${GFLAGS_DIR}.tar.gz
+[ -f ${GFLAGS_TAR} ] || wget ${GFLAGS_URL} -O ${GFLAGS_TAR}
 [ -d ${GFLAGS_DIR} ] || ( mkdir ${GFLAGS_DIR} && tar \
-  --strip-components=1 -C ${GFLAGS_DIR} -xf ${GFLAGS_DIR}.tar.gz )
-[ -f ${GFLAGS_LIB} ] || env -i PATH="${PATH}" \
-  CFLAGS='-m32' CXXFLAGS='-m32' LDFLAGS='-m32' \
-  bash -c "cd ${GFLAGS_DIR} && ./configure \
-  --prefix=`readlink -f ${GFLAGS_PREFIX}` && make && make install"
+  --strip-components=1 -C ${GFLAGS_DIR} -xf ${GFLAGS_TAR} )
+[ -f ${GFLAGS_LIB} ] || bash -c "cd ${GFLAGS_DIR} && ./configure \
+  ${CONFIGURE_FLAGS} --prefix=`readlink -f ${GFLAGS_PREFIX}` \
+  && make && make install"
 
 # get and build libusb
 LIBUSB_VERSION=1.0.9
 LIBUSB_APIVERSION=1.0
-LIBUSB_DIR=${EXTERNALS}/libusb-${LIBUSB_VERSION}
+LIBUSB_TAR=${EXTERNALS}/libusb-${LIBUSB_VERSION}.tar.bz2
+LIBUSB_DIR=${COMPILED}/libusb-${LIBUSB_VERSION}
 LIBUSB_PREFIX=${LIBUSB_DIR}-prefix
 LIBUSB_LIB=${LIBUSB_PREFIX}/lib/libusb-${LIBUSB_APIVERSION}.a
 LIBUSB_URL=http://sourceforge.net/projects/libusb/files/libusb-${LIBUSB_APIVERSION}/libusb-${LIBUSB_VERSION}/libusb-${LIBUSB_VERSION}.tar.bz2
-[ -f ${LIBUSB_DIR}.tar.bz2 ] || wget ${LIBUSB_URL} -O ${LIBUSB_DIR}.tar.bz2
+[ -f ${LIBUSB_TAR} ] || wget ${LIBUSB_URL} -O ${LIBUSB_TAR}
 [ -d ${LIBUSB_DIR} ] || ( mkdir ${LIBUSB_DIR} && tar \
-  --strip-components=1 -C ${LIBUSB_DIR} -xf ${LIBUSB_DIR}.tar.bz2 )
-[ -f ${LIBUSB_LIB} ] || env -i PATH="${PATH}" \
-  CFLAGS='-m32' CXXFLAGS='-m32' LDFLAGS='-m32' \
-  bash -c "cd ${LIBUSB_DIR} && ./configure \
-  --prefix=`readlink -f ${LIBUSB_PREFIX}` && make && make install"
+  --strip-components=1 -C ${LIBUSB_DIR} -xf ${LIBUSB_TAR} )
+[ -f ${LIBUSB_LIB} ] || bash -c "cd ${LIBUSB_DIR} && ./configure \
+	${CONFIGURE_FLAGS} --prefix=`readlink -f ${LIBUSB_PREFIX}` \
+	&& make && make install"
 
 # get the LLVM Compiler-RT source
 COMPILER_RT_TAG=RELEASE_32/final
@@ -109,15 +136,48 @@
 
 # get and build libevent
 LIBEVENT_VERSION=2.0.21
-LIBEVENT_DIR=${EXTERNALS}/libevent-${LIBEVENT_VERSION}
+LIBEVENT_TAR=${EXTERNALS}/libevent-${LIBEVENT_VERSION}.tar.gz
+LIBEVENT_DIR=${COMPILED}/libevent-${LIBEVENT_VERSION}
 LIBEVENT_PREFIX=${LIBEVENT_DIR}-prefix
 LIBEVENT_LIB=${LIBEVENT_PREFIX}/lib/libevent.a
 LIBEVENT_URL=https://github.com/downloads/libevent/libevent
 LIBEVENT_URL=${LIBEVENT_URL}/libevent-${LIBEVENT_VERSION}-stable.tar.gz
-[ -f ${LIBEVENT_DIR}.tar.gz ] || wget ${LIBEVENT_URL} -O ${LIBEVENT_DIR}.tar.gz
+[ -f ${LIBEVENT_TAR} ] || wget ${LIBEVENT_URL} -O ${LIBEVENT_TAR}
 [ -d ${LIBEVENT_DIR} ] || ( mkdir ${LIBEVENT_DIR} && tar \
-  --strip-components=1 -C ${LIBEVENT_DIR} -xf ${LIBEVENT_DIR}.tar.gz )
-[ -f ${LIBEVENT_LIB} ] || env -i PATH="${PATH}" \
-  CFLAGS='-m32' CXXFLAGS='-m32' LDFLAGS='-m32' \
-  bash -c "cd ${LIBEVENT_DIR} && ./configure \
-  --prefix=`readlink -f ${LIBEVENT_PREFIX}` && make && make install"
+  --strip-components=1 -C ${LIBEVENT_DIR} -xf ${LIBEVENT_TAR} )
+[ -f ${LIBEVENT_LIB} ] || bash -c "cd ${LIBEVENT_DIR} && ./configure \
+	${CONFIGURE_FLAGS} --prefix=`readlink -f ${LIBEVENT_PREFIX}` \
+	&& make && make install"
+
+# get and build gmp
+GMP_VERSION=5.1.3
+GMP_TAR=${EXTERNALS}/gmp-${GMP_VERSION}.tar.lz
+GMP_DIR=${COMPILED}/gmp-${GMP_VERSION}
+GMP_PREFIX=${GMP_DIR}-prefix
+GMP_LIB=${GMP_PREFIX}/lib/libgmp.a
+GMP_URL=ftp://ftp.gmplib.org/pub/gmp/gmp-${GMP_VERSION}.tar.lz
+[ -f ${GMP_TAR} ] || wget ${GMP_URL} -O ${GMP_TAR}
+[ -d ${GMP_DIR} ] || ( mkdir ${GMP_DIR} && tar \
+	--strip-components=1 -C ${GMP_DIR} -xf ${GMP_TAR} )
+[ -f ${GMP_LIB} ] || bash -c "cd ${GMP_DIR} && ./configure \
+	${CONFIGURE_FLAGS} --prefix=$(readlink -f ${GMP_PREFIX}) \
+	&& make && make install"
+
+# get and build libcdd
+LIBCDD_VERSION=094g
+LIBCDD_TAR=${EXTERNALS}/libcdd-${LIBCDD_VERSION}.tar.gz
+LIBCDD_DIR=${COMPILED}/libcdd-${LIBCDD_VERSION}
+LIBCDD_PREFIX=${LIBCDD_DIR}-prefix
+LIBCDD_LIB=${LIBCDD_PREFIX}/lib/libcdd.a
+LIBCDD_URL=ftp://ftp.ifor.math.ethz.ch/pub/fukuda/cdd/cddlib-${LIBCDD_VERSION}.tar.gz
+[ -f ${LIBCDD_TAR} ] || \
+        wget ${LIBCDD_URL} -O ${LIBCDD_TAR}
+[ -d ${LIBCDD_DIR} ] || ( mkdir ${LIBCDD_DIR} && tar \
+        --strip-components=1 -C ${LIBCDD_DIR} -xf ${LIBCDD_TAR} )
+[ -f ${LIBCDD_LIB} ] || LDFLAGS=-L${GMP_PREFIX}/lib \
+	bash -c "cd ${LIBCDD_DIR} && ./configure \
+	--disable-shared ${CONFIGURE_FLAGS} \
+	--prefix=$(readlink -f ${LIBCDD_PREFIX}) \
+	&& make gmpdir=${GMP_PREFIX} && make install"
+
+rm -rf ${TMPDIR}
diff --git a/aos/build/externals.gyp b/aos/build/externals.gyp
index 5f85b5c..34564e1 100644
--- a/aos/build/externals.gyp
+++ b/aos/build/externals.gyp
@@ -2,12 +2,14 @@
 # download_externals.sh makes sure that all of them have been downloaded.
 {
   'variables': {
-    'externals': '<(AOS)/externals',
-    'externals_abs': '<!(readlink -f ../externals)',
+    'externals': '<(AOS)/../output/downloaded',
+    'externals_abs': '<!(readlink -f ../../output/downloaded)',
+    'compiled': '<(externals)/../compiled-arm',
+    'compiled_abs': '<(externals_abs)/../compiled-arm',
 
 # These versions have to be kept in sync with the ones in download_externals.sh.
     'eigen_version': '3.1.3',
-    'gtest_version': '1.6.0-p2',
+    'gtest_version': '1.6.0-p1',
     'onejar_version': '0.97',
     'ctemplate_version': '129',
     'gflags_version': '2.0',
@@ -15,13 +17,14 @@
     'libusb_apiversion': '1.0',
     'compiler_rt_version': 'RELEASE_32_final',
     'libevent_version': '2.0.21',
+    'libcdd_version': '094g',
   },
   'targets': [
     {
       'target_name': 'WPILib',
       'type': 'static_library',
       'sources': [
-        '<!@(find <(externals)/WPILib/WPILib/ -name *.cpp)',
+        '<!@(find <(AOS)/externals/WPILib/WPILib/ -name *.cpp)',
       ],
       'cflags!': [
         '-Werror',
@@ -33,13 +36,13 @@
         '-O3'
       ],
       'include_dirs': [
-        '<(externals)/WPILib',
-        '<(externals)/WPILib/WPILib',
+        '<(AOS)/externals/WPILib',
+        '<(AOS)/externals/WPILib/WPILib',
       ],
       'direct_dependent_settings': {
         'cflags': [
-          '-isystem', '<(externals_abs)/WPILib',
-          '-isystem', '<(externals_abs)/WPILib/WPILib',
+          '-isystem', '<(AOS)/externals/WPILib',
+          '-isystem', '<(AOS)/externals/WPILib/WPILib',
         ],
       },
     },
@@ -47,14 +50,14 @@
       'target_name': 'WPILib-NetworkRobotValues',
       'type': 'static_library',
       'sources': [
-        '<(externals)/WPILib/WPILib/NetworkRobot/NetworkRobotValues.cpp'
+        '<(AOS)/externals/WPILib/WPILib/NetworkRobot/NetworkRobotValues.cpp'
       ],
       'include_dirs': [
-        '<(externals)/WPILib',
+        '<(AOS)/externals/WPILib',
       ],
       'direct_dependent_settings': {
         'include_dirs': [
-          '<(externals)/WPILib',
+          '<(AOS)/externals/WPILib',
         ],
       },
     },
@@ -101,10 +104,10 @@
       'target_name': 'libevent',
       'type': 'none',
       'link_settings': {
-        'libraries': ['<(externals_abs)/libevent-<(libevent_version)-prefix/lib/libevent.a'],
+        'libraries': ['<(compiled_abs)/libevent-<(libevent_version)-prefix/lib/libevent.a'],
       },
       'direct_dependent_settings': {
-        'include_dirs': ['<(externals)/libevent-<(libevent_version)-prefix/include'],
+        'include_dirs': ['<(compiled)/libevent-<(libevent_version)-prefix/include'],
       },
     },
     {
@@ -120,7 +123,10 @@
       'target_name': 'libjpeg',
       'type': 'none',
       'direct_dependent_settings': {
-        'libraries': ['<(externals_abs)/libjpeg/lib/libjpeg.a'],
+        'libraries': ['<(compiled_abs)/libjpeg/lib/libjpeg.a'],
+        'cflags': [
+          '-isystem', '<(compiled)',
+        ],
       },
     },
     {
@@ -184,30 +190,43 @@
       'target_name': 'ctemplate',
       'type': 'none',
       'link_settings': {
-        'libraries': ['<(externals_abs)/ctemplate-<(ctemplate_version)-prefix/lib/libctemplate.a'],
+        'libraries': ['<(compiled_abs)/ctemplate-<(ctemplate_version)-prefix/lib/libctemplate.a'],
       },
       'direct_dependent_settings': {
-        'include_dirs': ['<(externals)/ctemplate-<(ctemplate_version)-prefix/include'],
+        'include_dirs': ['<(compiled)/ctemplate-<(ctemplate_version)-prefix/include'],
       },
     },
     {
       'target_name': 'gflags',
       'type': 'none',
       'link_settings': {
-        'libraries': ['<(externals_abs)/gflags-<(gflags_version)-prefix/lib/libgflags.a'],
+        'libraries': ['<(compiled_abs)/gflags-<(gflags_version)-prefix/lib/libgflags.a'],
       },
       'direct_dependent_settings': {
-        'include_dirs': ['<(externals)/gflags-<(gflags_version)-prefix/include'],
+        'include_dirs': ['<(compiled)/gflags-<(gflags_version)-prefix/include'],
       },
     },
     {
       'target_name': 'libusb',
       'type': 'none',
       'link_settings': {
-        'libraries': ['<(externals_abs)/libusb-<(libusb_version)-prefix/lib/libusb-<(libusb_apiversion).a'],
+        'libraries': ['<(compiled_abs)/libusb-<(libusb_version)-prefix/lib/libusb-<(libusb_apiversion).a'],
       },
       'direct_dependent_settings': {
-        'include_dirs': ['<(externals)/libusb-<(libusb_version)-prefix/include'],
+        'include_dirs': ['<(compiled)/libusb-<(libusb_version)-prefix/include'],
+        'cflags': [
+          '-Wno-error=cast-align',
+        ],
+      },
+    },
+    {
+      'target_name': 'libcdd',
+      'type': 'none',
+      'link_settings': {
+        'libraries': ['<(compiled_abs)/libcdd-<(libcdd_version)-prefix/lib/libcdd.a'],
+      },
+      'direct_dependent_settings': {
+        'include_dirs': ['<(compiled_abs)/'],
       },
     },
   ],
diff --git a/aos/build/queues/output/message_dec.rb b/aos/build/queues/output/message_dec.rb
index fcc3c60..3b89149 100644
--- a/aos/build/queues/output/message_dec.rb
+++ b/aos/build/queues/output/message_dec.rb
@@ -35,7 +35,7 @@
 			format += ", "
 			format += elem.toPrintFormat()
 			if (elem.type == 'bool')
-				args.push("#{elem.name} ? 't' : 'f'")
+				args.push("#{elem.name} ? 'T' : 'f'")
 			else
 				args.push(elem.name)
 			end
diff --git a/aos/build/tools_config b/aos/build/tools_config
new file mode 100644
index 0000000..d47a3ce
--- /dev/null
+++ b/aos/build/tools_config
@@ -0,0 +1,13 @@
+# This is a shell fragment that sets up variables related to where the tools
+# that download_externals.sh downloads so build.sh can use.
+
+EXTERNALS=${AOS}/../output/downloaded
+
+NINJA_RELEASE=v1.4.0
+NINJA_DIR=${EXTERNALS}/ninja-${NINJA_RELEASE}
+NINJA=${NINJA_DIR}/ninja
+
+# From chromium@154360:trunk/src/DEPS.
+GYP_REVISION=1738
+GYP_DIR=${EXTERNALS}/gyp-${GYP_REVISION}
+GYP=${GYP_DIR}/gyp
diff --git a/aos/common/common.gyp b/aos/common/common.gyp
index f73f1f6..5958b7e 100644
--- a/aos/common/common.gyp
+++ b/aos/common/common.gyp
@@ -137,12 +137,14 @@
         '<(AOS)/build/aos.gyp:logging',
         'timing',
         'time',
+        'control_loop_queues',
       ],
       'export_dependent_settings': [
         '<(AOS)/common/messages/messages.gyp:aos_queues',
         '<(AOS)/build/aos.gyp:logging',
         'timing',
         'time',
+        'control_loop_queues',
       ],
     },
     {
diff --git a/aos/common/control_loop/ControlLoop-tmpl.h b/aos/common/control_loop/ControlLoop-tmpl.h
index a5666a9..69c3121 100644
--- a/aos/common/control_loop/ControlLoop-tmpl.h
+++ b/aos/common/control_loop/ControlLoop-tmpl.h
@@ -9,16 +9,16 @@
 
 // TODO(aschuh): Tests.
 
-template <class T, bool has_position>
-void ControlLoop<T, has_position>::ZeroOutputs() {
+template <class T, bool has_position, bool fail_no_position>
+void ControlLoop<T, has_position, fail_no_position>::ZeroOutputs() {
   aos::ScopedMessagePtr<OutputType> output =
       control_loop_->output.MakeMessage();
   Zero(output.get());
   output.Send();
 }
 
-template <class T, bool has_position>
-void ControlLoop<T, has_position>::Iterate() {
+template <class T, bool has_position, bool fail_no_position>
+void ControlLoop<T, has_position, fail_no_position>::Iterate() {
   // Temporary storage for printing out inputs and outputs.
   char state[1024];
 
@@ -60,8 +60,10 @@
         }
       } else {
         LOG(ERROR, "Never had a position.\n");
-        ZeroOutputs();
-        return;
+        if (fail_no_position) {
+          ZeroOutputs();
+          return;
+        }
       }
     }
     if (position) {
@@ -112,8 +114,8 @@
   status.Send();
 }
 
-template <class T, bool has_position>
-void ControlLoop<T, has_position>::Run() {
+template <class T, bool has_position, bool fail_no_position>
+void ControlLoop<T, has_position, fail_no_position>::Run() {
   while (true) {
     time::SleepUntil(NextLoopTime());
     Iterate();
diff --git a/aos/common/control_loop/ControlLoop.cc b/aos/common/control_loop/ControlLoop.cc
index f5253d4..ea62d85 100644
--- a/aos/common/control_loop/ControlLoop.cc
+++ b/aos/common/control_loop/ControlLoop.cc
@@ -4,8 +4,8 @@
 namespace control_loops {
 
 time::Time NextLoopTime(time::Time start) {
-  return (start / kLoopFrequency.ToNSec()) *
-      kLoopFrequency.ToNSec() +
+  return (start / static_cast<int32_t>(kLoopFrequency.ToNSec())) *
+      static_cast<int32_t>(kLoopFrequency.ToNSec()) +
       kLoopFrequency;
 }
 
diff --git a/aos/common/control_loop/ControlLoop.h b/aos/common/control_loop/ControlLoop.h
index 723d766..6af7235 100644
--- a/aos/common/control_loop/ControlLoop.h
+++ b/aos/common/control_loop/ControlLoop.h
@@ -37,7 +37,7 @@
 };
 
 // Control loops run this often, "starting" at time 0.
-const time::Time kLoopFrequency = time::Time::InSeconds(0.01);
+constexpr time::Time kLoopFrequency = time::Time::InSeconds(0.01);
 
 // Calculates the next time to run control loops after start.
 time::Time NextLoopTime(time::Time start = time::Time::Now());
@@ -50,7 +50,7 @@
 // If has_position is false, the control loop will always use NULL as the
 // position and not check the queue.  This is used for "loops" that control
 // motors open loop.
-template <class T, bool has_position = true>
+template <class T, bool has_position = true, bool fail_no_position = true>
 class ControlLoop : public SerializableControlLoop {
  public:
   // Maximum age of position packets before the loop will be disabled due to
diff --git a/aos/common/control_loop/Timing.cpp b/aos/common/control_loop/Timing.cpp
index 3a58036..8f42623 100644
--- a/aos/common/control_loop/Timing.cpp
+++ b/aos/common/control_loop/Timing.cpp
@@ -11,8 +11,8 @@
 void PhasedLoopXMS(int ms, int offset) {
   // TODO(brians): Tests!
   const Time frequency = Time::InMS(ms);
-  SleepUntil((Time::Now() / frequency.ToNSec()) *
-             frequency.ToNSec() +
+  SleepUntil((Time::Now() / static_cast<int32_t>(frequency.ToNSec())) *
+             static_cast<int32_t>(frequency.ToNSec()) +
              frequency + Time::InUS(offset));
 }
 
diff --git a/aos/common/logging/logging.h b/aos/common/logging/logging.h
index a5f07bb..6de118b 100644
--- a/aos/common/logging/logging.h
+++ b/aos/common/logging/logging.h
@@ -6,6 +6,7 @@
 
 #include <stdio.h>
 #include <stdint.h>
+#include <stdlib.h>
 
 #ifdef __VXWORKS__
 // Because the vxworks system headers miss the noreturn...
@@ -112,12 +113,112 @@
              format, ##args); \
 } while (0)
 
-// TODO(brians) add CHECK macros like glog
-// (<http://google-glog.googlecode.com/svn/trunk/doc/glog.html>)
-// and replace assert with one
-
 #ifdef __cplusplus
 }
 #endif
 
+#ifdef __cplusplus
+
+namespace aos {
+
+// CHECK* macros, similar to glog
+// (<http://google-glog.googlecode.com/svn/trunk/doc/glog.html>)'s, except they
+// don't support streaming in extra text. Some of the implementation is borrowed
+// from there too.
+// They all LOG(FATAL) with a helpful message when the check fails.
+// TODO(brians): Replace assert with CHECK
+// Portions copyright (c) 1999, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// CHECK dies with a fatal error if condition is not true.  It is *not*
+// controlled by NDEBUG, so the check will be executed regardless of
+// compilation mode.  Therefore, it is safe to do things like:
+//    CHECK(fp->Write(x) == 4)
+#define CHECK(condition)  \
+  if (__builtin_expect(!(condition), 0)) { \
+    LOG(FATAL, "CHECK(%s) failed\n", #condition); \
+  }
+
+// Helper functions for CHECK_OP macro.
+// The (int, int) specialization works around the issue that the compiler
+// will not instantiate the template version of the function on values of
+// unnamed enum type.
+#define DEFINE_CHECK_OP_IMPL(name, op) \
+  template <typename T1, typename T2> \
+  inline void LogImpl##name(const T1& v1, const T2& v2,    \
+                            const char* exprtext) { \
+    if (!__builtin_expect(v1 op v2, 1)) { \
+      LOG(FATAL, "CHECK(%s) failed\n", exprtext); \
+    } \
+  } \
+  inline void LogImpl##name(int v1, int v2, const char* exprtext) { \
+    ::aos::LogImpl##name<int, int>(v1, v2, exprtext); \
+  }
+
+// We use the full name Check_EQ, Check_NE, etc. in case the file including
+// base/logging.h provides its own #defines for the simpler names EQ, NE, etc.
+// This happens if, for example, those are used as token names in a
+// yacc grammar.
+DEFINE_CHECK_OP_IMPL(Check_EQ, ==)  // Compilation error with CHECK_EQ(NULL, x)?
+DEFINE_CHECK_OP_IMPL(Check_NE, !=)  // Use CHECK(x == NULL) instead.
+DEFINE_CHECK_OP_IMPL(Check_LE, <=)
+DEFINE_CHECK_OP_IMPL(Check_LT, < )
+DEFINE_CHECK_OP_IMPL(Check_GE, >=)
+DEFINE_CHECK_OP_IMPL(Check_GT, > )
+
+#define CHECK_OP(name, op, val1, val2) \
+  ::aos::LogImplCheck##name(val1, val2, \
+                            STRINGIFY(val1) STRINGIFY(op) STRINGIFY(val2))
+
+#define CHECK_EQ(val1, val2) CHECK_OP(_EQ, ==, val1, val2)
+#define CHECK_NE(val1, val2) CHECK_OP(_NE, !=, val1, val2)
+#define CHECK_LE(val1, val2) CHECK_OP(_LE, <=, val1, val2)
+#define CHECK_LT(val1, val2) CHECK_OP(_LT, < , val1, val2)
+#define CHECK_GE(val1, val2) CHECK_OP(_GE, >=, val1, val2)
+#define CHECK_GT(val1, val2) CHECK_OP(_GT, > , val1, val2)
+
+// A small helper for CHECK_NOTNULL().
+template <typename T>
+inline T* CheckNotNull(const char *value_name, T *t) {
+  if (t == NULL) {
+    LOG(FATAL, "'%s' must not be NULL\n", value_name);
+  }
+  return t;
+}
+
+// Check that the input is non NULL.  This very useful in constructor
+// initializer lists.
+#define CHECK_NOTNULL(val) \
+  ::aos::CheckNotNull(STRINGIFY(val), val)
+
+}  // namespace aos
+
+#endif  // __cplusplus
+
 #endif
diff --git a/aos/common/logging/logging_impl.cc b/aos/common/logging/logging_impl.cc
index bced835..980f65a 100644
--- a/aos/common/logging/logging_impl.cc
+++ b/aos/common/logging/logging_impl.cc
@@ -57,8 +57,8 @@
   const size_t size = output_size - strlen(continued);
   const int ret = vsnprintf(output, size, format, ap);
   if (ret < 0) {
-    LOG(FATAL, "vsnprintf(%p, %zd, %s, %p) failed with %d (%s)\n",
-        output, size, format, ap, errno, strerror(errno));
+    LOG(FATAL, "vsnprintf(%p, %zd, %s, args) failed with %d (%s)\n",
+        output, size, format, errno, strerror(errno));
   } else if (static_cast<uintmax_t>(ret) >= static_cast<uintmax_t>(size)) {
     // Overwrite the '\0' at the end of the existing data and
     // copy in the one on the end of continued.
@@ -120,6 +120,16 @@
 
 }  // namespace internal
 
+StreamLogImplementation::StreamLogImplementation(FILE *stream)
+    : stream_(stream) {}
+
+void StreamLogImplementation::DoLog(log_level level, const char *format,
+                                    va_list ap) {
+  LogMessage message;
+  internal::FillInMessage(level, format, ap, &message);
+  internal::PrintMessage(stream_, message);
+}
+
 void LogImplementation::DoVLog(log_level level, const char *format, va_list ap,
                    int levels) {
   Context *context = Context::Get();
diff --git a/aos/common/logging/logging_impl.h b/aos/common/logging/logging_impl.h
index 1416fe1..18f35bc 100644
--- a/aos/common/logging/logging_impl.h
+++ b/aos/common/logging/logging_impl.h
@@ -114,6 +114,17 @@
   LogImplementation *next_;
 };
 
+// A log implementation that dumps all messages to a C stdio stream.
+class StreamLogImplementation : public LogImplementation {
+ public:
+  StreamLogImplementation(FILE *stream);
+
+ private:
+  virtual void DoLog(log_level level, const char *format, va_list ap);
+
+  FILE *const stream_;
+};
+
 // Adds another implementation to the stack of implementations in this
 // task/thread.
 // Any tasks/threads created after this call will also use this implementation.
diff --git a/aos/common/logging/logging_impl_test.cc b/aos/common/logging/logging_impl_test.cc
index 16a0285..faaf1cd 100644
--- a/aos/common/logging/logging_impl_test.cc
+++ b/aos/common/logging/logging_impl_test.cc
@@ -125,7 +125,7 @@
   expected << "-";
   expected << (end_line + 1);
   expected << ": ";
-  expected << __PRETTY_FUNCTION__;
+  expected << __func__;
   expected << ": first part second part (=19) third part last part 5\n";
   EXPECT_TRUE(WasLogged(WARNING, expected.str()));
 }
diff --git a/aos/common/network/network.gyp b/aos/common/network/network.gyp
index 279bb53..60b37aa 100644
--- a/aos/common/network/network.gyp
+++ b/aos/common/network/network.gyp
@@ -1,6 +1,18 @@
 {
   'targets': [
     {
+      'target_name': 'team_number',
+      'type': 'static_library',
+      'sources': [
+        'team_number.cc',
+      ],
+      'dependencies': [
+        '<(AOS)/atom_code/atom_code.gyp:configuration',
+        '<(AOS)/common/common.gyp:once',
+        '<(AOS)/build/aos.gyp:logging',
+      ],
+    },
+    {
       'target_name': 'socket_so',
       'type': 'shared_library',
       'variables': {'no_rsync': 1},
diff --git a/aos/common/network/team_number.cc b/aos/common/network/team_number.cc
new file mode 100644
index 0000000..367f991
--- /dev/null
+++ b/aos/common/network/team_number.cc
@@ -0,0 +1,31 @@
+#include "aos/common/network/team_number.h"
+
+#include <netinet/in.h>
+#include <inttypes.h>
+
+#include "aos/common/once.h"
+#include "aos/atom_code/configuration.h"
+#include "aos/common/logging/logging.h"
+
+namespace aos {
+namespace network {
+namespace {
+
+uint16_t *DoGetTeamNumber() {
+  const in_addr &address = configuration::GetOwnIPAddress();
+  static uint16_t r =
+      (((address.s_addr & 0xFF00) >> 8) * 100) +
+      (((address.s_addr & 0xFF0000) >> 16) & 0xFF);
+  LOG(INFO, "team number is %" PRIu16 "\n", r);
+  return &r;
+}
+
+}  // namespace
+
+uint16_t GetTeamNumber() {
+  static Once<uint16_t> once(DoGetTeamNumber);
+  return *once.Get();
+}
+
+}  // namespace network
+}  // namespace aos
diff --git a/aos/common/network/team_number.h b/aos/common/network/team_number.h
new file mode 100644
index 0000000..f250c85
--- /dev/null
+++ b/aos/common/network/team_number.h
@@ -0,0 +1,17 @@
+#ifndef AOS_COMMON_NETWORK_TEAM_NUMBER_H_
+#define AOS_COMMON_NETWORK_TEAM_NUMBER_H_
+
+#include <stdint.h>
+
+namespace aos {
+namespace network {
+
+// Retrieves the current team number based off of the network address.
+// This function will only do the complicated stuff once so it is cheap to call
+// repeatedly.
+uint16_t GetTeamNumber();
+
+}  // namespace network
+}  // namespace aos
+
+#endif  // AOS_COMMON_NETWORK_TEAM_NUMBER_H_
diff --git a/aos/common/sensors/sensor_packer.h b/aos/common/sensors/sensor_packer.h
deleted file mode 100644
index cfcf045..0000000
--- a/aos/common/sensors/sensor_packer.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef AOS_COMMON_SENSORS_SENSOR_PACKER_H_
-#define AOS_COMMON_SENSORS_SENSOR_PACKER_H_
-
-namespace aos {
-namespace sensors {
-
-// An interface that handles reading input data and putting it into the sensor
-// values struct.
-// See sensors.h for an overview of where this fits in.
-template<class Values>
-class SensorPackerInterface {
- public:
-  virtual ~SensorPackerInterface() {}
-
-  // Reads the inputs (from WPILib etc) and writes the data into *values.
-  virtual void PackInto(Values *values) = 0;
-};
-
-}  // namespace sensors
-}  // namespace aos
-
-#endif  // AOS_COMMON_SENSORS_SENSOR_PACKER_H_
diff --git a/aos/common/sensors/sensor_receiver-tmpl.h b/aos/common/sensors/sensor_receiver-tmpl.h
deleted file mode 100644
index 8fb6cb4..0000000
--- a/aos/common/sensors/sensor_receiver-tmpl.h
+++ /dev/null
@@ -1,264 +0,0 @@
-#include "aos/common/inttypes.h"
-#include "aos/common/network_port.h"
-
-namespace aos {
-namespace sensors {
-
-template<class Values>
-const time::Time SensorReceiver<Values>::kJitterDelay =
-    time::Time::InSeconds(0.003);
-// Not a multiple of kSensorSendFrequency to unwedge ourself if we hit some bug
-// where it needs to get off of that frequency to work.
-template<class Values>
-const time::Time SensorReceiver<Values>::kGiveupTime =
-    time::Time::InSeconds(0.1555);
-
-template<class Values>
-SensorReceiver<Values>::SensorReceiver(
-    SensorUnpackerInterface<Values> *unpacker)
-    : unpacker_(unpacker),
-      start_time_(0, 0),
-      last_good_time_(0, 0) {
-  Unsynchronize();
-}
-
-template<class Values>
-void SensorReceiver<Values>::RunIteration() {
-  if (synchronized_) {
-    if (ReceiveData()) {
-      LOG(DEBUG, "receive said to try a reset\n");
-      Unsynchronize();
-    } else {
-      // TODO(brians): resync on crio reboots (and update the times...)
-      if (GoodPacket()) {
-        unpacker_->UnpackFrom(&data_.values);
-        last_good_time_ = time::Time::Now();
-      } else {
-        if ((time::Time::Now() - last_good_time_) > kGiveupTime) {
-          LOG(INFO, "resetting because didn't get a good one in too long\n");
-          Unsynchronize();
-        } else {
-          // We got a packet, but it wasn't an interesting one.
-        }
-      }
-    }
-  } else {
-    LOG(INFO, "resetting to try receiving data\n");
-    Reset();
-    if (Synchronize()) {
-      LOG(INFO, "synchronized successfully\n");
-      synchronized_ = true;
-      before_better_cycles_ = after_better_cycles_ = 0;
-      last_good_time_ = time::Time::Now();
-    } else {
-      LOG(INFO, "synchronization failed\n");
-    }
-  }
-}
-
-template<class Values>
-bool SensorReceiver<Values>::GoodPacket() {
-  bool good;
-  // If it's a multiple of kSensorSendFrequency from start_count_.
-  if (((data_.count - start_count_) % kSendsPerCycle) == 0) {
-    if (((data_.count - start_count_) / kSendsPerCycle) >=
-        ((NextLoopTime() - start_time_).ToNSec() / kLoopFrequency.ToNSec())) {
-      good = true;
-#if 0
-      if (((data_.count - start_count_) / kSendsPerCycle % 20) == 0) {
-        LOG(DEBUG, "dropping one for fun\n");
-        good = false;
-      }
-#endif
-    } else {
-      LOG(INFO,
-          "packet %" PRId32 " late. is packet #%d, wanted #%" PRId64 " now\n",
-          data_.count, (data_.count - start_count_) / kSendsPerCycle,
-          (NextLoopTime() - start_time_).ToNSec() / kLoopFrequency.ToNSec());
-      good = false;
-    }
-  } else {
-    good = false;
-  }
-
-  static time::Time last_time(0, 0);
-  time::Time now = time::Time::Now();
-  time::Time next_goal_time = NextLoopTime() - kJitterDelay;
-  // If this is the packet after the right one.
-  if (((data_.count - start_count_ - 1) % kSendsPerCycle) == 0) {
-    // If this one is much closer than the last one (aka the one that we used).
-    if ((now - next_goal_time).abs() * 11 / 10 <
-        (last_time - next_goal_time).abs()) {
-      LOG(DEBUG, "next one better than one being used %d\n",
-          after_better_cycles_);
-      if (after_better_cycles_ > kBadCyclesToSwitch) {
-        LOG(INFO, "switching to the packet after\n");
-        ++start_count_;
-        before_better_cycles_ = after_better_cycles_ = 0;
-      } else {
-        ++after_better_cycles_;
-      }
-    } else {
-      after_better_cycles_ = 0;
-    }
-  }
-  // If this is the right packet.
-  if (((data_.count - start_count_) % kSendsPerCycle) == 0) {
-    // If the last one was closer than this one (aka the one that we used).
-    if ((last_time - next_goal_time).abs() * 11 / 10 <
-        (now - next_goal_time).abs()) {
-      LOG(DEBUG, "previous better than one being used %d\n",
-          before_better_cycles_);
-      if (before_better_cycles_ > kBadCyclesToSwitch) {
-        LOG(INFO, "switching to the packet before\n");
-        --start_count_;
-        before_better_cycles_ = after_better_cycles_ = 0;
-      } else {
-        ++before_better_cycles_;
-      }
-    } else {
-      before_better_cycles_ = 0;
-    }
-  }
-  last_time = now;
-
-  return good;
-}
-
-// Looks for when the timestamps transition from before where we want to after
-// and then picks whichever one was closer. After that, reads kTestCycles and
-// makes sure that at most 1 is bad.
-template<class Values>
-bool SensorReceiver<Values>::Synchronize() {
-  time::Time old_received_time(0, 0);
-  const time::Time start_time = time::Time::Now();
-  // When we want to send out the next set of values.
-  time::Time goal_time = NextLoopTime(start_time) - kJitterDelay;
-  if (goal_time <= start_time) {
-    goal_time += kLoopFrequency;
-  }
-  assert(goal_time > start_time);
-  while (true) {
-    if (ReceiveData()) return false;
-    time::Time received_time = time::Time::Now();
-    if (received_time >= goal_time) {
-      // If this was the very first one we got, try again.
-      if (old_received_time == time::Time(0, 0)){
-        LOG(INFO, "first one we got was too late\n");
-        return false;
-      }
-
-      assert(old_received_time < goal_time);
-
-      // If the most recent one is closer than the last one.
-      if ((received_time - goal_time).abs() <
-          (old_received_time - goal_time).abs()) {
-        start_count_ = data_.count;
-      } else {
-        start_count_ = data_.count - 1;
-      }
-      start_time_ = goal_time;
-
-      int bad_count = 0;
-      for (int i = 0; i < kTestCycles;) {
-        ReceiveData();
-        received_time = time::Time::Now();
-        if (GoodPacket()) {
-          LOG(DEBUG, "checking packet count=%" PRId32
-              " received at %" PRId32 "s%" PRId32 "ns\n",
-              data_.count, received_time.sec(), received_time.nsec());
-          // If |the difference between the goal time for this numbered packet
-          // and the time we actually got this one| is too big.
-          if (((goal_time +
-                kSensorSendFrequency * (data_.count - start_count_)) -
-               received_time).abs() > kSensorSendFrequency) {
-            LOG(INFO, "rejected time of the last good packet. "
-                "got %" PRId32 "s%" PRId32 "ns."
-                " wanted %" PRId32 "s%" PRId32 "ns\n",
-                received_time.sec(), received_time.nsec(),
-                goal_time.sec(), goal_time.nsec());
-            ++bad_count;
-          }
-          ++i;
-        }
-        if (bad_count > 1) {
-          LOG(WARNING, "got multiple packets with bad timestamps\n");
-          return false;
-        }
-      }
-
-      Synchronized(goal_time + kLoopFrequency * kTestCycles);
-      return true;
-    }
-
-    old_received_time = received_time;
-  }
-}
-
-template<class Values>
-bool SensorReceiver<Values>::ReceiveData() {
-  int old_count = data_.count;
-  DoReceiveData();
-
-  if (data_.count < 0) {
-    LOG(FATAL, "data count overflowed. currently %" PRId32 "\n", data_.count);
-  }
-  if (data_.count < old_count) {
-    LOG(INFO, "count reset. was %" PRId32 ", now %" PRId32 "\n",
-        old_count, data_.count);
-    return true;
-  }
-  if (data_.count < start_count_) {
-    LOG(INFO, "count reset. started at %" PRId32 ", now %" PRId32 "\n",
-        start_count_, data_.count);
-  }
-  LOG(DEBUG, "received data count %" PRId32 "\n", data_.count);
-  return false;
-}
-
-template<class Values>
-void SensorReceiver<Values>::Unsynchronize() {
-  synchronized_ = false;
-  before_better_cycles_ = after_better_cycles_ = 0;
-}
-
-template<class Values>
-const time::Time NetworkSensorReceiver<Values>::kWarmupTime =
-    time::Time::InSeconds(0.075);
-
-template<class Values>
-NetworkSensorReceiver<Values>::NetworkSensorReceiver(
-    SensorUnpackerInterface<Values> *unpacker)
-    : SensorReceiver<Values>(unpacker),
-      socket_(NetworkPort::kSensors) {}
-
-template<class Values>
-void NetworkSensorReceiver<Values>::Reset() {
-  LOG(INFO, "beginning warm up\n");
-  time::Time start = time::Time::Now();
-  while ((time::Time::Now() - start) < kWarmupTime) {
-    socket_.Receive(this->data(), sizeof(*this->data()));
-  }
-  LOG(INFO, "done warming up\n");
-}
-
-template<class Values>
-void NetworkSensorReceiver<Values>::DoReceiveData() {
-  while (true) {
-    if (socket_.Receive(this->data(), sizeof(*this->data())) ==
-        sizeof(*this->data())) {
-      this->data()->checksum = ntoh(this->data()->checksum);
-      if (!this->data()->CheckChecksum()) {
-        LOG(WARNING, "got a bad packet\n");
-        continue;
-      }
-
-      this->data()->NetworkToHost();
-      return;
-    }
-    LOG(WARNING, "received incorrect amount of data\n");
-  }
-}
-
-}  // namespace sensors
-}  // namespace aos
diff --git a/aos/common/sensors/sensor_receiver.h b/aos/common/sensors/sensor_receiver.h
deleted file mode 100644
index 335ff08..0000000
--- a/aos/common/sensors/sensor_receiver.h
+++ /dev/null
@@ -1,120 +0,0 @@
-#ifndef AOS_COMMON_SENSORS_SENSOR_RECEIVER_H_
-#define AOS_COMMON_SENSORS_SENSOR_RECEIVER_H_
-
-#include "aos/common/sensors/sensor_unpacker.h"
-#include "aos/common/network/ReceiveSocket.h"
-#include "aos/common/sensors/sensors.h"
-#include "aos/common/time.h"
-#include "aos/common/gtest_prod.h"
-
-namespace aos {
-namespace sensors {
-namespace testing {
-
-FORWARD_DECLARE_TEST_CASE(SensorReceiverTest, Simple);
-FORWARD_DECLARE_TEST_CASE(SensorReceiverTest, BadStartup2);
-FORWARD_DECLARE_TEST_CASE(SensorReceiverTest, StartTimeAndCountMismatch);
-
-}  // namespace testing
-
-// A class that handles receiving sensor values from the cRIO.
-// See sensors.h for an overview of where this fits in.
-//
-// Abstract class to make testing the complex logic for choosing which data to
-// use easier.
-template<class Values>
-class SensorReceiver {
- public:
-  // Does not take ownership of unpacker.
-  SensorReceiver(SensorUnpackerInterface<Values> *unpacker);
-
-  void RunIteration();
-
- protected:
-  SensorData<Values> *data() { return &data_; }
-
- private:
-  // How long before the control loops run to aim for receiving sensor data (to
-  // prevent jitter if some packets arrive up to this much later).
-  static const time::Time kJitterDelay;
-  // How many cycles not to send data out to make sure that we're in phase
-  // (during this time, the code verifies that <= 1 cycle is not within 1
-  // cycle's time of kJitterDelay).
-  static const int kTestCycles = 8;
-  // How many cycles that we need (consecutively) of another packet being closer
-  // to the right time than the ones we're reading before we switch.
-  static const int kBadCyclesToSwitch = 8;
-  // If we don't get a good packet in this long, then we Synchronize() again.
-  static const time::Time kGiveupTime;
-
-  FRIEND_TEST_NAMESPACE(SensorReceiverTest, Simple, testing);
-  FRIEND_TEST_NAMESPACE(SensorReceiverTest, BadStartup2, testing);
-  FRIEND_TEST_NAMESPACE(SensorReceiverTest, StartTimeAndCountMismatch, testing);
-
-  // Subclasses need to implement this to read 1 set of data (blocking until it
-  // is available) into data().
-  // It needs to have the correct byte order etc and not be corrupted
-  // (subclasses can check the checksum if they want).
-  virtual void DoReceiveData() = 0;
-
-  // Optional: if subclasses can do anything to reinitialize after there are
-  // problems, they should do it here.
-  // This will be called right before calling DoReceiveData() the first time.
-  virtual void Reset() {}
-
-  // Optional: if subclasses want to be notified when this is first convinced
-  // that it has a good packet, they should do whatever here.
-  virtual void Synchronized(time::Time /*last_packet_ideal_time*/) {}
-
-  // Returns whether the current packet looks like a good one to use.
-  bool GoodPacket();
-
-  // Synchronizes with incoming packets and sets start_count_ to where we
-  // started reading.
-  // Returns whether it succeeded in locking on.
-  bool Synchronize();
-  // Receives a set of values and makes sure that it's sane.
-  // Returns whether to start over again with timing.
-  bool ReceiveData();
-  void Unsynchronize();
-
-  SensorUnpackerInterface<Values> *const unpacker_;
-  SensorData<Values> data_;
-  // The count that we started out (all other sent packets will be multiples of
-  // this).
-  int32_t start_count_;
-  // When start_count_ "should" have been received. Used for checking to make
-  // sure that we don't send out a packet late.
-  time::Time start_time_;
-  bool synchronized_;
-  int before_better_cycles_, after_better_cycles_;
-  // The time of the last packet that we sent out.
-  time::Time last_good_time_;
-
-  DISALLOW_COPY_AND_ASSIGN(SensorReceiver<Values>);
-};
-
-// A SensorReceiver that receives data from a SensorBroadcaster.
-template<class Values>
-class NetworkSensorReceiver : public SensorReceiver<Values> {
- public:
-  NetworkSensorReceiver(SensorUnpackerInterface<Values> *unpacker);
-
- private:
-  // How long to read data as fast as possible for (to clear out buffers etc).
-  static const time::Time kWarmupTime;
-
-  virtual void DoReceiveData();
-  virtual void Reset();
-
-  ReceiveSocket socket_;
-
-  DISALLOW_COPY_AND_ASSIGN(NetworkSensorReceiver<Values>);
-};
-
-}  // namespace sensors
-}  // namespace aos
-
-#include "aos/common/sensors/sensor_receiver-tmpl.h"
-
-#endif  // AOS_COMMON_SENSORS_SENSOR_RECEIVER_H_
diff --git a/aos/common/sensors/sensor_receiver_test.cc b/aos/common/sensors/sensor_receiver_test.cc
deleted file mode 100644
index 803ec47..0000000
--- a/aos/common/sensors/sensor_receiver_test.cc
+++ /dev/null
@@ -1,158 +0,0 @@
-#include "aos/common/sensors/sensor_receiver.h"
-
-#include "gtest/gtest.h"
-
-#include "aos/common/sensors/sensors.h"
-#include "aos/common/time.h"
-#include "aos/common/queue_testutils.h"
-
-using ::aos::time::Time;
-
-namespace aos {
-namespace sensors {
-namespace testing {
-
-struct TestValues {
-  int count;
-  int more_data;
-};
-class TestSensorReceiver : public SensorReceiver<TestValues>,
-    public SensorUnpackerInterface<TestValues> {
- public:
-  TestSensorReceiver()
-      : SensorReceiver<TestValues>(this),
-        resets_(0),
-        unpacks_(0) {
-    data()->count = 0;
-  }
-
-  void Reset() {
-    LOG(DEBUG, "reset for the %dth time\n", ++resets_);
-  }
-  void DoReceiveData() {
-    last_received_count_ = ++data()->count;
-    data()->values.count = last_received_count_;
-    Time::IncrementMockTime(kSensorSendFrequency);
-    data()->FillinChecksum();
-    data()->HostToNetwork();
-  }
-
-  int resets() { return resets_; }
-  int unpacks() { return unpacks_; }
-  using SensorReceiver<TestValues>::data;
-
-  void ResetFakeData() {
-    data()->count = 0;
-  }
-
-  void UnpackFrom(TestValues *data) {
-    // Make sure that it didn't lose one that we gave it.
-    EXPECT_EQ(last_received_count_, data->count);
-    ++unpacks_;
-    LOG(DEBUG, "%dth unpack\n", unpacks_);
-  }
- 
- private:
-  int resets_;
-  int unpacks_;
-  int last_received_count_;
-};
-
-class SensorReceiverTest : public ::testing::Test {
- protected:
-  SensorReceiverTest() {
-    ::aos::common::testing::EnableTestLogging();
-    Time::EnableMockTime(Time(971, 254));
-  }
-
-  TestSensorReceiver &receiver() { return receiver_; }
-
- private:
-  TestSensorReceiver receiver_;
-};
-
-TEST_F(SensorReceiverTest, Simple) {
-  static const int kIterations = 53;
-  for (int i = 0; i < kIterations; ++i) {
-    receiver().RunIteration();
-  }
-  EXPECT_EQ(1, receiver().resets());
-  // expected value is kIterations/kSendsPerCycle (rounded up) (the number of
-  // times that it should get a good one) - 1 (to compensate for the iteration
-  // when it synced itself up)
-  EXPECT_EQ((kIterations + kSendsPerCycle - 1) / kSendsPerCycle - 1,
-            receiver().unpacks());
-}
-
-TEST_F(SensorReceiverTest, CRIOReboot) {
-  for (int i = 0; i < 50; ++i) {
-    receiver().RunIteration();
-    if (i == 27) {
-      receiver().ResetFakeData();
-      time::Time::IncrementMockTime(time::Time::InSeconds(20));
-    }
-  }
-  EXPECT_EQ(2, receiver().resets());
-  EXPECT_GE(receiver().unpacks(), 4);
-}
-
-TEST_F(SensorReceiverTest, CRIOSkew) {
-  for (int i = 0; i < 505; ++i) {
-    receiver().RunIteration();
-    time::Time::IncrementMockTime(time::Time(0, 4000));
-  }
-  // TODO(brians) verify here that it actually corrects (happens twice with
-  // current constants)
-  EXPECT_EQ(1, receiver().resets());
-  EXPECT_EQ(50, receiver().unpacks());
-}
-
-TEST_F(SensorReceiverTest, BadStartup1) {
-  time::Time::SetMockTime(NextLoopTime() - Time(0, 100));
-  for (int i = 0; i < 55; ++i) {
-    receiver().RunIteration();
-  }
-  EXPECT_EQ(1, receiver().resets());
-  EXPECT_EQ(5, receiver().unpacks());
-}
-
-TEST_F(SensorReceiverTest, BadStartup2) {
-  time::Time::SetMockTime(NextLoopTime() -
-                          SensorReceiver<TestValues>::kJitterDelay -
-                          time::Time(0, 1));
-  for (int i = 0; i < 55; ++i) {
-    receiver().RunIteration();
-  }
-  EXPECT_EQ(2, receiver().resets());
-  EXPECT_EQ(5, receiver().unpacks());
-}
-
-TEST_F(SensorReceiverTest, BadStartup3) {
-  time::Time::SetMockTime(NextLoopTime() -
-                          time::Time::InSeconds(0.002) +
-                          kLoopFrequency / 20);
-  for (int i = 0; i < 55; ++i) {
-    receiver().RunIteration();
-  }
-  EXPECT_EQ(1, receiver().resets());
-  EXPECT_EQ(5, receiver().unpacks());
-}
-
-// I think that it somehow got this way once and never recovered.
-// It should never get this way, but if it does, it should recover.
-TEST_F(SensorReceiverTest, StartTimeAndCountMismatch) {
-  for (int i = 0; i < 1005; ++i) {
-    receiver().RunIteration();
-    if (i == 3) {
-      receiver().start_count_ += 10;
-    }
-  }
-  EXPECT_EQ(2, receiver().resets());
-  EXPECT_GT(receiver().unpacks(), 30);
-}
-
-// TODO(brians) finish writing tests and commenting them and the code
-
-}  // namespace testing
-}  // namespace sensors
-}  // namespace aos
diff --git a/aos/common/sensors/sensor_sink.h b/aos/common/sensors/sensor_sink.h
deleted file mode 100644
index 760f90e..0000000
--- a/aos/common/sensors/sensor_sink.h
+++ /dev/null
@@ -1,21 +0,0 @@
-#ifndef AOS_COMMON_SENSORS_SENSOR_SINK_H_
-#define AOS_COMMON_SENSORS_SENSOR_SINK_H_
-
-#include "aos/common/sensors/sensors.h"
-
-namespace aos {
-namespace sensors {
-
-// Generic class for something that can do something with sensor data.
-template<class Values>
-class SensorSinkInterface {
- public:
-  virtual ~SensorSinkInterface() {}
-
-  virtual void Process(SensorData<Values> *data) = 0;
-};
-
-}  // namespace sensors
-}  // namespace aos
-
-#endif  // AOS_COMMON_SENSORS_SENSOR_SINK_H_
diff --git a/aos/common/sensors/sensor_unpacker.h b/aos/common/sensors/sensor_unpacker.h
deleted file mode 100644
index b19e0c6..0000000
--- a/aos/common/sensors/sensor_unpacker.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef AOS_COMMON_SENSORS_SENSOR_UNPACKER_H_
-#define AOS_COMMON_SENSORS_SENSOR_UNPACKER_H_
-
-namespace aos {
-namespace sensors {
-
-// An interface that handles taking data from the sensor Values struct and
-// putting it into queues (for control loops etc).
-// See sensors.h for an overview of where this fits in.
-template<class Values>
-class SensorUnpackerInterface {
- public:
-  virtual ~SensorUnpackerInterface() {}
-
-  // Takes the data in *values and writes it out into queues etc.
-  virtual void UnpackFrom(Values *values) = 0;
-};
-
-}  // namespace sensors
-}  // namespace aos
-
-#endif  // AOS_COMMON_SENSORS_SENSOR_UNPACKER_H_
diff --git a/aos/common/sensors/sensors.cc b/aos/common/sensors/sensors.cc
deleted file mode 100644
index 60f411f..0000000
--- a/aos/common/sensors/sensors.cc
+++ /dev/null
@@ -1,89 +0,0 @@
-#include "aos/common/sensors/sensors.h"
-
-namespace aos {
-namespace sensors {
-
-const time::Time kSensorSendFrequency =
-    ::aos::control_loops::kLoopFrequency / kSendsPerCycle;
-
-namespace {
-
-// Table grabbed from <http://gcc.gnu.org/svn/gcc/trunk/libiberty/crc32.c>.
-const uint32_t crc32_table[] = {
-  0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9,
-  0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005,
-  0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
-  0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
-  0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9,
-  0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
-  0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011,
-  0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd,
-  0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
-  0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5,
-  0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81,
-  0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
-  0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49,
-  0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
-  0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
-  0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d,
-  0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae,
-  0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
-  0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,
-  0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca,
-  0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
-  0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02,
-  0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066,
-  0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
-  0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e,
-  0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692,
-  0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
-  0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a,
-  0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
-  0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
-  0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686,
-  0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a,
-  0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
-  0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
-  0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f,
-  0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
-  0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47,
-  0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b,
-  0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
-  0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623,
-  0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7,
-  0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
-  0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f,
-  0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
-  0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
-  0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b,
-  0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f,
-  0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
-  0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
-  0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c,
-  0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
-  0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24,
-  0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30,
-  0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
-  0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088,
-  0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654,
-  0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
-  0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c,
-  0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
-  0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
-  0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0,
-  0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c,
-  0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
-  0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
-};
-
-}  // namespace
-uint32_t CalculateChecksum(char *buf, size_t size) {
-  uint32_t ret = ~0;
-  for (size_t i = 0; i < size; ++i) {
-    ret = (ret << 8) ^ crc32_table[((ret >> 24) ^ buf[i]) & 255];
-  }
-  return ~ret;
-}
-
-}  // namespace sensors
-}  // namespace aos
diff --git a/aos/common/sensors/sensors.gyp b/aos/common/sensors/sensors.gyp
deleted file mode 100644
index b8a2092..0000000
--- a/aos/common/sensors/sensors.gyp
+++ /dev/null
@@ -1,76 +0,0 @@
-{
-  'targets': [
-    {
-      'target_name': 'sensor_sink',
-      'type': 'static_library',
-      'sources': [
-      ],
-      'dependencies': [
-        'sensors',
-      ],
-      'export_dependent_settings': [
-        'sensors',
-      ],
-    },
-    {
-      'target_name': 'sensors',
-      'type': 'static_library',
-      'sources': [
-        'sensors.cc'
-      ],
-      'dependencies': [
-        '<(AOS)/common/common.gyp:time',
-        '<(AOS)/common/common.gyp:controls',
-      ],
-      'export_dependent_settings': [
-        '<(AOS)/common/common.gyp:time',
-        '<(AOS)/common/common.gyp:controls',
-      ],
-    },
-    {
-      'target_name': 'sensors_test',
-      'type': '<(aos_target)',
-      'sources': [
-        'sensors_test.cc',
-      ],
-      'dependencies': [
-        '<(EXTERNALS):gtest',
-        'sensors',
-        '<(AOS)/common/common.gyp:queue_testutils',
-      ],
-    },
-    {
-      'target_name': 'sensor_receiver',
-      'type': 'static_library',
-      'sources': [
-        #'sensor_receiver-tmpl.h'
-      ],
-      'dependencies': [
-        '<(AOS)/common/network/network.gyp:socket',
-        'sensors',
-        '<(AOS)/common/common.gyp:time',
-        '<(AOS)/common/common.gyp:gtest_prod',
-      ],
-      'export_dependent_settings': [
-        '<(AOS)/common/network/network.gyp:socket',
-        'sensors',
-        '<(AOS)/common/common.gyp:time',
-        '<(AOS)/common/common.gyp:gtest_prod',
-      ],
-    },
-    {
-      'target_name': 'sensor_receiver_test',
-      'type': 'executable',
-      'sources': [
-        'sensor_receiver_test.cc',
-      ],
-      'dependencies': [
-        '<(EXTERNALS):gtest',
-        'sensor_receiver',
-        '<(AOS)/common/common.gyp:time',
-        'sensors',
-        '<(AOS)/common/common.gyp:queue_testutils',
-      ],
-    },
-  ],
-}
diff --git a/aos/common/sensors/sensors.h b/aos/common/sensors/sensors.h
deleted file mode 100644
index 78fd8a9..0000000
--- a/aos/common/sensors/sensors.h
+++ /dev/null
@@ -1,83 +0,0 @@
-#ifndef AOS_COMMON_SENSORS_SENSORS_H_
-#define AOS_COMMON_SENSORS_SENSORS_H_
-
-#include "aos/common/time.h"
-#include "aos/common/byteorder.h"
-#include "aos/common/control_loop/ControlLoop.h"
-#include "aos/common/inttypes.h"
-
-namespace aos {
-// This namespace contains all of the stuff for dealing with reading sensors and
-// communicating it to everything that needs it. There are 4 main classes whose
-// instances actually process the data. They must all be registered in the
-// appropriate ::aos::crio::ControlsManager hooks.
-//
-// SensorPackers get run on the cRIO to read inputs (from WPILib or elsewhere)
-// and put the values into the Values struct (which is templated for all of the
-// classes that use it).
-// SensorUnpackers get run on both the atom and the cRIO to take the data from
-// the Values struct and put them into queues for control loops etc.
-// SensorBroadcasters (on the cRIO) send the data to a SensorReceiver (on the
-// atom) to pass to its SensorUnpacker there.
-// CRIOControlLoopRunners register with a SensorBroadcaster to get called right
-// after reading the sensor data so that they can immediately pass it so a
-// SensorUnpacker and then run their control loops.
-// The actual SensorPacker and SensorUnpacker classes have the Interface suffix
-// on them.
-namespace sensors {
-
-// How many times per ::aos::control_loops::kLoopFrequency sensor
-// values get sent out by the cRIO.
-// This must evenly divide that frequency into multiples of sysClockRateGet().
-const int kSendsPerCycle = 10;
-// ::aos::control_loops::kLoopFrequency / kSendsPerCycle for
-// convenience.
-extern const time::Time kSensorSendFrequency;
-using ::aos::control_loops::kLoopFrequency;
-using ::aos::control_loops::NextLoopTime;
-
-uint32_t CalculateChecksum(char *buf, size_t size);
-
-// This is the struct that actually gets sent over the UDP socket.
-template<class Values>
-struct SensorData {
-  // All of the other 4-byte chunks in the message bitwise-exclusive-ORed
-  // together. Needed because it seems like nobody else checks... (vxworks not
-  // sending the UDP checksum or (not very likely) linux not checking it).
-  // TODO(brians): static_assert that this is at the front
-  uint32_t checksum;
-
-  Values values;
-  // Starts at 0 and goes up.
-  int32_t count;
-
-  void NetworkToHost() {
-    count = ntoh(count);
-  }
-  void HostToNetwork() {
-    count = hton(count);
-  }
-
-  void FillinChecksum() {
-    checksum = CalculateChecksum(reinterpret_cast<char *>(this) +
-                                 sizeof(checksum),
-                                 sizeof(*this) - sizeof(checksum));
-  }
-  // Returns whether or not checksum is correct.
-  bool CheckChecksum() {
-    uint32_t expected = CalculateChecksum(reinterpret_cast<char *>(this) +
-                                          sizeof(checksum),
-                                          sizeof(*this) - sizeof(checksum));
-    if (checksum != expected) {
-      LOG(INFO, "expected %" PRIx32 " but got %" PRIx32 "\n",
-          expected, checksum);
-      return false;
-    }
-    return true;
-  }
-} __attribute__((packed));
-
-}  // namespace sensors
-}  // namespace aos
-
-#endif  // AOS_COMMON_SENSORS_SENSORS_H_
diff --git a/aos/common/sensors/sensors_test.cc b/aos/common/sensors/sensors_test.cc
deleted file mode 100644
index 0df93c9..0000000
--- a/aos/common/sensors/sensors_test.cc
+++ /dev/null
@@ -1,38 +0,0 @@
-#include "aos/common/sensors/sensors.h"
-
-#include <stdint.h>
-
-#include "gtest/gtest.h"
-
-#include "aos/common/queue_testutils.h"
-
-namespace aos {
-namespace sensors {
-namespace testing {
-
-struct TestValues {
-  int32_t data1, data2;
-};
-
-TEST(SensorDataTest, Checksum) {
-  ::aos::common::testing::EnableTestLogging();
-
-  SensorData<TestValues> data;
-  data.values.data1 = 0;
-  data.values.data2 = 5;
-  data.FillinChecksum();
-  EXPECT_TRUE(data.CheckChecksum());
-  data.values.data1 = 1;
-  EXPECT_FALSE(data.CheckChecksum());
-  data.values.data1 = 0xFFFFFFFF;
-  EXPECT_FALSE(data.CheckChecksum());
-  data.values.data1 = 0;
-  EXPECT_TRUE(data.CheckChecksum());
-  data.values.data1 = 5;
-  data.values.data2 = 0;
-  EXPECT_FALSE(data.CheckChecksum());
-}
-
-}  // namespace testing
-}  // namespace sensors
-}  // namespace aos
diff --git a/aos/common/time.cc b/aos/common/time.cc
index c4f77a8..ced0c4d 100644
--- a/aos/common/time.cc
+++ b/aos/common/time.cc
@@ -32,7 +32,7 @@
 //  That would let me create a MockTime clock source.
 }
 
-void Time::EnableMockTime(const Time now) {
+void Time::EnableMockTime(const Time &now) {
   mock_time_enabled = true;
   MutexLocker time_mutex_locker(&time_mutex);
   current_mock_time = now;
@@ -43,7 +43,7 @@
   mock_time_enabled = false;
 }
 
-void Time::SetMockTime(const Time now) {
+void Time::SetMockTime(const Time &now) {
   MutexLocker time_mutex_locker(&time_mutex);
   if (!mock_time_enabled) {
     LOG(FATAL, "Tried to set mock time and mock time is not enabled\n");
@@ -51,6 +51,12 @@
   current_mock_time = now;
 }
 
+void Time::IncrementMockTime(const Time &amount) {
+  static ::aos::Mutex mutex;
+  ::aos::MutexLocker sync(&mutex);
+  SetMockTime(Now() + amount);
+}
+
 Time Time::Now(clockid_t clock) {
   if (mock_time_enabled) {
     MutexLocker time_mutex_locker(&time_mutex);
@@ -58,9 +64,6 @@
   } else {
     timespec temp;
     if (clock_gettime(clock, &temp) != 0) {
-      // TODO(aschuh): There needs to be a pluggable low level logging interface
-      // so we can break this dependency loop.  This also would help during
-      // startup.
       LOG(FATAL, "clock_gettime(%jd, %p) failed with %d: %s\n",
           static_cast<uintmax_t>(clock), &temp, errno, strerror(errno));
     }
@@ -107,6 +110,10 @@
   sec_ *= rhs;  // better not overflow, or the result is just too big
   nsec_ = temp % kNSecInSec;
   sec_ += (temp - nsec_) / kNSecInSec;
+  if (nsec_ < 0) {
+    nsec_ += kNSecInSec;
+    sec_ -= 1;
+  }
   return *this;
 }
 const Time Time::operator*(int32_t rhs) const {
@@ -115,6 +122,10 @@
 Time &Time::operator/=(int32_t rhs) {
   nsec_ = (sec_ % rhs) * (kNSecInSec / rhs) + nsec_ / rhs;
   sec_ /= rhs;
+  if (nsec_ < 0) {
+    nsec_ += kNSecInSec;
+    sec_ -= 1;
+  }
   return *this;
 }
 const Time Time::operator/(int32_t rhs) const {
@@ -128,12 +139,20 @@
   const int wraps = nsec_ / kNSecInSec;
   sec_ = wraps;
   nsec_ -= kNSecInSec * wraps;
+  if (nsec_ < 0) {
+    nsec_ += kNSecInSec;
+    sec_ -= 1;
+  }
   return *this;
 }
 const Time Time::operator%(int32_t rhs) const {
   return Time(*this) %= rhs;
 }
 
+const Time Time::operator-() const {
+  return Time(-sec_ - 1, kNSecInSec - nsec_);
+}
+
 bool Time::operator==(const Time &rhs) const {
   return sec_ == rhs.sec_ && nsec_ == rhs.nsec_;
 }
diff --git a/aos/common/time.h b/aos/common/time.h
index 6c80451..bc2dc3e 100644
--- a/aos/common/time.h
+++ b/aos/common/time.h
@@ -23,16 +23,22 @@
 // 0 <= nsec_ < kNSecInSec should always be true. All functions here will make
 // sure that that is true if it was on all inputs (including *this).
 //
+// Negative times are supported so that all of the normal arithmetic identities
+// work. nsec_ is still always positive.
+//
 // The arithmetic and comparison operators are overloaded because they make
 // complete sense and are very useful. The default copy and assignment stuff is
-// left because it works fine. Multiplication and division of Times by Times are
+// left because it works fine. Multiplication of Times by Times is
 // not implemented because I can't think of any uses for them and there are
-// multiple ways to do it.
+// multiple ways to do it. Division of Times by Times is implemented as the
+// ratio of them. Multiplication, division, and modulus of Times by integers are
+// implemented as interpreting the argument as nanoseconds.
 struct Time {
 #ifdef SWIG
 // All of the uses of constexpr here can safely be simply removed.
 // NOTE: This means that relying on the fact that constexpr implicitly makes
-// member functions const is not safe.
+// member functions const is not valid, so they all have to be explicitly marked
+// const.
 #define constexpr
 #endif  // SWIG
  public:
@@ -83,7 +89,6 @@
   static Time Now(clockid_t clock = kDefaultClock);
 
   // Constructs a Time representing seconds.
-  // TODO(brians): fix and test the negative cases for all of these
   static constexpr Time InSeconds(double seconds) {
     return (seconds < 0.0) ?
         Time(static_cast<int32_t>(seconds) - 1,
@@ -94,8 +99,11 @@
 
   // Constructs a time representing microseconds.
   static constexpr Time InNS(int64_t nseconds) {
-    return Time(nseconds / static_cast<int64_t>(kNSecInSec),
-                nseconds % kNSecInSec);
+    return (nseconds < 0) ?
+        Time(nseconds / static_cast<int64_t>(kNSecInSec) - 1,
+             (nseconds % kNSecInSec) + kNSecInSec) :
+        Time(nseconds / static_cast<int64_t>(kNSecInSec),
+             nseconds % kNSecInSec);
   }
 
   // Constructs a time representing microseconds.
@@ -108,7 +116,10 @@
 
   // Constructs a time representing mseconds.
   static constexpr Time InMS(int mseconds) {
-    return Time(mseconds / kMSecInSec, (mseconds % kMSecInSec) * kNSecInMSec);
+    return (mseconds < 0) ?
+        Time(mseconds / kMSecInSec - 1,
+             (mseconds % kMSecInSec) * kNSecInMSec + kNSecInSec) :
+        Time(mseconds / kMSecInSec, (mseconds % kMSecInSec) * kNSecInMSec);
   }
 
   // Checks whether or not this time is within amount nanoseconds of other.
@@ -138,7 +149,6 @@
   }
 
   // Returns the time represent in microseconds.
-  // TODO(brians): test this
   int64_t constexpr ToUSec() const {
     return static_cast<int64_t>(sec_) * static_cast<int64_t>(kUSecInSec) +
         (static_cast<int64_t>(nsec_) / static_cast<int64_t>(kNSecInUSec));
@@ -155,15 +165,22 @@
   Time &operator*=(int32_t rhs);
   Time &operator/=(int32_t rhs);
   Time &operator%=(int32_t rhs);
+  Time &operator%=(double rhs) = delete;
+  Time &operator*=(double rhs) = delete;
+  Time &operator/=(double rhs) = delete;
+  const Time operator*(double rhs) const = delete;
+  const Time operator/(double rhs) const = delete;
+  const Time operator%(double rhs) const = delete;
   #endif
   const Time operator+(const Time &rhs) const;
   const Time operator-(const Time &rhs) const;
   const Time operator*(int32_t rhs) const;
   const Time operator/(int32_t rhs) const;
-  // TODO(brians) test this
   double operator/(const Time &rhs) const;
   const Time operator%(int32_t rhs) const;
 
+  const Time operator-() const;
+
   bool operator==(const Time &rhs) const;
   bool operator!=(const Time &rhs) const;
   bool operator<(const Time &rhs) const;
@@ -194,14 +211,12 @@
   // Enables returning the mock time value for Now instead of checking the
   // system clock.  This should only be used when testing things depending on
   // time, or many things may/will break.
-  static void EnableMockTime(const Time now);
+  static void EnableMockTime(const Time &now);
   // Sets now when time is being mocked.
-  static void SetMockTime(const Time now);
-  // Convenience function to just increment the mock time by a certain amount.
-  static void IncrementMockTime(const Time amount) {
-    // TODO(brians) make this thread safe so it's more useful?
-    SetMockTime(Now() + amount);
-  }
+  static void SetMockTime(const Time &now);
+  // Convenience function to just increment the mock time by a certain amount in
+  // a thread safe way.
+  static void IncrementMockTime(const Time &amount);
   // Disables mocking time.
   static void DisableMockTime();
 
@@ -212,7 +227,9 @@
   static void CheckImpl(int32_t nsec);
   void Check() { CheckImpl(nsec_); }
   // A constexpr version of CheckImpl that returns the given value when it
-  // succeeds.
+  // succeeds or evaluates to non-constexpr and returns 0 when it fails.
+  // This will result in the usual LOG(FATAL) if this is used where it isn't
+  // required to be constexpr or a compile error if it is.
   static constexpr int32_t CheckConstexpr(int32_t nsec) {
     return (nsec >= kNSecInSec || nsec < 0) ? CheckImpl(nsec), 0 : nsec;
   }
diff --git a/aos/common/time_test.cc b/aos/common/time_test.cc
index e6b7bb0..ebc8284 100644
--- a/aos/common/time_test.cc
+++ b/aos/common/time_test.cc
@@ -56,6 +56,9 @@
   EXPECT_EQ(MACRO_DARG(Time(57, 6500)), t + MACRO_DARG(Time(3, 6000)));
   EXPECT_EQ(MACRO_DARG(Time(50, 300)),
             t + MACRO_DARG(Time(-5, Time::kNSecInSec - 200)));
+  EXPECT_EQ(Time(-46, 500), t + Time(-100, 0));
+  EXPECT_EQ(Time(-47, Time::kNSecInSec - 500),
+            Time(-101, Time::kNSecInSec - 1000) + t);
 }
 TEST(TimeTest, Subtraction) {
   Time t(54, 500);
@@ -66,28 +69,61 @@
             t - MACRO_DARG(Time(0, Time::kNSecInSec - 100)));
   EXPECT_EQ(MACRO_DARG(Time(55, 800)),
             t - MACRO_DARG(Time(-2, Time::kNSecInSec - 300)));
+  EXPECT_EQ(Time(54, 5500), t - Time(-1, Time::kNSecInSec - 5000));
+  EXPECT_EQ(Time(-50, Time::kNSecInSec - 300),
+            Time(5, 200) - t);
 }
 
 TEST(TimeTest, Multiplication) {
   Time t(54, Time::kNSecInSec / 3);
   EXPECT_EQ(MACRO_DARG(Time(108, Time::kNSecInSec / 3 * 2)), t * 2);
   EXPECT_EQ(MACRO_DARG(Time(271, Time::kNSecInSec / 3 * 2 - 1)), t * 5);
+  EXPECT_EQ(Time(-109, Time::kNSecInSec / 3 + 1), t * -2);
+  EXPECT_EQ(Time(-55, Time::kNSecInSec / 3 * 2 + 1), t * -1);
+  EXPECT_EQ(Time(-218, Time::kNSecInSec / 3 * 2 + 2), (t * -1) * 4);
 }
-TEST(TimeTest, Division) {
-  EXPECT_EQ(MACRO_DARG(Time(5, Time::kNSecInSec / 10 * 4 + 50)),
-            MACRO_DARG(Time(54, 500)) / 10);
+TEST(TimeTest, DivisionByInt) {
+  EXPECT_EQ(Time(5, Time::kNSecInSec / 10 * 4 + 50), Time(54, 500) / 10);
+  EXPECT_EQ(Time(2, Time::kNSecInSec / 4 * 3),
+            Time(5, Time::kNSecInSec / 2) / 2);
+  EXPECT_EQ(Time(-3, Time::kNSecInSec / 4 * 3),
+            Time(-5, Time::kNSecInSec / 2) / 2);
+}
+TEST(TimeTest, DivisionByTime) {
+  EXPECT_DOUBLE_EQ(2, Time(10, 0) / Time(5, 0));
+  EXPECT_DOUBLE_EQ(9, Time(27, 0) / Time(3, 0));
+  EXPECT_DOUBLE_EQ(9.25, Time(37, 0) / Time(4, 0));
+  EXPECT_DOUBLE_EQ(5.25, Time(36, Time::kNSecInSec / 4 * 3) / Time(7, 0));
+  EXPECT_DOUBLE_EQ(-5.25, Time(-37, Time::kNSecInSec / 4) / Time(7, 0));
+  EXPECT_DOUBLE_EQ(-5.25, Time(36, Time::kNSecInSec / 4 * 3) / Time(-7, 0));
+}
+
+TEST(TimeTest, Negation) {
+  EXPECT_EQ(Time(-5, 1234), -Time(4, Time::kNSecInSec - 1234));
+  EXPECT_EQ(Time(5, Time::kNSecInSec * 2 / 3 + 1),
+            -Time(-6, Time::kNSecInSec / 3));
 }
 
 TEST(TimeTest, Comparisons) {
-  EXPECT_TRUE(MACRO_DARG(Time(971, 254) > Time(971, 253)));
-  EXPECT_TRUE(MACRO_DARG(Time(971, 254) >= Time(971, 253)));
-  EXPECT_TRUE(MACRO_DARG(Time(971, 254) < Time(971, 255)));
-  EXPECT_TRUE(MACRO_DARG(Time(971, 254) <= Time(971, 255)));
-  EXPECT_TRUE(MACRO_DARG(Time(971, 254) >= Time(971, 253)));
-  EXPECT_TRUE(MACRO_DARG(Time(971, 254) <= Time(971, 254)));
-  EXPECT_TRUE(MACRO_DARG(Time(971, 254) >= Time(971, 254)));
-  EXPECT_TRUE(MACRO_DARG(Time(972, 254) > Time(971, 254)));
-  EXPECT_TRUE(MACRO_DARG(Time(971, 254) < Time(972, 254)));
+  EXPECT_TRUE(Time(971, 254) > Time(971, 253));
+  EXPECT_TRUE(Time(971, 254) >= Time(971, 253));
+  EXPECT_TRUE(Time(971, 254) < Time(971, 255));
+  EXPECT_TRUE(Time(971, 254) <= Time(971, 255));
+  EXPECT_TRUE(Time(971, 254) >= Time(971, 253));
+  EXPECT_TRUE(Time(971, 254) <= Time(971, 254));
+  EXPECT_TRUE(Time(971, 254) >= Time(971, 254));
+  EXPECT_TRUE(Time(972, 254) > Time(971, 254));
+  EXPECT_TRUE(Time(971, 254) < Time(972, 254));
+
+  EXPECT_TRUE(Time(-971, 254) > Time(-971, 253));
+  EXPECT_TRUE(Time(-971, 254) >= Time(-971, 253));
+  EXPECT_TRUE(Time(-971, 254) < Time(-971, 255));
+  EXPECT_TRUE(Time(-971, 254) <= Time(-971, 255));
+  EXPECT_TRUE(Time(-971, 254) >= Time(-971, 253));
+  EXPECT_TRUE(Time(-971, 254) <= Time(-971, 254));
+  EXPECT_TRUE(Time(-971, 254) >= Time(-971, 254));
+  EXPECT_TRUE(Time(-972, 254) < Time(-971, 254));
+  EXPECT_TRUE(Time(-971, 254) > Time(-972, 254));
 }
 
 TEST(TimeTest, Within) {
@@ -95,54 +131,73 @@
   EXPECT_FALSE(MACRO_DARG(Time(55, 5000).IsWithin(Time(55, 4900), 99)));
   EXPECT_TRUE(MACRO_DARG(Time(5, 0).IsWithin(Time(4, Time::kNSecInSec - 200),
                                              250)));
+  EXPECT_TRUE(Time(-5, Time::kNSecInSec - 200).IsWithin(Time(-4, 0), 250));
+  EXPECT_TRUE(Time(-5, 200).IsWithin(Time(-5, 0), 250));
 }
 
-TEST(TimeTest, Modulo) {
+TEST(TimeTest, Modulus) {
   EXPECT_EQ(MACRO_DARG(Time(0, Time::kNSecInSec / 10 * 2)),
             MACRO_DARG(Time(50, 0) % (Time::kNSecInSec / 10 * 3)));
+  EXPECT_EQ(Time(-1, Time::kNSecInSec / 10 * 8),
+            Time(-50, 0) % (Time::kNSecInSec / 10 * 3));
+  EXPECT_EQ(Time(-1, Time::kNSecInSec / 10 * 8),
+            Time(-50, 0) % (-Time::kNSecInSec / 10 * 3));
+  EXPECT_EQ(Time(0, Time::kNSecInSec / 10 * 2),
+            Time(50, 0) % (-Time::kNSecInSec / 10 * 3));
 }
 
+// TODO(brians): Finish tests for negatives from here on.
 TEST(TimeTest, InSeconds) {
   EXPECT_EQ(MACRO_DARG(Time(2, Time::kNSecInSec / 100 * 55 - 1)),
             Time::InSeconds(2.55));
+  EXPECT_EQ(MACRO_DARG(Time(-3, Time::kNSecInSec / 100 * 45)),
+            Time::InSeconds(-2.55));
 }
 
 TEST(TimeTest, ToSeconds) {
-  EXPECT_EQ(13.23, Time::InSeconds(13.23).ToSeconds());
+  EXPECT_DOUBLE_EQ(13.23, Time::InSeconds(13.23).ToSeconds());
+  EXPECT_NEAR(-13.23, Time::InSeconds(-13.23).ToSeconds(),
+              1.0 / Time::kNSecInSec * 2);
 }
 
-#ifdef __VXWORKS__
-TEST(TimeTest, ToTicks) {
-  EXPECT_EQ(sysClkRateGet() / 100,
-            MACRO_DARG(Time(0, Time::kNSecInSec / 100).ToTicks()));
-}
-TEST(TimeTest, InTicks) {
-  EXPECT_EQ(MACRO_DARG(Time(2, Time::kNSecInSec)),
-            Time::InTicks(sysClkRateGet() * 2.5));
-}
-#endif
-
 TEST(TimeTest, InMS) {
   Time t = Time::InMS(254971);
   EXPECT_EQ(254, t.sec());
   EXPECT_EQ(971000000, t.nsec());
+
+  Time t2 = Time::InMS(-254971);
+  EXPECT_EQ(-255, t2.sec());
+  EXPECT_EQ(Time::kNSecInSec - 971000000, t2.nsec());
+}
+
+TEST(TimeTest, ToMSec) {
+  EXPECT_EQ(254971, Time(254, 971000000).ToMSec());
+  EXPECT_EQ(-254971, Time(-255, Time::kNSecInSec - 971000000).ToMSec());
 }
 
 TEST(TimeTest, InNS) {
   Time t = Time::InNS(static_cast<int64_t>(973254111971ll));
   EXPECT_EQ(973, t.sec());
   EXPECT_EQ(254111971, t.nsec());
+
+  Time t2 = Time::InNS(static_cast<int64_t>(-973254111971ll));
+  EXPECT_EQ(-974, t2.sec());
+  EXPECT_EQ(Time::kNSecInSec - 254111971, t2.nsec());
 }
 
 TEST(TimeTest, InUS) {
   Time t = Time::InUS(254111971);
   EXPECT_EQ(254, t.sec());
   EXPECT_EQ(111971000, t.nsec());
+
+  Time t2 = Time::InUS(-254111971);
+  EXPECT_EQ(-255, t2.sec());
+  EXPECT_EQ(Time::kNSecInSec - 111971000, t2.nsec());
 }
 
-TEST(TimeTest, ToMSec) {
-  Time t(254, 971000000);
-  EXPECT_EQ(254971, t.ToMSec());
+TEST(TimeTest, ToUSec) {
+  EXPECT_EQ(254000971, Time(254, 971000).ToUSec());
+  EXPECT_EQ(-254000971, Time(-255, Time::kNSecInSec - 971000).ToUSec());
 }
 
 TEST(TimeTest, Abs) {
diff --git a/aos/common/util/util.gyp b/aos/common/util/util.gyp
index e295682..852f3d7 100644
--- a/aos/common/util/util.gyp
+++ b/aos/common/util/util.gyp
@@ -41,5 +41,23 @@
         '<(AOS)/build/aos.gyp:logging',
       ],
     },
+    {
+      'target_name': 'wrapping_counter',
+      'type': 'static_library',
+      'sources': [
+        'wrapping_counter.cc',
+      ],
+    },
+    {
+      'target_name': 'wrapping_counter_test',
+      'type': 'executable',
+      'sources': [
+        'wrapping_counter_test.cc',
+      ],
+      'dependencies': [
+        'wrapping_counter',
+        '<(EXTERNALS):gtest',
+      ],
+    },
   ],
 }
diff --git a/aos/common/util/wrapping_counter.cc b/aos/common/util/wrapping_counter.cc
new file mode 100644
index 0000000..61f5047
--- /dev/null
+++ b/aos/common/util/wrapping_counter.cc
@@ -0,0 +1,19 @@
+#include "aos/common/util/wrapping_counter.h"
+
+namespace aos {
+namespace util {
+
+WrappingCounter::WrappingCounter(int32_t initial_count)
+    : count_(initial_count), last_count_(0) {}
+
+int32_t WrappingCounter::Update(uint8_t current) {
+  if (last_count_ > current) {
+    count_ += 0x100;
+  }
+  count_ = (count_ & 0xffffff00) | current;
+  last_count_ = current;
+  return count_;
+}
+
+}  // namespace util
+}  // namespace aos
diff --git a/aos/common/util/wrapping_counter.h b/aos/common/util/wrapping_counter.h
new file mode 100644
index 0000000..fbf3611
--- /dev/null
+++ b/aos/common/util/wrapping_counter.h
@@ -0,0 +1,34 @@
+#ifndef AOS_COMMON_UTIL_WRAPPING_COUNTER_H_
+#define AOS_COMMON_UTIL_WRAPPING_COUNTER_H_
+
+#include <stdint.h>
+
+namespace aos {
+namespace util {
+
+// Deals correctly with 1-byte counters which wrap.
+// This is only possible if the counter never wraps twice between Update calls.
+// It will also fail if the counter ever goes down (that will be interpreted as
+// +255 instead of -1, for example).
+class WrappingCounter {
+ public:
+  WrappingCounter(int32_t initial_count = 0);
+
+  // Updates the internal counter with a new raw value.
+  // Returns count() for convenience.
+  int32_t Update(uint8_t current);
+
+  // Resets the actual count to value.
+  void Reset(int32_t value = 0) { count_ = value; }
+
+  int32_t count() const { return count_; }
+
+ private:
+  int32_t count_;
+  uint8_t last_count_;
+};
+
+}  // namespace util
+}  // namespace aos
+
+#endif  // AOS_COMMON_UTIL_WRAPPING_COUNTER_H_
diff --git a/aos/common/util/wrapping_counter_test.cc b/aos/common/util/wrapping_counter_test.cc
new file mode 100644
index 0000000..e257fb0
--- /dev/null
+++ b/aos/common/util/wrapping_counter_test.cc
@@ -0,0 +1,58 @@
+#include "aos/common/util/wrapping_counter.h"
+
+#include <limits.h>
+
+#include "gtest/gtest.h"
+
+namespace aos {
+namespace util {
+namespace testing {
+
+TEST(WrappingCounterTest, Basic) {
+  WrappingCounter test_counter;
+  EXPECT_EQ(0, test_counter.count());
+  EXPECT_EQ(1, test_counter.Update(1));
+  EXPECT_EQ(1, test_counter.Update(1));
+  EXPECT_EQ(2, test_counter.Update(2));
+  EXPECT_EQ(7, test_counter.Update(7));
+  EXPECT_EQ(7, test_counter.count());
+  EXPECT_EQ(123, test_counter.Update(123));
+  EXPECT_EQ(123, test_counter.count());
+}
+
+TEST(WrappingCounterTest, Reset) {
+  WrappingCounter test_counter;
+  test_counter.Update(5);
+  test_counter.Reset();
+  EXPECT_EQ(0, test_counter.count());
+  test_counter.Reset(56);
+  EXPECT_EQ(56, test_counter.count());
+}
+
+namespace {
+void test_wrapping(int16_t start, int16_t step) {
+  WrappingCounter test_counter;
+  for (int16_t i = start; i < INT16_MAX - step; i += step) {
+    EXPECT_EQ(i, test_counter.Update(i & 0xFF));
+  }
+}
+}
+
+// This tests the basic wrapping functionality.
+TEST(WrappingCounterTest, ReasonableWrapping) {
+  test_wrapping(0, 13);
+  test_wrapping(0, 53);
+  test_wrapping(0, 64);
+  test_wrapping(0, 73);
+}
+
+// It would be reasonable for these to fail if the implementation changes.
+TEST(WrappingCounterTest, UnreasonableWrapping) {
+  test_wrapping(0, 128);
+  test_wrapping(0, 213);
+  test_wrapping(0, 255);
+}
+
+}  // namespace testing
+}  // namespace util
+}  // namespace aos
diff --git a/aos/controls/polytope.h b/aos/controls/polytope.h
new file mode 100644
index 0000000..a873722
--- /dev/null
+++ b/aos/controls/polytope.h
@@ -0,0 +1,126 @@
+#ifndef _AOS_CONTROLS_POLYTOPE_H_
+#define _AOS_CONTROLS_POLYTOPE_H_
+
+#include "Eigen/Dense"
+#include "libcdd-094g-prefix/include/setoper.h"
+#include "libcdd-094g-prefix/include/cdd.h"
+
+namespace aos {
+namespace controls {
+
+// A n dimension polytope.
+template <int number_of_dimensions>
+class HPolytope {
+ public:
+  // Constructs a polytope given the H and k matricies.
+  HPolytope(Eigen::Matrix<double, Eigen::Dynamic, number_of_dimensions> H,
+            Eigen::Matrix<double, Eigen::Dynamic, 1> k)
+      : H_(H),
+        k_(k) {
+  }
+
+  static void Init() {
+    dd_set_global_constants();
+  }
+
+  // Returns a reference to H.
+  const Eigen::Matrix<double, Eigen::Dynamic,
+                      number_of_dimensions> &H() const {
+    return H_;
+  }
+
+  // Returns a reference to k.
+  const Eigen::Matrix<double, Eigen::Dynamic,
+                      1> &k() const {
+    return k_;
+  }
+
+  // Returns the number of dimensions in the polytope.
+  int ndim() const { return number_of_dimensions; }
+
+  // Returns the number of constraints currently in the polytope.
+  int num_constraints() const { return k_.rows(); }
+
+  // Returns true if the point is inside the polytope.
+  bool IsInside(Eigen::Matrix<double, number_of_dimensions, 1> point);
+
+  // Returns the list of vertices inside the polytope.
+  Eigen::Matrix<double, number_of_dimensions, Eigen::Dynamic> Vertices();
+
+ private:
+  Eigen::Matrix<double, Eigen::Dynamic, number_of_dimensions> H_;
+  Eigen::Matrix<double, Eigen::Dynamic, 1> k_;
+};
+
+template <int number_of_dimensions>
+bool HPolytope<number_of_dimensions>::IsInside(
+    Eigen::Matrix<double, number_of_dimensions, 1> point) {
+  auto ev = H_ * point;
+  for (int i = 0; i < num_constraints(); ++i) {
+    if (ev(i, 0) > k_(i, 0)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+template <int number_of_dimensions>
+Eigen::Matrix<double, number_of_dimensions, Eigen::Dynamic>
+    HPolytope<number_of_dimensions>::Vertices() {
+  dd_MatrixPtr matrix = dd_CreateMatrix(num_constraints(), ndim() + 1);
+
+  // Copy the data over. TODO(aschuh): Is there a better way?  I hate copying...
+  for (int i = 0; i < num_constraints(); ++i) {
+    dd_set_d(matrix->matrix[i][0], k_(i, 0));
+    for (int j = 0; j < ndim(); ++j) {
+      dd_set_d(matrix->matrix[i][j + 1], -H_(i, j));
+    }
+  }
+
+  matrix->representation = dd_Inequality;
+  matrix->numbtype = dd_Real;
+
+  dd_ErrorType error;
+  dd_PolyhedraPtr polyhedra = dd_DDMatrix2Poly(matrix, &error);
+  if (error != dd_NoError || polyhedra == NULL) {
+    dd_WriteErrorMessages(stderr, error);
+    dd_FreeMatrix(matrix);
+    Eigen::Matrix<double, number_of_dimensions, Eigen::Dynamic> ans(0, 0);
+    return ans;
+  }
+
+  dd_MatrixPtr vertex_matrix = dd_CopyGenerators(polyhedra);
+
+  int num_vertices = 0;
+  int num_rays = 0;
+  for (int i = 0; i < vertex_matrix->rowsize; ++i) {
+    if (dd_get_d(vertex_matrix->matrix[i][0]) == 0) {
+      num_rays += 1;
+    } else {
+      num_vertices += 1;
+    }
+  }
+
+  Eigen::Matrix<double, number_of_dimensions, Eigen::Dynamic> vertices(
+      number_of_dimensions, num_vertices);
+
+  int vertex_index = 0;
+  for (int i = 0; i < vertex_matrix->rowsize; ++i) {
+    if (dd_get_d(vertex_matrix->matrix[i][0]) != 0) {
+      for (int j = 0; j < number_of_dimensions; ++j) {
+        vertices(j, vertex_index) = dd_get_d(vertex_matrix->matrix[i][j + 1]);
+      }
+      ++vertex_index;
+    }
+  }
+  dd_FreeMatrix(vertex_matrix);
+  dd_FreePolyhedra(polyhedra);
+  dd_FreeMatrix(matrix);
+
+  return vertices;
+}
+
+}  // namespace controls
+}  // namespace aos
+
+#endif  // _AOS_CONTROLS_POLYTOPE_H_
diff --git a/aos/externals/.gitignore b/aos/externals/.gitignore
deleted file mode 100644
index 1af2e13..0000000
--- a/aos/externals/.gitignore
+++ /dev/null
@@ -1,27 +0,0 @@
-/ctemplate-129-prefix/
-/ctemplate-129.tar.gz
-/ctemplate-129/
-/eigen-3.1.3.tar.bz2
-/eigen-3.1.3/
-/gccdist.zip
-/gccdist/
-/gtest-1.6.0-p2/
-/gtest-1.6.0.zip
-/gyp-1488/
-/javacv-0.2-bin.zip
-/javacv-bin/
-/jpeg-8d/
-/jpegsrc.v8d.tar.gz
-/libjpeg/
-/ninja/
-/one-jar-boot-0.97.jar
-/gflags-2.0-prefix/
-/gflags-2.0.tar.gz
-/gflags-2.0/
-/libusb-1.0.9-prefix/
-/libusb-1.0.9.tar.bz2
-/libusb-1.0.9/
-/compiler-rt-RELEASE_32_final/
-/libevent-2.0.21-prefix/
-/libevent-2.0.21.tar.gz
-/libevent-2.0.21/
diff --git a/aos/externals/gyp.patch b/aos/externals/gyp.patch
index 9019406..b09b67d 100644
--- a/aos/externals/gyp.patch
+++ b/aos/externals/gyp.patch
@@ -1,7 +1,7 @@
 diff -rupN before/pylib/gyp/input.py after/pylib/gyp/input.py
 --- before/pylib/gyp/input.py	2012-11-20 16:38:09.394784918 -0800
 +++ after/pylib/gyp/input.py	2012-11-20 16:39:10.527105964 -0800
-@@ -2156,17 +2156,6 @@ def ValidateSourcesInTarget(target, targ
+@@ -2412,17 +2412,6 @@ def ValidateSourcesInTarget(target, targ
      basename = os.path.basename(name)  # Don't include extension.
      basenames.setdefault(basename, []).append(source)
  
@@ -11,10 +11,10 @@
 -      error += '  %s: %s\n' % (basename, ' '.join(files))
 -
 -  if error:
--    print ('static library %s has several files with the same basename:\n' %
--           target + error + 'Some build systems, e.g. MSVC08, '
--           'cannot handle that.')
--    raise KeyError, 'Duplicate basenames in sources section, see list above'
+-    print('static library %s has several files with the same basename:\n' %
+-          target + error + 'Some build systems, e.g. MSVC08, '
+-          'cannot handle that.')
+-    raise GypError('Duplicate basenames in sources section, see list above')
 -
  
  def ValidateRulesInTarget(target, target_dict, extra_sources_for_rules):