merging in new and improved claw code
diff --git a/aos/build/queues/compiler.rb b/aos/build/queues/compiler.rb
index e4312fd..58b2bf1 100644
--- a/aos/build/queues/compiler.rb
+++ b/aos/build/queues/compiler.rb
@@ -88,6 +88,7 @@
 	cpp_tree.add_cc_include("aos/common/inttypes.h".inspect)
 	cpp_tree.add_cc_include("aos/common/queue_types.h".inspect)
   cpp_tree.add_cc_include("aos/common/once.h".inspect)
+  cpp_tree.add_cc_include("aos/common/logging/logging_printf_formats.h".inspect)
 	cpp_tree.add_cc_using("::aos::to_network")
 	cpp_tree.add_cc_using("::aos::to_host")
 
diff --git a/aos/build/queues/objects/queue.rb b/aos/build/queues/objects/queue.rb
index 1199cc2..610bdf7 100644
--- a/aos/build/queues/objects/queue.rb
+++ b/aos/build/queues/objects/queue.rb
@@ -3,10 +3,11 @@
 	def initialize(type_name,name,length = nil) #lengths are for arrays
 		@type_name = type_name
 		@type = type_name.to_s
+    @type = '::aos::time::Time' if @type == 'Time'
 		@name = name
 		@length = length
 	end
-	CommonMistakes = {"short" => "int16_t","int" => "int32_t","long" => "int64_t"}
+	CommonMistakes = {"short" => "int16_t","int" => "int32_t","long" => "int64_t","time" => "Time"}
 	def check_type_error(locals)
 		if(!(Sizes[@type] || (@length != nil && @type == "char")) )
 			if(correction = CommonMistakes[@type])
@@ -48,7 +49,8 @@
                        "int8_t" => "%\" PRId8 \"",
                        "int16_t" => "%\" PRId16 \"",
                        "int32_t" => "%\" PRId32 \"",
-                       "int64_t" => "%\" PRId64 \""}
+                       "int64_t" => "%\" PRId64 \"",
+                       "::aos::time::Time" => "\" AOS_TIME_FORMAT \""}
         def toPrintFormat()
 		if(format = PrintFormat[@type])
 			return format;
@@ -60,12 +62,12 @@
 ERROR_MSG
 	end
 
-	Sizes = {"bool" => 1, "float" => 4,"double" => 8}
+	Sizes = {"bool" => 1, "float" => 4,"double" => 8,"::aos::time::Time" => 8}
 	[8,16,32,64].each do |len|
 		Sizes["int#{len}_t"] = len / 8
 		Sizes["uint#{len}_t"] = len / 8
 	end
-	Zero = {"float" => "0.0f","double" => "0.0","bool" => "false"}
+	Zero = {"float" => "0.0f","double" => "0.0","bool" => "false","::aos::time::Time" => "::aos::time::Time(0, 0)"}
 	def size()
 		if(size = Sizes[@type]); return size; end
 		return 1 if(@type == "char")
diff --git a/aos/build/queues/output/message_dec.rb b/aos/build/queues/output/message_dec.rb
index 59e2f35..40a2570 100644
--- a/aos/build/queues/output/message_dec.rb
+++ b/aos/build/queues/output/message_dec.rb
@@ -301,6 +301,8 @@
 	def fetchPrintArgs(args, parent = "")
 		if (self.type == 'bool')
 			args.push("#{parent}#{self.name} ? 'T' : 'f'")
+    elsif (self.type == '::aos::time::Time')
+      args.push("AOS_TIME_ARGS(#{parent}#{self.name}.sec(), #{parent}#{self.name}.nsec())")
 		else
 			args.push("#{parent}#{self.name}")
 		end
diff --git a/aos/build/queues/print_field.rb b/aos/build/queues/print_field.rb
index a86140f..c7b8530 100644
--- a/aos/build/queues/print_field.rb
+++ b/aos/build/queues/print_field.rb
@@ -1,8 +1,8 @@
 require File.dirname(__FILE__) + '/load.rb'
 
-TypeNames = [8, 16, 32, 64].collect do |size|
-  ["uint#{size}_t", "int#{size}_t"]
-end.flatten + ['bool', 'float', 'char', 'double']
+# TODO(brians): Special-case Time too and float/double if we can find a good way to do it.
+GenericTypeNames = ['float', 'double', 'char', '::aos::time::Time']
+IntegerSizes = [8, 16, 32, 64]
 
 WriteIffChanged.open(ARGV[0]) do |output|
   output.puts <<END
@@ -15,13 +15,16 @@
 #include <stdio.h>
 
 #include "aos/common/byteorder.h"
+#include "aos/common/time.h"
+#include "aos/common/print_field_helpers.h"
+#include "aos/common/logging/logging_printf_formats.h"
 
 namespace aos {
 
 bool PrintField(char *output, size_t *output_bytes, const void *input,
                 size_t *input_bytes, uint32_t type) {
   switch (type) {
-#{TypeNames.collect do |name|
+#{GenericTypeNames.collect do |name|
   message_element = Target::MessageElement.new(name, 'value')
   statement = MessageElementStmt.new(name, 'value')
   message_element.size = statement.size
@@ -39,11 +42,45 @@
                            #{print_args[0]});
         if (ret < 0) return false;
         if (static_cast<unsigned int>(ret) >= *output_bytes) return false;
-        *output_bytes -= ret + 1;
+        *output_bytes -= ret;
         return true;
       }
 END2
 end.join('')}
+#{IntegerSizes.collect do |size|
+  [true, false].collect do |signed|
+    size_bytes = size / 8
+    name = "#{signed ? '' : 'u'}int#{size}_t"
+    message_element = Target::MessageElement.new(name, 'value')
+    message_element.size = size_bytes
+    next <<END2
+    case #{message_element.getTypeID()}:
+      {
+        if (*input_bytes < #{size_bytes}) return false;
+        *input_bytes -= #{size_bytes};
+        #{name} value;
+        to_host(static_cast<const char *>(input), &value);
+        return PrintInteger<#{name}>(output, value, output_bytes);
+      }
+END2
+  end
+end.flatten.join('')}
+#{
+  message_element = Target::MessageElement.new('bool', 'value')
+  message_element.size = 1
+  r = <<END2
+    case #{message_element.getTypeID()}:
+      {
+        if (*input_bytes < 1) return false;
+        if (*output_bytes < 1) return false;
+        *input_bytes -= 1;
+        bool value = static_cast<const char *>(input)[0];
+        *output_bytes += 1;
+        *output = value ? 'T' : 'f';
+        return true;
+      }
+END2
+}
     default:
       return false;
   }
diff --git a/aos/build/queues/queue_primitives.rb b/aos/build/queues/queue_primitives.rb
index 2c9594e..421c3b4 100644
--- a/aos/build/queues/queue_primitives.rb
+++ b/aos/build/queues/queue_primitives.rb
@@ -4,7 +4,7 @@
 
 TypeNames = [8, 16, 32, 64].collect do |size|
   ["uint#{size}_t", "int#{size}_t"]
-end.flatten + ['bool', 'float', 'char', 'double']
+end.flatten + ['bool', 'float', 'char', 'double', '::aos::time::Time']
 
 FileUtils.mkdir_p(File.dirname(ARGV[0]))
 WriteIffChanged.open(ARGV[0]) do |output|
@@ -14,12 +14,15 @@
 
 #include <stdint.h>
 
+#include "aos/common/time.h"
+
 namespace aos {
 namespace queue_primitive_types {
 #{TypeNames.collect do |name|
   message_element = Target::MessageElement.new(name, 'value')
   statement = MessageElementStmt.new(name, 'value')
   message_element.size = statement.size
+  name = 'Time' if name == '::aos::time::Time'
   next <<END2
   static const uint32_t #{name}_p = #{message_element.getTypeID()};
 END2
@@ -40,7 +43,7 @@
   message_element.size = statement.size
   next <<END2
 template<>
-class TypeID<#{name}> {
+class TypeID< #{name}> {
  public:
   static const uint32_t id = #{message_element.getTypeID()};
 };
diff --git a/aos/common/common.gyp b/aos/common/common.gyp
index 8847d40..4b9d602 100644
--- a/aos/common/common.gyp
+++ b/aos/common/common.gyp
@@ -57,6 +57,10 @@
         '<(AOS)/linux_code/ipc_lib/ipc_lib.gyp:shared_mem',
         '<(AOS)/linux_code/ipc_lib/ipc_lib.gyp:core_lib',
         'mutex',
+        'time',
+      ],
+      'export_dependent_settings': [
+        'time',
       ],
       'actions': [
         {
@@ -231,6 +235,8 @@
         'test_queue',
         '<(AOS)/common/util/util.gyp:thread',
         'die',
+        # We want to run it with the assertions etc to try and catch bugs there.
+        '<(AOS)/linux_code/ipc_lib/ipc_lib.gyp:queue_debug',
       ],
     },
     {
diff --git a/aos/common/logging/logging.h b/aos/common/logging/logging.h
index 673cc9a..114007b 100644
--- a/aos/common/logging/logging.h
+++ b/aos/common/logging/logging.h
@@ -8,6 +8,8 @@
 #include <stdint.h>
 #include <stdlib.h>
 
+#include "aos/common/macros.h"
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -28,9 +30,6 @@
 DECL_LEVELS;
 #undef DECL_LEVEL
 
-#define STRINGIFY(x) TO_STRING(x)
-#define TO_STRING(x) #x
-
 // Not static const size_t for C code.
 #define LOG_MESSAGE_LEN 400
 
diff --git a/aos/common/logging/logging_impl.cc b/aos/common/logging/logging_impl.cc
index b74b69d..e7b0a5e 100644
--- a/aos/common/logging/logging_impl.cc
+++ b/aos/common/logging/logging_impl.cc
@@ -7,6 +7,7 @@
 #include "aos/common/inttypes.h"
 #include "aos/common/once.h"
 #include "aos/common/queue_types.h"
+#include "aos/common/logging/logging_printf_formats.h"
 
 namespace aos {
 namespace logging {
@@ -138,17 +139,13 @@
 }
 
 void PrintMessage(FILE *output, const LogMessage &message) {
-#define NSECONDS_DIGITS 5
-#define BASE_FORMAT                                      \
-  "%.*s(%" PRId32 ")(%05" PRIu16 "): %-7s at %010" PRId32 \
-  ".%0" STRINGIFY(NSECONDS_DIGITS) PRId32 "s: "
-#define BASE_ARGS                                             \
-  static_cast<int>(message.name_length), message.name,        \
-      static_cast<int32_t>(message.source), message.sequence, \
-      log_str(message.level), message.seconds, (message.nseconds + 5000) / 10000
-      switch (message.type) {
+#define BASE_ARGS                                                              \
+  AOS_LOGGING_BASE_ARGS(                                                       \
+      message.name_length, message.name, static_cast<int32_t>(message.source), \
+      message.sequence, message.level, message.seconds, message.nseconds)
+  switch (message.type) {
     case LogMessage::Type::kString:
-      fprintf(output, BASE_FORMAT "%.*s", BASE_ARGS,
+      fprintf(output, AOS_LOGGING_BASE_FORMAT "%.*s", BASE_ARGS,
               static_cast<int>(message.message_length), message.message);
       break;
     case LogMessage::Type::kStruct: {
@@ -169,7 +166,7 @@
         LOG(WARNING, "%zu extra bytes on message of type %s\n", input_length,
             type_cache::Get(message.structure.type_id).name.c_str());
       }
-      fprintf(output, BASE_FORMAT "%.*s: %.*s\n", BASE_ARGS,
+      fprintf(output, AOS_LOGGING_BASE_FORMAT "%.*s: %.*s\n", BASE_ARGS,
               static_cast<int>(message.structure.string_length),
               message.structure.serialized,
               static_cast<int>(sizeof(buffer) - output_length), buffer);
@@ -192,14 +189,12 @@
         LOG(FATAL, "printing %dx%d matrix of type %" PRIu32 " failed\n",
             message.matrix.rows, message.matrix.cols, message.matrix.type);
       }
-      fprintf(output, BASE_FORMAT "%.*s: %.*s\n", BASE_ARGS,
+      fprintf(output, AOS_LOGGING_BASE_FORMAT "%.*s: %.*s\n", BASE_ARGS,
               static_cast<int>(message.matrix.string_length),
               message.matrix.data,
               static_cast<int>(sizeof(buffer) - output_length), buffer);
     } break;
   }
-#undef NSECONDS_DIGITS
-#undef BASE_FORMAT
 #undef BASE_ARGS
 }
 
diff --git a/aos/common/logging/logging_printf_formats.h b/aos/common/logging/logging_printf_formats.h
new file mode 100644
index 0000000..be186bc
--- /dev/null
+++ b/aos/common/logging/logging_printf_formats.h
@@ -0,0 +1,30 @@
+#ifndef AOS_COMMON_LOGGING_LOGGING_PRINTF_FORMATS_H_
+#define AOS_COMMON_LOGGING_LOGGING_PRINTF_FORMATS_H_
+
+#include "aos/common/macros.h"
+
+// This file has printf(3) formats and corresponding arguments for printing out
+// times and log messages.
+// They are all split out as macros because there are 2 things that want to
+// print using the same format: log_displayer and PrintMessage in
+// logging_impl.cc.
+
+#define AOS_TIME_FORMAT \
+  "%010" PRId32 ".%0" STRINGIFY(AOS_TIME_NSECONDS_DIGITS) PRId32 "s"
+#define AOS_TIME_ARGS(sec, nsec)                      \
+  sec, (nsec + (AOS_TIME_NSECONDS_DENOMINATOR / 2)) / \
+      AOS_TIME_NSECONDS_DENOMINATOR
+
+#define AOS_LOGGING_BASE_FORMAT \
+  "%.*s(%" PRId32 ")(%05" PRIu16 "): %-7s at " AOS_TIME_FORMAT ": "
+#define AOS_LOGGING_BASE_ARGS(name_length, name, source, sequence, level, sec, \
+                              nsec)                                            \
+  static_cast<int>(name_length), name, source, sequence,                       \
+      ::aos::logging::log_str(level), AOS_TIME_ARGS(sec, nsec)
+
+// These 2 define how many digits we use to print out the nseconds fields of
+// times. They have to stay matching.
+#define AOS_TIME_NSECONDS_DIGITS 5
+#define AOS_TIME_NSECONDS_DENOMINATOR 10000
+
+#endif  // AOS_COMMON_LOGGING_LOGGING_PRINTF_FORMATS_H_
diff --git a/aos/common/macros.h b/aos/common/macros.h
index 2018b36..ba23fe4 100644
--- a/aos/common/macros.h
+++ b/aos/common/macros.h
@@ -22,4 +22,7 @@
 #define UNUSED_VARIABLE
 #endif
 
+#define STRINGIFY(x) TO_STRING(x)
+#define TO_STRING(x) #x
+
 #endif  // _AOS_COMMON_MACROS_H_
diff --git a/aos/common/print_field_helpers.h b/aos/common/print_field_helpers.h
new file mode 100644
index 0000000..48acdf6
--- /dev/null
+++ b/aos/common/print_field_helpers.h
@@ -0,0 +1,41 @@
+#ifndef AOS_COMMON_PRINT_FIELD_HELPERS_H_
+#define AOS_COMMON_PRINT_FIELD_HELPERS_H_
+
+#include <stdint.h>
+
+#include <type_traits>
+
+namespace aos {
+
+template<typename T>
+inline bool PrintInteger(char *buf, T val, size_t *output) {
+  static const bool is_signed = ::std::is_signed<T>::value;
+
+  size_t len = 0;
+  if (is_signed && val <= 0) {
+    while (*output > len && (val != 0 || len == 0)) {
+      buf[len++] = '0' - (val % 10);
+      val /= 10;
+    }
+    buf[len++] = '-';
+  } else {
+    while (*output > len && (val != 0 || len == 0)) {
+      buf[len++] = '0' + (val % 10);
+      val /= 10;
+    }
+  }
+  // If we have enough space.
+  if (*output >= len) {
+    for (size_t i = 0; i < (len >> 1); i++) {
+      std::swap(buf[len - 1 - i], buf[i]);
+    }
+    *output -= len;
+    return true;
+  } else {
+    return false;
+  }
+}
+
+}  // namespace aos
+
+#endif  // AOS_COMMON_PRINT_FIELD_HELPERS_H_
diff --git a/aos/common/queue_types.cc b/aos/common/queue_types.cc
index 93cf135..8c22d90 100644
--- a/aos/common/queue_types.cc
+++ b/aos/common/queue_types.cc
@@ -148,12 +148,12 @@
                         type_cache::Get(type.fields[i]->type))) {
         return false;
       }
+      // Ignore the trailing '\0' that the subcall put on.
+      output -= 1;
     }
 
-    // Update the input and output pointers, ignoring the trailing '\0' that the
-    // subcall put on.
-    output += output_bytes_before - *output_bytes - 1;
-    *output_bytes += 1;
+    // Update the input and output pointers.
+    output += output_bytes_before - *output_bytes;
     input =
         static_cast<const char *>(input) + input_bytes_before - *input_bytes;
   }
@@ -208,10 +208,8 @@
         return false;
       }
       CHECK_EQ(0u, input_bytes);
-      // Update the output pointer, ignoring the trailing '\0' that
-      // the subcall put on.
-      output += output_bytes_before - *output_bytes - 1;
-      *output_bytes += 1;
+      // Update the output pointer.
+      output += output_bytes_before - *output_bytes;
     }
 
     if (*output_bytes < 1) return false;
diff --git a/aos/common/queue_types.h b/aos/common/queue_types.h
index b95c946..eb0527e 100644
--- a/aos/common/queue_types.h
+++ b/aos/common/queue_types.h
@@ -102,6 +102,7 @@
 //
 // Prints the value from 1 primitive message field into output.
 // The implementation of this is generated by the ruby code.
+// Does not include a trailing '\0' in what it subtracts from *output_bytes.
 bool PrintField(char *output, size_t *output_bytes, const void *input,
                 size_t *input_bytes, uint32_t type)
     __attribute__((warn_unused_result));
diff --git a/aos/common/time.h b/aos/common/time.h
index c646661..ca1d207 100644
--- a/aos/common/time.h
+++ b/aos/common/time.h
@@ -47,7 +47,7 @@
   static const int32_t kNSecInUSec = 1000;
   static const int32_t kMSecInSec = 1000;
   static const int32_t kUSecInSec = 1000000;
-  constexpr Time(int32_t sec, int32_t nsec)
+  constexpr Time(int32_t sec = 0, int32_t nsec = 0)
       : sec_(sec), nsec_(CheckConstexpr(nsec)) {
   }
   #ifndef SWIG
diff --git a/aos/externals/WPILib/WPILib.a b/aos/externals/WPILib/WPILib.a
deleted file mode 100644
index 27cc22f..0000000
--- a/aos/externals/WPILib/WPILib.a
+++ /dev/null
Binary files differ
diff --git a/aos/externals/WPILib/WPILib/DriverStation.cpp b/aos/externals/WPILib/WPILib/DriverStation.cpp
index dfd92c0..e90beae 100644
--- a/aos/externals/WPILib/WPILib/DriverStation.cpp
+++ b/aos/externals/WPILib/WPILib/DriverStation.cpp
@@ -158,11 +158,11 @@
   }
 	if (!lastEnabled && IsEnabled()) 
 	{
-		// If starting teleop, assume that autonomous just took up 15 seconds
+		// If starting teleop, assume that autonomous just took up 10 seconds
 		if (IsAutonomous())
 			m_approxMatchTimeOffset = Timer::GetFPGATimestamp();
 		else
-			m_approxMatchTimeOffset = Timer::GetFPGATimestamp() - 15.0;
+			m_approxMatchTimeOffset = Timer::GetFPGATimestamp() - 10.0;
 	}
 	else if (lastEnabled && !IsEnabled())
 	{
diff --git a/aos/externals/WPILib/WPILib/RobotBase.cpp b/aos/externals/WPILib/WPILib/RobotBase.cpp
index 393b397..a42938b 100644
--- a/aos/externals/WPILib/WPILib/RobotBase.cpp
+++ b/aos/externals/WPILib/WPILib/RobotBase.cpp
@@ -19,7 +19,7 @@
 RobotBase* RobotBase::m_instance = NULL;
 
 const char *FILE_NAME = "/c/FRC_Lib_Version.ini";
-const char *VERSION_STRING = "C++ 2014 Update 0";
+const char *VERSION_STRING = "C++ 2014 Update 1";
 
 
 void RobotBase::setInstance(RobotBase* robot)
diff --git a/aos/externals/WPILib/WPILib/Scripts/CopyWPILibToUpdateDirectory.cmd b/aos/externals/WPILib/WPILib/Scripts/CopyWPILibToUpdateDirectory.cmd
index 2445cce..26ecc83 100644
--- a/aos/externals/WPILib/WPILib/Scripts/CopyWPILibToUpdateDirectory.cmd
+++ b/aos/externals/WPILib/WPILib/Scripts/CopyWPILibToUpdateDirectory.cmd
@@ -6,7 +6,7 @@
 mkdir vxworks-6.3\target\h\WPILib\CAN
 mkdir vxworks-6.3\target\h\WPILib\ChipObject
 mkdir vxworks-6.3\target\h\WPILib\ChipObject\fpgainterfacecapi
-mkdir vxworks-6.3\target\h\WPILib\CInterfaces
+mkdir vxworks-6.3\target\h\WPILib\Interfaces
 mkdir vxworks-6.3\target\h\WPILib\Commands
 mkdir vxworks-6.3\target\h\WPILib\NetworkCommunication
 mkdir vxworks-6.3\target\h\WPILib\SmartDashboard
@@ -32,7 +32,7 @@
 del vxworks-6.3\target\h\WPIlib\Buttons\*.h
 del vxworks-6.3\target\h\WPIlib\CAN\*.h
 del vxworks-6.3\target\h\WPIlib\ChipObject\*.h
-del vxworks-6.3\target\h\WPIlib\CInterfaces\*.h
+del vxworks-6.3\target\h\WPIlib\Interfaces\*.h
 del vxworks-6.3\target\h\WPIlib\Commands\*.h
 del vxworks-6.3\target\h\WPIlib\NetworkCommunication\*.h
 del vxworks-6.3\target\h\WPIlib\SmartDashboard\*.h
@@ -61,7 +61,7 @@
 copy C:\WindRiver\workspace\WPILib\CAN\*.h vxworks-6.3\target\h\WPILib\CAN
 copy C:\WindRiver\workspace\WPILib\ChipObject\*.h vxworks-6.3\target\h\WPILib\ChipObject
 copy C:\WindRiver\workspace\WPILib\ChipObject\fpgainterfacecapi\*.h vxworks-6.3\target\h\WPILib\ChipObject\fpgainterfacecapi
-copy C:\WindRiver\workspace\WPILib\CInterfaces\*.h vxworks-6.3\target\h\WPILib\CInterfaces
+copy C:\WindRiver\workspace\WPILib\Interfaces\*.h vxworks-6.3\target\h\WPILib\Interfaces
 copy C:\WindRiver\workspace\WPILib\Commands\*.h vxworks-6.3\target\h\WPILib\Commands
 copy C:\WindRiver\workspace\WPILib\NetworkCommunication\*.h vxworks-6.3\target\h\WPILib\NetworkCommunication
 copy C:\WindRiver\workspace\WPILib\SmartDashboard\*.h vxworks-6.3\target\h\WPILib\SmartDashboard
diff --git a/aos/externals/WPILib/WPILib/SerialPort.cpp b/aos/externals/WPILib/WPILib/SerialPort.cpp
index 7a1047e..f948f0a 100644
--- a/aos/externals/WPILib/WPILib/SerialPort.cpp
+++ b/aos/externals/WPILib/WPILib/SerialPort.cpp
@@ -183,13 +183,18 @@
 	uint32_t retCount = 0;
 	if (!m_consoleModeEnabled)
 	{
-		ViStatus localStatus = viBufRead(m_portHandle, (ViPBuf)buffer, count, (ViPUInt32)&retCount);
+		ViStatus localStatus = viRead(m_portHandle, (ViPBuf)buffer, count, (ViPUInt32)&retCount);
 		switch (localStatus)
 		{
 		case VI_SUCCESS_TERM_CHAR:
 		case VI_SUCCESS_MAX_CNT:
 		case VI_ERROR_TMO: // Timeout
 			break;
+		case VI_ERROR_IO:
+		case VI_ERROR_ASRL_OVERRUN:	
+			wpi_setError(localStatus);
+			Reset();
+			break;
 		default:
 			wpi_setError(localStatus);
 		}
@@ -209,7 +214,7 @@
 	uint32_t retCount = 0;
 	if (!m_consoleModeEnabled)
 	{
-		ViStatus localStatus = viBufWrite(m_portHandle, (ViPBuf)buffer, count, (ViPUInt32)&retCount);
+		ViStatus localStatus = viWrite(m_portHandle, (ViPBuf)buffer, count, (ViPUInt32)&retCount);
 		wpi_setError(localStatus);
 	}
 	return retCount;
diff --git a/aos/externals/WPILib/WPILib/networktables2/AbstractNetworkTableEntryStore.cpp b/aos/externals/WPILib/WPILib/networktables2/AbstractNetworkTableEntryStore.cpp
index 00829a0..8d268b2 100644
--- a/aos/externals/WPILib/WPILib/networktables2/AbstractNetworkTableEntryStore.cpp
+++ b/aos/externals/WPILib/WPILib/networktables2/AbstractNetworkTableEntryStore.cpp
@@ -32,7 +32,7 @@
 	 */
 	NetworkTableEntry* AbstractNetworkTableEntryStore::GetEntry(std::string& name){
 		{ 
-			NTSynchronized sync(LOCK);
+			NTSynchronized sync(block_namedEntries);
 			std::map<std::string, NetworkTableEntry*>::iterator value_itr = namedEntries.find(name);
 			if(value_itr != namedEntries.end()) {
 				return value_itr->second;
@@ -43,7 +43,7 @@
 	
 	NetworkTableEntry* AbstractNetworkTableEntryStore::GetEntry(EntryId entryId){
 		{ 
-			NTSynchronized sync(LOCK);
+			NTSynchronized sync(block_namedEntries);
 			
 			std::map<EntryId, NetworkTableEntry*>::iterator value_itr = idEntries.find(entryId);
 			if(value_itr != idEntries.end()) {
@@ -55,7 +55,7 @@
 	
 	std::vector<std::string>* AbstractNetworkTableEntryStore::keys(){
 		{ 
-			NTSynchronized sync(LOCK);
+			NTSynchronized sync(block_namedEntries);
 			std::vector<std::string>* keys = new std::vector<std::string>();
 			std::map<std::string, NetworkTableEntry*>::iterator itr;
 			
@@ -77,7 +77,7 @@
 	 */
 	void AbstractNetworkTableEntryStore::clearEntries(){
 		{ 
-			NTSynchronized sync(LOCK);
+			NTSynchronized sync(block_namedEntries);
 			namedEntries.clear();
 			idEntries.clear();
 		}
@@ -88,7 +88,7 @@
 	 */
 	void AbstractNetworkTableEntryStore::clearIds(){
 		{ 
-			NTSynchronized sync(LOCK);
+			NTSynchronized sync(block_namedEntries);
 			std::map<std::string, NetworkTableEntry*>::iterator itr;
 			idEntries.clear();
 			
@@ -119,7 +119,7 @@
 	 */
 	void AbstractNetworkTableEntryStore::PutOutgoing(std::string& name, NetworkTableEntryType* type, EntryValue value){
 		{ 
-			NTSynchronized sync(LOCK);
+			NTSynchronized sync(block_namedEntries);
 			std::map<std::string, NetworkTableEntry*>::iterator index = namedEntries.find(name);
 			NetworkTableEntry* tableEntry;
 			if(index == namedEntries.end())//if the name does not exist in the current entries
@@ -167,7 +167,7 @@
 	
 	void AbstractNetworkTableEntryStore::offerIncomingAssignment(NetworkTableEntry* entry){
 		{ 
-			NTSynchronized sync(LOCK);
+			NTSynchronized sync(block_namedEntries);
 			std::map<std::string, NetworkTableEntry*>::iterator itr = namedEntries.find(entry->name);
 			NetworkTableEntry* tableEntry;
 			if(addEntry(entry)){
@@ -203,7 +203,7 @@
 	 */
 	void AbstractNetworkTableEntryStore::notifyEntries(ITable* table, ITableListener* listener){
 		{ 
-			NTSynchronized sync(LOCK);
+			NTSynchronized sync(block_namedEntries);
 			std::map<std::string, NetworkTableEntry*>::iterator itr;
 			for(itr = namedEntries.begin(); itr != namedEntries.end(); itr++)
 			{
diff --git a/aos/externals/WPILib/WPILib/networktables2/AbstractNetworkTableEntryStore.h b/aos/externals/WPILib/WPILib/networktables2/AbstractNetworkTableEntryStore.h
index b394cfb..7d6903f 100644
--- a/aos/externals/WPILib/WPILib/networktables2/AbstractNetworkTableEntryStore.h
+++ b/aos/externals/WPILib/WPILib/networktables2/AbstractNetworkTableEntryStore.h
@@ -36,6 +36,7 @@
 class AbstractNetworkTableEntryStore : public IncomingEntryReceiver{
 protected:
 	std::map<EntryId,NetworkTableEntry*> idEntries;
+	NTReentrantSemaphore block_namedEntries;
 	std::map<std::string,NetworkTableEntry*> namedEntries;
 	TableListenerManager& listenerManager;
 
diff --git a/aos/externals/WPILib/WPILib/networktables2/NetworkTableEntry.cpp b/aos/externals/WPILib/WPILib/networktables2/NetworkTableEntry.cpp
index 9538c91..658c7c7 100644
--- a/aos/externals/WPILib/WPILib/networktables2/NetworkTableEntry.cpp
+++ b/aos/externals/WPILib/WPILib/networktables2/NetworkTableEntry.cpp
@@ -20,6 +20,17 @@
 	m_isDirty = false;
 }
 
+NetworkTableEntry::NetworkTableEntry(const NetworkTableEntry &other) :
+	name(other.name),
+	id(other.id),
+	sequenceNumber(other.sequenceNumber),
+	type(other.type),
+	m_isNew(other.m_isNew),
+	m_isDirty(other.m_isDirty)
+{
+	value = type->copyValue(other.value);
+}
+
 NetworkTableEntry::~NetworkTableEntry(){
   type->deleteValue(value);
 }
diff --git a/aos/externals/WPILib/WPILib/networktables2/NetworkTableEntry.h b/aos/externals/WPILib/WPILib/networktables2/NetworkTableEntry.h
index 2a29004..27223e4 100644
--- a/aos/externals/WPILib/WPILib/networktables2/NetworkTableEntry.h
+++ b/aos/externals/WPILib/WPILib/networktables2/NetworkTableEntry.h
@@ -42,6 +42,7 @@
 	
 	NetworkTableEntry(std::string& name, NetworkTableEntryType* type, EntryValue value);
 	NetworkTableEntry(EntryId id, std::string& name, SequenceNumber sequenceNumber, NetworkTableEntryType* type, EntryValue value);
+	NetworkTableEntry(const NetworkTableEntry &);
 	virtual ~NetworkTableEntry();
 
 	EntryId GetId();
diff --git a/aos/externals/WPILib/WPILib/networktables2/WriteManager.cpp b/aos/externals/WPILib/WPILib/networktables2/WriteManager.cpp
index bbe08f5..64688e3 100644
--- a/aos/externals/WPILib/WPILib/networktables2/WriteManager.cpp
+++ b/aos/externals/WPILib/WPILib/networktables2/WriteManager.cpp
@@ -54,10 +54,15 @@
 
 void WriteManager::offerOutgoingAssignment(NetworkTableEntry* entry) {
 	{ 
-		NTSynchronized sync(transactionsLock);
-		((std::queue<NetworkTableEntry*>*)incomingAssignmentQueue)->push(entry);
-		
-		if(((std::queue<NetworkTableEntry*>*)incomingAssignmentQueue)->size()>=queueSize){
+		bool test_queue_overflow=false;
+		{
+			NTSynchronized sync(transactionsLock);
+			((std::queue<NetworkTableEntry*>*)incomingAssignmentQueue)->push(entry);
+
+			test_queue_overflow=(((std::queue<NetworkTableEntry*>*)incomingAssignmentQueue)->size()>=queueSize);
+		}
+		if (test_queue_overflow)
+		{
 			run();
 			writeWarning("assignment queue overflowed. decrease the rate at which you create new entries or increase the write buffer size");
 		}
@@ -67,9 +72,15 @@
 
 void WriteManager::offerOutgoingUpdate(NetworkTableEntry* entry) {
 	{ 
-		NTSynchronized sync(transactionsLock);
-		((std::queue<NetworkTableEntry*>*)incomingUpdateQueue)->push(entry);
-		if(((std::queue<NetworkTableEntry*>*)incomingUpdateQueue)->size()>=queueSize){
+		bool test_queue_overflow=false;
+		{
+			NTSynchronized sync(transactionsLock);
+			((std::queue<NetworkTableEntry*>*)incomingUpdateQueue)->push(entry);
+			test_queue_overflow=(((std::queue<NetworkTableEntry*>*)incomingUpdateQueue)->size()>=queueSize);
+
+		}
+		if (test_queue_overflow)
+		{
 			run();
 			writeWarning("update queue overflowed. decrease the rate at which you update entries or increase the write buffer size");
 		}
@@ -97,10 +108,17 @@
 		entry = ((std::queue<NetworkTableEntry*>*)outgoingAssignmentQueue)->front();
 		((std::queue<NetworkTableEntry*>*)outgoingAssignmentQueue)->pop();
 		{
-			NTSynchronized sync(entryStore.LOCK);
-			entry->MakeClean();
-			wrote = true;
-			receiver.offerOutgoingAssignment(entry);
+			NetworkTableEntry * entryCopy;
+
+			{
+				NTSynchronized sync(entryStore.LOCK);
+				entry->MakeClean();
+				wrote = true;
+				entryCopy = new NetworkTableEntry(*entry);
+			}
+
+			receiver.offerOutgoingAssignment(entryCopy);
+			delete entryCopy;
 		}
 	}
 	
@@ -108,10 +126,17 @@
 		entry = ((std::queue<NetworkTableEntry*>*)outgoingUpdateQueue)->front();
 		((std::queue<NetworkTableEntry*>*)outgoingUpdateQueue)->pop();
 		{ 
-			NTSynchronized sync(entryStore.LOCK);
-			entry->MakeClean();
-			wrote = true;
-			receiver.offerOutgoingUpdate(entry);
+			NetworkTableEntry * entryCopy;
+
+			{
+				NTSynchronized sync(entryStore.LOCK);
+				entry->MakeClean();
+				wrote = true;
+				entryCopy = new NetworkTableEntry(*entry);
+			}
+
+			receiver.offerOutgoingUpdate(entryCopy);
+			delete entryCopy;
 		}
 	}
 	
diff --git a/aos/externals/WPILib/WPILib/networktables2/client/ClientNetworkTableEntryStore.cpp b/aos/externals/WPILib/WPILib/networktables2/client/ClientNetworkTableEntryStore.cpp
index d2fc19d..15c0e1f 100644
--- a/aos/externals/WPILib/WPILib/networktables2/client/ClientNetworkTableEntryStore.cpp
+++ b/aos/externals/WPILib/WPILib/networktables2/client/ClientNetworkTableEntryStore.cpp
@@ -17,7 +17,7 @@
 
 bool ClientNetworkTableEntryStore::addEntry(NetworkTableEntry* newEntry){
 	{
-		NTSynchronized sync(LOCK);
+		NTSynchronized sync(block_namedEntries);
 		NetworkTableEntry* entry = (NetworkTableEntry*)namedEntries[newEntry->name];
 
 		if(entry!=NULL){
diff --git a/aos/externals/WPILib/WPILib/networktables2/connection/NetworkTableConnection.cpp b/aos/externals/WPILib/WPILib/networktables2/connection/NetworkTableConnection.cpp
index 6f675b0..13c61fc 100644
--- a/aos/externals/WPILib/WPILib/networktables2/connection/NetworkTableConnection.cpp
+++ b/aos/externals/WPILib/WPILib/networktables2/connection/NetworkTableConnection.cpp
@@ -19,6 +19,7 @@
 
 void NetworkTableConnection::SetIOStream(IOStream* stream)
 {
+	isValid=(stream!=NULL);
 	ioStream->SetIOStream(stream);  //just passing through
 }
 
@@ -102,7 +103,7 @@
 }
 
 void NetworkTableConnection::read(ConnectionAdapter& adapter) {
-	int messageType = ioStream->readByte();
+	int messageType = (isValid)?ioStream->readByte():KEEP_ALIVE;
 	switch (messageType) {
 	case KEEP_ALIVE:
 		adapter.keepAlive();
diff --git a/aos/externals/WPILib/WPILib/networktables2/server/NetworkTableServer.cpp b/aos/externals/WPILib/WPILib/networktables2/server/NetworkTableServer.cpp
index ea85356..a0f3677 100644
--- a/aos/externals/WPILib/WPILib/networktables2/server/NetworkTableServer.cpp
+++ b/aos/externals/WPILib/WPILib/networktables2/server/NetworkTableServer.cpp
@@ -35,6 +35,9 @@
 
 void NetworkTableServer::Close(){
 	try{
+		//Note: streamProvider must come before the incomingStreamMonitor so the that task can complete first for the thread to close 
+		//  [9/1/2013 Terminator] 
+		streamProvider.close(); 
 		incomingStreamMonitor.stop();
 		writeManager.stop();
 		connectionList.closeAll();
diff --git a/aos/externals/WPILib/WPILib/networktables2/server/ServerConnectionAdapter.cpp b/aos/externals/WPILib/WPILib/networktables2/server/ServerConnectionAdapter.cpp
index 195f6e7..62323d8 100644
--- a/aos/externals/WPILib/WPILib/networktables2/server/ServerConnectionAdapter.cpp
+++ b/aos/externals/WPILib/WPILib/networktables2/server/ServerConnectionAdapter.cpp
@@ -36,6 +36,9 @@
 	gotoState(new ServerConnectionState_Error(e));
 	adapterListener.close(*this, true);
 	m_IsAdapterListenerClosed=true;
+	if (readThread)    {
+	  readThread->stop();
+	}
 }
 
 void ServerConnectionAdapter::ioException(IOException& e) {
@@ -47,6 +50,9 @@
 		gotoState(new ServerConnectionState_Error(e));
 	adapterListener.close(*this, false);
 	m_IsAdapterListenerClosed=true;
+	if (readThread)    {
+	  readThread->stop();
+	}
 }
 
 
diff --git a/aos/externals/WPILib/WPILib/networktables2/server/ServerIncomingStreamMonitor.cpp b/aos/externals/WPILib/WPILib/networktables2/server/ServerIncomingStreamMonitor.cpp
index 51c5733..44bf367 100644
--- a/aos/externals/WPILib/WPILib/networktables2/server/ServerIncomingStreamMonitor.cpp
+++ b/aos/externals/WPILib/WPILib/networktables2/server/ServerIncomingStreamMonitor.cpp
@@ -7,6 +7,7 @@
 
 #include "networktables2/server/ServerIncomingStreamMonitor.h"
 #include "networktables2/stream/IOStream.h"
+#include "networktables2/util/System.h"
 
 ServerIncomingStreamMonitor::ServerIncomingStreamMonitor(IOStreamProvider& _streamProvider, ServerNetworkTableEntryStore& _entryStore,
 		ServerIncomingConnectionListener& _incomingListener, ServerAdapterManager& _adapterListener, NetworkTableEntryTypeManager& _typeManager,
@@ -69,6 +70,7 @@
 				ServerConnectionAdapter* connectionAdapter = new ServerConnectionAdapter(newStream, entryStore, entryStore, adapterListener, typeManager, threadManager);
 				incomingListener.OnNewConnection(*connectionAdapter);
 			}
+			sleep_ms(100); //avoid busy wait
 		}
 	}
 	catch (IOException& e)
diff --git a/aos/externals/WPILib/WPILib/networktables2/server/ServerNetworkTableEntryStore.cpp b/aos/externals/WPILib/WPILib/networktables2/server/ServerNetworkTableEntryStore.cpp
index b1d86c9..b49bbf5 100644
--- a/aos/externals/WPILib/WPILib/networktables2/server/ServerNetworkTableEntryStore.cpp
+++ b/aos/externals/WPILib/WPILib/networktables2/server/ServerNetworkTableEntryStore.cpp
@@ -18,7 +18,7 @@
 
 bool ServerNetworkTableEntryStore::addEntry(NetworkTableEntry* newEntry)
 {
-	NTSynchronized sync(LOCK);
+	NTSynchronized sync(block_namedEntries);
 	NetworkTableEntry* entry = namedEntries[newEntry->name];
 	
 	if (entry == NULL)
@@ -44,13 +44,20 @@
  */
 void ServerNetworkTableEntryStore::sendServerHello(NetworkTableConnection& connection)
 {
-	NTSynchronized sync(LOCK);
-	std::map<std::string, NetworkTableEntry*>::iterator itr;
-	for (itr = namedEntries.begin(); itr != namedEntries.end(); itr++)
+	std::vector<NetworkTableEntry *> entry_list;
 	{
-		NetworkTableEntry* entry = itr->second;
-		connection.sendEntryAssignment(*entry);
+		NTSynchronized sync(block_namedEntries);
+		std::map<std::string, NetworkTableEntry*>::iterator itr;
+		for (itr = namedEntries.begin(); itr != namedEntries.end(); itr++)
+		{
+			NetworkTableEntry* entry = itr->second;
+			entry_list.push_back(entry);
+		}
 	}
+
+	for (size_t i=0;i<entry_list.size();i++)
+		connection.sendEntryAssignment(*(entry_list[i]));
+
 	connection.sendServerHelloComplete();
 	connection.flush();
 }
diff --git a/aos/externals/WPILib/WPILib/networktables2/stream/FDIOStream.cpp b/aos/externals/WPILib/WPILib/networktables2/stream/FDIOStream.cpp
index da8e13d..55e2ac2 100644
--- a/aos/externals/WPILib/WPILib/networktables2/stream/FDIOStream.cpp
+++ b/aos/externals/WPILib/WPILib/networktables2/stream/FDIOStream.cpp
@@ -11,13 +11,8 @@
 
 #include <errno.h>
 #include <stdlib.h>
-#ifdef _WRS_KERNEL
 #include <ioLib.h>
 #include <selectLib.h>
-#else
-#include <unistd.h>
-#include <sys/time.h>
-#endif
 #include <string.h>
 #include <stdio.h>
 
@@ -27,6 +22,13 @@
   //	f = fdopen(_fd, "rbwb");
   //	if(f==NULL)
   //		throw IOException("Could not open stream from file descriptor", errno);
+  // Set the TCP socket to be non-blocking
+  int on = 1;
+  if (ioctl(fd, FIONBIO, (int)&on) < 0)
+  {
+    ::close(fd);
+    throw IOException("Could not set socket to non-blocking mode");
+  }
 }
 FDIOStream::~FDIOStream(){
 	close();
@@ -69,14 +71,35 @@
 	return totalRead;
 }
 int FDIOStream::write(const void* ptr, int numbytes){
-  int numWrote = ::write(fd, (char*)ptr, numbytes);//TODO: this is bad
-  //int numWrote = fwrite(ptr, 1, numbytes, f);
-  if(numWrote==numbytes)
-    return numWrote;
-  perror("write error: ");
-  fflush(stderr);
-  throw IOException("Could not write all bytes to fd stream");
-	
+	int numWrote = ::write(fd, (char*)ptr, numbytes);
+	if(numWrote==numbytes)
+		return numWrote;
+
+	if (numWrote == -1 && (errno == EWOULDBLOCK || errno == EAGAIN))
+	{
+		// see if write timeout expires
+		struct timeval timeout;
+		fd_set fdSet;
+
+		FD_ZERO(&fdSet);
+		FD_SET(fd, &fdSet);
+		timeout.tv_sec = 1;		// wait 1 second for the other side to connect
+		timeout.tv_usec = 0;
+
+		int select_result = select(FD_SETSIZE, NULL, &fdSet, NULL, &timeout);
+		if ( select_result < 0)
+			throw IOException("Select returned an error on write");
+
+		if (FD_ISSET(fd, &fdSet)) {
+			numWrote = ::write(fd, (char*)ptr, numbytes);
+			if(numWrote==numbytes)
+				return numWrote;
+		}
+	}
+ 	
+	perror("write error: ");
+	fflush(stderr);
+	throw IOException("Could not write all bytes to fd stream");
 }
 void FDIOStream::flush(){
   //if(fflush(f)==EOF)
diff --git a/aos/linux_code/ipc_lib/ipc_lib.gyp b/aos/linux_code/ipc_lib/ipc_lib.gyp
index fe8b2e0..68cd13b 100644
--- a/aos/linux_code/ipc_lib/ipc_lib.gyp
+++ b/aos/linux_code/ipc_lib/ipc_lib.gyp
@@ -46,6 +46,26 @@
         'core_lib',
         '<(AOS)/build/aos.gyp:logging_interface',
       ],
+      'defines': [
+        'QUEUE_DEBUG=0',
+      ],
+    },
+    # A version of the queue code compiled with assertions enabled etc.
+    {
+      'target_name': 'queue_debug',
+      'type': 'static_library',
+      'sources': [
+        'queue.cc',
+      ],
+      'dependencies': [
+        'queue',
+      ],
+      'export_dependent_settings': [
+        'queue',
+      ],
+      'defines': [
+        'QUEUE_DEBUG=1',
+      ],
     },
     {
       'target_name': 'raw_queue_test',
@@ -55,7 +75,7 @@
       ],
       'dependencies': [
         '<(EXTERNALS):gtest',
-        'queue',
+        'queue_debug',
         '<(AOS)/build/aos.gyp:logging',
         'core_lib',
         '<(AOS)/common/common.gyp:queue_testutils',
diff --git a/aos/linux_code/ipc_lib/queue.cc b/aos/linux_code/ipc_lib/queue.cc
index 211882f..8513e32 100644
--- a/aos/linux_code/ipc_lib/queue.cc
+++ b/aos/linux_code/ipc_lib/queue.cc
@@ -1,3 +1,7 @@
+#if !QUEUE_DEBUG
+#define NDEBUG
+#endif
+
 #include "aos/linux_code/ipc_lib/queue.h"
 
 #include <stdio.h>
@@ -43,7 +47,7 @@
 struct RawQueue::MessageHeader {
   // This gets incremented and decremented with atomic instructions without any
   // locks held.
-  int ref_count;
+  int32_t ref_count;
   MessageHeader *next;
   // Gets the message header immediately preceding msg.
   static MessageHeader *Get(const void *msg) {
@@ -51,14 +55,10 @@
         static_cast<uint8_t *>(const_cast<void *>(msg)) - sizeof(MessageHeader),
         alignof(MessageHeader)));
   }
-  void Swap(MessageHeader *other) {
-    MessageHeader temp;
-    memcpy(&temp, other, sizeof(temp));
-    memcpy(other, this, sizeof(*other));
-    memcpy(this, &temp, sizeof(*this));
-  }
+  // Padding to make the total size 8 bytes if we have 4-byte pointers or bump
+  // it to 16 if a pointer is 8 bytes by itself.
 #if __SIZEOF_POINTER__ == 8
-  char padding[16 - sizeof(next) - sizeof(ref_count)];
+  char padding[4];
 #elif __SIZEOF_POINTER__ == 4
   // No padding needed to get 8 byte total size.
 #else
@@ -66,9 +66,16 @@
 #endif
 };
 
-struct RawQueue::ReadData {
-  bool writable_start;
-};
+inline int RawQueue::index_add1(int index) {
+  // Doing it this way instead of with % is more efficient on ARM.
+  int r = index + 1;
+  assert(index <= data_length_);
+  if (r == data_length_) {
+    return 0;
+  } else {
+    return r;
+  }
+}
 
 void RawQueue::DecrementMessageReferenceCount(const void *msg) {
   MessageHeader *header = MessageHeader::Get(msg);
@@ -88,7 +95,7 @@
   }
 }
 
-void RawQueue::IncrementMessageReferenceCount(const void *msg) const {
+inline void RawQueue::IncrementMessageReferenceCount(const void *msg) const {
   MessageHeader *const header = MessageHeader::Get(msg);
   __atomic_add_fetch(&header->ref_count, 1, __ATOMIC_RELAXED);
   if (kRefDebug) {
@@ -96,6 +103,71 @@
   }
 }
 
+inline void RawQueue::DoFreeMessage(const void *msg) {
+  MessageHeader *header = MessageHeader::Get(msg);
+  if (kRefDebug) {
+    printf("%p ref free to %p: %p\n", this, recycle_, msg);
+  }
+
+  if (__builtin_expect(recycle_ != nullptr, 0)) {
+    void *const new_msg = recycle_->GetMessage();
+    if (new_msg == nullptr) {
+      fprintf(stderr, "queue: couldn't get a message"
+              " for recycle queue %p\n", recycle_);
+    } else {
+      // Nobody else has a reference to the message at this point, so no need to
+      // be fancy about it.
+      ++header->ref_count;
+      if (!recycle_->WriteMessage(const_cast<void *>(msg), kOverride)) {
+        fprintf(stderr, "queue: %p->WriteMessage(%p, kOverride) failed."
+                " aborting\n", recycle_, msg);
+        printf("see stderr\n");
+        abort();
+      }
+      msg = new_msg;
+      header = MessageHeader::Get(new_msg);
+    }
+  }
+
+  // This works around GCC bug 60272 (fixed in 4.8.3).
+  // new_next should just get replaced with header->next (and the body of the
+  // loop should become empty).
+  // The bug is that the store to new_next after the compare/exchange is
+  // unconditional but it should only be if it fails, which could mean
+  // overwriting what somebody else who preempted us right then changed it to.
+  // TODO(brians): Get rid of this workaround once we get a new enough GCC.
+  MessageHeader *new_next = __atomic_load_n(&free_messages_, __ATOMIC_RELAXED);
+  do {
+    header->next = new_next;
+  } while (__builtin_expect(
+      !__atomic_compare_exchange_n(&free_messages_, &new_next, header, true,
+                                   __ATOMIC_RELEASE, __ATOMIC_RELAXED),
+      0));
+}
+
+void *RawQueue::GetMessage() {
+  MessageHeader *header = __atomic_load_n(&free_messages_, __ATOMIC_RELAXED);
+  do {
+    if (__builtin_expect(header == nullptr, 0)) {
+      LOG(FATAL, "overused pool of queue %p\n", this);
+    }
+  } while (__builtin_expect(
+      !__atomic_compare_exchange_n(&free_messages_, &header, header->next, true,
+                                   __ATOMIC_ACQ_REL, __ATOMIC_RELAXED),
+      0));
+  void *msg = reinterpret_cast<uint8_t *>(header + 1);
+  // It might be uninitialized, 0 from a previous use, or 1 from previously
+  // being recycled.
+  header->ref_count = 1;
+  static_assert(
+      __atomic_always_lock_free(sizeof(header->ref_count), &header->ref_count),
+      "we access this using not specifically atomic loads and stores");
+  if (kRefDebug) {
+    printf("%p ref alloc: %p\n", this, msg);
+  }
+  return msg;
+}
+
 RawQueue::RawQueue(const char *name, size_t length, int hash, int queue_length)
     : readable_(&data_lock_), writable_(&data_lock_) {
   static_assert(shm_ok<RawQueue::MessageHeader>::value,
@@ -103,6 +175,10 @@
   static_assert((sizeof(RawQueue::MessageHeader) % 8) == 0,
                 "need to revalidate size/alignent assumptions");
 
+  if (queue_length < 1) {
+    LOG(FATAL, "queue length %d needs to be at least 1\n", queue_length);
+  }
+
   const size_t name_size = strlen(name) + 1;
   char *temp = static_cast<char *>(shm_malloc(name_size));
   memcpy(temp, name, name_size);
@@ -120,9 +196,6 @@
   }
 
   data_length_ = queue_length + 1;
-  if (data_length_ < 2) {  // TODO(brians) when could this happen?
-    data_length_ = 2;
-  }
   data_ = static_cast<void **>(shm_malloc(sizeof(void *) * data_length_));
   data_start_ = 0;
   data_end_ = 0;
@@ -130,26 +203,31 @@
 
   msg_length_ = length + sizeof(MessageHeader);
 
-  MessageHeader *previous = nullptr;
-  for (int i = 0; i < queue_length + kExtraMessages; ++i) {
-    MessageHeader *const message =
-        static_cast<MessageHeader *>(shm_malloc(msg_length_));
-    free_messages_ = message;
-    message->next = previous;
-    previous = message;
+  // Create all of the messages for the free list and stick them on.
+  {
+    MessageHeader *previous = nullptr;
+    for (int i = 0; i < queue_length + kExtraMessages; ++i) {
+      MessageHeader *const message =
+          static_cast<MessageHeader *>(shm_malloc(msg_length_));
+      free_messages_ = message;
+      message->next = previous;
+      previous = message;
+    }
   }
 
   if (kFetchDebug) {
     printf("made queue %s\n", name);
   }
 }
+
 RawQueue *RawQueue::Fetch(const char *name, size_t length, int hash,
                     int queue_length) {
   if (kFetchDebug) {
     printf("fetching queue %s\n", name);
   }
   if (mutex_lock(&global_core->mem_struct->queues.lock) != 0) {
-    return NULL;
+    LOG(FATAL, "mutex_lock(%p) failed\n",
+        &global_core->mem_struct->queues.lock);
   }
   RawQueue *current = static_cast<RawQueue *>(
       global_core->mem_struct->queues.pointer);
@@ -183,6 +261,7 @@
   mutex_unlock(&global_core->mem_struct->queues.lock);
   return r;
 }
+
 RawQueue *RawQueue::Fetch(const char *name, size_t length, int hash,
                     int queue_length,
                     int recycle_hash, int recycle_length, RawQueue **recycle) {
@@ -198,58 +277,17 @@
   return r;
 }
 
-void RawQueue::DoFreeMessage(const void *msg) {
-  MessageHeader *header = MessageHeader::Get(msg);
-  if (kRefDebug) {
-    printf("%p ref free->%p: %p\n", this, recycle_, msg);
-  }
-
-  if (recycle_ != NULL) {
-    void *const new_msg = recycle_->GetMessage();
-    if (new_msg == NULL) {
-      fprintf(stderr, "queue: couldn't get a message"
-              " for recycle queue %p\n", recycle_);
-    } else {
-      IncrementMessageReferenceCount(msg);
-      if (!recycle_->WriteMessage(const_cast<void *>(msg), kOverride)) {
-        fprintf(stderr, "queue: %p->WriteMessage(%p, kOverride) failed."
-                " aborting\n", recycle_, msg);
-        printf("see stderr\n");
-        abort();
-      }
-      msg = new_msg;
-      header = MessageHeader::Get(new_msg);
-    }
-  }
-
-  header->next = __atomic_load_n(&free_messages_, __ATOMIC_RELAXED);
-  while (
-      !__atomic_compare_exchange_n(&free_messages_, &header->next, header,
-                                   true, __ATOMIC_RELEASE, __ATOMIC_RELAXED)) {
-  }
-}
-
 bool RawQueue::WriteMessage(void *msg, int options) {
-  // TODO(brians): Test this function.
   if (kWriteDebug) {
     printf("queue: %p->WriteMessage(%p, %x)\n", this, msg, options);
   }
-  if (msg == NULL || msg < reinterpret_cast<void *>(global_core->mem_struct) ||
-      msg > static_cast<void *>((
-              reinterpret_cast<char *>(global_core->mem_struct) +
-              global_core->size))) {
-    fprintf(stderr, "queue: attempt to write bad message %p to %p. aborting\n",
-            msg, this);
-    printf("see stderr\n");
-    abort();
-  }
   {
     MutexLocker locker(&data_lock_);
     bool writable_waited = false;
 
     int new_end;
     while (true) {
-      new_end = (data_end_ + 1) % data_length_;
+      new_end = index_add1(data_end_);
       // If there is room in the queue right now.
       if (new_end != data_start_) break;
       if (options & kNonBlock) {
@@ -264,7 +302,7 @@
         }
         // Avoid leaking the message that we're going to overwrite.
         DecrementMessageReferenceCount(data_[data_start_]);
-        data_start_ = (data_start_ + 1) % data_length_;
+        data_start_ = index_add1(data_start_);
       } else {  // kBlock
         if (kWriteDebug) {
           printf("queue: going to wait for writable_ of %p\n", this);
@@ -297,17 +335,18 @@
   return true;
 }
 
-void RawQueue::ReadCommonEnd(ReadData *read_data) {
+inline void RawQueue::ReadCommonEnd() {
   if (is_writable()) {
     if (kReadDebug) {
       printf("queue: %ssignalling writable_ of %p\n",
-             read_data->writable_start ? "not " : "", this);
+             writable_start_ ? "not " : "", this);
     }
-    if (!read_data->writable_start) writable_.Signal();
+    if (!writable_start_) writable_.Signal();
   }
 }
-bool RawQueue::ReadCommonStart(int options, int *index, ReadData *read_data) {
-  read_data->writable_start = is_writable();
+
+bool RawQueue::ReadCommonStart(int options, int *index) {
+  writable_start_ = is_writable();
   while (data_start_ == data_end_ || ((index != NULL) && messages_ <= *index)) {
     if (options & kNonBlock) {
       if (kReadDebug) {
@@ -331,27 +370,15 @@
   }
   return true;
 }
-void *RawQueue::ReadPeek(int options, int start) const {
-  void *ret;
-  if (options & kFromEnd) {
-    int pos = data_end_ - 1;
-    if (pos < 0) {  // if it needs to wrap
-      pos = data_length_ - 1;
-    }
-    if (kReadDebug) {
-      printf("queue: %p reading from line %d: %d\n", this, __LINE__, pos);
-    }
-    ret = data_[pos];
-  } else {
-    assert(start != -1);
-    if (kReadDebug) {
-      printf("queue: %p reading from line %d: %d\n", this, __LINE__, start);
-    }
-    ret = data_[start];
+
+inline int RawQueue::LastMessageIndex() const {
+  int pos = data_end_ - 1;
+  if (pos < 0) {  // If it wrapped around.
+    pos = data_length_ - 1;
   }
-  IncrementMessageReferenceCount(ret);
-  return ret;
+  return pos;
 }
+
 const void *RawQueue::ReadMessage(int options) {
   // TODO(brians): Test this function.
   if (kReadDebug) {
@@ -361,25 +388,28 @@
 
   MutexLocker locker(&data_lock_);
 
-  ReadData read_data;
-  if (!ReadCommonStart(options, NULL, &read_data)) {
+  if (!ReadCommonStart(options, nullptr)) {
     if (kReadDebug) {
       printf("queue: %p common returned false\n", this);
     }
     return NULL;
   }
 
-  if (options & kPeek) {
-    msg = ReadPeek(options, data_start_);
-  } else {
-    if (options & kFromEnd) {
+  if (options & kFromEnd) {
+    if (options & kPeek) {
+      if (kReadDebug) {
+        printf("queue: %p shortcutting c2: %d\n", this, LastMessageIndex());
+      }
+      msg = data_[LastMessageIndex()];
+      IncrementMessageReferenceCount(msg);
+    } else {
       while (true) {
         if (kReadDebug) {
           printf("queue: %p start of c2\n", this);
         }
         // This loop pulls each message out of the buffer.
         const int pos = data_start_;
-        data_start_ = (data_start_ + 1) % data_length_;
+        data_start_ = index_add1(data_start_);
         // If this is the last one.
         if (data_start_ == data_end_) {
           if (kReadDebug) {
@@ -391,20 +421,25 @@
         // This message is not going to be in the queue any more.
         DecrementMessageReferenceCount(data_[pos]);
       }
+    }
+  } else {
+    if (kReadDebug) {
+      printf("queue: %p reading from d2: %d\n", this, data_start_);
+    }
+    msg = data_[data_start_];
+    if (options & kPeek) {
+      IncrementMessageReferenceCount(msg);
     } else {
-      if (kReadDebug) {
-        printf("queue: %p reading from d2: %d\n", this, data_start_);
-      }
-      msg = data_[data_start_];
-      data_start_ = (data_start_ + 1) % data_length_;
+      data_start_ = index_add1(data_start_);
     }
   }
-  ReadCommonEnd(&read_data);
+  ReadCommonEnd();
   if (kReadDebug) {
     printf("queue: %p read returning %p\n", this, msg);
   }
   return msg;
 }
+
 const void *RawQueue::ReadMessageIndex(int options, int *index) {
   if (kReadDebug) {
     printf("queue: %p->ReadMessageIndex(%x, %p(*=%d))\n",
@@ -414,8 +449,7 @@
 
   MutexLocker locker(&data_lock_);
 
-  ReadData read_data;
-  if (!ReadCommonStart(options, index, &read_data)) {
+  if (!ReadCommonStart(options, index)) {
     if (kReadDebug) {
       printf("queue: %p common returned false\n", this);
     }
@@ -424,12 +458,16 @@
 
   // TODO(parker): Handle integer wrap on the index.
 
-  // Where we're going to start reading.
-  int my_start;
-
   if (options & kFromEnd) {
-    my_start = -1;
+    if (kReadDebug) {
+      printf("queue: %p reading from c1: %d\n", this, LastMessageIndex());
+    }
+    msg = data_[LastMessageIndex()];
+    if (!(options & kPeek)) *index = messages_;
   } else {
+    // Where we're going to start reading.
+    int my_start;
+
     const int unread_messages = messages_ - *index;
     assert(unread_messages > 0);
     int current_messages = data_end_ - data_start_;
@@ -457,72 +495,25 @@
         printf("queue: %p original read from %d\n", this, my_start);
       }
       if (data_start_ < data_end_) {
-        assert(my_start >= data_start_);
-      } else {
-        if (my_start < 0) my_start += data_length_;
+        assert(my_start >= 0);
       }
+      if (my_start < 0) my_start += data_length_;
     }
-  }
 
-  if (options & kPeek) {
-    msg = ReadPeek(options, my_start);
-  } else {
-    if (options & kFromEnd) {
-      if (kReadDebug) {
-        printf("queue: %p start of c1\n", this);
-      }
-      int pos = data_end_ - 1;
-      if (kReadIndexDebug) {
-        printf("queue: %p end pos start %d\n", this, pos);
-      }
-      if (pos < 0) {  // If it wrapped.
-        pos = data_length_ - 1;  // Unwrap it.
-      }
-      if (kReadDebug) {
-        printf("queue: %p reading from c1: %d\n", this, pos);
-      }
-      msg = data_[pos];
-      *index = messages_;
-    } else {
-      if (kReadDebug) {
-        printf("queue: %p reading from d1: %d\n", this, my_start);
-      }
-      // This assert checks that we're either within both endpoints (duh) or
-      // not between them (if the queue is wrapped around).
-      assert((my_start >= data_start_ && my_start < data_end_) ||
-             ((my_start >= data_start_) == (my_start > data_end_)));
-      // More sanity checking.
-      assert((my_start >= 0) && (my_start < data_length_));
-      msg = data_[my_start];
-      ++(*index);
+    if (kReadDebug) {
+      printf("queue: %p reading from d1: %d\n", this, my_start);
     }
-    IncrementMessageReferenceCount(msg);
+    // We have to be either after the start or before the end, even if the queue
+    // is wrapped around (should be both if it's not).
+    assert((my_start >= data_start_) || (my_start < data_end_));
+    // More sanity checking.
+    assert((my_start >= 0) && (my_start < data_length_));
+    msg = data_[my_start];
+    if (!(options & kPeek)) ++(*index);
   }
-  ReadCommonEnd(&read_data);
-  return msg;
-}
+  IncrementMessageReferenceCount(msg);
 
-void *RawQueue::GetMessage() {
-  // TODO(brians): Test this function.
-
-  MessageHeader *header = __atomic_load_n(&free_messages_, __ATOMIC_RELAXED);
-  do {
-    if (__builtin_expect(header == nullptr, 0)) {
-      LOG(FATAL, "overused pool of queue %p\n", this);
-    }
-  } while (
-      !__atomic_compare_exchange_n(&free_messages_, &header, header->next, true,
-                                   __ATOMIC_ACQ_REL, __ATOMIC_RELAXED));
-  void *msg = reinterpret_cast<uint8_t *>(header + 1);
-  // It might be uninitialized, 0 from a previous use, or 1 from previously
-  // getting recycled.
-  header->ref_count = 1;
-  static_assert(
-      __atomic_always_lock_free(sizeof(header->ref_count), &header->ref_count),
-      "we access this using not specifically atomic loads and stores");
-  if (kRefDebug) {
-    printf("%p ref alloc: %p\n", this, msg);
-  }
+  ReadCommonEnd();
   return msg;
 }
 
diff --git a/aos/linux_code/ipc_lib/queue.h b/aos/linux_code/ipc_lib/queue.h
index 33ed9f4..d4d2609 100644
--- a/aos/linux_code/ipc_lib/queue.h
+++ b/aos/linux_code/ipc_lib/queue.h
@@ -1,6 +1,8 @@
 #ifndef AOS_LINUX_CODE_IPC_LIB_QUEUE_H_
 #define AOS_LINUX_CODE_IPC_LIB_QUEUE_H_
 
+#include <assert.h>
+
 #include "aos/linux_code/ipc_lib/shared_mem.h"
 #include "aos/common/mutex.h"
 #include "aos/common/condition.h"
@@ -33,6 +35,7 @@
   // length is how large each message will be
   // hash can differentiate multiple otherwise identical queues
   // queue_length is how many messages the queue will be able to hold
+  // Will never return NULL.
   static RawQueue *Fetch(const char *name, size_t length, int hash,
                       int queue_length);
   // Same as above, except sets up the returned queue so that it will put
@@ -47,6 +50,7 @@
   // NOTE: calling this function with the same (name,length,hash,queue_length)
   // but multiple recycle_queue_lengths will result in each freed message being
   // put onto an undefined one of the recycle queues.
+  // Will never return NULL.
   static RawQueue *Fetch(const char *name, size_t length, int hash,
                       int queue_length,
                       int recycle_hash, int recycle_queue_length,
@@ -81,7 +85,8 @@
   // Writes a message into the queue.
   // This function takes ownership of msg.
   // NOTE: msg must point to a valid message from this queue
-  // Returns true on success.
+  // Returns true on success. A return value of false means msg has already been
+  // freed.
   bool WriteMessage(void *msg, int options);
 
   // Reads a message out of the queue.
@@ -92,9 +97,9 @@
   // IMPORTANT: The return value (if not NULL) must eventually be passed to
   // FreeMessage.
   const void *ReadMessage(int options);
-  // Exactly the same as aos_queue_read_msg, except it will never return the
-  // same message twice with the same index argument. However, it may not
-  // return some messages that pass through the queue.
+  // The same as ReadMessage, except it will never return the
+  // same message twice (when used with the same index argument). However,
+  // may not return some messages that pass through the queue.
   // *index should start as 0. index does not have to be in shared memory, but
   // it can be.
   const void *ReadMessageIndex(int options, int *index);
@@ -105,7 +110,7 @@
   // valid memory where it's pointing to.
   // Returns NULL for error.
   // IMPORTANT: The return value (if not NULL) must eventually be passed to
-  // FreeMessage.
+  // FreeMessage or WriteMessage.
   void *GetMessage();
 
   // It is ok to call this method with a NULL msg.
@@ -119,10 +124,12 @@
 
  private:
   struct MessageHeader;
-  struct ReadData;
+
+  // Adds 1 to the given index and handles wrapping correctly.
+  int index_add1(int index);
 
   bool is_readable() { return data_end_ != data_start_; }
-  bool is_writable() { return ((data_end_ + 1) % data_length_) != data_start_; }
+  bool is_writable() { return index_add1(data_end_) != data_start_; }
 
   // These next 4 allow finding the right one.
   const char *name_;
@@ -149,6 +156,10 @@
   // A pointer to the first in the linked list of free messages.
   MessageHeader *free_messages_;
 
+  // Keeps track of if the queue was writable before a read so we can Signal() a
+  // reader if we transition it.
+  bool writable_start_;
+
   // Actually frees the given message.
   void DoFreeMessage(const void *msg);
   // Calls DoFreeMessage if appropriate.
@@ -159,14 +170,14 @@
   // Must be called with data_lock_ locked.
   // *read_data will be initialized.
   // Returns with a readable message in data_ or false.
-  bool ReadCommonStart(int options, int *index, ReadData *read_data);
+  bool ReadCommonStart(int options, int *index);
   // Deals with setting/unsetting readable_ and writable_.
   // Must be called after data_lock_ has been unlocked.
   // read_data should be the same thing that was passed in to ReadCommonStart.
-  void ReadCommonEnd(ReadData *read_data);
-  // Handles reading with kPeek.
-  // start can be -1 if options has kFromEnd set.
-  void *ReadPeek(int options, int start) const;
+  void ReadCommonEnd();
+  // Returns the index of the last message.
+  // Useful for reading with kPeek.
+  int LastMessageIndex() const;
 
   // Gets called by Fetch when necessary (with placement new).
   RawQueue(const char *name, size_t length, int hash, int queue_length);
diff --git a/aos/linux_code/ipc_lib/raw_queue_test.cc b/aos/linux_code/ipc_lib/raw_queue_test.cc
index e91655a..ca84c51 100644
--- a/aos/linux_code/ipc_lib/raw_queue_test.cc
+++ b/aos/linux_code/ipc_lib/raw_queue_test.cc
@@ -471,6 +471,12 @@
   EXPECT_EQ(message2, queue->GetMessage());
 }
 
+// All of the tests from here down are designed to test every branch to
+// make sure it does what it's supposed to. They are generally pretty repetitive
+// and boring, and some of them may duplicate other tests above, but these ones
+// make it a lot easier to figure out what's wrong with bugs not related to race
+// conditions.
+
 TEST_F(RawQueueTest, ReadIndexNotFull) {
   RawQueue *const queue = RawQueue::Fetch("Queue", sizeof(TestMessage), 1, 2);
   const TestMessage *message, *peek_message;
@@ -877,5 +883,47 @@
   EXPECT_EQ(0, kExtraMessages + 2 - queue->FreeMessages());
 }
 
+// Tests that writing with kNonBlock fails and frees the message.
+TEST_F(RawQueueTest, WriteDontBlock) {
+  RawQueue *const queue = RawQueue::Fetch("Queue", sizeof(TestMessage), 1, 1);
+  void *message;
+
+  PushMessage(queue, 971);
+  int free_before = queue->FreeMessages();
+  message = queue->GetMessage();
+  ASSERT_NE(nullptr, message);
+  EXPECT_NE(free_before, queue->FreeMessages());
+  EXPECT_FALSE(queue->WriteMessage(message, RawQueue::kNonBlock));
+  EXPECT_EQ(free_before, queue->FreeMessages());
+}
+
+// Tests that writing with kOverride pushes the last message out of the queue.
+TEST_F(RawQueueTest, WriteOverride) {
+  RawQueue *const queue = RawQueue::Fetch("Queue", sizeof(TestMessage), 1, 2);
+  TestMessage *message1;
+
+  PushMessage(queue, 971);
+  PushMessage(queue, 1768);
+  int free_before = queue->FreeMessages();
+  message1 = static_cast<TestMessage *>(queue->GetMessage());
+  ASSERT_NE(nullptr, message1);
+  EXPECT_NE(free_before, queue->FreeMessages());
+  message1->data = 254;
+  EXPECT_TRUE(queue->WriteMessage(message1, RawQueue::kOverride));
+  EXPECT_EQ(free_before, queue->FreeMessages());
+
+  const TestMessage *message2;
+  message2 =
+      static_cast<const TestMessage *>(queue->ReadMessage(RawQueue::kNonBlock));
+  EXPECT_EQ(1768, message2->data);
+  queue->FreeMessage(message2);
+  EXPECT_EQ(free_before + 1, queue->FreeMessages());
+  message2 =
+      static_cast<const TestMessage *>(queue->ReadMessage(RawQueue::kNonBlock));
+  EXPECT_EQ(254, message2->data);
+  queue->FreeMessage(message2);
+  EXPECT_EQ(free_before + 2, queue->FreeMessages());
+}
+
 }  // namespace testing
 }  // namespace aos
diff --git a/aos/linux_code/logging/binary_log_writer.cc b/aos/linux_code/logging/binary_log_writer.cc
index 7b9b6da..a14cd6c 100644
--- a/aos/linux_code/logging/binary_log_writer.cc
+++ b/aos/linux_code/logging/binary_log_writer.cc
@@ -186,22 +186,17 @@
       case LogMessage::Type::kStruct: {
         char *position = output_strings + msg->name_length;
 
-        memcpy(position, &msg->structure.type_id,
-               sizeof(msg->structure.type_id));
+        memcpy(position, &msg->structure.type_id, sizeof(msg->structure.type_id));
         position += sizeof(msg->structure.type_id);
         output->message_size += sizeof(msg->structure.type_id);
 
-        uint32_t length = msg->structure.string_length;
+        const uint32_t length = msg->structure.string_length;
         memcpy(position, &length, sizeof(length));
         position += sizeof(length);
-        memcpy(position, msg->structure.serialized, length);
-        position += length;
+        memcpy(position, msg->structure.serialized, length + msg->message_length);
+        position += length + msg->message_length;
         output->message_size += sizeof(length) + length;
 
-        memcpy(position,
-               msg->structure.serialized + msg->structure.string_length,
-               msg->message_length);
-
         output->type = LogFileMessageHeader::MessageType::kStruct;
       } break;
       case LogMessage::Type::kMatrix: {
diff --git a/aos/linux_code/logging/log_displayer.cc b/aos/linux_code/logging/log_displayer.cc
index 1cc5f43..cbf4891 100644
--- a/aos/linux_code/logging/log_displayer.cc
+++ b/aos/linux_code/logging/log_displayer.cc
@@ -10,8 +10,9 @@
 #include <algorithm>
 
 #include "aos/linux_code/logging/binary_log_file.h"
-#include "aos/common/logging/logging_impl.h"
 #include "aos/common/queue_types.h"
+#include "aos/common/logging/logging_impl.h"
+#include "aos/common/logging/logging_printf_formats.h"
 
 using ::aos::logging::linux_code::LogFileMessageHeader;
 
@@ -156,7 +157,6 @@
   }
 
   const LogFileMessageHeader *msg;
-  ::aos::logging::LogMessage log_message;
   do {
     msg = accessor.ReadNextMessage(follow);
     if (msg == NULL) {
@@ -192,84 +192,82 @@
       }
     }
 
-    log_message.source = msg->source;
-    log_message.sequence = msg->sequence;
-    log_message.level = msg->level;
-    log_message.seconds = msg->time_sec;
-    log_message.nseconds = msg->time_nsec;
-    memcpy(log_message.name, reinterpret_cast<const char *>(msg) + sizeof(*msg),
-           ::std::min<size_t>(sizeof(log_message.name), msg->name_size));
-    log_message.message_length = msg->message_size;
-    log_message.name_length = msg->name_size;
-
+    const char *position =
+        reinterpret_cast<const char *>(msg + 1) + msg->name_size;
+#define BASE_ARGS                                                           \
+  AOS_LOGGING_BASE_ARGS(                                                    \
+      msg->name_size, reinterpret_cast<const char *>(msg + 1), msg->source, \
+      msg->sequence, msg->level, msg->time_sec, msg->time_nsec)
     switch (msg->type) {
-      case LogFileMessageHeader::MessageType::kStruct: {
-        const char *position =
-            reinterpret_cast<const char *>(msg + 1) + msg->name_size;
-        memcpy(&log_message.structure.type_id, position,
-               sizeof(log_message.structure.type_id));
-        position += sizeof(log_message.structure.type_id);
-
-        uint32_t length;
-        memcpy(&length, position, sizeof(length));
-        log_message.structure.string_length = length;
-        position += sizeof(length);
-        memcpy(log_message.structure.serialized, position, length);
-        position += length;
-
-        log_message.message_length -=
-            sizeof(log_message.structure.type_id) + sizeof(uint32_t) +
-            log_message.structure.string_length;
-        memcpy(log_message.structure.serialized +
-                   log_message.structure.string_length,
-               position, log_message.message_length);
-
-        log_message.type = ::aos::logging::LogMessage::Type::kStruct;
+      case LogFileMessageHeader::MessageType::kString:
+        fprintf(stdout, AOS_LOGGING_BASE_FORMAT "%.*s", BASE_ARGS,
+                static_cast<int>(msg->message_size), position);
         break;
-      }
-      case LogFileMessageHeader::MessageType::kMatrix: {
-        const char *position =
-            reinterpret_cast<const char *>(msg + 1) + msg->name_size;
-        memcpy(&log_message.matrix.type, position,
-               sizeof(log_message.matrix.type));
-        position += sizeof(log_message.matrix.type);
+      case LogFileMessageHeader::MessageType::kStruct: {
+        uint32_t type_id;
+        memcpy(&type_id, position, sizeof(type_id));
+        position += sizeof(type_id);
 
-        uint32_t length;
-        memcpy(&length, position, sizeof(length));
-        log_message.matrix.string_length = length;
-        position += sizeof(length);
+        uint32_t string_length;
+        memcpy(&string_length, position, sizeof(string_length));
+        position += sizeof(string_length);
+
+        char buffer[2048];
+        size_t output_length = sizeof(buffer);
+        size_t input_length =
+            msg->message_size -
+            (sizeof(type_id) + sizeof(uint32_t) + string_length);
+        if (!PrintMessage(buffer, &output_length, position + string_length,
+                          &input_length, ::aos::type_cache::Get(type_id))) {
+          LOG(FATAL, "printing message (%.*s) of type %s into %zu-byte buffer "
+                     "failed\n",
+              static_cast<int>(string_length), position,
+              ::aos::type_cache::Get(type_id).name.c_str(), sizeof(buffer));
+        }
+        if (input_length > 0) {
+          LOG(WARNING, "%zu extra bytes on message of type %s\n",
+              input_length, ::aos::type_cache::Get(type_id).name.c_str());
+        }
+        fprintf(stdout, AOS_LOGGING_BASE_FORMAT "%.*s: %.*s\n", BASE_ARGS,
+                static_cast<int>(string_length), position,
+                static_cast<int>(sizeof(buffer) - output_length), buffer);
+      } break;
+      case LogFileMessageHeader::MessageType::kMatrix: {
+        uint32_t type;
+        memcpy(&type, position, sizeof(type));
+        position += sizeof(type);
+
+        uint32_t string_length;
+        memcpy(&string_length, position, sizeof(string_length));
+        position += sizeof(string_length);
 
         uint16_t rows;
         memcpy(&rows, position, sizeof(rows));
-        log_message.matrix.rows = rows;
         position += sizeof(rows);
         uint16_t cols;
         memcpy(&cols, position, sizeof(cols));
-        log_message.matrix.cols = cols;
         position += sizeof(cols);
 
-        log_message.message_length -=
-            sizeof(log_message.matrix.type) + sizeof(uint32_t) +
-            sizeof(uint16_t) + sizeof(uint16_t) + length;
-        CHECK_EQ(
-            log_message.message_length,
-            ::aos::MessageType::Sizeof(log_message.matrix.type) * rows * cols);
-        memcpy(log_message.matrix.data, position,
-               log_message.message_length + length);
-
-        log_message.type = ::aos::logging::LogMessage::Type::kMatrix;
-        break;
-      } case LogFileMessageHeader::MessageType::kString:
-        memcpy(
-            log_message.message,
-            reinterpret_cast<const char *>(msg) + sizeof(*msg) + msg->name_size,
-            ::std::min<size_t>(sizeof(log_message.message), msg->message_size));
-        log_message.type = ::aos::logging::LogMessage::Type::kString;
-        break;
+        const size_t matrix_bytes =
+            msg->message_size -
+            (sizeof(type) + sizeof(uint32_t) + sizeof(uint16_t) +
+             sizeof(uint16_t) + string_length);
+        CHECK_EQ(matrix_bytes, ::aos::MessageType::Sizeof(type) * rows * cols);
+        char buffer[2048];
+        size_t output_length = sizeof(buffer);
+        if (!::aos::PrintMatrix(buffer, &output_length,
+                                position + string_length, type, rows, cols)) {
+          LOG(FATAL, "printing %dx%d matrix of type %" PRIu32 " failed\n", rows,
+              cols, type);
+        }
+        fprintf(stdout, AOS_LOGGING_BASE_FORMAT "%.*s: %.*s\n", BASE_ARGS,
+                static_cast<int>(string_length), position,
+                static_cast<int>(sizeof(buffer) - output_length), buffer);
+      } break;
       case LogFileMessageHeader::MessageType::kStructType:
         LOG(FATAL, "shouldn't get here\n");
         break;
-    };
-    ::aos::logging::internal::PrintMessage(stdout, log_message);
+    }
+#undef BASE_ARGS
   } while (msg != NULL);
 }
diff --git a/aos/prime/output/motor_output.cc b/aos/prime/output/motor_output.cc
index 54add2d..249ccfd 100644
--- a/aos/prime/output/motor_output.cc
+++ b/aos/prime/output/motor_output.cc
@@ -53,14 +53,14 @@
     values_.compressor_channel = 0;
     values_.solenoid_module = -1;
 
+    RunIteration();
+
     ::aos::robot_state.FetchLatest();
     if (!::aos::robot_state.get() || ::aos::robot_state->fake) {
       LOG(DEBUG, "fake robot state -> not outputting\n");
       continue;
     }
 
-    RunIteration();
-
     char buffer[sizeof(values_) + ::buffers::kOverhead];
     ssize_t size = values_.SerializeTo(buffer, sizeof(buffer));
     if (size <= 0) {
@@ -89,6 +89,10 @@
   values_.pwm_outputs[channel - 1] = bounds.Map(value);
 }
 
+void MotorOutput::SetRawPWMOutput(uint8_t channel, uint8_t value) {
+  values_.pwm_outputs[channel - 1] = value;
+}
+
 void MotorOutput::DisablePWMOutput(uint8_t channel) {
   values_.pwm_outputs[channel - 1] = 0;
 }
diff --git a/aos/prime/output/motor_output.h b/aos/prime/output/motor_output.h
index 53bdc83..01e271a 100644
--- a/aos/prime/output/motor_output.h
+++ b/aos/prime/output/motor_output.h
@@ -51,11 +51,13 @@
   void SetSolenoid(uint8_t channel, bool set);
   void SetPWMOutput(uint8_t channel, double value,
                     const MotorControllerBounds &bounds);
+  void SetRawPWMOutput(uint8_t cahnnel, uint8_t value);
   void DisablePWMOutput(uint8_t channel);
   void SetDigitalOutput(uint8_t channel, bool value);
 
   // The data that's going to get sent over.
-  // Gets reset (everything set so that it won't do anything) each time through.
+  // Gets reset (everything set so that it won't do anything) each time through
+  // except for solenoids.
   NetworkRobotMotors values_;
 
  private:
diff --git a/bbb_cape/src/bbb/bbb.gyp b/bbb_cape/src/bbb/bbb.gyp
index 1da4732..5f5b590 100644
--- a/bbb_cape/src/bbb/bbb.gyp
+++ b/bbb_cape/src/bbb/bbb.gyp
@@ -46,6 +46,17 @@
       ],
     },
     {
+      'target_name': 'export_uart',
+      'type': 'static_library',
+      'sources': [
+        'export_uart.cc',
+      ],
+      'dependencies': [
+        '<(AOS)/build/aos.gyp:logging',
+        '<(AOS)/common/common.gyp:time',
+      ],
+    },
+    {
       'target_name': 'uart_reader',
       'type': 'static_library',
       'sources': [
@@ -56,6 +67,7 @@
         '<(AOS)/build/aos.gyp:logging',
         '<(AOS)/common/common.gyp:time',
         'byte_io',
+        'export_uart',
       ],
       'export_dependent_settings': [
         '<(AOS)/common/common.gyp:time',
diff --git a/bbb_cape/src/bbb/export_uart.cc b/bbb_cape/src/bbb/export_uart.cc
new file mode 100644
index 0000000..ccf751c
--- /dev/null
+++ b/bbb_cape/src/bbb/export_uart.cc
@@ -0,0 +1,59 @@
+#include "bbb/export_uart.h"
+
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+
+#include "aos/common/logging/logging.h"
+#include "aos/common/time.h"
+
+namespace bbb {
+namespace {
+
+// TODO(brians): Determine this in some way that allows easy switching for
+// testing with /dev/ttyUSB0 for example.
+const char *device = "/dev/ttyO1";
+
+bool easy_access(const char *path) {
+  if (access(path, R_OK | W_OK) == 0) return true;
+  if (errno == EACCES || errno == ENOENT) return false;
+  LOG(FATAL, "access(%s, F_OK) failed with %d: %s\n", path, errno,
+      strerror(errno));
+}
+
+}  // namespace
+
+const char *UartDevice() { return device; }
+
+void ExportUart() {
+  if (easy_access(device)) {
+    LOG(INFO, "unexporting BB-UART1\n");
+    if (system("bash -c 'echo -$(cat /sys/devices/bone_capemgr.*/slots"
+               " | fgrep BB-UART1"
+               " | cut -d : -f 1 | tr -d \" \")"
+               " > /sys/devices/bone_capemgr.*/slots'") == -1) {
+      LOG(FATAL, "system([disable OMAP UART]) failed with %d: %s\n", errno,
+          strerror(errno));
+    }
+    while (easy_access(device)) {
+      LOG(DEBUG, "waiting for BB-UART1 to be unexported\n");
+      ::aos::time::SleepFor(::aos::time::Time::InSeconds(0.1));
+    }
+  }
+
+  LOG(INFO, "exporting BB-UART1\n");
+  // 2 strings to work around a VIM bug where the indenter locks up when they're
+  // combined as 1...
+  if (system("bash -c 'echo BB-UART1 > /sys/devices/bone_capemgr.*"
+             "/slots'") ==
+      -1) {
+    LOG(FATAL, "system([enable OMAP UART]) failed with %d: %s\n", errno,
+        strerror(errno));
+  }
+  while (!easy_access(device)) {
+    LOG(DEBUG, "waiting for BB-UART1 to be exported\n");
+    ::aos::time::SleepFor(::aos::time::Time::InSeconds(0.1));
+  }
+}
+
+}  // namespace bbb
diff --git a/bbb_cape/src/bbb/export_uart.h b/bbb_cape/src/bbb/export_uart.h
new file mode 100644
index 0000000..4f91a57
--- /dev/null
+++ b/bbb_cape/src/bbb/export_uart.h
@@ -0,0 +1,15 @@
+#ifndef BBB_EXPORT_UART_H_
+#define BBB_EXPORT_UART_H_
+
+namespace bbb {
+
+// Returns a pointer to static memory with the name of the device file for the
+// UART.
+const char *UartDevice();
+
+// Unexports (if already exported) and then reexports the UART cape slot.
+void ExportUart();
+
+}  // namespace bbb
+
+#endif  // BBB_EXPORT_UART_H_
diff --git a/bbb_cape/src/bbb/hex_byte_reader.h b/bbb_cape/src/bbb/hex_byte_reader.h
index 8f44c9a..8bbbe6d 100644
--- a/bbb_cape/src/bbb/hex_byte_reader.h
+++ b/bbb_cape/src/bbb/hex_byte_reader.h
@@ -15,8 +15,9 @@
   explicit HexByteReader(const ::std::string &filename);
   virtual ~HexByteReader() {}
 
-  virtual ssize_t ReadBytes(uint8_t *dest, size_t max_bytes,
-                            const ::aos::time::Time &timeout) override;
+  virtual ssize_t ReadBytes(
+      uint8_t *dest, size_t max_bytes,
+      const ::aos::time::Time &timeout = ::aos::time::Time(0, 0)) override;
 
   // Returns the total number of bytes that we will eventually read out.
   unsigned int GetSize();
diff --git a/bbb_cape/src/bbb/sensor_reader.cc b/bbb_cape/src/bbb/sensor_reader.cc
index c0e9604..86d4d8b 100644
--- a/bbb_cape/src/bbb/sensor_reader.cc
+++ b/bbb_cape/src/bbb/sensor_reader.cc
@@ -16,12 +16,20 @@
 
 uint32_t ReadChecksum(const ::std::string &filename) {
   HexByteReader reader(filename);
-  uint32_t r = ::cape::CalculateChecksum(&reader);
-  /*static const uint8_t fill[4] = {0xFF, 0xFF, 0xFF, 0xFF};
-  for (size_t i = reader.GetSize(); i < 0x100000 - 0x4000; i += 4) {
-    r = ::cape::CalculateChecksum(fill, 4, r);
-  }*/
-  return r;
+  {
+    static const size_t kSkipBytes = 0x4000;
+    size_t i = 0;
+    uint8_t buffer[1024];
+    while (i < kSkipBytes) {
+      ssize_t read =
+          reader.ReadBytes(buffer, ::std::min<size_t>(sizeof(buffer), kSkipBytes - i));
+      if (read < 0) {
+        LOG(FATAL, "error skipping bytes before actual data\n");
+      }
+      i += read;
+    }
+  }
+  return ::cape::CalculateChecksum(&reader);
 }
 
 }  // namespace
@@ -49,13 +57,16 @@
       LOG(WARNING, "Too long since good packet received. Resetting.\n");
       manager_.Reset();
       ResetHappened();
+      continue;
     }
     if (packet_finder_.ReadPacket(next_timeout)) {
       last_received_time_ = ::aos::time::Time::Now();
       const DataStruct *data = packet_finder_.get_packet<DataStruct>();
-      if (data->flash_checksum != expected_checksum_ && false) {
-        LOG(WARNING, "Cape code checksum is %" PRIu32 ". Expected %" PRIu32
-                     ". Reflashing.\n",
+      if (data->flash_checksum != expected_checksum_) {
+        // TODO(brians): Fix the custom bootloader stuff and then change this to
+        // WARNING.
+        LOG(FATAL, "Cape code checksum is 0x%" PRIx32 ". Expected 0x%" PRIx32
+                   ". Reflashing.\n",
             data->flash_checksum, expected_checksum_);
         manager_.DownloadHex(hex_filename_);
         ResetHappened();
@@ -65,6 +76,7 @@
         LOG(WARNING, "cape timestamp decreased: %" PRIu64 " to %" PRIu64 "\n",
             last_cape_timestamp_, data->timestamp);
         ResetHappened();
+        continue;
       }
       last_cape_timestamp_ = data->timestamp;
       return data;
diff --git a/bbb_cape/src/bbb/uart_reader.cc b/bbb_cape/src/bbb/uart_reader.cc
index 9abb284..7f88d51 100644
--- a/bbb_cape/src/bbb/uart_reader.cc
+++ b/bbb_cape/src/bbb/uart_reader.cc
@@ -7,6 +7,8 @@
 
 #include "aos/common/logging/logging.h"
 
+#include "bbb/export_uart.h"
+
 // This is the code for receiving data from the cape via UART.
 // fragment active.
 // `su -c "echo BB-UART1 > /sys/devices/bone_capemgr.*/slots"` works, but
@@ -16,48 +18,10 @@
 namespace bbb {
 namespace {
 
-// TODO(brians): Determine this in some way that allows easy switching for
-// testing with /dev/ttyUSB0 for example.
-const char *device = "/dev/ttyO1";
-
-bool easy_access(const char *path) {
-  if (access(path, R_OK | W_OK) == 0) return true;
-  if (errno == EACCES || errno == ENOENT) return false;
-  LOG(FATAL, "access(%s, F_OK) failed with %d: %s\n", path, errno,
-      strerror(errno));
-}
-
 int open_device() {
-  if (easy_access(device)) {
-    LOG(INFO, "unexporting BB-UART1\n");
-    if (system("bash -c 'echo -$(cat /sys/devices/bone_capemgr.*/slots"
-               " | fgrep BB-UART1"
-               " | cut -d : -f 1 | tr -d \" \")"
-               " > /sys/devices/bone_capemgr.*/slots'") == -1) {
-      LOG(FATAL, "system([disable OMAP UART]) failed with %d: %s\n", errno,
-          strerror(errno));
-    }
-    while (easy_access(device)) {
-      LOG(DEBUG, "waiting for BB-UART1 to be unexported\n");
-      ::aos::time::SleepFor(::aos::time::Time::InSeconds(0.1));
-    }
-  }
+  ExportUart();
 
-  LOG(INFO, "exporting BB-UART1\n");
-  // 2 strings to work around a VIM bug where the indenter locks up when they're
-  // combined as 1...
-  if (system("bash -c 'echo BB-UART1 > /sys/devices/bone_capemgr.*"
-             "/slots'") ==
-      -1) {
-    LOG(FATAL, "system([enable OMAP UART]) failed with %d: %s\n", errno,
-        strerror(errno));
-  }
-  while (!easy_access(device)) {
-    LOG(DEBUG, "waiting for BB-UART1 to be exported\n");
-    ::aos::time::SleepFor(::aos::time::Time::InSeconds(0.1));
-  }
-
-  return open(device, O_RDWR | O_NOCTTY | O_NONBLOCK);
+  return open(UartDevice(), O_RDWR | O_NOCTTY | O_NONBLOCK);
 }
 
 }  // namespace
@@ -77,7 +41,7 @@
   
   if (fd_ < 0) {
     LOG(FATAL, "open(%s, O_RDWR | O_NOCTTY | O_NOBLOCK) failed with %d: %s\n",
-        device, errno, strerror(errno));
+        UartDevice(), errno, strerror(errno));
   }
 
   if (aos_uart_reader_set_tty_options(fd_, baud_rate) != 0) {
diff --git a/bbb_cape/src/bbb/uart_reader.h b/bbb_cape/src/bbb/uart_reader.h
index a8edc6e..7861003 100644
--- a/bbb_cape/src/bbb/uart_reader.h
+++ b/bbb_cape/src/bbb/uart_reader.h
@@ -17,8 +17,9 @@
   explicit UartReader(int32_t baud_rate);
   virtual ~UartReader();
 
-  virtual ssize_t ReadBytes(uint8_t *dest, size_t max_bytes,
-                            const ::aos::time::Time &timeout_time) override;
+  virtual ssize_t ReadBytes(
+      uint8_t *dest, size_t max_bytes,
+      const ::aos::time::Time &timeout_time = ::aos::time::Time(0, 0)) override;
   virtual bool WriteBytes(uint8_t *bytes, size_t number_bytes) override;
 
  private:
diff --git a/bbb_cape/src/cape/analog.c b/bbb_cape/src/cape/analog.c
index 297afd6..14c176c 100644
--- a/bbb_cape/src/cape/analog.c
+++ b/bbb_cape/src/cape/analog.c
@@ -48,7 +48,7 @@
 }
 
 void TIM_IRQHandler(void) {
-  TIM->SR = ~TIM_SR_CC1IF;
+  TIM->SR = ~TIM_SR_UIF;
 
   if (frame != 2) {
     // We're not done with the previous reading yet, so we're going to reset and
@@ -91,13 +91,15 @@
   NVIC_SetPriority(TIM_IRQn, 6);
   NVIC_EnableIRQ(TIM_IRQn);
 
+  // We set it up to trigger at 4.44KHz (each sensor at just over 500Hz).
+  // 1/(1.875MHz)*32 = 17067ns (58.6Khz), and we don't want to be close (other
+  // interrupts do get in the way, and there's no reason to be).
   TIM->CR1 = 0;
-  TIM->DIER = TIM_DIER_CC1IE;
-  TIM->CCMR1 = 0;
-  // Make each tick take 1500ns.
-  TIM->PSC = (60 * 1500 / 1000) - 1;
-  // Call the interrupt after 1 tick.
-  TIM->CCR1 = 1;
+  TIM->DIER = TIM_DIER_UIE;
+  // Make each tick take 45000ns.
+  TIM->PSC = (60 * 45000 / 1000) - 1;
+  // Only count to 5 before triggering the interrupt and wrapping around.
+  TIM->ARR = 5;
 
   SPI->CR1 = 0;  // make sure it's disabled
   SPI->CR1 =
diff --git a/bbb_cape/src/cape/data_struct.h b/bbb_cape/src/cape/data_struct.h
index d60a0e9..6d747bb 100644
--- a/bbb_cape/src/cape/data_struct.h
+++ b/bbb_cape/src/cape/data_struct.h
@@ -82,9 +82,12 @@
       int32_t left_drive;
       int32_t right_drive;
 
-      // The length of the pulse from the ultrasonic sensor in 100kHZ ticks.
+      // The length of the pulse from the ultrasonic sensor in 100KHz ticks.
       uint32_t ultrasonic_pulse_length;
 
+      // The length of the pulse from the sidecar PWM output in 10MHz ticks.
+      uint32_t output_check_pulse_length;
+
       int32_t shooter_position, pusher_distal_posedge_position,
           pusher_proximal_posedge_position;
 
diff --git a/bbb_cape/src/cape/digital.h b/bbb_cape/src/cape/digital.h
index 698aeed..6071ca8 100644
--- a/bbb_cape/src/cape/digital.h
+++ b/bbb_cape/src/cape/digital.h
@@ -7,6 +7,8 @@
 
 // For all of the digital functions, a high voltage level on the input reads as
 // 1 (and a low to high transition is a positive edge).
+// Encoder inputs 0-7 A and B are mapped to "digital inputs" 12-27 (12 is 0A,
+// 13 is B, 14 is 1A, etc).
 
 static inline int digital_read(int num) {
   switch (num) {
@@ -34,6 +36,38 @@
       return !(GPIOA->IDR & (1 << 7));
     case 11:
       return !(GPIOB->IDR & (1 << 2));
+    case 12:  // encoder 0
+      return !(GPIOC->IDR & (1 << 6));
+    case 13:
+      return !(GPIOC->IDR & (1 << 7));
+    case 14:  // encoder 1
+      return !(GPIOC->IDR & (1 << 0));
+    case 15:
+      return !(GPIOC->IDR & (1 << 1));
+    case 16:  // encoder 2
+      return !(GPIOA->IDR & (1 << 0));
+    case 17:
+      return !(GPIOA->IDR & (1 << 1));
+    case 18:  // encoder 3
+      return !(GPIOA->IDR & (1 << 2));
+    case 19:
+      return !(GPIOA->IDR & (1 << 3));
+    case 20:  // encoder 4
+      return !(GPIOA->IDR & (1 << 8));
+    case 21:
+      return !(GPIOB->IDR & (1 << 0));
+    case 22:  // encoder 5
+      return !(GPIOA->IDR & (1 << 5));
+    case 23:
+      return !(GPIOB->IDR & (1 << 3));
+    case 24:  // encoder 6
+      return !(GPIOA->IDR & (1 << 6));
+    case 25:
+      return !(GPIOB->IDR & (1 << 5));
+    case 26:  // encoder 7
+      return !(GPIOB->IDR & (1 << 6));
+    case 27:
+      return !(GPIOB->IDR & (1 << 7));
     default:
       return 0;
   }
diff --git a/bbb_cape/src/cape/fill_packet.c b/bbb_cape/src/cape/fill_packet.c
index 8d1f72a..a0b2b13 100644
--- a/bbb_cape/src/cape/fill_packet.c
+++ b/bbb_cape/src/cape/fill_packet.c
@@ -80,9 +80,14 @@
   encoder_init();
   digital_init();
 
-  flash_checksum =
-      crc_calculate((void *)MAIN_FLASH_START,
-                    (size_t)(MAIN_FLASH_END - MAIN_FLASH_START) / 4);
+  {
+    extern uint32_t __flash_end, __data_start__, __data_end__;
+    const uint32_t main_flash_end = (uint32_t) & __flash_end + (uint32_t) &
+                                    __data_end__ - (uint32_t) & __data_start__;
+    flash_checksum =
+        crc_calculate((void *)MAIN_FLASH_START,
+                      (size_t)(main_flash_end - MAIN_FLASH_START) / 4);
+  }
 
   led_set(LED_ERR, 0);
   gyro_init();
diff --git a/bbb_cape/src/cape/gcc_arm.ld b/bbb_cape/src/cape/gcc_arm.ld
index 1a1cb27..26a43e8 100644
--- a/bbb_cape/src/cape/gcc_arm.ld
+++ b/bbb_cape/src/cape/gcc_arm.ld
@@ -142,4 +142,9 @@
 
 	/* Check if data + heap + stack exceeds RAM limit */
 	ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack")
+
+	.flash_end :
+	{
+		__flash_end = .;
+	} > FLASH
 }
diff --git a/bbb_cape/src/cape/peripherial_usage.notes b/bbb_cape/src/cape/peripherial_usage.notes
index 757f14a..c8005c3 100644
--- a/bbb_cape/src/cape/peripherial_usage.notes
+++ b/bbb_cape/src/cape/peripherial_usage.notes
@@ -57,4 +57,4 @@
 [robots]
 robot_comp
   TIM11
-  TIM11_IRQ:3 (aka TIM1_TRG_COM)
+  TIM11_IRQ:1 (aka TIM1_TRG_COM)
diff --git a/bbb_cape/src/cape/robot_comp.c b/bbb_cape/src/cape/robot_comp.c
index cab3e28..c33dc36 100644
--- a/bbb_cape/src/cape/robot_comp.c
+++ b/bbb_cape/src/cape/robot_comp.c
@@ -6,9 +6,7 @@
 #include "cape/analog.h"
 #include "cape/digital.h"
 #include "cape/util.h"
-
-// TIM11.1 on PB9, aka digital input 6.
-static volatile uint32_t ultrasonic_pulse_length = 0;
+#include "cape/timer.h"
 
 typedef struct {
   uint32_t posedges, negedges;
@@ -91,27 +89,15 @@
 CLAW(10, 11, 9, bottom_claw, 7);
 SHOOTER(7, 5, 4, 8, 0)
 
-void TIM1_TRG_COM_TIM11_IRQHandler(void) {
-  TIM11->SR = ~TIM_SR_CC1IF;
-  if (digital_read(6)) {
-    TIM11->EGR = TIM_EGR_UG;
-  } else {
-    ultrasonic_pulse_length = TIM11->CCR1;
-  }
-}
+// TIM11.1 on PB9, aka digital input 6.
+timer_declare(TIM11, TIM1_TR_GCOM_TIM11_IRQHandler, 1, 1, ultrasonic)
 
 void robot_init(void) {
   gpio_setup_alt(GPIOB, 9, 3);
   RCC->APB2ENR |= RCC_APB2ENR_TIM11EN;
-  TIM11->CR1 = TIM_CR1_URS;
-  TIM11->DIER = TIM_DIER_CC1IE;
   TIM11->CCMR1 = TIM_CCMR1_CC1S_0 /* input pin 1 -> timer input 1 */;
-  TIM11->CCER = TIM_CCER_CC1P | TIM_CCER_CC1NP | TIM_CCER_CC1E;
-  TIM11->EGR = TIM_EGR_UG;
-  TIM11->PSC = 1200 - 1;  // 100kHZ timer
-  TIM11->CR1 |= TIM_CR1_CEN;
-  NVIC_SetPriority(TIM1_TRG_COM_TIM11_IRQn, 3);
-  NVIC_EnableIRQ(TIM1_TRG_COM_TIM11_IRQn);
+  TIM11->PSC = 1200 - 1;  // 100KHz timer
+  //timer_setup(TIM11, TIM1_TRG_COM_TIM11_IRQn, 1);
 }
 
 void robot_fill_packet(struct DataStruct *packet) {
@@ -125,7 +111,7 @@
   packet->main.battery_voltage_high = analog_get(5);
   packet->main.battery_voltage_low = analog_get(3);
 
-  packet->main.ultrasonic_pulse_length = ultrasonic_pulse_length;
+  packet->main.ultrasonic_pulse_length = ultrasonic_length;
 
   fill_top_claw_values(packet);
   fill_bottom_claw_values(packet);
diff --git a/bbb_cape/src/cape/timer.h b/bbb_cape/src/cape/timer.h
new file mode 100644
index 0000000..0cca0de
--- /dev/null
+++ b/bbb_cape/src/cape/timer.h
@@ -0,0 +1,34 @@
+#ifndef CAPE_TIMER_H_
+#define CAPE_TIMER_H_
+
+#include <STM32F2XX.h>
+
+// inverted is 1 for timing low periods, 0 for high ones.
+#define timer_declare(timer, irq, input, inverted, name)                   \
+  static volatile uint32_t name##_length = 0;                              \
+  void irq(void) {                                                         \
+    timer->SR = ~TIM_SR_CC##input##IF;                                     \
+    const uint32_t ccer = timer->CCER;                                     \
+    timer->CCER = ccer ^ (TIM_CCER_CC##input##P | TIM_CCER_CC##input##NP); \
+    const uint32_t rising = ccer & TIM_CCER_CC##input##P;                  \
+    if (inverted ? rising : !rising) {                                     \
+      name##_length = timer->CCR##input;                                   \
+    } else {                                                               \
+      timer->EGR = TIM_EGR_UG;                                             \
+    }                                                                      \
+  }
+
+// You need to enable the clock, set up the alt function for the input pin,
+// set the prescaler, and set up the timer input before calling this.
+#define timer_setup(timer, irq, input)                           \
+  do {                                                           \
+    timer->CR1 = TIM_CR1_URS;                                    \
+    timer->DIER = TIM_DIER_CC##input##IE;                        \
+    timer->CCER = TIM_CCER_CC##input##P | TIM_CCER_CC##input##E; \
+    timer->EGR = TIM_EGR_UG;                                     \
+    timer->CR1 |= TIM_CR1_CEN;                                   \
+    NVIC_SetPriority(irq, 1);                                    \
+    NVIC_EnableIRQ(irq);                                         \
+  } while (0)
+
+#endif  // CAPE_TIMER_H_
diff --git a/bbb_cape/src/flasher/flasher.gyp b/bbb_cape/src/flasher/flasher.gyp
index 2d506b8..fba1477 100644
--- a/bbb_cape/src/flasher/flasher.gyp
+++ b/bbb_cape/src/flasher/flasher.gyp
@@ -17,6 +17,7 @@
         '<(EXTERNALS):stm32flash',
         '<(AOS)/build/aos.gyp:logging',
         '<(DEPTH)/bbb_cape/src/bbb/bbb.gyp:gpios',
+        '<(DEPTH)/bbb_cape/src/bbb/bbb.gyp:export_uart',
         '<(AOS)/common/common.gyp:time',
       ],
     },
diff --git a/bbb_cape/src/flasher/stm32_flasher.cc b/bbb_cape/src/flasher/stm32_flasher.cc
index 48887d2..a48abc4 100644
--- a/bbb_cape/src/flasher/stm32_flasher.cc
+++ b/bbb_cape/src/flasher/stm32_flasher.cc
@@ -19,6 +19,7 @@
 }
 
 #include "bbb/gpo.h"
+#include "bbb/export_uart.h"
 
 namespace {
 
@@ -48,9 +49,6 @@
   }
   ::std::string target = argv[1];
 
-  //::std::string device = "/dev/ttyUSB0";
-  // TODO(brians): Figure out an intelligent way to set the device to use.
-  ::std::string device = "/dev/ttyO1";
   serial_baud_t baud_rate = SERIAL_BAUD_57600;
 
   ::std::string filename =
@@ -112,17 +110,21 @@
     LOG(FATAL, "opening file %s failed\n", filename.c_str());
   }
 
-  serial_t *serial = serial_open(device.c_str());
+  ::bbb::ExportUart();
+
+  const char *device = ::bbb::UartDevice();
+
+  serial_t *serial = serial_open(device);
   if (serial == NULL) {
     LOG(FATAL, "failed to open serial port %s because of %d: %s\n",
-        device.c_str(), errno, strerror(errno));
+        device, errno, strerror(errno));
   }
   if (serial_setup(serial, baud_rate,
                    SERIAL_BITS_8,
                    SERIAL_PARITY_EVEN,
                    SERIAL_STOPBIT_1) != SERIAL_ERR_OK) {
     LOG(FATAL, "setting up serial port %s failed because of %d: %s\n",
-        device.c_str(), errno, strerror(errno));
+        device, errno, strerror(errno));
   }
   LOG(INFO, "serial configuration: %s\n", serial_get_setup_str(serial));
 
diff --git a/frc971/actions/action.h b/frc971/actions/action.h
index fe17676..9ae31e8 100644
--- a/frc971/actions/action.h
+++ b/frc971/actions/action.h
@@ -8,6 +8,7 @@
 #include "aos/common/control_loop/Timing.h"
 #include "aos/common/logging/logging.h"
 #include "aos/common/network/team_number.h"
+#include "aos/common/time.h"
 
 #include "frc971/constants.h"
 
@@ -57,18 +58,25 @@
     }
   }
 
-  // will run until the done condition is met.
+  // will run until the done condition is met or times out.
   // will return false if successful and true if the action was canceled or
-  // failed.
+  // failed or end_time was reached before it succeeded.
   // done condition are defined as functions that return true when done and have
   // some sort of blocking statement(FetchNextBlocking) to throttle spin rate.
-  bool WaitUntil(::std::function<bool(void)> done_condition) {
+  // end_time is when to stop and return true. Time(0, 0) (the default) means
+  // never time out.
+  bool WaitUntil(::std::function<bool(void)> done_condition,
+                 const ::aos::time::Time &end_time = ::aos::time::Time(0, 0)) {
     while (!done_condition()) {
       if (ShouldCancel() || abort_) {
         // Clear abort bit as we have just aborted.
         abort_ = false;
         return true;
       }
+      if (::aos::time::Time::Now() >= end_time) {
+        LOG(INFO, "WaitUntil timed out\n");
+        return true;
+      }
     }
     if (ShouldCancel() || abort_) {
       // Clear abort bit as we have just aborted.
diff --git a/frc971/actions/actions.gyp b/frc971/actions/actions.gyp
index 7cfb7a5..2a840f1 100644
--- a/frc971/actions/actions.gyp
+++ b/frc971/actions/actions.gyp
@@ -97,6 +97,7 @@
         'action',
         'shoot_action_queue',
         'action_client',
+        '<(AOS)/common/common.gyp:time',
       ],
     },
     {
@@ -134,12 +135,14 @@
         '<(AOS)/build/aos.gyp:logging',
         '<(AOS)/common/network/network.gyp:team_number',
         '<(DEPTH)/frc971/frc971.gyp:constants',
+        '<(AOS)/common/common.gyp:time',
       ],
       'export_dependent_settings': [
         '<(AOS)/common/common.gyp:timing',
         '<(AOS)/build/aos.gyp:logging',
         '<(AOS)/common/network/network.gyp:team_number',
         '<(DEPTH)/frc971/frc971.gyp:constants',
+        '<(AOS)/common/common.gyp:time',
       ],
     },
     {
diff --git a/frc971/actions/shoot_action.cc b/frc971/actions/shoot_action.cc
index b1e27b4..3e73b67 100644
--- a/frc971/actions/shoot_action.cc
+++ b/frc971/actions/shoot_action.cc
@@ -12,6 +12,11 @@
 namespace frc971 {
 namespace actions {
 
+constexpr double ShootAction::kOffsetRadians;
+constexpr double ShootAction::kClawShootingSeparation;
+constexpr double ShootAction::kClawShootingSeparationGoal;
+constexpr ::aos::time::Time ShootAction::kTimeout;
+
 ShootAction::ShootAction(actions::ShootActionQueueGroup* s)
     : actions::ActionBase<actions::ShootActionQueueGroup>(s) {}
 
@@ -38,13 +43,18 @@
     LOG(WARNING, "sending shooter goal failed\n");
     return;
   }
+
+  LOG(INFO, "finished\n");
 }
 
 void ShootAction::InnerRunAction() {
-  LOG(INFO, "Shooting at the original angle and power.\n");
+  LOG(INFO, "Shooting at the current angle and power.\n");
+  const ::aos::time::Time end_time = ::aos::time::Time::Now() + kTimeout;
 
   // wait for claw to be ready
-  if (WaitUntil(::std::bind(&ShootAction::DoneSetupShot, this))) return;
+  if (WaitUntil(::std::bind(&ShootAction::DoneSetupShot, this), end_time)) {
+    return;
+  }
 
   // Turn the intake off.
   control_loops::claw_queue_group.goal.FetchLatest();
@@ -77,7 +87,7 @@
   }
 
   // wait for record of shot having been fired
-  if (WaitUntil(::std::bind(&ShootAction::DoneShot, this))) return;
+  if (WaitUntil(::std::bind(&ShootAction::DoneShot, this), end_time)) return;
 
   // Turn the intake off.
   control_loops::claw_queue_group.goal.FetchLatest();
diff --git a/frc971/actions/shoot_action.h b/frc971/actions/shoot_action.h
index 6d29ca7..c5ebb07 100644
--- a/frc971/actions/shoot_action.h
+++ b/frc971/actions/shoot_action.h
@@ -1,5 +1,7 @@
 #include <memory>
 
+#include "aos/common/time.h"
+
 #include "frc971/actions/shoot_action.q.h"
 #include "frc971/actions/action.h"
 #include "frc971/actions/action_client.h"
@@ -23,6 +25,9 @@
   static constexpr double kOffsetRadians = 0.4;
   static constexpr double kClawShootingSeparation = 0.10;
   static constexpr double kClawShootingSeparationGoal = 0.10;
+  // If we don't get to actually shooting within this amount of time, we stop to
+  // avoid firing unexpectedly after a long delay.
+  static constexpr ::aos::time::Time kTimeout = ::aos::time::Time::InSeconds(1);
 
  protected:
   // completed shot
diff --git a/frc971/actions/shoot_action.q b/frc971/actions/shoot_action.q
index d080071..081d627 100644
--- a/frc971/actions/shoot_action.q
+++ b/frc971/actions/shoot_action.q
@@ -8,10 +8,7 @@
   message Goal {
     // If true, run this action.  If false, cancel the action if it is
     // currently running.
-    bool run; // Shot power in joules.
-    double shot_power;
-    // Claw angle when shooting.
-    double shot_angle;
+    bool run;
   };
 
   queue Goal goal;
diff --git a/frc971/control_loops/claw/claw.q b/frc971/control_loops/claw/claw.q
index 116a182..53289ee 100644
--- a/frc971/control_loops/claw/claw.q
+++ b/frc971/control_loops/claw/claw.q
@@ -22,7 +22,7 @@
   double negedge_value;
 };
 
-// All angles here are 0 horizontal, positive up.
+// All angles here are 0 vertical, positive "up" (aka backwards).
 queue_group ClawGroup {
   implements aos.control_loops.ControlLoop;
 
diff --git a/frc971/input/joystick_reader.cc b/frc971/input/joystick_reader.cc
index 7b97bbd..698fe45 100644
--- a/frc971/input/joystick_reader.cc
+++ b/frc971/input/joystick_reader.cc
@@ -87,23 +87,29 @@
 const ClawGoal kFlippedIntakeGoal = {2.0, kGrabSeparation};
 const ClawGoal kFlippedIntakeOpenGoal = {0.95, 1.0};
 
-//const ShotGoal kLongShotGoal = {
-    //{-M_PI / 2.0 + 0.46, kShootSeparation}, 120, false, kIntakePower};
+// 34" between near edge of colored line and rear edge of bumper
 const ShotGoal kLongShotGoal = {
-    {-1.04, kShootSeparation}, 140, 0.04, kIntakePower};
-const ShotGoal kMediumShotGoal = {
-    {-0.90, kShootSeparation}, 105, 0.2, kIntakePower};
-const ShotGoal kShortShotGoal = {
-    {-0.670, kShootSeparation}, 71.0, 0, kIntakePower};
-const ShotGoal kTrussShotGoal = {
-    {-0.05, kShootSeparation}, 61.0, 0, kIntakePower};
-
+    {-1.06, kShootSeparation}, 140, 0.04, kIntakePower};
+// 3/4" plunger {-1.04, kShootSeparation}, 140, 0.04, kIntakePower};
 const ShotGoal kFlippedLongShotGoal = {
     {0.97, kShootSeparation}, 140, 0.08, kIntakePower};
+// 3/4 " plunger {0.97, kShootSeparation}, 140, 0.08, kIntakePower};
+
+// 78" between near edge of colored line and rear edge of bumper
+const ShotGoal kMediumShotGoal = {
+    {-0.95, kShootSeparation}, 105, 0.2, kIntakePower};
+// 3/4" plunger {-0.90, kShootSeparation}, 105, 0.2, kIntakePower};
 const ShotGoal kFlippedMediumShotGoal = {
     {0.80, kShootSeparation}, 105, 0.2, kIntakePower};
+// 3/4" plunger {0.80, kShootSeparation}, 105, 0.2, kIntakePower};
+
+const ShotGoal kShortShotGoal = {
+    {-0.670, kShootSeparation}, 71.0, 0.4, kIntakePower};
 const ShotGoal kFlippedShortShotGoal = {
-    {0.57, kShootSeparation}, 80.0, 0, kIntakePower};
+    {0.57, kShootSeparation}, 80.0, 0.4, kIntakePower};
+
+const ShotGoal kTrussShotGoal = {
+    {-0.05, kShootSeparation}, 73.0, 0, kIntakePower};
 
 // Makes a new ShootAction action.
 ::std::unique_ptr<TypedAction< ::frc971::actions::CatchActionGroup>>
diff --git a/frc971/input/sensor_receiver.cc b/frc971/input/sensor_receiver.cc
index 7648db8..199df99 100644
--- a/frc971/input/sensor_receiver.cc
+++ b/frc971/input/sensor_receiver.cc
@@ -71,7 +71,8 @@
 }
 
 double sonar_translate(uint32_t in) {
-  return static_cast<double>(in) / 1000.0 * 2.0;
+  return static_cast<double>(in) * 10.0 /*us/tick*/ / 147.0 /*in/us*/ *
+         0.0254 /*m/in*/;
 }
 
 double hall_translate(const constants::ShifterHallEffect &k, uint16_t in_low,
@@ -138,8 +139,8 @@
                     const ::aos::time::Time &cape_timestamp,
                     State *state) {
   ::frc971::logging_structs::CapeReading reading_to_log(
-      cape_timestamp.sec(), cape_timestamp.nsec(),
-      sizeof(*data), sonar_translate(data->main.ultrasonic_pulse_length),
+      cape_timestamp, static_cast<uint16_t>(sizeof(*data)),
+      sonar_translate(data->main.ultrasonic_pulse_length),
       data->main.low_left_drive_hall, data->main.high_left_drive_hall,
       data->main.low_right_drive_hall, data->main.high_right_drive_hall);
   LOG_STRUCT(DEBUG, "cape reading", reading_to_log);
diff --git a/frc971/output/motor_writer.cc b/frc971/output/motor_writer.cc
index dca221b..eefd7d6 100644
--- a/frc971/output/motor_writer.cc
+++ b/frc971/output/motor_writer.cc
@@ -12,11 +12,10 @@
 #include "frc971/control_loops/drivetrain/drivetrain.q.h"
 #include "frc971/control_loops/claw/claw.q.h"
 #include "frc971/control_loops/shooter/shooter.q.h"
+#include "frc971/queues/output_check.q.h"
 
 using ::aos::util::SimpleLogInterval;
 
-using ::frc971::control_loops::drivetrain;
-
 namespace frc971 {
 namespace output {
 
@@ -39,13 +38,14 @@
     values_.solenoid_module = 0;
 
     if (true) {
-      drivetrain.output.FetchLatest();
-      if (drivetrain.output.IsNewerThanMS(kOutputMaxAgeMS)) {
-        LOG_STRUCT(DEBUG, "will output", *drivetrain.output.get());
-        SetPWMOutput(3, drivetrain.output->right_voltage / 12.0, kTalonBounds);
-        SetPWMOutput(6, -drivetrain.output->left_voltage / 12.0, kTalonBounds);
-        SetSolenoid(7, drivetrain.output->left_high);
-        SetSolenoid(8, drivetrain.output->right_high);
+      static auto &drivetrain = ::frc971::control_loops::drivetrain.output;
+      drivetrain.FetchLatest();
+      if (drivetrain.IsNewerThanMS(kOutputMaxAgeMS)) {
+        LOG_STRUCT(DEBUG, "will output", *drivetrain);
+        SetPWMOutput(3, drivetrain->right_voltage / 12.0, kTalonBounds);
+        SetPWMOutput(6, -drivetrain->left_voltage / 12.0, kTalonBounds);
+        SetSolenoid(7, drivetrain->left_high);
+        SetSolenoid(8, drivetrain->right_high);
       } else {
         DisablePWMOutput(3);
         DisablePWMOutput(8);
@@ -59,7 +59,7 @@
           ::frc971::control_loops::shooter_queue_group.output;
       shooter.FetchLatest();
       if (shooter.IsNewerThanMS(kOutputMaxAgeMS)) {
-        LOG_STRUCT(DEBUG, "will output", *shooter.get());
+        LOG_STRUCT(DEBUG, "will output", *shooter);
         SetPWMOutput(7, shooter->voltage / 12.0, kTalonBounds);
         SetSolenoid(6, !shooter->latch_piston);
         SetSolenoid(5, !shooter->brake_piston);
@@ -75,7 +75,7 @@
       static auto &claw = ::frc971::control_loops::claw_queue_group.output;
       claw.FetchLatest();
       if (claw.IsNewerThanMS(kOutputMaxAgeMS)) {
-        LOG_STRUCT(DEBUG, "will output", *claw.get());
+        LOG_STRUCT(DEBUG, "will output", *claw);
         SetPWMOutput(9, claw->intake_voltage / 12.0, kTalonBounds);
         SetPWMOutput(8, claw->intake_voltage / 12.0, kTalonBounds);
         SetPWMOutput(1, -claw->bottom_claw_voltage / 12.0, kTalonBounds);
@@ -93,6 +93,16 @@
       }
       claw_old_.Print();
     }
+
+    {
+      auto message = ::frc971::output_check_queue.MakeMessage();
+      ++output_check_;
+      if (output_check_ == 0) output_check_ = 1;
+      SetRawPWMOutput(10, output_check_);
+      message->sent_value = output_check_;
+      LOG_STRUCT(DEBUG, "sending", *message);
+      message.Send();
+    }
   }
 
   SimpleLogInterval drivetrain_old_ =
@@ -101,6 +111,8 @@
       SimpleLogInterval(kOldLogInterval, WARNING, "shooter too old");
   SimpleLogInterval claw_old_ =
       SimpleLogInterval(kOldLogInterval, WARNING, "claw too old");
+
+  uint8_t output_check_ = 0;
 };
 
 constexpr ::aos::time::Time MotorWriter::kOldLogInterval;
diff --git a/frc971/output/output.gyp b/frc971/output/output.gyp
index bc2d604..de41943 100644
--- a/frc971/output/output.gyp
+++ b/frc971/output/output.gyp
@@ -53,6 +53,7 @@
         '<(AOS)/common/logging/logging.gyp:queue_logging',
         '<(DEPTH)/frc971/control_loops/claw/claw.gyp:claw_loop',
         '<(DEPTH)/frc971/control_loops/shooter/shooter.gyp:shooter_loop',
+        '<(DEPTH)/frc971/queues/queues.gyp:output_check',
       ],
     },
   ],
diff --git a/frc971/prime/camera/camera.gyp b/frc971/prime/camera/camera.gyp
deleted file mode 100644
index 6a6b13c..0000000
--- a/frc971/prime/camera/camera.gyp
+++ /dev/null
@@ -1,30 +0,0 @@
-{
-  'targets': [
-    {
-      'target_name': 'frc971_camera',
-      'variables': {
-        'srcdirs': ['.'],
-        'manifest': 'frc971_camera.mf',
-      },
-      'dependencies': [
-        '<(AOS)/linux_code/camera/camera.gyp:aos_camera',
-        '<(DEPTH)/frc971/queues/queues.gyp:frc971_queues_so',
-      ],
-      'export_dependent_settings': [
-        '<(AOS)/linux_code/camera/camera.gyp:aos_camera',
-        '<(DEPTH)/frc971/queues/queues.gyp:frc971_queues_so',
-      ],
-      'includes': ['../../../aos/build/java.gypi'],
-    },
-    {
-      'target_name': 'frc971',
-      'variables': {
-        'main_jar': 'frc971_camera',
-      },
-      'dependencies': [
-        'frc971_camera',
-      ],
-      'includes': ['../../../aos/build/onejar.gypi'],
-    },
-  ],
-}
diff --git a/frc971/prime/camera/frc971_camera.mf b/frc971/prime/camera/frc971_camera.mf
deleted file mode 100644
index e3929a2..0000000
--- a/frc971/prime/camera/frc971_camera.mf
+++ /dev/null
@@ -1,2 +0,0 @@
-Main-Class: org.spartanrobotics.camera.Test
-
diff --git a/frc971/prime/camera/org/spartanrobotics/camera/QueueReader.java b/frc971/prime/camera/org/spartanrobotics/camera/QueueReader.java
deleted file mode 100644
index 347b0c2..0000000
--- a/frc971/prime/camera/org/spartanrobotics/camera/QueueReader.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package org.spartanrobotics.camera;
-
-import aos.NativeLoader;
-import aos.QueueLogHandler;
-import frc971.control_loops.Piston_q;
-
-public class QueueReader {
-
-	public static void main(String[] args) {
-		QueueLogHandler.UseForAll();
-		NativeLoader.load("frc971_queues_so");
-		System.out.println(Piston_q.shifters.FetchLatest());
-		System.out.println(Piston_q.shifters.getSet());
-	}
-
-}
diff --git a/frc971/prime/camera/org/spartanrobotics/camera/QueueTest.java b/frc971/prime/camera/org/spartanrobotics/camera/QueueTest.java
deleted file mode 100644
index a71f447..0000000
--- a/frc971/prime/camera/org/spartanrobotics/camera/QueueTest.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package org.spartanrobotics.camera;
-
-import aos.NativeLoader;
-import aos.QueueLogHandler;
-import frc971.control_loops.Piston_q;
-
-public class QueueTest {
-	
-	public static void main(String[] args) {
-		QueueLogHandler.UseForAll();
-		NativeLoader.load("frc971_queues_so");
-		Piston_q.shifters.SafeMakeWithBuilder().set(false).Send();
-	}
-	
-}
diff --git a/frc971/prime/camera/org/spartanrobotics/camera/Test.java b/frc971/prime/camera/org/spartanrobotics/camera/Test.java
deleted file mode 100644
index 86c06bc..0000000
--- a/frc971/prime/camera/org/spartanrobotics/camera/Test.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package org.spartanrobotics.camera;
-
-import java.io.IOException;
-import com.googlecode.javacv.cpp.opencv_core;
-import com.googlecode.javacv.cpp.opencv_core.CvPoint;
-import com.googlecode.javacv.cpp.opencv_core.CvScalar;
-import com.googlecode.javacv.cpp.opencv_core.IplImage;
-import com.googlecode.javacv.cpp.opencv_imgproc;
-
-import aos.CameraProcessor;
-import aos.DebugServer;
-import aos.ImageGetter;
-import aos.ServableImage;
-import aos.Thresholder;
-
-public class Test extends CameraProcessor {
-	private final DebugServer server = new DebugServer(9719);
-	private final IplImage hsv = IplImage.create(ImageGetter.width, ImageGetter.height, opencv_core.IPL_DEPTH_8U, 3);
-	private final ServableImage thresholded = new ServableImage(ImageGetter.width, ImageGetter.height, opencv_core.IPL_DEPTH_8U, 1);
-	
-	private Test(String[] args) throws IOException {
-		super(args);
-		
-		server.addImage("/start", start);
-		server.addImage("/thresholded", thresholded, new DebugServer.Palette().add(0, 0, 0, 0).add(0, 0xFF, 0, 0xFF).add(0, 0, 0xFF, 0xFF));
-	}
-
-	@Override
-	protected void RunIteration() {
-		server.setTimestamp(getter.getTimestamp());
-		
-		opencv_imgproc.cvCvtColor(start.getImage(), hsv, opencv_imgproc.CV_RGB2HSV);
-		Thresholder.threshold(hsv, thresholded.getImage(), 0, 100, 160, 0, 255, 0, 255);
-		thresholded.recordSnapshot(1);
-		if (thresholded.isDebugging()) {
-			opencv_core.cvCircle(thresholded.getImage(), new CvPoint(200, 200), 50, new CvScalar(2, 2, 2, 2), 5, 8, 0);
-		}
-		thresholded.releaseImage();
-	}
-	
-	public static void main(String[] args) throws IOException {
-		new Test(args).Run();
-	}
-}
diff --git a/frc971/prime/prime.gyp b/frc971/prime/prime.gyp
index c4db795..3ad28ba 100644
--- a/frc971/prime/prime.gyp
+++ b/frc971/prime/prime.gyp
@@ -27,11 +27,30 @@
         '<(DEPTH)/bbb_cape/src/flasher/flasher.gyp:stm32_flasher',
         '../output/output.gyp:led_setter',
       ],
+      'variables': {
+        'cape_src': '<(DEPTH)/bbb_cape/src/cape',
+        'cape_hex': '<(cape_src)/.obj/main_comp.hex',
+      },
+      'actions': [
+        {
+          'action_name': 'make_cape',
+          'inputs': [
+            '<!@(find <(cape_src) -name ".*" -prune -o -type f -print)',
+            '<(cape_src)/Makefile',
+          ],
+          'outputs': [
+            '<(cape_hex)',
+          ],
+          'action': ['make', '-C', '<(cape_src)'],
+          'message': 'Building cape code',
+        },
+      ],
       'copies': [
         {
           'destination': '<(rsync_dir)',
           'files': [
             'start_list.txt',
+            '<(cape_hex)',
           ],
         },
       ],
diff --git a/frc971/queues/output_check.q b/frc971/queues/output_check.q
new file mode 100644
index 0000000..0573426
--- /dev/null
+++ b/frc971/queues/output_check.q
@@ -0,0 +1,8 @@
+package frc971;
+
+message OutputCheck {
+	uint8_t sent_value;
+};
+// Each message here represents a value that was sent to the cRIO.
+// The sent timestamp of the message is when the value was sent.
+queue OutputCheck output_check_queue;
diff --git a/frc971/queues/queues.gyp b/frc971/queues/queues.gyp
index 8434437..d71be25 100644
--- a/frc971/queues/queues.gyp
+++ b/frc971/queues/queues.gyp
@@ -22,19 +22,14 @@
       'includes': ['../../aos/build/queues.gypi'],
     },
     {
-      'target_name': 'frc971_queues_so',
-      'type': 'loadable_module',
-      'sources': ['<@(queue_files)'],
+      'target_name': 'output_check',
+      'type': 'static_library',
+      'sources': [
+        'output_check.q',
+      ],
       'variables': {
         'header_path': 'frc971/queues',
       },
-      'dependencies': [
-      ],
-      'direct_dependent_settings': {
-        'variables': {
-          'jni_libs': ['frc971_queues_so'],
-        },
-      },
       'includes': ['../../aos/build/queues.gypi'],
     },
   ],
diff --git a/frc971/queues/to_log.q b/frc971/queues/to_log.q
index ded9b64..341d921 100644
--- a/frc971/queues/to_log.q
+++ b/frc971/queues/to_log.q
@@ -1,9 +1,8 @@
 package frc971.logging_structs;
 
 struct CapeReading {
-  uint32_t sec;
-  uint32_t nsec;
-  uint64_t struct_size;
+  Time time;
+  uint16_t struct_size;
   double sonar;
 
   uint16_t left_low;