# Beyond Bootloader
## Basic Info
The Beyond bootloader is entered from the main application by a bootloader entry command. After this command is received, the Beyond will restart and enumerate as a new USB device with different Product ID from the main application:
| Mode | Vendor ID | Product ID |
|- |-|-|
|Main application | 0x35BD | 0x0101|
|Bootloader | 0x35BD | 0x4004|

The bootloader has a similar communication protocol as the main application. It uses USB HID packets for all communications. One key difference is that the PC->HMD communication is a standard HID report, rather than a feature report like in the main app. For example, when using the Python hid library, the bootloader should be messaged with the write() function instead of send_feature_report().

The reports are always 64 bytes long. But not all of the bytes will be used, anything after the valid data will just be a zero byte. So if you are receiving a message that’s only 10 bytes long, you’ll get 64 bytes – the first 10 will be useful, the next 54 will all be zero.

## Flash Programming Instructions
Flash memory must be erased before programming. The erase action changes all bits in a Flash region to 1’s. Programming can only change a 1 to a 0. This means every byte must be 0xFF before programming in order to ensure that the correct value was really programmed.

This bootloader can erase only the application region in Flash memory. The bootloader itself resides in the lowest 16kB of Flash on the SAMG55 microcontroller, leaving the remaining 496kB for the application.

The Flash memory is programmed by sending several WRITE_DATA commands followed by a PROGRAM_DATA command. This is done for each Flash page (512 bytes) to be programmed. A page is the only allowable size of Flash that can be programmed at once.

The bootloader caches up to a full Flash page of bytes with the WRITE_DATA commands. They can be sent in any order, but going from low to high address is probably easier to deal with. Note that only a single page can be cached at once. If you wrap around after a full page (more than 0x200 / 512 bytes), the previously cached data will be overwritten. 

Less than one page can be sent if there isn’t enough data to fill a full page. However, the number of bytes to be written must be divisible by 8. The Flash controller writes in 64-bit chunks. When sending write requests, add filler bytes with 0x00 or 0xFF (or whatever you want, really) to reach the next 8 byte boundary.

## Flash Memory Verification

When started, the bootloader first checks the application stored in Flash memory. If it verifies correctly, the application is launched. Otherwise, the bootloader remains in control allowing you to rewrite the application. 

Verification is done with a Cyclic Redundancy Check (CRC) over the entire application in Flash. The application must have its length stored at an offset of 0x400 from the start of the app region. The app region starts at 0x0040.4000, so the length is stored in a 32-bit value at 0x0040.4400. The 32-bit CRC is stored at the end of the application, the next 4 bytes after the end of the app. The bootloader compares the computed CRC with the stored CRC, and if they match, boots into the application.

*Binary files to be loaded should already have the length and CRC added. You shouldn’t have to place this into memory manually when interacting with the bootloader. The information in this section is just for reference.*

## CRC Details
### 8-bit CRC for commands
For commands requiring a CRC, the CRC is calculated over all bytes in the command, including the initial command code. The generator polynomial is 0x07, the initial value is 0x00, and the input and output are not inverted.

Example Python calculation:

```python
def crc8_calc(databytes):
    crc8_init = 0x00
    CRC8POLY = 0x07
    for bb in databytes:
        crc8_init = crc8_init ^ bb
        for k in range(8):
            if(crc8_init & 0x80):
                crc8_init = (0xFF & (crc8_init << 1)) ^ CRC8POLY
            else:
                crc8_init = (0xFF & (crc8_init << 1))
    return crc8_init
```

### 32-bit CRC for application Flash
The entire application region is used to calculate the 32-bit CRC verification. Application starts at 0x0040.4000 in Flash, and ends after `length` bytes. `length` is stored as a 32-bit integer (LSB first) at 0x0040.4400. 

The CRC-32 uses the BZIP2 generator. This has a polynomial of 0x04C11DB7, initial input of 0xFFFFFFFF, and the output is XOR’d with 0xFFFFFFFF (meaning the output bits are inverted).

Example Python calculation (and yes, I am cheating here and simply using an available pypi package):

```python
from crc import Crc32, Calculator
crccalc = Calculator(Crc32.BZIP2)
crcvalue = crccalc.checksum(databytes)
```

## Codes for PC->HMD Commands

| Command | Code (ASCII) | Code (Hex) | Description |
| - | - | - | - |
| [SW_VER](#software-version) | * | 0x2a | Request the software version of the currently flashed bootloader firmware. The application firmware is only accessible when the main app is running. |
| [BOOT_APP](#boot-application) | B | 0x42 | Load the flashed application | 
| [CLEAR_APP](#clear-application) | " | 0x22 | Erases the entire application region in Flash memory | 
| [ERASE_FLASH](#erase-flash) | e | 0x65 | Erases a specified block of Flash memory | 
| [WRITE_DATA](#rite-data) | D | 0x44  |Write 8 to 32 bytes of data to specified location in Flash. Does not save the data, PROGRAM_DATA command commits it to Flash|
| [PROGRAM_DATA](#program-data) | P | 0x50 | Finishes writing a page of Flash previously written with WRITE_DATA commands. One page = 512 bytes |
| [READ_CRC](#read-crc) | C | 0x43 | Reads the 32-bit CRC value programmed in the application in Flash. |
| [CALC_CRC](#calculate-crc) | M | 0x4d | Computes the 32-bit CRC value of the currently programmed application in Flash. This can be compared to the stored value retrieved by READ_CRC to validate the programming.|

## Status codes for HMD->PC Responses
| Command | Code (ASCII) | Code (Hex) | Description |
| - | - | - | - |
| SUCCESS | NUL | 0x00 | Generic response for successful action |
| FAIL | not NUL | not 0x00 | Failure codes:<br> 1- Lock error (Flash region was locked) <br> 2 - Command error (unrecognized command) <br> 3 - Verify error (Flash programming did not verify correctly) <br> 4 - Address error (Flash address out of range) <br> 5 - Size error (wrong size given for a command) <br> 6 - CRC error |

## Command structure

### Software version
PC->HMD Request:
| Byte# | Content |
| - | - | 
| 0 | * |

HMD->PC Response:
| Byte# | Content | 
| - | - | 
| 0 - 64 | Software version string (null-terminated) |

### Boot application
PC->HMD Request:
| Byte# | Content |
| - | - | 
| 0 | B |

No HMD->PC response, will restart into application

### Clear application
PC->HMD Request:
| Byte# | Content |
| - | - | 
| 0 | " |

HMD replies with status code.

__NOTE:__ *Please use with caution. There is no checking done on this command, if any HID packet is received with 0x22 in the first byte, the application Flash region will be cleared.*

### Erase Flash
PC->HMD Request:
| Byte# | Content |
| - | - | 
| 0 | e |
| 1 | Size code |
| 2 - 5 | Memory address <br> 32-bit unsigned integer, LSB first (little endian)|
| 6 | 8-bit CRC |

HMD replies with status code.

__Notes:__
Byte 0 : command (0x65, equivalent to 'e' in ASCII)
Byte 1 : selection of size to delete. Can be any of the following:

0. Delete 8kB (16 pages). Note: page = 512B. 16 pages is minimum erasable size
1. Delete 16kB (32 pages)
2. Erase sector. There are various sector sizes, so this is a little tricky.
### Flash layout
```mermaid
---

---
block-beta

  columns 3
  block:maingroup1:2
    columns 2

      A["8 Kbytes"]
      B["Small sector 0"]

  

      C["8 Kbytes"]
      D["Small sector 1"]

    

      E["112 Kbytes"]
      F["Larger sector"]

  end
  G["Sector 0"]
  H["128 Kbytes"]:2
  I["Sector 1"]
  J["128 Kbytes"]:2
  K["Sector 2"]
  L["..."]:3
  M["128 Kbytes"]:2
  N["Sector n"]
```

There are 4 sectors in total, each with 128kB. But the first sector is split into subsectors.

Starting from lowest address in Flash (0x0040.0000), there are two 8kB small sub-sectors

So those are from 0x0040.0000 to 0x0040.2000 and 0x0040.2000 to 0x0040.4000

Then, there is a 112kB larger subsector from 0x0040.4000 to 0x0042.0000

And then there are 3 128kB sectors. 

Final layout looks like:
- Sector 0: 0x0040.0000 to 0x0042.0000 (128kB)
  - Subsector 0: 0x0040.0000 to 0x0040.2000 (8kB)
  - Subsector 1: 0x0040.2000 to 0x0040.4000 (8kB)
  - Subsector 2: 0x0040.4000 to 0x0042.0000 (112kB)
- Sector 1: 0x0042.0000 to 0x0044.0000 (128kB)
- Sector 2: 0x0044.0000 to 0x0046.0000 (128kB)
- Sector 3: 0x0046.0000 to 0x0048.0000 (128kB)

The bootloader uses the first two small subsectors. Application firmware starts at 0x0040.4000 and can use the rest of the Flash.

Bytes 2, 3, 4, 5 : address (little endian), must be within app space (between 0x00404000 and 0x0047FFF8)
Note that the address must be aligned on the erase size boundary, depending on the size of erase chosen. If erasing 16kB, then the address must be a multiple of 16kB, etc.

Byte 6 : crc-8 single byte crc to ensure data integrity. 
CRC is calculated on ENTIRE command, including byte 0. Uses 0x7 as the generator polynomial, initial input is 0x00.

### Write Data
PC->HMD Request
| Byte# | Content | 
| - | - |
| 0 | D |
| 1 | Length |
| 2 - 5 | Memory address<br> 32-bit unsigned integer, LSB first (little endian) |
| 6 - (6+length-1) | Data to program |
| 6 + length | 8-bit CRC | 

HMD replies with status code.

__Notes:__
0 : command (0x44, ‘D’ in ASCII)
1 : length of bytes to write (must be multiple of 8, flash writes are minimum 64 bits, max is 32 bytes)
2,3,4,5 : address (little endian), must be within app space (between 0x00404000 and 0x0047FFF8)
6->6+length-1 : data
6+length : crc-8 single byte crc to ensure data integrity.
	CRC is calculated on ENTIRE command, including byte 0
	uses 0x7 as the generator polynomial, initial input is 0x00

### Program Data
PC->HMD Request
| Byte# | Content | 
| - | - |
| 0 | P | 
| 1 | Length (must be zero) |
| 2 - 5 | Page address <br> 32-bit unsigned integer, LSB first (little endian)|
| 6 | 8-bit CRC |

HMD replies with status code.

__Notes:__
0 : command (0x50, 'P' in ASCII)
1 : length of bytes to write (must always be zero)
2,3,4,5 : address of the Flash page to program(little endian), must be within app space (between 0x00404000 and 0x0047FFF8). Flash page must be aligned to a 512 byte (0x200) boundary.
6: crc-8 single byte crc to ensure data integrity.
	CRC is calculated on ENTIRE command, including byte 0
	uses 0x7 as the generator polynomial, initial input is 0x00

### Read CRC
PC->HMD Request
| Byte# | Content | 
| - | - |
| 0 | C | 

HMD->PC Response
| Byte# | Content | 
| - | - |
| 0 - 3 | CRC value stored in application Flash. <br>32-bit unsigned integer, MSB first (big endian) | 

### Calculate CRC
PC->HMD Request
| Byte# | Content | 
| - | - |
| 0 | M | 

HMD->PC Response
| Byte# | Content | 
| - | - |
| 0 - 3 | CRC value calculated over the data stored in application Flash. <br>32-bit unsigned integer, MSB first (big endian) | 
