Skip to content

dotbot/firmware: reset the device last, and through CTRL-AP - #281

Merged
geonnave merged 2 commits into
DotBots:developfrom
geonnave:flash-reset-sequence
Jul 27, 2026
Merged

dotbot/firmware: reset the device last, and through CTRL-AP#281
geonnave merged 2 commits into
DotBots:developfrom
geonnave:flash-reset-sequence

Conversation

@geonnave

Copy link
Copy Markdown
Contributor

The problem

After dotbot device flash-swarmit-sandbox, the DotBot did not rejoin the network until someone physically pressed reset. Same for dotbot device info, which left a running bot off the air indefinitely - looking exactly like dead hardware.

Two independent causes, both here in the flasher.

1. The reset never landed. nrfjprog --reset issues a SysResetReq, and the SwarmIT bootloader sets SCB_AIRCR.SYSRESETREQS so non-secure code cannot reboot the robot mid-experiment. That is a deliberate sandbox guarantee and should stay, so the flasher has to reset from the debug domain instead (--debugreset, CTRL-AP), which firmware cannot veto.

2. The reset was not last - the dominant cause. flash_role read the config page back after resetting. That read attaches the debugger to the network core, which resets it, and the application core never notices: the bot keeps running with no radio. CTRL-AP alone did not fix anything until this ordering was corrected.

The approach

Program every image first, read back, then perform a single CTRL-AP reset plus an explicit --run as the genuinely final device operation. Resetting between writes would boot the cores against a half-provisioned device, so the two flash helpers take reset=False and the caller owns the one reset at the end.

device info gets the same treatment from the other side: it now states that reading the network id resets the device, asks before doing it (-y skips, matching swarm flash), and resets afterwards so the bot comes back on its own instead of being stranded. read_device_id moves to the application core's FICR, which reads back with no side effect at all, leaving the network id as the only destructive read - so the prompt guards one narrow thing rather than the whole command.

Worth a reviewer's attention

  • No firmware change is needed. Two were written during diagnosis and reverted: bounded IPC handshake retries (built on a misreading - the shared-memory pattern that looked like a hang is what a healthy bot shows) and a guard against entering an erased application slot (redundant: WDT0 is armed before the jump and the boot intent is cleared every boot, so a bad jump already self-recovers in ~2 s and cannot loop).
  • The first boot after a flash reports lockup in RESETREAS. That register accumulates until the bootloader clears it, and the bit is set during programming while the application core executes from flash being erased. It is self-limiting to that one boot; the device is healthy.

Validation

On hardware, bot A23EFBCB596212AE with a bootloader built from unmodified sources: three consecutive flashes joined with no button press, and an OTA app flash + start runs. device info -y reads correctly and the bot returns on its own within ~15 s. 41 unit tests pass, including new coverage that declining the prompt leaves the device untouched, that -y skips it, and that read_device_id never passes CP_NETWORK.

flash-mari-gateway shares this code path so it likely benefits too, but the gateway runs different firmware and was not tested.

geonnave added 2 commits July 27, 2026 16:03
Flashing left the bot off the network until someone pressed reset. Two
causes: `--reset` is a SysResetReq, which the SwarmIT bootloader refuses via
SCB_AIRCR.SYSRESETREQS, and the config-page readback halts the network core,
so a reset done before it left the device programmed but stopped. Program
every image first, read back, then reset once over CTRL-AP and start the
core. Verified over three consecutive flashes with no button press.

AI-assisted: Claude Opus 5
Attaching the debugger to the network core resets it, and the application
core does not notice, so the bot keeps running with no radio and looks dead
until the whole device is reset. `device info` now says so and asks before
reading, takes -y to skip, and resets the device afterwards so it comes back
on its own. The device id moves to the application core's FICR, which reads
back with no side effect at all.

AI-assisted: Claude Opus 5
@codecov

codecov Bot commented Jul 27, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 83.50%. Comparing base (0df33ae) to head (7549c57).
⚠️ Report is 1 commits behind head on develop.

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           develop     #281      +/-   ##
===========================================
- Coverage    83.50%   83.50%   -0.01%     
===========================================
  Files          121      121              
  Lines        11237    11266      +29     
  Branches       570      569       -1     
===========================================
+ Hits          9384     9408      +24     
- Misses        1850     1854       +4     
- Partials         3        4       +1     
Files with missing lines Coverage Δ
dotbot/cli/device.py 85.14% <100.00%> (+0.93%) ⬆️
dotbot/tests/test_device.py 100.00% <100.00%> (ø)

... and 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@geonnave
geonnave merged commit 31ed2d6 into DotBots:develop Jul 27, 2026
14 checks passed
@geonnave
geonnave deleted the flash-reset-sequence branch July 27, 2026 15:45
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