diff --git a/DOCUMENTATION.md b/DOCUMENTATION.md index df784e3..3ef6d23 100644 --- a/DOCUMENTATION.md +++ b/DOCUMENTATION.md @@ -15,6 +15,7 @@ If you are interested in using and understanding TAB, refer to this document. * [Bootlaoder Erase](#bootloader-erase) * [Bootloader Write Page](#bootloader-write-page) * [Bootloader Write Page Addr32](#bootloader-write-page-addr32) + * [Bootloader Jump](#bootloader-jump) * [Protocol](#protocol): TAB protocol * [License](#license) @@ -261,6 +262,24 @@ of the board using the address provided. * Addr Byte4 is the LSByte * Page Data has 128 bytes. +### Bootloader Jump + +The command instructs the bootloader to jump to a different address in memory +* Name: `bootloader_jump` +* Required parameters: None +* Optional parameters: None +* Reply: + * If the bootloader is active and successfully performs the jump: + `bootloader_ack` with the JUMP payload + * If the bootloader is active and fails to perform the jump: + `bootloader_nack` + * Otherwise: `common_nack` + +**Header** + +| Start Byte 0 | Start Byte 1 | Remaining Bytes | HW ID LSByte | HW ID MSByte | MSG ID LSByte | MSG ID MSByte | Route Nibbles | Opcode | +| ------------ | ------------ | --------------- | ------------ | ------------ | ------------- | ------------- | ------------- | ------ | +| 0x22 | 0x69 | 0x06 | 0xHH | 0xHH | 0xHH | 0xHH | 0xSD | 0x0b | ## Protocol diff --git a/c-examples/cdh-monolithic/cdh_monolithic.c b/c-examples/cdh-monolithic/cdh_monolithic.c index ded7324..203bd2d 100644 --- a/c-examples/cdh-monolithic/cdh_monolithic.c +++ b/c-examples/cdh-monolithic/cdh_monolithic.c @@ -2,7 +2,7 @@ // TAB C Example CDH Monolithic // // Written by Bradley Denby -// Other contributors: None +// Other contributors: Chad Taylor // // See the top-level LICENSE file for the license. @@ -16,6 +16,12 @@ // TAB header #include // TAB header +//// in_bootloader is an extern variable read by bootloader_running +int in_bootloader; + +//// app_jump_pending is an extern variable modified in write_reply +int app_jump_pending; + // Main int main(void) { // MCU initialization @@ -26,11 +32,25 @@ int main(void) { clear_rx_cmd_buff(&rx_cmd_buff); tx_cmd_buff_t tx_cmd_buff = {.size=CMD_MAX_LEN}; clear_tx_cmd_buff(&tx_cmd_buff); + in_bootloader = 1; + app_jump_pending = 0; // TAB loop while(1) { - rx_usart1(&rx_cmd_buff); // Collect command bytes - reply(&rx_cmd_buff, &tx_cmd_buff); // Command reply logic - tx_usart1(&tx_cmd_buff); // Send a response if any + if(!app_jump_pending) { + rx_usart1(&rx_cmd_buff); // Collect command bytes + reply(&rx_cmd_buff, &tx_cmd_buff); // Command reply logic + tx_usart1(&tx_cmd_buff); // Send a response if any + } else { // Jump triggered + while(!tx_cmd_buff.empty) { // If jumping to user app, + tx_usart1(&tx_cmd_buff); // finish sending response if any + } + for(size_t i=0; i<4000000; i++) { // Wait for UART TX FIFO to flush + __asm__ volatile("nop"); + } + app_jump_pending = 0; // Housekeeping + in_bootloader = 0; + bl_jump_to_app(); // Jump + } } // Should never reach this point return 0; diff --git a/c-examples/cdh-monolithic/support/cdh.c b/c-examples/cdh-monolithic/support/cdh.c index d700c83..6fd6ae2 100644 --- a/c-examples/cdh-monolithic/support/cdh.c +++ b/c-examples/cdh-monolithic/support/cdh.c @@ -14,6 +14,7 @@ #include // used in init_gpio #include // used in init_clock, init_rtc #include // used in init_uart +#include // SCB_VTOR // Board-specific header #include // Header file @@ -21,6 +22,10 @@ // TAB header #include // TAOLST protocol macros, typedefs, fnctns +// Variables +extern int in_bootloader; // Used in bootloader main to indicate MCU state +extern int app_jump_pending; // Used in bootloader main to signal jump to app + // Functions required by TAB // This example implementation of handle_common_data checks whether the bytes @@ -132,9 +137,46 @@ int handle_bootloader_write_page_addr32(rx_cmd_buff_t* rx_cmd_buff){ } } -// This example implementation of bootloader_active always returns true +// This example implementation of bl_check_app checks whether the jump address +// is valid or not +int bl_check_app(void) { + // Does the first four bytes of the application represent the initialization + // location of a stack pointer within the boundaries of the RAM? + return (((*(uint32_t*)APP_ADDR)-SRAM1_BASE) <= SRAM1_SIZE); +} + +// This example implementation of bl_jump_to_app jumps to a hardcoded +// address in memory called APP_ADDR +void bl_jump_to_app(void) { + // The first 4 bytes hold the stack address, so jump address is after that + uint32_t jump_addr = + *(volatile uint32_t*)(APP_ADDR+((uint32_t)0x00000004U)); + // Create a jump() function + void (*jump)(void) = (void (*)(void))jump_addr; + // Set the vector table + SCB_VTOR = APP_ADDR; + // Set the master stack pointer + __asm__ volatile("msr msp, %0"::"g" (*(volatile uint32_t*)APP_ADDR)); + // Jump to the application + jump(); +} + +// This example implementation of handle_bootloader_jump sets app_jump_pending +// to 1 to trigger a jump after checking for a valid app address +int handle_bootloader_jump(void){ + if (bl_check_app()) { + app_jump_pending = 1; + return 1; + } else { // Something wrong, abort jump + return 0; + } + +} + +// This example implementation of bootloader_active always returns whether the +// board is in bootloader mode or not int bootloader_active(void) { - return 1; + return in_bootloader; } // Board initialization functions diff --git a/c-examples/cdh-monolithic/support/cdh.h b/c-examples/cdh-monolithic/support/cdh.h index d4fbcc7..7988bf7 100644 --- a/c-examples/cdh-monolithic/support/cdh.h +++ b/c-examples/cdh-monolithic/support/cdh.h @@ -19,12 +19,19 @@ //// Application start address #define APP_ADDR ((uint32_t)0x08008000U) +//// SRAM1 start address +#define SRAM1_BASE ((uint32_t)0x20000000U) + +//// SRAM1 size +#define SRAM1_SIZE ((uint32_t)0x00040000U) + // Functions required by TAB int handle_common_data(common_data_t common_data_buff_i); int handle_bootloader_erase(void); int handle_bootloader_write_page(rx_cmd_buff_t* rx_cmd_buff); int handle_bootloader_write_page_addr32(rx_cmd_buff_t* rx_cmd_buff); +int handle_bootloader_jump(void); int bootloader_active(void); // Board initialization functions @@ -32,6 +39,11 @@ int bootloader_active(void); void init_clock(void); void init_uart(void); +// Board jump functions + +int bl_check_app(void); +void bl_jump_to_app(void); + // Feature functions void rx_usart1(rx_cmd_buff_t* rx_cmd_buff_o); diff --git a/c-implementation/tab.c b/c-implementation/tab.c index 5994323..e1f671b 100644 --- a/c-implementation/tab.c +++ b/c-implementation/tab.c @@ -19,6 +19,7 @@ extern int handle_common_data(common_data_t common_data_buff_i); extern int handle_bootloader_erase(void); extern int handle_bootloader_write_page(rx_cmd_buff_t* rx_cmd_buff); extern int handle_bootloader_write_page_addr32(rx_cmd_buff_t* rx_cmd_buff); +extern int handle_bootloader_jump(void); extern int bootloader_active(void); // Helper functions @@ -248,6 +249,22 @@ void write_reply(rx_cmd_buff_t* rx_cmd_buff_o, tx_cmd_buff_t* tx_cmd_buff_o) { tx_cmd_buff_o->data[OPCODE_INDEX] = COMMON_NACK_OPCODE; } break; + case BOOTLOADER_JUMP_OPCODE: + if(bootloader_active()) { + success = handle_bootloader_jump(); + if(success) { + tx_cmd_buff_o->data[MSG_LEN_INDEX] = ((uint8_t)0x07); + tx_cmd_buff_o->data[OPCODE_INDEX] = BOOTLOADER_ACK_OPCODE; + tx_cmd_buff_o->data[PLD_START_INDEX] = BOOTLOADER_ACK_REASON_JUMP; + } else { + tx_cmd_buff_o->data[MSG_LEN_INDEX] = ((uint8_t)0x06); + tx_cmd_buff_o->data[OPCODE_INDEX] = BOOTLOADER_NACK_OPCODE; + } + } else { + tx_cmd_buff_o->data[MSG_LEN_INDEX] = ((uint8_t)0x06); + tx_cmd_buff_o->data[OPCODE_INDEX] = COMMON_NACK_OPCODE; + } + break; default: break; } diff --git a/c-implementation/tab.h b/c-implementation/tab.h index 127e62e..fb4646d 100644 --- a/c-implementation/tab.h +++ b/c-implementation/tab.h @@ -32,6 +32,7 @@ #define BOOTLOADER_ERASE_OPCODE ((uint8_t)0x0c) #define BOOTLOADER_WRITE_PAGE_OPCODE ((uint8_t)0x02) #define BOOTLOADER_WRITE_PAGE_ADDR32_OPCODE ((uint8_t)0x20) +#define BOOTLOADER_JUMP_OPCODE ((uint8_t)0x0b) //// BOOTLOADER_ACK reasons #define BOOTLOADER_ACK_REASON_PONG ((uint8_t)0x00) diff --git a/python-examples/tx/tx_example.py b/python-examples/tx/tx_example.py index f82161d..ffee661 100644 --- a/python-examples/tx/tx_example.py +++ b/python-examples/tx/tx_example.py @@ -215,8 +215,7 @@ #10. Test Bootloader Write Page with expected reply of Bootloader Ack # with Page Number reason -print("Bootloader Write Page") -cmd = TxCmd(BOOTLOADER_WRITE_PAGE_OPCODE, HWID, msgid, SRC, DST) +cmd = TxCmd(BOOTLOADER_WRITE_PAGE_OPCODE, HWID, msgid, GND, CDH) dummy_page_num = 1 dummy_page = [0] * 128 cmd.bootloader_write_page(page_number=dummy_page_num, page_data=dummy_page) @@ -238,7 +237,7 @@ #11. Test Bootloader Write Page Addr32 with expected reply of # Bootloader Ack with Address reason -cmd = TxCmd(BOOTLOADER_WRITE_PAGE_ADDR32_OPCODE, HWID, msgid, SRC, DST) +cmd = TxCmd(BOOTLOADER_WRITE_PAGE_ADDR32_OPCODE, HWID, msgid, GND, CDH) page_num = 0 addr_write = START_ADDR + page_num * BYTES_PER_CMD dummy_page = [0] * 128 @@ -256,4 +255,23 @@ print('reply: '+str(rx_cmd_buff)+'\n') cmd.clear() rx_cmd_buff.clear() -msgid += 1 \ No newline at end of file +msgid += 1 + +#11. Test Bootloader Jump with expected reply of +# Bootloader Nack +cmd = TxCmd(BOOTLOADER_JUMP_OPCODE, HWID, msgid, GND, CDH) +byte_i = 0 +while rx_cmd_buff.state != RxCmdBuffState.COMPLETE: + if byte_i < cmd.get_byte_count(): + serial_port.write(cmd.data[byte_i].to_bytes(1, byteorder='big')) + byte_i += 1 + if serial_port.in_waiting>0: + bytes = serial_port.read(1) + for b in bytes: + rx_cmd_buff.append_byte(b) +print('txcmd: '+str(cmd)) +print('reply: '+str(rx_cmd_buff)+'\n') +cmd.clear() +rx_cmd_buff.clear() +msgid += 1 +time.sleep(1.0) \ No newline at end of file diff --git a/python-implementation/tab.py b/python-implementation/tab.py index 575b7cb..8d3a169 100644 --- a/python-implementation/tab.py +++ b/python-implementation/tab.py @@ -29,6 +29,7 @@ BOOTLOADER_ERASE_OPCODE = 0x0c BOOTLOADER_WRITE_PAGE_OPCODE = 0x02 BOOTLOADER_WRITE_PAGE_ADDR32_OPCODE = 0x20 +BOOTLOADER_JUMP_OPCODE = 0x0b ## Route Nibble IDs GND = 0x00 @@ -229,6 +230,9 @@ def generate_reply(self, rx_cmd_buff): elif rx_cmd_buff.data[OPCODE_INDEX] == BOOTLOADER_WRITE_PAGE_ADDR32_OPCODE: self.data[MSG_LEN_INDEX] = 0x06 self.data[OPCODE_INDEX] = COMMON_NACK_OPCODE + elif rx_cmd_buff.data[OPCODE_INDEX] == BOOTLOADER_JUMP_OPCODE: + self.data[MSG_LEN_INDEX] = 0x06 + self.data[OPCODE_INDEX] = COMMON_NACK_OPCODE # Helper functions @@ -319,6 +323,8 @@ def cmd_bytes_to_str(data): pld_str += ' hex_data:' for i in range(0,data[MSG_LEN_INDEX]-0x07): pld_str += '{:02x}'.format(data[PLD_START_INDEX+4+i]) + elif data[OPCODE_INDEX] == BOOTLOADER_JUMP_OPCODE: + cmd_str += 'bootloader_jump' # string construction common to all commands cmd_str += ' hw_id:0x{:04x}'.format(\ (data[HWID_MSB_INDEX]<<8)|(data[HWID_LSB_INDEX]<<0)\ @@ -371,6 +377,8 @@ def __init__(self, opcode, hw_id, msg_id, src, dst): elif self.data[OPCODE_INDEX] == BOOTLOADER_WRITE_PAGE_ADDR32_OPCODE: self.data[MSG_LEN_INDEX] = 0x0a self.data[PLD_START_INDEX] = 0x00 + elif self.data[OPCODE_INDEX] == BOOTLOADER_JUMP_OPCODE: + self.data[MSG_LEN_INDEX] = 0x06 else: self.data[MSG_LEN_INDEX] = 0x06