- boot_usart: bare-metal USART1 460800, polled TX, 3KB DMA ring RX, SysTick millis
- boot_cli: polled line editor + mini printf + command subset; wire-compatible
with the app UART CLI (prompt/devinfo cur bank/ota marker) so
ble_ota_update.py --uart works unchanged against the bootloader
- share app_ota.c/app_bootset.c into the Boot build via BOOT_FIRMWARE ifdef
(single OTA engine source); frame constants moved to shared Boot/src/ota_wire.h
- entry: 2s Enter window after the boot banner, or forced when no jumpable
image (invalid bootsetting + APP1 vector sanity fail) - brick recovery path
- OTA target in boot = inactive bank per bootsetting (APP1 when invalid)
- merge_image.py: hard-fail when boot bin exceeds the 16KB region
- APP V1.00.28 (shared-source touch only, behavior unchanged)
- tested: normal boot / download CLI / OTA APP1<->APP2 round trip / bricked
recovery (bootsetting+APP1 sector erased -> forced download -> OTA restore)
- docs: dev log sec.52, ble_protocol sec.6.8, AGENTS.md
- app_ota.c: after END ok, wait until the RSP is consumed by the host
(BLE e0005 read-out / UART TX done) plus 300ms grace before resetting,
2s timeout fallback; polled from the BLE schedule task (rwip_schedule
must keep running for the ATT read to be processed)
- main.c: app_ota_reset_poll() in the BLE schedule task loop
- docs: ble_protocol.md 6.6 note, dev log section 43, AGENTS.md sync