# Bootloader

The Beyond bootloader occupies the first **16 KB** of Flash and provides USB-based firmware programming for the application region.

## Memory Layout

```
0x00400000 ┌─────────────────────────────┐
           │  Bootloader (16 KB)         │
           │  Subsector 0: 8 KB          │
0x00402000 │  Subsector 1: 8 KB          │
0x00404000 ├─────────────────────────────┤
           │  Application (496 KB)       │
           │  Subsector 2: 112 KB        │
0x00420000 │  Sector 1: 128 KB           │
0x00440000 │  Sector 2: 128 KB           │
0x00460000 │  Sector 3: 128 KB           │
0x00480000 └─────────────────────────────┘
```

**Application start:** `0x00404000`  
**Application length stored at:** `0x00404400` (32-bit LE, offset 0x400 from app start)  
**Application CRC stored at:** End of application (next 4 bytes after last app byte)

## Boot Sequence

1. Bootloader starts on power-up
2. Reads application length from `0x00404400`
3. Computes CRC-32 (BZIP2) over the application bytes
4. Compares computed CRC with stored CRC at end of application
5. **Match:** Boots into application
6. **Mismatch:** Stays in bootloader mode for reprogramming

## USB Interface

The bootloader enumerates as a separate USB HID device:

| | Application | Bootloader |
|-|-------------|------------|
| VID | 0x35BD | 0x35BD |
| PID | 0x0101 | 0x4004 |
| PC->HMD | Feature reports (`send_feature_report`) | Standard reports (`write`) |
| Report size | 64 bytes | 64 bytes |

**Key difference:** The bootloader uses **standard HID reports**, not feature reports. Host software must use `write()` instead of `send_feature_report()`.

## Bootloader Commands

| Command | Code | Description |
|---------|------|-------------|
| SW_VER | `*` (0x2A) | Get bootloader firmware version |
| BOOT_APP | `B` (0x42) | Launch the application (no reply) |
| CLEAR_APP | `"` (0x22) | Erase entire application region (**no safety check!**) |
| ERASE_FLASH | `e` (0x65) | Erase specified flash block (with CRC-8) |
| WRITE_DATA | `D` (0x44) | Write 8–32 bytes to flash cache (with CRC-8) |
| PROGRAM_DATA | `P` (0x50) | Commit cached page to flash (with CRC-8) |
| READ_CRC | `C` (0x43) | Read stored CRC from application |
| CALC_CRC | `M` (0x4D) | Compute CRC over current application |

### Status Codes

| Code | Meaning |
|------|---------|
| 0x00 | Success |
| 0x01 | Lock error (flash region locked) |
| 0x02 | Command error (unrecognized) |
| 0x03 | Verify error (programming failed) |
| 0x04 | Address error (out of range) |
| 0x05 | Size error (wrong size) |
| 0x06 | CRC error (command integrity check failed) |

## Flash Programming Procedure

### Erase

Flash must be erased (all bits set to 1) before programming. Erase sizes:

| Size Code | Erase Size |
|-----------|------------|
| 0 | 8 KB (16 pages, minimum erasable) |
| 1 | 16 KB (32 pages) |
| 2 | Full sector (varies by sector) |

Address must be aligned to the erase size boundary.

### Program

Each flash page (512 bytes) is programmed in two steps:

1. **WRITE_DATA** — Send data in chunks of 8–32 bytes (must be multiple of 8, since flash writes in 64-bit chunks). Repeat until page is filled.
2. **PROGRAM_DATA** — Commit the cached page to flash. Address must be 512-byte aligned.

Data chunks can be sent in any order but sequential (low to high) is easiest. Only one page can be cached at a time.

If less than a full page of data is needed, pad to the next 8-byte boundary with filler bytes (`0xFF` recommended).

### Verify

After programming:

1. Send `CALC_CRC` to compute CRC over the programmed application
2. Send `READ_CRC` to read the stored CRC
3. Compare — if they match, programming was successful
4. Send `BOOT_APP` to launch the new application

## CRC Details

### Command CRC-8 (integrity check on programming commands)

- **Polynomial:** `0x07`
- **Initial value:** `0x00` (different from config region CRC!)
- **No inversion**
- Computed over the entire command including byte 0

### Application CRC-32 (firmware verification)

- **Algorithm:** CRC-32 BZIP2
- **Polynomial:** `0x04C11DB7`
- **Initial value:** `0xFFFFFFFF`
- **Output XOR:** `0xFFFFFFFF` (output bits inverted)
- Computed over application bytes from `0x00404000` for `length` bytes

```python
from crc import Crc32, Calculator
crccalc = Calculator(Crc32.BZIP2)
crcvalue = crccalc.checksum(databytes)
```

## Entering Bootloader Mode

From the running application:
- Send HID `BOOTLOADER` command (`B`, 0x42)
- MCU performs graceful shutdown and restarts into bootloader
- Shutdown procedure corrected in v0.3.9 (was trapped trying to use I2C after FreeRTOS shut down)

From the crash handler:
- Reset-to-bootloader added in v0.2.18

**Full specification:** `docs/Bootloader_Info.md`  
**Python tools:** `scripts/syn_fw_loader.py`, `scripts/usb_fw_updater.py`
