added support for downloading to our custom bootloader
diff --git a/bbb_cape/src/bbb/bbb.gyp b/bbb_cape/src/bbb/bbb.gyp
index d6c7d80..e46c99f 100644
--- a/bbb_cape/src/bbb/bbb.gyp
+++ b/bbb_cape/src/bbb/bbb.gyp
@@ -18,13 +18,15 @@
],
'dependencies': [
'<(AOS)/common/common.gyp:once',
+ '<(AOS)/build/aos.gyp:logging',
+ 'byte_io',
],
},
{
- 'target_name': 'byte_reader',
+ 'target_name': 'byte_io',
'type': 'static_library',
'sources': [
- # 'byte_reader.h',
+ # 'byte_io.h',
],
'dependencies': [
'<(AOS)/common/common.gyp:time',
@@ -43,11 +45,11 @@
'dependencies': [
'<(AOS)/build/aos.gyp:logging',
'<(AOS)/common/common.gyp:time',
- 'byte_reader',
+ 'byte_io',
],
'export_dependent_settings': [
'<(AOS)/common/common.gyp:time',
- 'byte_reader',
+ 'byte_io',
],
},
{
@@ -72,6 +74,7 @@
'packet_finder',
'<(AOS)/common/common.gyp:queue_testutils',
'<(AOS)/common/common.gyp:time',
+ 'byte_io',
],
},
{
@@ -92,16 +95,15 @@
'packet_finder.cc',
],
'dependencies': [
- '<(DEPTH)/bbb_cape/src/cape/cape.gyp:cows',
'<(AOS)/build/aos.gyp:logging',
- 'crc',
'<(AOS)/common/common.gyp:time',
- 'byte_reader',
+ '<(DEPTH)/bbb_cape/src/cape/cape.gyp:cows',
+ 'crc',
+ 'byte_io',
],
'export_dependent_settings': [
'<(AOS)/build/aos.gyp:logging',
'<(AOS)/common/common.gyp:time',
- 'byte_reader',
],
},
{
@@ -130,7 +132,6 @@
'packet_finder',
'data_struct',
'<(AOS)/common/common.gyp:time',
- 'gpios',
],
},
{
@@ -152,21 +153,67 @@
'sensor_reader.cc',
],
'dependencies': [
- 'uart_reader',
'packet_finder',
'data_struct',
+ 'cape_manager',
'<(AOS)/common/common.gyp:time',
+ 'hex_byte_reader',
+ 'crc',
'sensor_generation',
'<(AOS)/linux_code/linux_code.gyp:configuration',
- 'crc',
- '<(EXTERNALS):stm32flash',
],
'export_dependent_settings': [
- 'uart_reader',
'packet_finder',
'data_struct',
+ 'cape_manager',
'<(AOS)/common/common.gyp:time',
],
},
+ {
+ 'target_name': 'cape_flasher',
+ 'type': 'static_library',
+ 'sources': [
+ 'cape_flasher.cc',
+ ],
+ 'dependencies': [
+ 'byte_io',
+ 'crc',
+ ],
+ },
+ {
+ 'target_name': 'hex_byte_reader',
+ 'type': 'static_library',
+ 'sources': [
+ 'hex_byte_reader.cc',
+ ],
+ 'dependencies': [
+ 'byte_io',
+ '<(AOS)/common/common.gyp:time',
+ '<(EXTERNALS):stm32flash',
+ '<(AOS)/build/aos.gyp:logging',
+ ],
+ 'export_dependent_settings': [
+ 'byte_io',
+ '<(AOS)/common/common.gyp:time',
+ ],
+ },
+ {
+ 'target_name': 'cape_manager',
+ 'type': 'static_library',
+ 'sources': [
+ 'cape_manager.cc',
+ ],
+ 'dependencies': [
+ 'gpios',
+ 'uart_reader',
+ 'cape_flasher',
+ '<(AOS)/common/common.gyp:time',
+ 'hex_byte_reader',
+ ],
+ 'export_dependent_settings': [
+ 'gpios',
+ 'uart_reader',
+ ],
+ },
],
}
diff --git a/bbb_cape/src/bbb/byte_io.h b/bbb_cape/src/bbb/byte_io.h
new file mode 100644
index 0000000..41708e9
--- /dev/null
+++ b/bbb_cape/src/bbb/byte_io.h
@@ -0,0 +1,51 @@
+#ifndef BBB_BYTE_READER_H_
+#define BBB_BYTE_READER_H_
+
+#include <sys/types.h>
+
+#include "aos/common/time.h"
+
+namespace bbb {
+
+class ByteReaderInterface {
+ public:
+ virtual ~ByteReaderInterface() {}
+
+ // Implemented by subclasses to provide a data source
+ // for these algorithms.
+ // Returns the number of bytes read, -1 if there is an error in errno, or -2
+ // if reading takes longer than timeout.
+ virtual ssize_t ReadBytes(
+ uint8_t *dest, size_t max_bytes,
+ const ::aos::time::Time &timeout = ::aos::time::Time(0, 0)) = 0;
+};
+
+class ByteWriterInterface {
+ public:
+ virtual ~ByteWriterInterface() {}
+
+ // Implemented by subclasses to actually write the data somewhere.
+ // Returns true if it succeeds or false if it fails and there is an error in
+ // errno.
+ virtual bool WriteBytes(uint8_t *bytes, size_t number_bytes) = 0;
+};
+
+class ByteReaderWriterInterface : public ByteReaderInterface,
+ public ByteWriterInterface {};
+
+class ByteReaderAndWriter : public ByteReaderWriterInterface {
+ public:
+ ByteReaderAndWriter(ByteReaderInterface *reader, ByteWriterInterface *writer)
+ : reader_(reader), writer_(writer) {}
+
+ ByteReaderInterface *reader() { return reader_; }
+ ByteWriterInterface *writer() { return writer_; }
+
+ private:
+ ByteReaderInterface *const reader_;
+ ByteWriterInterface *const writer_;
+};
+
+} // namespace bbb
+
+#endif // BBB_BYTE_READER_H_
diff --git a/bbb_cape/src/bbb/byte_reader.h b/bbb_cape/src/bbb/byte_reader.h
deleted file mode 100644
index 80bb208..0000000
--- a/bbb_cape/src/bbb/byte_reader.h
+++ /dev/null
@@ -1,25 +0,0 @@
-#ifndef BBB_BYTE_READER_H_
-#define BBB_BYTE_READER_H_
-
-#include <sys/types.h>
-
-#include "aos/common/time.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, -1 if there is an error in errno, or -2
- // if reading takes longer than timeout.
- virtual ssize_t ReadBytes(AlignedChar *dest, size_t max_bytes,
- const ::aos::time::Time &timeout_time) = 0;
-};
-
-} // namespace bbb
-
-#endif // BBB_BYTE_READER_H_
diff --git a/bbb_cape/src/bbb/cape_flasher.cc b/bbb_cape/src/bbb/cape_flasher.cc
new file mode 100644
index 0000000..744c045
--- /dev/null
+++ b/bbb_cape/src/bbb/cape_flasher.cc
@@ -0,0 +1,97 @@
+#include "bbb/cape_flasher.h"
+
+#include <errno.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "aos/common/logging/logging.h"
+
+#include "bbb/crc.h"
+#include "bbb/byte_io.h"
+
+namespace bbb {
+namespace {
+namespace command {
+
+const uint8_t kAck = 0x79;
+const uint8_t kNack = 0x1F;
+
+} // namespace command
+} // namespace
+
+CapeFlasher::CapeFlasher(ByteReaderWriterInterface *uart) : uart_(uart) {}
+
+void CapeFlasher::Download(ByteReaderInterface *file) {
+ uint8_t bootloader_receive = 0;
+ uint8_t buffer[256];
+ ssize_t bootloader_read = 0;
+
+ while (bootloader_read <= 0 || bootloader_receive != command::kNack) {
+ bootloader_read = uart_->ReadBytes(&bootloader_receive, 1,
+ ::aos::time::Time::InSeconds(2));
+ if (bootloader_read == -1) {
+ LOG(WARNING, "reading from %p (uart) failed with %d: %s\n", uart_, errno,
+ strerror(errno));
+ } else if (bootloader_read == -2) {
+ LOG(WARNING, "timeout reading from uart %p\n", uart_);
+ }
+ }
+
+ while (true) {
+ size_t total_read = 0;
+ bool done = false;
+ while (total_read < sizeof(buffer)) {
+ ssize_t read = file->ReadBytes(buffer, sizeof(buffer));
+ if (read == -2) {
+ if (total_read == 0) return;
+ done = true;
+ memset(buffer + total_read, 0xFF, sizeof(buffer) - total_read);
+ total_read = sizeof(buffer);
+ } else if (read == -1) {
+ LOG(FATAL, "reading from file %p returned error %d: %s\n", file, errno,
+ strerror(errno));
+ } else {
+ total_read += read;
+ }
+ }
+
+ WriteBuffer(buffer, sizeof(buffer));
+ if (done) return;
+ }
+}
+
+void CapeFlasher::WriteBuffer(uint8_t *buffer, size_t size) {
+ while (true) {
+ uart_->WriteBytes(buffer, size);
+ uint32_t checksum = cape::CalculateChecksum(buffer, size);
+ uart_->WriteBytes(reinterpret_cast<uint8_t *>(&checksum),
+ sizeof(checksum));
+
+ uint8_t bootloader_receive;
+ ssize_t bootloader_read = uart_->ReadBytes(
+ &bootloader_receive, 1, ::aos::time::Time::InSeconds(2));
+ if (bootloader_read == -1) {
+ LOG(WARNING, "reading from %p (uart) failed with %d: %s\n", uart_,
+ errno, strerror(errno));
+ } else if (bootloader_read == -2) {
+ LOG(WARNING, "timeout reading from uart %p\n", uart_);
+ do {
+ uint8_t byte = 0;
+ uart_->WriteBytes(&byte, 1);
+ bootloader_read = uart_->ReadBytes(&bootloader_receive, 1,
+ ::aos::time::Time::InSeconds(0.1));
+ } while (bootloader_read <= 0 || bootloader_receive != command::kNack);
+ switch (bootloader_receive) {
+ case command::kAck:
+ return;
+ case command::kNack:
+ break;
+ default:
+ LOG(WARNING, "unknown bootloader response %" PRIu8 "\n",
+ bootloader_receive);
+ }
+ }
+ }
+}
+
+} // namespace bbb
diff --git a/bbb_cape/src/bbb/cape_flasher.h b/bbb_cape/src/bbb/cape_flasher.h
new file mode 100644
index 0000000..852321e
--- /dev/null
+++ b/bbb_cape/src/bbb/cape_flasher.h
@@ -0,0 +1,35 @@
+#ifndef BBB_CAPE_SRC_BBB_CAPE_FLASHER_H_
+#define BBB_CAPE_SRC_BBB_CAPE_FLASHER_H_
+
+#include <string>
+
+#include "aos/common/macros.h"
+
+namespace bbb {
+
+class ByteReaderInterface;
+class ByteReaderWriterInterface;
+
+// Talks to the custom bootloader on the cape MCU. Expects for the cape to be
+// freshly booted into the bootloader when initialized.
+class CapeFlasher {
+ public:
+ explicit CapeFlasher(ByteReaderWriterInterface *uart);
+
+ // Downloads a file.
+ // file should give the raw bytes to download, starting at the start of the
+ // main code. All reads will be done with a timeout of 0. Stops on the first
+ // timeout.
+ void Download(ByteReaderInterface *file);
+
+ private:
+ void WriteBuffer(uint8_t *buffer, size_t size);
+
+ ByteReaderWriterInterface *const uart_;
+
+ DISALLOW_COPY_AND_ASSIGN(CapeFlasher);
+};
+
+} // namespace bbb
+
+#endif // BBB_CAPE_SRC_BBB_CAPE_FLASHER_H_
diff --git a/bbb_cape/src/bbb/cape_manager.cc b/bbb_cape/src/bbb/cape_manager.cc
new file mode 100644
index 0000000..d9b1e28
--- /dev/null
+++ b/bbb_cape/src/bbb/cape_manager.cc
@@ -0,0 +1,35 @@
+#include "bbb/cape_manager.h"
+
+#include <string.h>
+#include <errno.h>
+
+#include "aos/common/time.h"
+
+#include "bbb/cape_flasher.h"
+#include "bbb/hex_byte_reader.h"
+
+namespace bbb {
+
+CapeManager::CapeManager()
+ : uart_(750000), reset_(2, 5, true), custom_bootloader_(2, 3, false) {}
+
+void CapeManager::DownloadHex(const ::std::string &filename) {
+ HexByteReader file(filename);
+ CapeFlasher flasher(&uart_);
+ DoReset(true);
+ flasher.Download(&file);
+ DoReset(false);
+}
+
+void CapeManager::DoReset(bool bootloader) {
+ static constexpr ::aos::time::Time kTimeout =
+ ::aos::time::Time::InSeconds(0.1);
+ reset_.Set(false);
+ ::aos::time::SleepFor(kTimeout);
+ custom_bootloader_.Set(bootloader);
+ ::aos::time::SleepFor(kTimeout);
+ reset_.Set(true);
+ ::aos::time::SleepFor(kTimeout);
+}
+
+} // namespace bbb
diff --git a/bbb_cape/src/bbb/cape_manager.h b/bbb_cape/src/bbb/cape_manager.h
new file mode 100644
index 0000000..1cc1a57
--- /dev/null
+++ b/bbb_cape/src/bbb/cape_manager.h
@@ -0,0 +1,39 @@
+#ifndef BBB_CAPE_SRC_BBB_CAPE_MANAGER_H_
+#define BBB_CAPE_SRC_BBB_CAPE_MANAGER_H_
+
+#include <string>
+
+#include "aos/common/macros.h"
+
+#include "bbb/gpo.h"
+#include "bbb/uart_reader.h"
+
+namespace bbb {
+
+// Manages the connection to the cape (including GPIOs, running the bootloader,
+// setting up the serial connection, etc).
+class CapeManager {
+ public:
+ CapeManager();
+
+ // Downloads a .hex file using the custom bootloader.
+ void DownloadHex(const ::std::string &filename);
+
+ // Resets the cape.
+ void Reset() { DoReset(false); }
+
+ UartReader *uart() { return &uart_; }
+
+ private:
+ void DoReset(bool bootloader);
+
+ UartReader uart_;
+
+ Gpo reset_, custom_bootloader_;
+
+ DISALLOW_COPY_AND_ASSIGN(CapeManager);
+};
+
+} // namespace bbb
+
+#endif // BBB_CAPE_SRC_BBB_CAPE_MANAGER_H_
diff --git a/bbb_cape/src/bbb/crc.cc b/bbb_cape/src/bbb/crc.cc
index b16eb94..7c14706 100644
--- a/bbb_cape/src/bbb/crc.cc
+++ b/bbb_cape/src/bbb/crc.cc
@@ -1,6 +1,13 @@
#include "bbb/crc.h"
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
#include "aos/common/once.h"
+#include "aos/common/logging/logging.h"
+
+#include "bbb/byte_io.h"
// There are various implementations that look a lot like this scattered around
// the internet.
@@ -26,11 +33,13 @@
} // namespace
-uint32_t CalculateChecksum(uint8_t *data, size_t length) {
+uint32_t CalculateChecksum(uint8_t *data, size_t length, uint32_t initial) {
+ assert((length % 4) == 0);
+
static ::aos::Once<const uint32_t> table_once(GenerateTable);
const uint32_t *const table = table_once.Get();
- uint32_t r = 0xFFFFFFFF;
+ uint32_t r = initial;
for (size_t i = 0; i < (length / 4); ++i) {
for (int ii = 3; ii >= 0; --ii) {
@@ -41,4 +50,23 @@
return r;
}
+uint32_t CalculateChecksum(::bbb::ByteReaderInterface *reader) {
+ uint8_t buffer[256];
+ int remainder_bytes = 0;
+ uint32_t checksum = 0xFFFFFFFF;
+ while (true) {
+ ssize_t read = reader->ReadBytes(&buffer[remainder_bytes],
+ sizeof(buffer) - remainder_bytes);
+ if (read == -2) return checksum;
+ if (read == -1) {
+ LOG(FATAL, "reader %p failed to read with %d: %s\n",
+ reader, errno, strerror(errno));
+ }
+ size_t checksum_bytes = (read / 4) * 4;
+ checksum = CalculateChecksum(buffer, checksum_bytes, checksum);
+ remainder_bytes = read - checksum_bytes;
+ memmove(buffer, &buffer[checksum_bytes], remainder_bytes);
+ }
+}
+
} // namespace cape
diff --git a/bbb_cape/src/bbb/crc.h b/bbb_cape/src/bbb/crc.h
index 7a8eb95..4d1dea7 100644
--- a/bbb_cape/src/bbb/crc.h
+++ b/bbb_cape/src/bbb/crc.h
@@ -4,11 +4,24 @@
#include <string.h>
#include <stdint.h>
+namespace bbb {
+
+class ByteReaderInterface;
+
+} // namespace bbb
namespace cape {
// Calculates a CRC32 checksum for data. This is definitely the same one as the
// cape MCU does in hardware which seems to be the same one as Ethernet etc use.
-uint32_t CalculateChecksum(uint8_t *data, size_t length);
+// length is the number of bytes of data to read. It must be a multiple of 4.
+// initial can be a previous return value to continue the same checksum over
+// more data.
+uint32_t CalculateChecksum(uint8_t *data, size_t length,
+ uint32_t initial = 0xFFFFFFFF);
+// Reads all data out of reader and does a checksum over all of it in reasonably
+// sized pieces. Does all of the reads with a timeout of 0. Stops on the first
+// timeout.
+uint32_t CalculateChecksum(::bbb::ByteReaderInterface *reader);
} // namespace cape
diff --git a/bbb_cape/src/bbb/gpi.cc b/bbb_cape/src/bbb/gpi.cc
index 5bb4902..520d985 100644
--- a/bbb_cape/src/bbb/gpi.cc
+++ b/bbb_cape/src/bbb/gpi.cc
@@ -12,6 +12,7 @@
}
bool Gpi::Read() {
+ rewind(value_handle_);
int value = fgetc(value_handle_);
if (value < 0) {
LOG(FATAL, "fgetc(%p) for pin (%d,%d) failed with %d: %s\n",
diff --git a/bbb_cape/src/bbb/gpios.cc b/bbb_cape/src/bbb/gpios.cc
index 79d38bc..0aca731 100644
--- a/bbb_cape/src/bbb/gpios.cc
+++ b/bbb_cape/src/bbb/gpios.cc
@@ -5,7 +5,7 @@
#include <errno.h>
#include <string.h>
-#include "aos/common/logging/logging_impl.h"
+#include "aos/common/logging/logging.h"
namespace bbb {
diff --git a/bbb_cape/src/bbb/gpo.cc b/bbb_cape/src/bbb/gpo.cc
index b43c4b0..f02ded3 100644
--- a/bbb_cape/src/bbb/gpo.cc
+++ b/bbb_cape/src/bbb/gpo.cc
@@ -12,6 +12,7 @@
: GpioPin(bank, pin, false, initial_value) {}
void Gpo::Set(bool high) {
+ rewind(value_handle_);
if (fputc(high ? '1' : '0', value_handle_) < 0) {
LOG(FATAL, "fputc(%c, %p) for pin (%d,%d) failed with %d: %s\n",
high ? '1': '0', value_handle_, bank_, pin_, errno, strerror(errno));
diff --git a/bbb_cape/src/bbb/gpo.h b/bbb_cape/src/bbb/gpo.h
index 893fe4a..493ddd3 100644
--- a/bbb_cape/src/bbb/gpo.h
+++ b/bbb_cape/src/bbb/gpo.h
@@ -1,7 +1,7 @@
#ifndef BBB_CAPE_SRC_BBB_GPO_H_
#define BBB_CAPE_SRC_BBB_GPO_H_
-#include "gpios.h"
+#include "bbb/gpios.h"
namespace bbb {
diff --git a/bbb_cape/src/bbb/hex_byte_reader.cc b/bbb_cape/src/bbb/hex_byte_reader.cc
new file mode 100644
index 0000000..968e771
--- /dev/null
+++ b/bbb_cape/src/bbb/hex_byte_reader.cc
@@ -0,0 +1,52 @@
+#include "bbb/hex_byte_reader.h"
+
+#include <string.h>
+#include <errno.h>
+
+#include "stm32flash/parsers/parser.h"
+#include "stm32flash/parsers/hex.h"
+
+#include "aos/common/logging/logging.h"
+
+namespace bbb {
+namespace {
+
+const parser_t kParser = PARSER_HEX;
+
+__attribute__((noreturn)) void DieParserError(parser_err_t perr) {
+ if (perr == PARSER_ERR_SYSTEM) {
+ LOG(ERROR, "%d: %s\n", errno, strerror(errno));
+ }
+ LOG(FATAL, "%s error: %s\n", kParser.name, parser_errstr(perr));
+}
+
+} // namespace
+
+HexByteReader::HexByteReader(const ::std::string &filename)
+ : parser_status_(kParser.init()) {
+ if (parser_status_ == NULL) {
+ LOG(FATAL, "%s parser failed to initialize.\n", kParser.name);
+ }
+ parser_err_t perr = kParser.open(parser_status_, filename.c_str(), 0);
+ if (perr != PARSER_ERR_OK) {
+ DieParserError(perr);
+ }
+}
+
+ssize_t HexByteReader::ReadBytes(uint8_t *dest, size_t max_bytes,
+ const ::aos::time::Time &/*timeout*/) {
+ unsigned int bytes = max_bytes;
+ parser_err_t perr = kParser.read(parser_status_, dest, &bytes);
+ if (perr != PARSER_ERR_OK) {
+ if (perr == PARSER_ERR_SYSTEM) return -1;
+ DieParserError(perr);
+ }
+ if (bytes == 0) return -2;
+ return bytes;
+}
+
+unsigned int HexByteReader::GetSize() {
+ return kParser.size(parser_status_);
+}
+
+} // namespace bbb
diff --git a/bbb_cape/src/bbb/hex_byte_reader.h b/bbb_cape/src/bbb/hex_byte_reader.h
new file mode 100644
index 0000000..8f44c9a
--- /dev/null
+++ b/bbb_cape/src/bbb/hex_byte_reader.h
@@ -0,0 +1,30 @@
+#ifndef BBB_CAPE_SRC_BBB_HEX_BYTE_READER_H_
+#define BBB_CAPE_SRC_BBB_HEX_BYTE_READER_H_
+
+#include <string>
+
+#include "aos/common/time.h"
+
+#include "bbb/byte_io.h"
+
+namespace bbb {
+
+// Reads bytes from a .hex file.
+class HexByteReader : public ByteReaderInterface {
+ public:
+ 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;
+
+ // Returns the total number of bytes that we will eventually read out.
+ unsigned int GetSize();
+
+ private:
+ void *const parser_status_;
+};
+
+} // namespace bbb
+
+#endif // BBB_CAPE_SRC_BBB_HEX_BYTE_READER_H_
diff --git a/bbb_cape/src/bbb/packet_finder.cc b/bbb_cape/src/bbb/packet_finder.cc
index 713ea69..aac6a0f 100644
--- a/bbb_cape/src/bbb/packet_finder.cc
+++ b/bbb_cape/src/bbb/packet_finder.cc
@@ -3,18 +3,21 @@
#include <errno.h>
#include <inttypes.h>
#include <stdlib.h>
+#include <string.h>
#include <algorithm>
#include "aos/common/logging/logging.h"
-#include "bbb_cape/src/cape/cows.h"
+
+#include "cape/cows.h"
#include "bbb/crc.h"
+#include "bbb/byte_io.h"
using ::aos::time::Time;
namespace bbb {
-PacketFinder::PacketFinder(ByteReader *reader, size_t packet_size)
+PacketFinder::PacketFinder(ByteReaderInterface *reader, size_t packet_size)
: reader_(reader),
packet_size_(packet_size),
buf_(new AlignedChar[packet_size_]),
@@ -32,8 +35,9 @@
int zeros_found = 0;
while (true) {
size_t already_read = ::std::max(0, packet_bytes_);
- ssize_t new_bytes = reader_->ReadBytes(
- buf_ + already_read, packet_size_ - already_read, timeout_time);
+ ssize_t new_bytes =
+ reader_->ReadBytes((uint8_t *)(buf_ + already_read),
+ packet_size_ - already_read, timeout_time);
if (new_bytes < 0) {
if (new_bytes == -1) {
LOG(ERROR, "ReadBytes(%p, %zd) failed with %d: %s\n",
diff --git a/bbb_cape/src/bbb/packet_finder.h b/bbb_cape/src/bbb/packet_finder.h
index 9b74583..80cb8b8 100644
--- a/bbb_cape/src/bbb/packet_finder.h
+++ b/bbb_cape/src/bbb/packet_finder.h
@@ -8,15 +8,15 @@
#include "aos/common/time.h"
#include "aos/common/macros.h"
-#include "bbb/byte_reader.h"
-
namespace bbb {
+class ByteReaderInterface;
+
class PacketFinder {
public:
// *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(ByteReaderInterface *reader, size_t packet_size);
~PacketFinder();
// Returns true if it succeeds or false if it gets an I/O error (or timeout)
@@ -37,7 +37,8 @@
}
private:
- typedef ByteReader::AlignedChar AlignedChar;
+ // We have 64-bit ints in some of our data.
+ typedef char __attribute__((aligned(8))) 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,7 +51,7 @@
// data.
bool ProcessPacket();
- ByteReader *const reader_;
+ ByteReaderInterface *const reader_;
const size_t packet_size_;
AlignedChar *const buf_;
diff --git a/bbb_cape/src/bbb/packet_finder_test.cc b/bbb_cape/src/bbb/packet_finder_test.cc
index 437bf8d..b9dd97a 100644
--- a/bbb_cape/src/bbb/packet_finder_test.cc
+++ b/bbb_cape/src/bbb/packet_finder_test.cc
@@ -5,7 +5,7 @@
#include "aos/common/queue_testutils.h"
#include "aos/common/time.h"
-#include "bbb/byte_reader.h"
+#include "bbb/byte_io.h"
namespace bbb {
namespace testing {
@@ -17,12 +17,12 @@
}
};
-class TestByteReader : public ByteReader {
+class TestByteReader : public ByteReaderInterface {
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,
+ virtual ssize_t ReadBytes(uint8_t *dest, size_t max_bytes,
const ::aos::time::Time &/*timeout_time*/)
override {
size_t to_transfer = ::std::min(max_bytes, bytes_left_);
diff --git a/bbb_cape/src/bbb/sensor_reader.cc b/bbb_cape/src/bbb/sensor_reader.cc
index a685881..13d6add 100644
--- a/bbb_cape/src/bbb/sensor_reader.cc
+++ b/bbb_cape/src/bbb/sensor_reader.cc
@@ -5,62 +5,30 @@
#include <inttypes.h>
#include <stdint.h>
-#include "stm32flash/parsers/parser.h"
-#include "stm32flash/parsers/hex.h"
-
#include "aos/linux_code/configuration.h"
#include "bbb/sensor_generation.q.h"
#include "bbb/crc.h"
+#include "bbb/hex_byte_reader.h"
namespace bbb {
namespace {
-__attribute__((noreturn)) void PrintParserError(parser_t *parser,
- parser_err_t perr) {
- if (perr == PARSER_ERR_SYSTEM) {
- LOG(ERROR, "%d: %s\n", errno, strerror(errno));
- }
- LOG(FATAL, "%s error: %s\n", parser->name, parser_errstr(perr));
-}
-
-uint32_t ReadChecksum(const ::std::string &cape_code) {
- parser_t *parser = &PARSER_HEX;
- void *p_st = parser->init();
- if (p_st == NULL) {
- LOG(FATAL, "%s parser failed to initialize.\n", parser->name);
- }
- ::std::string filename =
- ::std::string(::aos::configuration::GetRootDirectory()) + "/main_" +
- cape_code + ".hex";
- parser_err_t perr = parser->open(p_st, filename.c_str(), 0);
- if (perr != PARSER_ERR_OK) {
- PrintParserError(parser, perr);
- }
-
- const unsigned int allocated_size = parser->size(p_st);
- uint8_t *buffer = new uint8_t[allocated_size];
- unsigned int read_size = allocated_size;
- if (parser->read(p_st, buffer, &read_size) != PARSER_ERR_OK) {
- PrintParserError(parser, perr);
- }
- if (allocated_size != read_size) {
- LOG(WARNING, "expected %u bytes but got %u\n", allocated_size, read_size);
- }
-
- uint32_t r = ::cape::CalculateChecksum(buffer, read_size);
- parser->close(p_st);
- return r;
+uint32_t ReadChecksum(const ::std::string &filename) {
+ HexByteReader reader(filename);
+ return ::cape::CalculateChecksum(&reader);
}
} // namespace
SensorReader::SensorReader(const ::std::string &cape_code)
- : reader_(750000),
- packet_finder_(&reader_, DATA_STRUCT_SEND_SIZE - 4),
- expected_checksum_(ReadChecksum(cape_code)) {
+ : hex_filename_(::std::string(::aos::configuration::GetRootDirectory()) +
+ "/main_" + cape_code + ".hex"),
+ manager_(),
+ packet_finder_(manager_.uart(), DATA_STRUCT_SEND_SIZE - 4),
+ expected_checksum_(ReadChecksum(hex_filename_)) {
static_assert(sizeof(SensorGeneration::reader_pid) >= sizeof(pid_t),
- "pid_t is really big");
+ "pid_t is really big?");
ResetHappened();
}
@@ -72,12 +40,20 @@
::aos::time::Time next_timeout = last_received_time_ + kTimeout;
if (next_timeout <= ::aos::time::Time::Now()) {
LOG(WARNING, "too long since good packet received\n");
- Reset(false);
+ manager_.Reset();
+ ResetHappened();
}
if (packet_finder_.ReadPacket(next_timeout)) {
last_received_time_ = ::aos::time::Time::Now();
const DataStruct *data = packet_finder_.get_packet<DataStruct>();
- // TODO(brians): Check the flash checksum and reflash it if necessary.
+ if (data->flash_checksum != expected_checksum_) {
+ LOG(WARNING, "Cape code checksum is %" PRIu32 ". Expected %" PRIu32
+ ". Reflashing.\n",
+ data->flash_checksum, expected_checksum_);
+ manager_.DownloadHex(hex_filename_);
+ ResetHappened();
+ continue;
+ }
if (data->timestamp < last_cape_timestamp_) {
LOG(WARNING, "cape timestamp decreased: %" PRIu64 " to %" PRIu64 "\n",
last_cape_timestamp_, data->timestamp);
@@ -94,12 +70,6 @@
return ::aos::time::Time::InUS(last_cape_timestamp_ * 10);
}
-void SensorReader::Reset(bool reflash) {
- LOG(INFO, "Reset(%s)\n", reflash ? "true" : "false");
- // TODO(brians): Actually reset it and maybe reflash it.
- ResetHappened();
-}
-
void SensorReader::ResetHappened() {
sensor_generation.MakeWithBuilder().reader_pid(getpid())
.cape_resets(cape_resets_++).Send();
diff --git a/bbb_cape/src/bbb/sensor_reader.h b/bbb_cape/src/bbb/sensor_reader.h
index a1b489d..48c863a 100644
--- a/bbb_cape/src/bbb/sensor_reader.h
+++ b/bbb_cape/src/bbb/sensor_reader.h
@@ -8,9 +8,9 @@
#include "aos/common/time.h"
#include "aos/common/macros.h"
-#include "bbb/uart_reader.h"
#include "bbb/packet_finder.h"
#include "bbb/data_struct.h"
+#include "bbb/cape_manager.h"
namespace bbb {
@@ -25,7 +25,7 @@
// cape_code is the name of the code that should be deployed to the cape if
// it's not already there.
- SensorReader(const ::std::string &cape_code);
+ explicit SensorReader(const ::std::string &cape_code);
// Reads in 1 data packet, handles the gyro data in it, and returns a pointer
// to it.
@@ -40,7 +40,9 @@
// Called after a reset happens.
void ResetHappened();
- UartReader reader_;
+ const ::std::string hex_filename_;
+
+ CapeManager manager_;
PacketFinder packet_finder_;
const uint32_t expected_checksum_;
diff --git a/bbb_cape/src/bbb/uart_reader.cc b/bbb_cape/src/bbb/uart_reader.cc
index cebe127..a82faa1 100644
--- a/bbb_cape/src/bbb/uart_reader.cc
+++ b/bbb_cape/src/bbb/uart_reader.cc
@@ -8,11 +8,11 @@
#include "aos/common/logging/logging.h"
// This is the code for receiving data from the cape via UART.
-// NOTE: In order for this to work, you MUST HAVE
-// "capemgr.enable_partno=BB_UART1"
-// in your BBB's /media/BEAGLEBONE/uEnv.txt file!
-// `su -c "echo BB-UART1 > /sys/devices/bone_capemgr.*/slots"` works too, but
-// you have to do it every time.
+// NOTE: In order for this to work, you must have the BB-UART1 device tree
+// fragment active.
+// `su -c "echo BB-UART1 > /sys/devices/bone_capemgr.*/slots"` works, but
+// you have to do it every time. It is also possible to set it up to do that
+// every time it boots.
namespace bbb {
namespace {
@@ -53,7 +53,7 @@
if (fd_ > 0) close(fd_);
}
-ssize_t UartReader::ReadBytes(AlignedChar *dest, size_t max_bytes,
+ssize_t UartReader::ReadBytes(uint8_t *dest, size_t max_bytes,
const ::aos::time::Time &timeout_time) {
do {
::aos::time::Time timeout = timeout_time - ::aos::time::Time::Now();
@@ -76,4 +76,14 @@
return -1;
}
+bool UartReader::WriteBytes(uint8_t *bytes, size_t number_bytes) {
+ size_t written = 0;
+ while (written < number_bytes) {
+ ssize_t r = write(fd_, &bytes[written], number_bytes - written);
+ if (r == -1) return false;
+ written += r;
+ }
+ return true;
+}
+
} // namespace bbb
diff --git a/bbb_cape/src/bbb/uart_reader.h b/bbb_cape/src/bbb/uart_reader.h
index c441167..a6cf34c 100644
--- a/bbb_cape/src/bbb/uart_reader.h
+++ b/bbb_cape/src/bbb/uart_reader.h
@@ -8,17 +8,18 @@
#include "aos/common/time.h"
#include "aos/common/macros.h"
-#include "bbb/byte_reader.h"
+#include "bbb/byte_io.h"
namespace bbb {
-class UartReader : public ByteReader {
+class UartReader : public ByteReaderWriterInterface {
public:
- UartReader(int32_t baud_rate);
+ explicit UartReader(int32_t baud_rate);
virtual ~UartReader();
- virtual ssize_t ReadBytes(AlignedChar *dest, size_t max_bytes,
+ virtual ssize_t ReadBytes(uint8_t *dest, size_t max_bytes,
const ::aos::time::Time &timeout_time) override;
+ virtual bool WriteBytes(uint8_t *bytes, size_t number_bytes) override;
private:
const int fd_;
diff --git a/bbb_cape/src/cape/bootloader.c b/bbb_cape/src/cape/bootloader.c
index 199a3d1..39f3080 100644
--- a/bbb_cape/src/cape/bootloader.c
+++ b/bbb_cape/src/cape/bootloader.c
@@ -4,6 +4,7 @@
#include "cape/bootloader_handoff.h"
#include "cape/led.h"
+#include "cape/util.h"
// Actually runs the bootloader code.
// Implemented in bootloader_impl.c.
@@ -64,6 +65,7 @@
RCC_AHB1ENR_GPIOAEN | RCC_AHB1ENR_GPIOBEN | RCC_AHB1ENR_GPIOCEN;
led_init();
led_set(LED_HB, 1);
+ gpio_set_pupd(GPIOC, 2, 2);
setup_main_clock();
@@ -72,8 +74,8 @@
while (!(SYSCFG->CMPCR & SYSCFG_CMPCR_READY)) {} // wait for it to be ready
if (GPIOC->IDR & (1 << 2)) {
- jump_to_main();
- } else {
bootloader_start();
+ } else {
+ jump_to_main();
}
}
diff --git a/bbb_cape/src/cape/bootloader_impl.c b/bbb_cape/src/cape/bootloader_impl.c
index 1c1fde4..15d28b1 100644
--- a/bbb_cape/src/cape/bootloader_impl.c
+++ b/bbb_cape/src/cape/bootloader_impl.c
@@ -12,7 +12,7 @@
// erases from MAIN_FLASH_START_SECTOR to MAIN_FLASH_END_SECTOR, and keeps
// writing until MAIN_FLASH_END (if it gets data).
//
-// The bootloader sends READY when it is first ready to receive bytes. It then
+// The bootloader sends a NACK when it is first ready to receive bytes. It then
// expects DATA_BYTES-sized packets (+ the checksum calculated with the standard
// CRC algorithm). When it successfully receives one and writes it out, it sends
// ACK. If it has any errors, it waits until there's a 1-second gap (or it
@@ -22,7 +22,6 @@
#define ACK 0x79
#define NACK 0x1F
-#define READY 0x7F
static void process_buffer(uint32_t *buffer) {
static uint32_t *out_pointer = (uint32_t *)MAIN_FLASH_START;
@@ -67,7 +66,7 @@
int error = 0;
int bytes_received = 0;
- uart_byte_send(READY);
+ uart_byte_send(NACK);
while (1) {
// Receive with a 1 second timeout.
diff --git a/bbb_cape/src/cape/util.h b/bbb_cape/src/cape/util.h
index d19a7e9..9188adb 100644
--- a/bbb_cape/src/cape/util.h
+++ b/bbb_cape/src/cape/util.h
@@ -57,6 +57,11 @@
SET_BITS(port->MODER, 2, 0 /* input */, pin);
}
+// dir: 0 => none, 1 => up, 2 => down
+static inline void gpio_set_pupd(GPIO_TypeDef *port, int pin, int dir) {
+ SET_BITS(port->PUPDR, 2, dir, pin);
+}
+
// exti is which EXTI line to set
// port is 0 for A, 1 for B, etc
static inline void EXTI_set(int exti, int port) {