Skip to content

dfu: triple tap reset to enter BLE OTA DFU - #57

Open
Dreikor17 wants to merge 1 commit into
oltaco:masterfrom
Dreikor17:feature/triple-tap-ble-dfu
Open

Dreikor17 wants to merge 1 commit into
oltaco:masterfrom
Dreikor17:feature/triple-tap-ble-dfu

Conversation

@Dreikor17

@Dreikor17 Dreikor17 commented Aug 24, 2026

Copy link
Copy Markdown

Checklist

  • Please provide specific title of the PR describing the change

Description of Change

Adds a third tap to the reset gesture that already exists:

Reset taps Result
1 Normal boot into the application
2 USB DFU — UF2 drive + CDC serial
3 BLE OTA DFU

How it works

The no-init word at 0x20007F7C already survives a pin reset in order to detect a double tap. It now holds a tap stage rather than a flag: DFU_DBL_RESET_MAGIC means one tap seen, the new DFU_TPL_RESET_MAGIC means two. The count has to live in that word because the DBL_RESET region in the linker script is exactly 4 bytes, and the NOINIT block above it is the OTA bond exchange area.

The second tap no longer falls straight through into USB DFU. It arms the third-tap magic and waits one more DFU_TPL_RESET_DELAY — 0.5s, matching the existing double-tap window. A third tap inside that window is picked up on the next boot and forces _ota_dfu, routing into the BLE OTA path already used by DFU_MAGIC_OTA_RESET (bootloader_dfu_start(true, 0, false)). If the window expires, the device enters USB DFU exactly as before.

The status LED blinks three times faster while the window is open, so it is visible that the third tap is available. It is restored before USB DFU starts, so neither destination sees an altered LED state.

Why

Most boards here already have a button route into BLE OTA DFU — either the BUTTON_DFU + BUTTON_FRESET combo, or the single-button idiom of pointing both at the same pin so that holding one button on boot enters OTA. This is not trying to replace that.

What it adds is a route that needs no button at all, which matters in three cases:

  1. Boards with no usable button. On the RAK 4631 and RAK 3401, BUTTON_1 and BUTTON_2 are both P0.08, which the board.h comment notes is not connected. There is no button route on those two: BLE OTA DFU can only be entered from the running application (buttonless DFU service / GPREGRET), or by having no valid application at all. A device running firmware that exposes no DFU service has no way in short of SWD.
  2. A device in an enclosure where reset is reachable but the user button is not.
  3. Consistency — the same gesture works everywhere, instead of the user having to know which button this particular board wants held.

Scope

TRIPLE_TAP_BLE_DFU defaults to 1. A board opts out by defining it as 0 in its board.h, which restores an immediate double-tap into USB DFU. It is forced off on nrf52832, where a GPIO reset clears SRAM so the tap state cannot survive — the same reason double-tap detection is already skipped there.

Everything new is behind #if TRIPLE_TAP_BLE_DFU, including the new led_state() case.

Happy to narrow this to an opt-in for specific boards if you would rather — that is a one-line change to the default, and the per-board #define mechanism is already in place.

Trade-off

Double tap into USB DFU now takes 0.5s longer, on every board, because the bootloader has to wait to see whether a third tap is coming. That is inherent to the gesture and it is the main cost of this PR. DFU_TPL_RESET_DELAY is a separate constant from DFU_DBL_RESET_DELAY if you would prefer a different window.

Flash cost

224–240 bytes. All 17 boards built from master and from this branch, with __DATE__/__TIME__ pinned (src/usb/uf2/compile_date.h bakes them into the UF2 ghost FAT, so builds are otherwise not comparable):

Board before after after % of 38 KB
heltec_t114 35400 35624 91.6%
heltec_t096 35004 35228 90.5%
heltec_t1 34964 35204 90.5%
wismesh_tag 33004 33228 85.4%
(remaining 13 boards) 84.8% – 85.3%

The fullest board after the change is heltec_t114, with about 3.2 KB of the region still free.

Testing

  • Tested on RAK 4631 hardware. All three gestures land in the expected mode.
  • Not tested on any other board's hardware. The other 16 are build-verified only. The logic is board-independent — it touches only check_dfu_mode() and one led_state() case — but that is reasoning, not evidence, and it is worth saying plainly given this now defaults to on everywhere.
  • All 17 boards compile clean under the project's -Wall -Wextra -Werror.

Also

README gains an Entering DFU mode section describing the tap behaviour, plus short pointers to it from Installation and Troubleshooting.

The no-init word at 0x20007F7C already survives a pin reset in order to
detect a double tap. Make it hold a tap stage rather than a flag, so that
a second tap arms DFU_TPL_RESET_MAGIC and waits one more 0.5s window
before committing to USB DFU. A third tap inside that window selects BLE
OTA DFU instead. The status LED blinks three times faster while the
window is open. If it expires the device enters USB DFU exactly as
before, just 0.5s later.

This gives a route into BLE OTA DFU that does not depend on the running
application cooperating, on the application being absent, or on knowing
which button to hold. The RAK 4631 and RAK 3401 have no button route at
all: BUTTON_1 and BUTTON_2 both sit on P0.08, which is not connected.

TRIPLE_TAP_BLE_DFU defaults to 1 and a board can opt out by defining it
as 0 in its board.h. It is forced off on nrf52832, where a GPIO reset
clears SRAM and the tap state cannot survive, which is the same reason
double tap detection is skipped there.

Costs 224-240 bytes of flash. All 17 boards were built before and after;
the fullest afterwards is heltec_t114 at 91.6% of the 38 KB region.
@Dreikor17 Dreikor17 changed the title dfu: triple tap reset to enter BLE OTA DFU on RAK 4631 and RAK 3401 dfu: triple tap reset to enter BLE OTA DFU Sep 7, 2026
@Dreikor17
Dreikor17 force-pushed the feature/triple-tap-ble-dfu branch from 75ee35f to 1c2ba23 Compare September 7, 2026 12:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant