mirror of
https://github.com/mikecarper/MeshCore.git
synced 2026-10-22 10:22:34 +00:00
Record nRF52 Bluetooth DFU qualification results
This commit is contained in:
1 parent
65a8cfd721
commit
ad2f2097da
2 files changed
+196
-2
No files matched your search
@@ -39,11 +39,12 @@ Completed validation reports, experiments, and test guides are collected here. O
|
||||
- [Contact-cache and NimBLE RAM qualification](companion_contact_cache_results.md)
|
||||
- [USB Companion ASCII default validation](companion_usb_ascii_validation.md)
|
||||
- [USB Companion client compatibility](companion_usb_client_validation.md)
|
||||
- [Full USB logging repair — 1.17.1.6](full_usb_logging_validation.md)
|
||||
- [Full USB logging repair - 1.17.1.6](full_usb_logging_validation.md)
|
||||
- [Home-screen text spacing](home_text_spacing.md)
|
||||
- [ESP32-S3 NimBLE trial results, 2026-09-08](nimble_companion_trial_results.md)
|
||||
- [ESP32-S3 NimBLE Full Companion trial](nimble_companion_trial.md)
|
||||
- [nRF52 USB READY hang](nrf52-usb-ready-fix.md)
|
||||
- [nRF52 Bluetooth DFU application handoff](nrf52-bluetooth-dfu-handoff.md)
|
||||
- [Native USB backpressure and radio liveness](usb_serial_backpressure.md)
|
||||
- [Small-screen message fonts](v4_pixel5_font_trial.md)
|
||||
|
||||
@@ -52,7 +53,7 @@ Completed validation reports, experiments, and test guides are collected here. O
|
||||
- [Stock nRF52 bootloader version audit](bootloader_version_stock_audit.md)
|
||||
- [CLI setting dispatch audit](cli_settings_audit.md)
|
||||
- [Hardware validation checklist](hardware_validation_checklist.md)
|
||||
- [XIAO Bluetooth stealth hardware validation — 2026-09-07](hardware_validation_bluetooth_stealth_2026-09-07.md)
|
||||
- [XIAO Bluetooth stealth hardware validation - 2026-09-07](hardware_validation_bluetooth_stealth_2026-09-07.md)
|
||||
- [Shrinking the per-connection TLS footprint on non-PSRAM observers](mbedtls-tls-footprint.md)
|
||||
- [nRF52 Companion automatic ExtraFS recovery](nrf52_companion_storage_recovery.md)
|
||||
- [PR #7 review and validation](pr7_review_validation.md)
|
||||
|
||||
@@ -0,0 +1,193 @@
|
||||
# nRF52 Bluetooth DFU handoff
|
||||
|
||||
## Confirmed application defect
|
||||
|
||||
The released RAK4631 application
|
||||
`RAK_4631_repeater-v1.17.1.7-halo-keymind-cascade-dev-2d03e098`
|
||||
contains an unsafe transition from the running application into the Bluetooth
|
||||
DFU bootloader. This transition belongs to the application's Bluefruit
|
||||
`BLEDfu` service. Replacing the bootloader does not replace that application
|
||||
code.
|
||||
|
||||
The original callback changes `CONTROL` to select the main stack pointer
|
||||
(MSP) while its compiler-generated C frame still belongs to the FreeRTOS
|
||||
process stack pointer (PSP). The compiled callback then restores its C frame
|
||||
using MSP. With the observed stack state, that restore reads outside nRF52840
|
||||
SRAM before reaching the bootloader entry point. A compiler/emulator
|
||||
regression reproduces the fault.
|
||||
|
||||
This defect explains why a Bluetooth flasher can reach "enabling bootloader"
|
||||
and then lose the device before the application transfer starts. It is
|
||||
consistent with the reported solid blue LED and later application restart.
|
||||
The exact reset cause and timing in the user's report remain unrecorded.
|
||||
The standard application enables a 60-second watchdog; Android can also
|
||||
report a separate 30-second GATT connection timeout. See the physical
|
||||
comparison below rather than attributing every timeout to the watchdog.
|
||||
|
||||
## Application fix
|
||||
|
||||
`scripts/nrf52_ble_dfu_fix.py` patches a private build copy of the pinned
|
||||
framework's `BLEDfu.cpp`. It preserves the legacy `B1` DFU entry marker,
|
||||
retained peer/bond record, and SoftDevice vector-table handoff. It leaves
|
||||
PlatformIO's shared framework cache unchanged.
|
||||
|
||||
The callback now enters the naked, nonreturning assembly helper
|
||||
`mesh_nrf52_dfu_jump`. The helper loads the bootloader vectors, sets its MSP,
|
||||
selects MSP, clears inherited interrupt masks, and branches directly to the
|
||||
bootloader. No compiler-generated C stack access follows the stack switch.
|
||||
The supported handler-mode path constructs an explicit exception-return
|
||||
frame. The callback also clears SysTick, pending FreeRTOS system exceptions,
|
||||
and both external interrupt banks before the handoff.
|
||||
|
||||
Every environment inheriting `nrf52_base` uses the private patch and the
|
||||
compiled-image check in `scripts/check_nrf52_ble_dfu_handoff.py`. The check
|
||||
requires the qualified helper instructions, rejects a `CONTROL` write in
|
||||
the C callback, and verifies that the callback branches to the helper.
|
||||
An unrecognized framework source or an unsafe compiled handoff fails the
|
||||
build check.
|
||||
|
||||
## Verification completed
|
||||
|
||||
- The DFU regression suite passed all 10 tests. It compiles Cortex-M4
|
||||
fixtures with `-Os`, `-Oz`, and `-Oz` with LTO. The Cortex-M emulator
|
||||
reproduces the original invalid stack access and verifies the fixed PSP
|
||||
and MSP caller paths, retained peer bytes, and handler exception frame.
|
||||
Tests also reject damaged or bypassed helpers and partially patched
|
||||
framework sources.
|
||||
- Current standard and unified-LoRa-OTA RAK4631, Heltec T096, and Heltec T114 application builds passed
|
||||
their compiled Bluetooth DFU handoff check. These are build results;
|
||||
they do not establish physical Bluetooth transfer success.
|
||||
- Existing identity/settings recovery, common radio persistence, and
|
||||
companion primary radio persistence suites passed all 7 tests.
|
||||
- The compiled CLI settings suite passed all 9 tests, including the
|
||||
four-field radio response expected by the setup application.
|
||||
|
||||
The CI regression requires both the ARM compiler and Cortex-M emulator;
|
||||
missing dependencies must not silently turn qualification into skipped
|
||||
tests.
|
||||
|
||||
## Installing the fix on an affected application
|
||||
|
||||
An already installed affected application may fail before it can enter
|
||||
Bluetooth DFU. Install an application containing this fix once through USB
|
||||
UF2, or force the board into hardware DFU and use the matching application
|
||||
package. Use the board's supported recovery entry procedure. Installing a
|
||||
new bootloader does not replace the unsafe callback in the application.
|
||||
OTAFIX recovery 2.4.12 adds a narrow fault fallback for this legacy callback:
|
||||
when the forwarded HardFault occurs with the B1 Bluetooth DFU request marker,
|
||||
it sets A8 and resets directly into BLE DFU without touching the broken stack.
|
||||
Other faults keep their existing halt behavior. The unchanged 1.17.1.7 app
|
||||
was physically observed reaching DFU through this fallback. This supplies
|
||||
an alternative to USB application installation when the corrected bootloader
|
||||
has already been installed; complete application transfer is recorded below.
|
||||
|
||||
The recovery bootloader is a temporary bridge for bootloader migration.
|
||||
Complete migration to the normal physical-board bootloader according to
|
||||
the recovery release instructions. An `R_` bootloader version is not itself
|
||||
evidence that Bluetooth DFU is disabled.
|
||||
|
||||
## Separate setup-page and settings report
|
||||
|
||||
The reporter's first application install produced setup-page errors, while
|
||||
the same application worked after an erase UF2 and reinstall. Application
|
||||
UF2 installs normally preserve the application's filesystem. The standard
|
||||
MeshCore erase firmware formats both InternalFS and ExtraFS, which changes
|
||||
stored identity and preferences.
|
||||
|
||||
That result is consistent with a retained-state problem, but it does not
|
||||
identify which setting, file, or client state failed. The original state
|
||||
was lost after the erase, and the exact setup-page error was not recorded.
|
||||
The Bluetooth handoff regression does not prove the cause of that earlier
|
||||
setup failure.
|
||||
|
||||
The old app also appends `,preamble=32 (auto)` to `get radio` on this
|
||||
test device. Current firmware restores the four-field radio reply expected
|
||||
by the official setup app (commit `ca23d38e`). Its compiled CLI settings
|
||||
regression checks this compatibility contract. This is another concrete
|
||||
older-application compatibility issue, although the reporter's original
|
||||
setup-page error was not captured and cannot be attributed conclusively.
|
||||
|
||||
Current firmware already includes truncated preference checks, bounded
|
||||
strings, non-finite radio-value sanitization, durable identity retries, and
|
||||
filesystem startup recovery. The 7 passing settings tests qualify those
|
||||
existing protections. This Bluetooth fix adds no automatic wipe and does
|
||||
not require an erase as its installation step.
|
||||
|
||||
## Hardware testing
|
||||
|
||||
### Published recovery baseline
|
||||
|
||||
On 2026-10-01, RAK4631 USB serial `9AB3B64C641BA927` ran the exact reported
|
||||
`v1.17.1.7-halo-keymind-cascade-dev-2d03e098` application and published recovery
|
||||
`R_0x02040BFF` (2.4.11). Nordic nRF Connect 4.24.3 on a second LG phone running
|
||||
Android 5.1.1 attempted the fixed application ZIP. It failed before payload
|
||||
transfer: the graph stayed at zero, the initial opcode disconnected, repeated
|
||||
GATT 133 reconnect errors followed, and the device later answered `ver` with
|
||||
the unchanged application. No RAK DFU advertisement was seen in a later scan.
|
||||
USB data remained connected for this baseline.
|
||||
|
||||
### Bootloader fallback with the unchanged old application: PASS
|
||||
|
||||
The final recovery qualification image uses packed test version `0x02040CFF`,
|
||||
production-length text `R_v0.11.0-OTAFIX2.4.12`, and bootloader CRC `5B8F3E90`.
|
||||
It is a development qualification image, not the tagged production artifact.
|
||||
The combined serial DFU ZIP installed it, then USB UF2 restored the unchanged
|
||||
reported 1.17.1.7 application. Both identities were checked before retrying.
|
||||
|
||||
At 16:57:51 local time Nordic requested the same application ZIP. The
|
||||
bootloader advertised `4631_DFU` at the original `C3:C6:A8:FC:AD:A6` address
|
||||
about 11.7 seconds later. Nordic reconnected automatically, transferred the
|
||||
531,708-byte application image from the 532,510-byte ZIP at about
|
||||
2.2 kB/s, and activated the application at 17:02:19.
|
||||
Afterward USB CLI reported `v1.17.1.8-ble-dfu-test (Build: 01-Oct-2026)` and
|
||||
`OTAFIX2.4.12`. USB data was connected throughout this test.
|
||||
|
||||
No erase firmware was used. Seven queried values retained identical digests:
|
||||
name, TX power, latitude, longitude, frequency, airtime factor, and public
|
||||
identity. The radio tuple also stayed `869.6179809,62.5,8,5`; its old digest
|
||||
exactly matches the new tuple plus the old preamble suffix. The differing raw
|
||||
radio reply is the intended setup-client compatibility fix, not lost settings.
|
||||
These are checks of the queried fields, not a dump of the entire filesystem.
|
||||
|
||||
The older application lacks a hash-bound EndF trailer. The installed recovery
|
||||
bootloader safely refused its USB bootloader updater while that app was valid,
|
||||
because it could not prove the staging scratch range was unused. This guard
|
||||
is unchanged. The combined serial/Bluetooth DFU ZIP supplies the supported
|
||||
installation path; permissive image identity policy does not disable flash
|
||||
bounds or live-application staging safety.
|
||||
|
||||
### Fixed application through MeshCore Open
|
||||
|
||||
Pending on the second phone. The current Android legacy Open build
|
||||
9.5.5/code 26 reached the Bluetooth updater, but `Enable radio updater`
|
||||
rejected a selected route's hash width before sending its command. Open
|
||||
commit `03b0d707` preserves each supported route's own width and rejects
|
||||
malformed routes before sending. Its 81 focused tests passed, including
|
||||
13 new tests through the real route preparation and command path.
|
||||
|
||||
The corrected API 21/ARMv7 Open build 9.5.5/code 27 was installed with
|
||||
the phone's pairing data retained. Its SHA-256 is
|
||||
`5a3a2f83299f1d4e27f242680335494d0ac49db5f8fa3e2ee8b71902f1924d33`.
|
||||
The second phone disappeared from the VM's USB inventory during USB
|
||||
re-enumeration before a completed Open transfer could be recorded. The
|
||||
automatic USB configuration watcher was stopped. Record transfer completion,
|
||||
installed version, USB power/data state, and restored radio state after
|
||||
reconnecting that phone before claiming an Open physical pass.
|
||||
|
||||
### Hardware restored while the phone test is pending
|
||||
|
||||
The RAK4631 was returned to the published normal 2.4.10 `auto` bootloader
|
||||
and the fixed `v1.17.1.8-ble-dfu-test` application. The ordinary application
|
||||
has no `EndF` marker, so its bootloader UF2 replacement was safely refused;
|
||||
the combined normal DFU ZIP and application UF2 supplied the working path.
|
||||
No erase firmware was used.
|
||||
|
||||
A supplemental Linux Bluetooth check reached the application's DFU service
|
||||
revision `0100`, requested handoff, and reached `4631_DFU` revision `0800`
|
||||
at the same Bluetooth address. It then requested a return to the application.
|
||||
After subscribing to control notifications on the bootloader connection,
|
||||
the exit request returned the node to the application. Final CLI queries
|
||||
confirmed the normal 2.4.10 bootloader, fixed application, saved radio tuple
|
||||
`869.6179809,62.5,8,5`, and all seven unchanged settings digests. USB data
|
||||
was restored. This checks the restored node's Bluetooth entry and exit;
|
||||
it is not an Open transfer.
|
||||
Reference in new issue
Block a user