# Bootloader OTA Operator Guide This guide explains the Universal Shifters single-slot bootloader update flow in `abawo_bt_app`. ## App-Side Flow 1. Connect to the target button and open **Device Details**. 2. In **Firmware Update**, select a local raw application `.bin` with **Select Firmware**. 3. The app validates size and vector table before enabling the update. 4. Review file metadata: size, session id, CRC32, app start, image version, and reset vector. 5. Tap **Start Update** and keep the phone close to the button. 6. The app sends `EnterDfu` to the running application, waits for reset, and connects to `US-DFU`. 7. The app sends bootloader `START`; this erases the active app slot. 8. The app transfers offset-based frames and tracks bootloader `expected_offset`. 9. The app sends `FINISH`, waits for final OK, then waits for the bootloader reset. 10. Success is shown only after the updated app reconnects and status verification passes. ## Image Requirements - File extension must be `.bin`. - Image must be at least 8 bytes and no larger than `0x3F000` bytes (252 KiB). - Image bytes must start at application address `0x00030000`. - Initial stack pointer must be aligned and within `0x20000000..=0x20010000`. - Reset vector must have the Thumb bit set and point inside the image after the first two vector words. - Flags are always `0`; encrypted/signed update flags are not supported by the current bootloader. - Image version is currently sent as `0` unless a later packaging flow provides it. ## Operational Notes - Single-slot update is destructive after bootloader `START`; the previous app is erased before image transfer. - If transfer fails after `START`, recovery is through bootloader DFU or external reflash. - Gear writes and **Connect Button to Bike** stay disabled while OTA is running. - If BLE drops during transfer, retry promptly while the bootloader is still advertising `US-DFU`. - Cancel after `START` sends bootloader `ABORT` and leaves the device in bootloader/recovery flow. ## Troubleshooting | Symptom in app | Likely cause | Operator action | | --- | --- | --- | | Invalid stack pointer or reset vector | `.bin` is not a raw app image for `0x00030000` | Rebuild/export the application image from the correct linker layout. | | Could not connect to bootloader DFU mode | Phone did not find `US-DFU` after app reset | Move closer, retry, and verify the device is advertising `US-DFU`. | | Timed out waiting for bootloader DFU status | Status indication/read did not arrive | Reconnect to `US-DFU` and retry. | | Bootloader status `bounds error` | Image length or app start rejected | Use a valid app image no larger than `0x3F000` bytes (252 KiB). | | Bootloader status `CRC error` | Full-image CRC did not match flash contents | Re-export or re-download the `.bin`, then retry. | | Bootloader status `vector table error` | Bootloader rejected the written vector table | Rebuild firmware for app start `0x00030000`. | | Bootloader status `flash error` | Flash erase/write/read failed | Retry once; if repeated, service or externally reflash the device. | | Bootloader status `boot metadata error` | Bootloader could not persist boot metadata | Treat as service risk; retry reflash, then return device if repeated. | | Updated app did not reconnect | New app did not boot/confirm or reconnect window expired | Scan for `US-DFU`; if present, retry OTA with a known-good image. | | Updated app reconnected but verification failed | Normal app status read failed | Reconnect manually and verify status; retry only if the device is still in bootloader or unusable. | Escalate with app logs, device identifier, firmware filename/hash, and observed bootloader status when a known-good image repeatedly fails. ## Manual QA Checklist - [ ] Happy path: select valid `.bin`, enter bootloader, transfer, finish, reboot, reconnect, completed. - [ ] Image validation: invalid extension, empty file, too-small file, too-large file, invalid SP, invalid reset vector. - [ ] UI state gating: gear ratio save and trainer assignment remain disabled during OTA. - [ ] Queue-full/status recovery: app sends `GET_STATUS` and resumes from returned offset. - [ ] Cancel path: cancel after `START` sends `[ABORT, session]` and shows canceled state. - [ ] Bootloader status errors: CRC/vector/flash/metadata statuses show actionable messages. - [ ] Reconnect timeout: no updated app reconnect produces a clear failure message. - [ ] Regression check: after successful update, status and firmware telemetry still load normally.