fixed at least 1 bug in the uart handling code and cleaned it up a lot
diff --git a/aos/build/aos_all.gyp b/aos/build/aos_all.gyp
index 1aa6063..0629be5 100644
--- a/aos/build/aos_all.gyp
+++ b/aos/build/aos_all.gyp
@@ -21,6 +21,8 @@
         '../common/common.gyp:die_test',
         '../common/util/util.gyp:trapezoid_profile_test',
         '../common/util/util.gyp:wrapping_counter_test',
+        '<(DEPTH)/bbb_cape/src/bbb/bbb.gyp:cows_test',
+        '<(DEPTH)/bbb_cape/src/bbb/bbb.gyp:packet_finder_test',
         'Common',
       ],
     },
diff --git a/bbb_cape/src/bbb/bbb.gyp b/bbb_cape/src/bbb/bbb.gyp
index 82f328a..9ea4bb3 100644
--- a/bbb_cape/src/bbb/bbb.gyp
+++ b/bbb_cape/src/bbb/bbb.gyp
@@ -19,20 +19,53 @@
       'target_name': 'uart_reader',
       'type': 'static_library',
       'dependencies': [
-        'crc',
-        '<(DEPTH)/bbb_cape/src/cape/cape.gyp:cows',
         '<(DEPTH)/bbb_cape/src/cape/cape.gyp:data_struct',
         '<(AOS)/build/aos.gyp:logging',
+        'packet_finder',
       ],
       'export_dependent_settings': [
         '<(DEPTH)/bbb_cape/src/cape/cape.gyp:data_struct',
       ],
       'sources': [
         'uart_reader.cc',
-        'packet_finder.cc',
         'uart_reader_termios2.c',
       ],
     },
+    {
+      'target_name': 'cows_test',
+      'type': 'executable',
+      'dependencies': [
+        '<(EXTERNALS):gtest',
+        '<(DEPTH)/bbb_cape/src/cape/cape.gyp:cows',
+      ],
+      'sources': [
+        'cows_test.cc',
+      ],
+    },
+    {
+      'target_name': 'packet_finder_test',
+      'type': 'executable',
+      'dependencies': [
+        '<(EXTERNALS):gtest',
+        'packet_finder',
+        '<(AOS)/common/common.gyp:queue_testutils',
+      ],
+      'sources': [
+        'packet_finder_test.cc',
+      ],
+    },
+    {
+      'target_name': 'packet_finder',
+      'type': 'static_library',
+      'sources': [
+        'packet_finder.cc',
+      ],
+      'dependencies': [
+        '<(DEPTH)/bbb_cape/src/cape/cape.gyp:cows',
+        '<(AOS)/build/aos.gyp:logging',
+        'crc',
+      ],
+    },
     #{
     #  'target_name': 'uart_reader_test',
     #  'type': 'executable',
diff --git a/bbb_cape/src/bbb/byte_reader.h b/bbb_cape/src/bbb/byte_reader.h
new file mode 100644
index 0000000..8319ccb
--- /dev/null
+++ b/bbb_cape/src/bbb/byte_reader.h
@@ -0,0 +1,21 @@
+#ifndef BBB_BYTE_READER_H_
+#define BBB_BYTE_READER_H_
+
+#include <sys/types.h>
+
+namespace bbb {
+
+class ByteReader {
+ public:
+  // We have 64-bit ints in some of our data.
+  typedef char __attribute__((aligned(8))) AlignedChar;
+
+  // Implemented by subclasses to provide a data source 
+  // for these algorithms.
+  // Returns the number of bytes read or -1 if there is an error in errno.
+  virtual ssize_t ReadBytes(AlignedChar *dest, size_t max_bytes) = 0;
+};
+
+}  // namespace bbb
+
+#endif  // BBB_BYTE_READER_H_
diff --git a/bbb_cape/src/bbb/cows_test.cc b/bbb_cape/src/bbb/cows_test.cc
new file mode 100644
index 0000000..06eba5b
--- /dev/null
+++ b/bbb_cape/src/bbb/cows_test.cc
@@ -0,0 +1,17 @@
+#include "cape/cows.h"
+
+#include <gtest/gtest.h>
+
+namespace testing {
+
+TEST(CowsTest, StupidZeros) {
+  static const uint8_t kTestInput[] = {0x02, 0x00, 0x00, 0x00, 0x00, 0x08, 0x01,
+                                       0x00};
+  uint32_t input[3];
+  memcpy(input, kTestInput, 12);
+  uint32_t output[2];
+  EXPECT_EQ(
+      1u, cows_unstuff(input, sizeof(kTestInput), output, sizeof(output) * 4));
+}
+
+}  // namespace testing
diff --git a/bbb_cape/src/bbb/packet_finder.cc b/bbb_cape/src/bbb/packet_finder.cc
index dfc5784..298edc7 100644
--- a/bbb_cape/src/bbb/packet_finder.cc
+++ b/bbb_cape/src/bbb/packet_finder.cc
@@ -2,6 +2,7 @@
 
 #include <errno.h>
 #include <inttypes.h>
+#include <assert.h>
 
 #include <algorithm>
 
@@ -9,15 +10,14 @@
 #include "bbb_cape/src/cape/cows.h"
 #include "bbb/crc.h"
 
-#define PACKET_SIZE (DATA_STRUCT_SEND_SIZE - 4)
-
 namespace bbb {
 
-PacketFinder::PacketFinder()
-    : buf_(new AlignedChar[PACKET_SIZE]),
-      unstuffed_data_(new AlignedChar[PACKET_SIZE - 4]) {
-  static_assert((PACKET_SIZE % 4) == 0,
-                "We can't do checksums of lengths that aren't multiples of 4.");
+PacketFinder::PacketFinder(ByteReader *reader, size_t packet_size)
+    : reader_(reader),
+      packet_size_(packet_size),
+      buf_(new AlignedChar[packet_size_]),
+      unstuffed_data_(new AlignedChar[packet_size_ - 4]) {
+  assert((packet_size_ % 4) == 0);
 }
 
 PacketFinder::~PacketFinder() {
@@ -33,11 +33,10 @@
   while (true) {
     size_t already_read = ::std::max(0, packet_bytes_);
     ssize_t new_bytes =
-        ReadBytes(buf_ + already_read, PACKET_SIZE - already_read);
+        reader_->ReadBytes(buf_ + already_read, packet_size_ - already_read);
     if (new_bytes < 0) {
-      if (errno == EINTR) continue;
       LOG(ERROR, "ReadBytes(%p, %zd) failed with %d: %s\n",
-          buf_ + already_read, PACKET_SIZE - already_read,
+          buf_ + already_read, packet_size_ - already_read,
           errno, strerror(errno));
       return false;
     }
@@ -53,6 +52,7 @@
             new_bytes -= to_check + 1;
             memmove(buf_, buf_ + to_check + 1, new_bytes);
             to_check = 0;
+            break;
           }
         } else {
           zeros_found = 0;
@@ -61,29 +61,29 @@
     }
     if (packet_bytes_ != -1) {  // if we decided that these are good bytes
       packet_bytes_ += new_bytes;
-      if (packet_bytes_ == PACKET_SIZE) return true;
+      if (packet_bytes_ == static_cast<ssize_t>(packet_size_)) return true;
     }
   }
 }
 
 bool PacketFinder::ProcessPacket() {
   uint32_t unstuffed = cows_unstuff(
-      reinterpret_cast<uint32_t *>(buf_), PACKET_SIZE,
-      reinterpret_cast<uint32_t *>(unstuffed_data_), PACKET_SIZE - 4);
+      reinterpret_cast<uint32_t *>(buf_), packet_size_,
+      reinterpret_cast<uint32_t *>(unstuffed_data_), packet_size_ - 4);
   if (unstuffed == 0) {
     LOG(WARNING, "invalid packet\n");
     return false;
-  } else if (unstuffed != (PACKET_SIZE - 4) / 4) {
+  } else if (unstuffed != (packet_size_ - 4) / 4) {
     LOG(WARNING, "packet is %" PRIu32 " words instead of %" PRIu32 "\n",
-        unstuffed, (PACKET_SIZE - 4) / 4);
+        unstuffed, (packet_size_ - 4) / 4);
     return false;
   }
 
   // Make sure the checksum checks out.
   uint32_t sent_checksum;
-  memcpy(&sent_checksum, unstuffed_data_ + PACKET_SIZE - 8, 4);
+  memcpy(&sent_checksum, unstuffed_data_ + packet_size_ - 8, 4);
   uint32_t calculated_checksum = cape::CalculateChecksum(
-      reinterpret_cast<uint8_t *>(unstuffed_data_), PACKET_SIZE - 8);
+      reinterpret_cast<uint8_t *>(unstuffed_data_), packet_size_ - 8);
   if (sent_checksum != calculated_checksum) {
     LOG(WARNING, "sent checksum: %" PRIx32 " vs calculated: %" PRIx32"\n",
         sent_checksum, calculated_checksum);
@@ -99,12 +99,12 @@
   if (!ProcessPacket()) {
     packet_bytes_ = -1;
     int zeros = 0;
-    for (int i = 0; i < PACKET_SIZE; ++i) {
+    for (size_t i = 0; i < packet_size_; ++i) {
       if (buf_[i] == 0) {
         ++zeros;
         if (zeros == 4) {
           LOG(INFO, "found another packet start at %d\n", i);
-          packet_bytes_ = PACKET_SIZE - (i + 1);
+          packet_bytes_ = packet_size_ - (i + 1);
           memmove(buf_, buf_ + i + 1, packet_bytes_);
           return false;
         }
diff --git a/bbb_cape/src/bbb/packet_finder.h b/bbb_cape/src/bbb/packet_finder.h
index ee2e133..8d02caf 100644
--- a/bbb_cape/src/bbb/packet_finder.h
+++ b/bbb_cape/src/bbb/packet_finder.h
@@ -4,6 +4,10 @@
 #include <stdint.h>
 #include <string.h>
 
+#include "aos/common/logging/logging.h"
+
+#include "bbb/byte_reader.h"
+
 #define DATA_STRUCT_NAME DataStruct
 #include "cape/data_struct.h"
 #undef DATA_STRUCT_NAME
@@ -12,8 +16,10 @@
 
 class PacketFinder {
  public:
-  PacketFinder();
-  virtual ~PacketFinder();
+  // *reader has to stay alive for the entire lifetime of this object but this
+  // object does not take ownership.
+  explicit PacketFinder(ByteReader *reader, size_t packet_size);
+  ~PacketFinder();
 
   // Returns true if it succeeds or false if it gets an I/O error first.
   bool ReadPacket();
@@ -25,19 +31,12 @@
   const T *get_packet() {
     static_assert(alignof(T) <= alignof(*unstuffed_data_),
                   "We need to align our data better.");
-    /*static_assert(sizeof(T) <= PACKET_SIZE - 8,
-                  "We aren't getting that much data.");*/
+    CHECK(sizeof(T) <= packet_size_ - 8);
     return reinterpret_cast<const T *>(unstuffed_data_);
   }
 
- protected:
-  typedef char __attribute__((aligned(8))) AlignedChar;
-
  private:
-  // Implemented by subclasses to provide a data source 
-  // for these algorithms.
-  // Returns the number of bytes read or -1 if there is an error in errno.
-  virtual int ReadBytes(AlignedChar *dest, size_t max_bytes) = 0;
+  typedef ByteReader::AlignedChar AlignedChar;
 
   // Reads bytes until there are 4 zeros and then fills up buf_.
   // Returns true if it finds one or false if it gets an I/O error first or the
@@ -50,6 +49,9 @@
   // data.
   bool ProcessPacket();
 
+  ByteReader *const reader_;
+  const size_t packet_size_;
+
   AlignedChar *const buf_;
   AlignedChar *const unstuffed_data_;
 
diff --git a/bbb_cape/src/bbb/packet_finder_test.cc b/bbb_cape/src/bbb/packet_finder_test.cc
new file mode 100644
index 0000000..e2e820a
--- /dev/null
+++ b/bbb_cape/src/bbb/packet_finder_test.cc
@@ -0,0 +1,122 @@
+#include "bbb/packet_finder.h"
+
+#include "gtest/gtest.h"
+
+#include "aos/common/queue_testutils.h"
+
+#include "bbb/byte_reader.h"
+
+namespace bbb {
+namespace testing {
+
+class PacketFinderTest : public ::testing::Test {
+ public:
+  void SetUp() override {
+    ::aos::common::testing::EnableTestLogging();
+  }
+};
+
+class TestByteReader : public ByteReader {
+ public:
+  TestByteReader(const void *data, size_t data_size)
+      : data_(data), data_size_(data_size), bytes_left_(data_size) {}
+
+  virtual ssize_t ReadBytes(AlignedChar *dest, size_t max_bytes) {
+    size_t to_transfer = ::std::min(max_bytes, bytes_left_);
+    memcpy(dest, static_cast<const uint8_t *>(data_) + data_size_ - bytes_left_,
+           to_transfer);
+    bytes_left_ -= to_transfer;
+    return to_transfer;
+  }
+
+ private:
+  const void *const data_;
+  const size_t data_size_;
+  size_t bytes_left_;
+};
+
+TEST_F(PacketFinderTest, StupidZeros) {
+  static const uint8_t kTestData[] = {
+    0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xC0, 0x07, 0x01, 0x00,
+    0x02, 0x00, 0x00, 0x00, 0x69, 0x3D, 0xE0, 0x03, 0x02, 0x00, 0x00, 0x00,
+    0x43, 0x5E, 0x12, 0x16, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x2A, 0x00, 0x00, 0x00, 0x10, 0x00,
+    0x2A, 0x00, 0x1B, 0x00, 0x4E, 0x01, 0x72, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x04, 0x00, 0x00, 0x00, 0xF1, 0xFF, 0xFF, 0xFF, 0x90, 0x01, 0x00, 0x20,
+    0x00, 0xED, 0x00, 0xE0, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+    0x00, 0x38, 0x00, 0x40, 0x05, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
+    0x00, 0x10, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x00, 0xED, 0x00, 0xE0,
+    0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+    0xFF, 0x8E, 0xFE, 0x9E, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+    0xD0, 0x07, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0xA1, 0x79, 0xE0, 0x03,
+    0x02, 0x00, 0x00, 0x00, 0x43, 0x5E, 0x12, 0x16, 0x01, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x2A, 0x00,
+    0x00, 0x00, 0x10, 0x00, 0x29, 0x00, 0x1B, 0x00, 0x50, 0x01, 0x72, 0x00,
+    0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xF1, 0xFF, 0xFF, 0xFF,
+    0x90, 0x01, 0x00, 0x20, 0x00, 0xED, 0x00, 0xE0, 0x01, 0x00, 0x00, 0x00,
+    0x05, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x40, 0x03, 0x00, 0x00, 0x00,
+    0x00, 0xB0, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+    0xF1, 0xFF, 0xFF, 0xFF, 0x00, 0x38, 0x00, 0x40, 0x00, 0x38, 0x00, 0x40,
+    0x82, 0x00, 0x00, 0x00, 0xE6, 0x6F, 0x7E, 0xC7, 0x00, 0x00, 0x00, 0x00,
+    0x02, 0x00, 0x00, 0x00, 0xE0, 0x07, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00,
+    0xDA, 0xB5, 0xE0, 0x03, 0x02, 0x00, 0x00, 0x00, 0x43, 0x5E, 0x12, 0x16,
+    0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+    0x02, 0x00, 0x2B, 0x00, 0x00, 0x00, 0x10, 0x00, 0x2A, 0x00, 0x1B, 0x00,
+    0x50, 0x01, 0x72, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+    0xF1, 0xFF, 0xFF, 0xFF, 0x90, 0x01, 0x00, 0x20, 0x00, 0xED, 0x00, 0xE0,
+    0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x40,
+    0x05, 0x00, 0x00, 0x00, 0x00, 0xD0, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
+    0x06, 0x00, 0x00, 0x00, 0xF1, 0xFF, 0xFF, 0xFF, 0x00, 0x38, 0x00, 0x40,
+    0x00, 0x38, 0x00, 0x40, 0x80, 0x00, 0x00, 0x00, 0xDD, 0xD1, 0x5D, 0x8E,
+    0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xF0, 0x07, 0x01, 0x00,
+    0x02, 0x00, 0x00, 0x00, 0x13, 0xF2, 0xE0, 0x03, 0x02, 0x00, 0x00, 0x00,
+    0x43, 0x5E, 0x12, 0x16, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x2B, 0x00, 0x00, 0x00, 0x10, 0x00,
+    0x29, 0x00, 0x1B, 0x00, 0x50, 0x01, 0x72, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x04, 0x00, 0x00, 0x00, 0xF1, 0xFF, 0xFF, 0xFF, 0x90, 0x01, 0x00, 0x20,
+    0x00, 0xED, 0x00, 0xE0, 0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+    0x00, 0x38, 0x00, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00,
+    0x00, 0x10, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0xED, 0x00, 0xE0,
+    0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+    0x68, 0x26, 0xC4, 0xF1, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+    0x00, 0x08, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x4B, 0x2E, 0xE1, 0x03,
+    0x02, 0x00, 0x00, 0x00, 0x43, 0x5E, 0x12, 0x16, 0x01, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x2A, 0x00,
+    0x00, 0x00, 0x10, 0x00, 0x2A, 0x00, 0x1C, 0x00, 0x50, 0x01, 0x72, 0x00,
+    0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xF1, 0xFF, 0xFF, 0xFF,
+    0x90, 0x01, 0x00, 0x20, 0x00, 0xED, 0x00, 0xE0, 0x01, 0x00, 0x00, 0x00,
+    0x05, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x40, 0x04, 0x00, 0x00, 0x00,
+    0x00, 0xC0, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+    0xF1, 0xFF, 0xFF, 0xFF, 0x00, 0x38, 0x00, 0x40, 0x00, 0x38, 0x00, 0x40,
+    0x00, 0x38, 0x00, 0x40, 0xAD, 0x8B, 0x6A, 0x10, 0x00, 0x00, 0x00, 0x00,
+    0x02, 0x00, 0x00, 0x00, 0x10, 0x08, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00,
+    0x84, 0x6A, 0xE1, 0x03, 0x02, 0x00, 0x00, 0x00, 0x43, 0x5E, 0x12, 0x16,
+    0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+    0x02, 0x00, 0x2A, 0x00, 0x00, 0x00, 0x10, 0x00, 0x29, 0x00, 0x1B, 0x00,
+    0x4E, 0x01, 0x72, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+    0xF1, 0xFF, 0xFF, 0xFF, 0x90, 0x01, 0x00, 0x20, 0x00, 0xED, 0x00, 0xE0,
+    0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x40,
+    0x06, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
+    0x39, 0x00, 0x00, 0x00, 0x00, 0xED, 0x00, 0xE0, 0x01, 0x00, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xFC, 0x94, 0x39, 0xF5,
+    0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00
+  };
+  TestByteReader reader(kTestData, sizeof(kTestData));
+  PacketFinder packet_finder(&reader, 144);
+  EXPECT_TRUE(packet_finder.ReadPacket());
+}
+
+}  // namespace testing
+}  // namespace bbb
diff --git a/bbb_cape/src/bbb/uart_reader.cc b/bbb_cape/src/bbb/uart_reader.cc
index 7b00c00..03cd248 100644
--- a/bbb_cape/src/bbb/uart_reader.cc
+++ b/bbb_cape/src/bbb/uart_reader.cc
@@ -52,8 +52,12 @@
   if (fd_ > 0) close(fd_);
 }
 
-int UartReader::ReadBytes(AlignedChar *dest, size_t max_bytes) {
-  return read(fd_, dest, max_bytes);
+ssize_t UartReader::ReadBytes(AlignedChar *dest, size_t max_bytes) {
+  do {
+    ssize_t r = read(fd_, dest, max_bytes);
+    if (r != -1) return r;
+  } while (errno == EINTR);
+  return -1;
 }
 
 }  // namespace bbb
diff --git a/bbb_cape/src/bbb/uart_reader.h b/bbb_cape/src/bbb/uart_reader.h
index bd022b0..f87af1b 100644
--- a/bbb_cape/src/bbb/uart_reader.h
+++ b/bbb_cape/src/bbb/uart_reader.h
@@ -4,16 +4,16 @@
 #include <stdint.h>
 #include <string.h>
 
-#include "bbb/packet_finder.h"
+#include "bbb/byte_reader.h"
 
 namespace bbb {
 
-class UartReader : public PacketFinder {
+class UartReader : public ByteReader {
  public:
   UartReader(int32_t baud_rate);
   virtual ~UartReader();
 
-  int ReadBytes(AlignedChar *dest, size_t max_bytes);
+  virtual ssize_t ReadBytes(AlignedChar *dest, size_t max_bytes);
 
  private:
   const int fd_;
diff --git a/bbb_cape/src/bbb/uart_reader_test.cc b/bbb_cape/src/bbb/uart_reader_test.cc
index 80f634a..53be07e 100644
--- a/bbb_cape/src/bbb/uart_reader_test.cc
+++ b/bbb_cape/src/bbb/uart_reader_test.cc
@@ -1,7 +1,5 @@
 #include "bbb/uart_reader.h"
 
-#include <termios.h>
-
 #include "gtest/gtest.h"
 
 namespace bbb {
diff --git a/bbb_cape/src/cape/cows.c b/bbb_cape/src/cape/cows.c
index b896fd7..bcf6308 100644
--- a/bbb_cape/src/cape/cows.c
+++ b/bbb_cape/src/cape/cows.c
@@ -2,11 +2,18 @@
 
 #include <limits.h>
 
+#if __STDC_HOSTED__
+#include <assert.h>
+#else
+#define assert(...)
+#endif
+
 // This implementation is based on
 // <http://www.jacquesf.com/2011/03/consistent-overhead-byte-stuffing/>.
 
 uint32_t cows_stuff(const void *__restrict__ source_in, size_t source_length,
                     void *__restrict__ destination_in) {
+  assert((source_length % 4) == 0);
   const uint32_t *restrict source = (const uint32_t *)source_in;
   uint32_t *restrict destination = (uint32_t *)destination_in;
   size_t source_index = 0;
@@ -14,7 +21,7 @@
   size_t code_index = 0;
   uint32_t code = 1;
 
-  while (source_index < ((source_length - 1) / 4) + 1) {
+  while (source_index < source_length / 4) {
     if (source[source_index] == 0) {
       destination[code_index] = code;
       code = 1;
@@ -37,11 +44,13 @@
 uint32_t cows_unstuff(const uint32_t *__restrict__ source, size_t source_length,
                       uint32_t *__restrict__ destination,
                       size_t destination_length) {
+  assert((source_length % 4) == 0);
+  assert((destination_length % 4) == 0);
   size_t source_index = 0;
   size_t destination_index = 0;
   uint32_t code;
 
-  while (source_index < ((source_length - 1) / 4) + 1) {
+  while (1) {
     code = source[source_index];
     if (source_index + code > source_length / 4 && code != 1) {
       return 0;
@@ -50,13 +59,19 @@
     ++source_index;
 
     for (uint32_t i = 1; i < code; ++i) {
+      if (destination_index >= destination_length / 4) {
+        return 0;
+      }
       destination[destination_index++] = source[source_index++];
-      if (destination_index > destination_length / 4) return 0;
     }
-    if (code != UINT32_MAX && source_index != source_length / 4) {
+    if (source_index == source_length / 4) {
+      return destination_index;
+    }
+    if (code != UINT32_MAX) {
+      if (destination_index >= destination_length / 4) {
+        return 0;
+      }
       destination[destination_index++] = 0;
-      if (destination_index > destination_length / 4) return 0;
     }
   }
-  return destination_index;
 }
diff --git a/bbb_cape/src/cape/cows.h b/bbb_cape/src/cape/cows.h
index 442c368..9c47827 100644
--- a/bbb_cape/src/cape/cows.h
+++ b/bbb_cape/src/cape/cows.h
@@ -14,10 +14,10 @@
 // because that's more efficient on 32-bit processors. I'm calling it Consistent
 // Overhead Word Stuffing.
 
-// source_length will be rounded up a multiple of 4. That many bytes of source
+// source_length must be a multiple of 4. That many bytes of source
 // will be read.
 // destination must have at least
-// ([source_length rounded up to a multiple of 4] / (2^32 - 1) rounded up) * 4
+// ((source_length / (2^32 - 1)) rounded up) * 4
 // more bytes than source_length available.
 // source and destination both have to be 4-byte aligned.
 // Returns the total number of words written (not necessarily the maximum given
@@ -25,7 +25,7 @@
 uint32_t cows_stuff(const void *__restrict__ source, size_t source_length,
                     void *__restrict__ destination);
 
-// source_length will be rounded up a multiple of 4. That many bytes of source
+// source_length must be a multiple of 4. That many bytes of source
 // will be read.
 // source and destination both have to be 4-byte aligned.
 // Returns the total number of words written to destination or 0 for error.
diff --git a/bbb_cape/src/cape/data_struct.h b/bbb_cape/src/cape/data_struct.h
index 68491eb..367c359 100644
--- a/bbb_cape/src/cape/data_struct.h
+++ b/bbb_cape/src/cape/data_struct.h
@@ -61,7 +61,7 @@
 // The number of bytes that we actually send (so it stays consistent) (including
 // the byte-stuffing overhead and the CRC on the end).
 // This will always be a multiple of 4.
-#define DATA_STRUCT_SEND_SIZE 200
+#define DATA_STRUCT_SEND_SIZE 148
 
 #ifdef __cplusplus
 #define STATIC_ASSERT(cond, msg) static_assert(cond, #msg)