started working on automatically downloading cape code
diff --git a/bbb_cape/src/bbb/bbb.gyp b/bbb_cape/src/bbb/bbb.gyp
index 9e24f0c..7c14d3d 100644
--- a/bbb_cape/src/bbb/bbb.gyp
+++ b/bbb_cape/src/bbb/bbb.gyp
@@ -154,6 +154,9 @@
'data_struct',
'<(AOS)/common/common.gyp:time',
'sensor_generation',
+ '<(AOS)/linux_code/linux_code.gyp:configuration',
+ 'crc',
+ '<(EXTERNALS):stm32flash',
],
'export_dependent_settings': [
'uart_reader',
diff --git a/bbb_cape/src/bbb/sensor_reader.cc b/bbb_cape/src/bbb/sensor_reader.cc
index 2c36ae3..a685881 100644
--- a/bbb_cape/src/bbb/sensor_reader.cc
+++ b/bbb_cape/src/bbb/sensor_reader.cc
@@ -3,13 +3,62 @@
#include <sys/types.h>
#include <unistd.h>
#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"
namespace bbb {
+namespace {
-SensorReader::SensorReader(const ::std::string &/*cape_code*/)
- : reader_(750000), packet_finder_(&reader_, DATA_STRUCT_SEND_SIZE - 4) {
+__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;
+}
+
+} // namespace
+
+SensorReader::SensorReader(const ::std::string &cape_code)
+ : reader_(750000),
+ packet_finder_(&reader_, DATA_STRUCT_SEND_SIZE - 4),
+ expected_checksum_(ReadChecksum(cape_code)) {
static_assert(sizeof(SensorGeneration::reader_pid) >= sizeof(pid_t),
"pid_t is really big");
ResetHappened();
diff --git a/bbb_cape/src/bbb/sensor_reader.h b/bbb_cape/src/bbb/sensor_reader.h
index 722dfe3..a1b489d 100644
--- a/bbb_cape/src/bbb/sensor_reader.h
+++ b/bbb_cape/src/bbb/sensor_reader.h
@@ -1,6 +1,8 @@
#ifndef BBB_CAPE_SRC_BBB_SENSOR_READER_H_
#define BBB_CAPE_SRC_BBB_SENSOR_READER_H_
+#include <stdint.h>
+
#include <string>
#include "aos/common/time.h"
@@ -41,6 +43,8 @@
UartReader reader_;
PacketFinder packet_finder_;
+ const uint32_t expected_checksum_;
+
int cape_resets_ = 0;
::aos::time::Time last_received_time_ = ::aos::time::Time::InSeconds(0);
uint64_t last_cape_timestamp_;
diff --git a/bbb_cape/src/cape/Makefile b/bbb_cape/src/cape/Makefile
index 2971e88..ce65f8b 100644
--- a/bbb_cape/src/cape/Makefile
+++ b/bbb_cape/src/cape/Makefile
@@ -53,6 +53,8 @@
uart_common \
uart_byte \
led \
+ bootloader_impl \
+ crc \
OBJECTS_main_test := $(OBJECTS_main_common) \
robot_test \
diff --git a/bbb_cape/src/cape/bootloader.c b/bbb_cape/src/cape/bootloader.c
index 3562252..199a3d1 100644
--- a/bbb_cape/src/cape/bootloader.c
+++ b/bbb_cape/src/cape/bootloader.c
@@ -5,6 +5,10 @@
#include "cape/bootloader_handoff.h"
#include "cape/led.h"
+// Actually runs the bootloader code.
+// Implemented in bootloader_impl.c.
+void bootloader_start(void) __attribute__((noreturn));
+
// Sets everything up and then jumps to the main code.
static void jump_to_main(void) __attribute__((noreturn));
static void jump_to_main(void) {
@@ -54,7 +58,8 @@
void _start(void) {
// Enable the GPIO pin clocks.
- // We don't have anything on the 1 port D pin, so don't bother enabling it.
+ // We don't have anything attached to the 1 port D pin, so don't bother
+ // enabling it.
RCC->AHB1ENR |=
RCC_AHB1ENR_GPIOAEN | RCC_AHB1ENR_GPIOBEN | RCC_AHB1ENR_GPIOCEN;
led_init();
@@ -66,5 +71,9 @@
SYSCFG->CMPCR |= SYSCFG_CMPCR_CMP_PD; // enable IO compensation cell
while (!(SYSCFG->CMPCR & SYSCFG_CMPCR_READY)) {} // wait for it to be ready
- jump_to_main();
+ if (GPIOC->IDR & (1 << 2)) {
+ jump_to_main();
+ } else {
+ bootloader_start();
+ }
}
diff --git a/bbb_cape/src/cape/bootloader_handoff.h b/bbb_cape/src/cape/bootloader_handoff.h
index 1e48e90..3804d97 100644
--- a/bbb_cape/src/cape/bootloader_handoff.h
+++ b/bbb_cape/src/cape/bootloader_handoff.h
@@ -9,6 +9,10 @@
// Where the main code's flash starts.
#define MAIN_FLASH_START BOOTLOADER_FLASH_SIZE
+#define MAIN_FLASH_START_SECTOR 1
+#define MAIN_FLASH_END_SECTOR 11
+#define MAIN_FLASH_END 0x100000
+
#define RAM_START 0x20000000
#define RAM_SIZE 0x20000
diff --git a/bbb_cape/src/cape/bootloader_impl.c b/bbb_cape/src/cape/bootloader_impl.c
new file mode 100644
index 0000000..1c1fde4
--- /dev/null
+++ b/bbb_cape/src/cape/bootloader_impl.c
@@ -0,0 +1,103 @@
+#include "cape/bootloader_handoff.h"
+
+#include <string.h>
+
+#include "cape/uart_byte.h"
+#include "cape/uart_common.h"
+#include "cape/crc.h"
+#include "cape/util.h"
+
+// The protocol is pretty simple. Basically, when the bootloader is started, it
+// expects repeated "packets" of data to write. It starts at MAIN_FLASH_START,
+// 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
+// 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
+// receives all the bytes and sees a checksum error) and then sends a NACK.
+
+#define DATA_BYTES 256
+
+#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;
+ if ((out_pointer + DATA_BYTES / 4) >= (uint32_t *)MAIN_FLASH_END) return;
+
+ while (FLASH->SR & FLASH_SR_BSY) {}
+ FLASH->CR |= FLASH_CR_PG;
+ for (int i = 0; i < (DATA_BYTES / 4); ++i) {
+ *(out_pointer++) = buffer[i];
+ }
+ while (FLASH->SR & FLASH_SR_BSY) {}
+ FLASH->CR &= ~FLASH_CR_PG;
+}
+
+__attribute__((noreturn)) void bootloader_start(void) {
+ crc_init();
+
+ // Unlock the flash so we can program it.
+ FLASH->KEYR = 0x45670123;
+ FLASH->KEYR = 0xCDEF89AB;
+ while (FLASH->CR & FLASH_CR_LOCK) {}
+
+ FLASH->CR =
+ (FLASH->CR & ~(FLASH_CR_PSIZE_0 | FLASH_CR_PSIZE_1)) | FLASH_CR_PSIZE_1;
+
+ FLASH->CR |= FLASH_CR_SER;
+ for (int i = MAIN_FLASH_START_SECTOR; i <= MAIN_FLASH_END_SECTOR; ++i) {
+ while (FLASH->SR & FLASH_SR_BSY) {}
+ FLASH->CR = (FLASH->CR & ~(FLASH_CR_SNB_0 | FLASH_CR_SNB_1 |
+ FLASH_CR_SNB_2 | FLASH_CR_SNB_3)) |
+ i << 3;
+ FLASH->CR |= FLASH_CR_STRT;
+ while (FLASH->CR & FLASH_SR_BSY) {}
+ }
+ FLASH->CR &= ~FLASH_CR_SER;
+
+ uart_common_configure(115200);
+ uart_byte_configure();
+
+ uint8_t buffer[DATA_BYTES + 4] __attribute__((aligned(4)));
+ // Whether we've already encountered an error in this block or not.
+ int error = 0;
+ int bytes_received = 0;
+
+ uart_byte_send(READY);
+
+ while (1) {
+ // Receive with a 1 second timeout.
+ int received = uart_byte_receive(60000, 1000 - 1);
+ if (received < 0) {
+ if (received == -1) {
+ uart_byte_send(NACK);
+ error = 0;
+ bytes_received = 0;
+ } else {
+ error = 1;
+ }
+ } else { // successfully received a byte
+ if (error == 0) {
+ buffer[bytes_received++] = (uint8_t)received;
+ if (bytes_received == sizeof(buffer)) {
+ bytes_received = 0;
+ uint32_t checksum;
+ memcpy(&checksum, &buffer[DATA_BYTES], 4);
+ uint32_t *buffer32;
+ uint8_t *buffer8 = buffer;
+ memcpy(&buffer32, &buffer8, 4);
+ if (crc_calculate(buffer32, DATA_BYTES / 4) != checksum) {
+ uart_byte_send(NACK);
+ } else {
+ process_buffer(buffer32);
+ uart_byte_send(ACK);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/bbb_cape/src/cape/uart_byte.c b/bbb_cape/src/cape/uart_byte.c
index cfcf1bf..2cd95b4 100644
--- a/bbb_cape/src/cape/uart_byte.c
+++ b/bbb_cape/src/cape/uart_byte.c
@@ -24,8 +24,15 @@
}
}
+ int r = UART->DR; // do it now to clear interrupts etc
+
+ if (UART->SR & USART_SR_PE) r = -2;
+ if (UART->SR & USART_SR_FE) r = -3;
+ if (UART->SR & USART_SR_NE) r = -4;
+ if (UART->SR & USART_SR_ORE) r = -5;
+
TIMEOUT_TIM->CR1 &= ~TIM_CR1_CEN;
- return UART->DR;
+ return r;
}
void uart_byte_send(uint8_t value) {
diff --git a/bbb_cape/src/cape/uart_byte.h b/bbb_cape/src/cape/uart_byte.h
index e037e36..3423d7a 100644
--- a/bbb_cape/src/cape/uart_byte.h
+++ b/bbb_cape/src/cape/uart_byte.h
@@ -8,7 +8,13 @@
// Spins until 1 byte is received or some amount of time. The timeout is
// timeout_count*(timeout_divider+1)/60MHz.
-// The result is <0 for timeout or the received byte.
+// The result is <0 for timeout/error or the received byte.
+// errors:
+// -1 timeout
+// -2 parity
+// -3 framing
+// -4 noise detected
+// -5 overrun
int uart_byte_receive(uint16_t timeout_count, uint16_t timeout_divider);
// Spins until 1 byte can be written out.
diff --git a/bbb_cape/src/cape/uart_common.c b/bbb_cape/src/cape/uart_common.c
index 03d4cdd..f22c597 100644
--- a/bbb_cape/src/cape/uart_common.c
+++ b/bbb_cape/src/cape/uart_common.c
@@ -13,6 +13,12 @@
gpio_setup_alt(GPIOA, 10, 7);
RCC->APB2ENR |= RCC_APB2ENR_UARTEN;
+ UART->CR1 =
+ //USART_CR1_M /* 9th bit for the parity */ |
+ //USART_CR1_PCE /* enable parity (even by default) */ |
+ //USART_CR1_OVER8 /* support going faster */ |
+ 0;
+
// baud = 60MHz / kMultiplier * (whole_part + fraction / kMultiplier))
static const int kMultiplier = 16 /* 8 * (2 - OVER8) */;
// The divisor of FPCLK that we want (*2).
@@ -22,10 +28,6 @@
// The fractional part of the divisor (*2).
int fraction = divisor % (kMultiplier * 2);
UART->BRR = (mantissa << 4) | ((fraction + 1) / 2);
- UART->CR1 =
- //USART_CR1_M /* 9th bit for the parity */ |
- //USART_CR1_PCE /* enable parity (even by default) */ |
- //USART_CR1_OVER8 /* support going faster */ |
- 0;
+
UART->CR1 |= USART_CR1_UE; // enable it
}
diff --git a/bbb_cape/src/flasher/.gitignore b/bbb_cape/src/flasher/.gitignore
deleted file mode 100644
index 0c665e0..0000000
--- a/bbb_cape/src/flasher/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-stm32flash/
diff --git a/bbb_cape/src/flasher/build.sh b/bbb_cape/src/flasher/build.sh
index ed4937f..ecf6a2b 100755
--- a/bbb_cape/src/flasher/build.sh
+++ b/bbb_cape/src/flasher/build.sh
@@ -1,10 +1,5 @@
#!/bin/bash
-set -e
-
cd $(dirname $0)
-[[ -d stm32flash ]] || ( git clone https://git.gitorious.org/stm32flash/stm32flash.git stm32flash &&
- cd stm32flash && git checkout 8399fbe1baf2b7d097746786458021d92895d71b )
-
../../../aos/build/build.sh linux flasher.gyp no flasher "$@"
diff --git a/bbb_cape/src/flasher/flasher.gyp b/bbb_cape/src/flasher/flasher.gyp
index c9e190e..dea4e5c 100644
--- a/bbb_cape/src/flasher/flasher.gyp
+++ b/bbb_cape/src/flasher/flasher.gyp
@@ -14,24 +14,9 @@
'stm32_flasher.cc',
],
'dependencies': [
- 'stm32flash',
+ '<(EXTERNALS):stm32flash',
'<(AOS)/build/aos.gyp:logging',
],
},
- {
- 'target_name': 'stm32flash',
- 'type': 'static_library',
- 'sources': [
- 'stm32flash/init.c',
- 'stm32flash/parsers/hex.c',
- 'stm32flash/serial_common.c',
- 'stm32flash/serial_platform.c',
- 'stm32flash/utils.c',
- 'stm32flash/stm32.c',
- ],
- 'cflags': [
- '-Wno-error',
- ],
- },
],
}