You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The serial transport should offer an option to hook MCUboot serial recovery — win the CONFIG_BOOT_SERIAL_WAIT_FOR_DFU window that opens on reset — so that a command can be run against the bootloader on a device whose application may not be running at all.
smpmgr --port /dev/ttyACM0 --hook-mcuboot-recovery image state read
Background
CONFIG_BOOT_SERIAL_WAIT_FOR_DFU makes MCUboot pause after reset before it chain-loads the application. The Kconfig help states the entry condition precisely (boot/zephyr/Kconfig.serial_recovery):
If y, MCUboot waits for a prescribed duration of time to allow for DFU to be invoked. The serial recovery can be entered by receiving any mcumgr command.
Two properties matter for a client:
Entry is triggered on receiving a command, not on answering one. No reply is needed to win.
CONFIG_BOOT_SERIAL_WAIT_FOR_DFU_TIMEOUT defaults to 500 ms, but is routinely configured far shorter to keep boot latency down. A few tens of milliseconds is a realistic target.
Why the current shape cannot win a short window
smpclient couples the send and the wait — the write and the read live inside one timeout (SMPClient.request):
So a retry loop can only probe as often as timeout_s allows, and the two ends squeeze it from both sides:
Too large, and consecutive probes are further apart than the window is wide, so a window that opens just after a write closes before the next one lands.
Too small, and the deadline elapses at the first suspension point inside send_and_receive, cancelling the write before it reaches the wire.
There is no value that reliably catches a 50 ms window, because the knob is measuring the wrong thing.
Proposed behaviour
Decouple writing from waiting for the duration of the hook:
Write a small read request (image state read works well) back to back from one task, with no delay between frames by default.
Concurrently wait for the first frame to come back. Its content does not matter — a reply of any kind means the bootloader is in recovery.
Drain before handing over. Every probe that queued behind the one that won will also be answered, and those replies would otherwise desync the sequence numbers of the next request. Reading until the port goes quiet is enough.
Run the user's command against the now-hooked bootloader.
Once entered, MCUboot stays in serial recovery until it is told to boot or is reset, so the hook can also be a standalone command that exits and lets a later invocation do the work.
Relationship to existing issues
Complementary to os reset: add boot_mode (enter MCUboot serial recovery) #100. That covers the warm path: a running application is asked to reboot into the bootloader via the retention boot mode, which needs CONFIG_MCUMGR_GRP_OS_RESET_BOOT_MODE on the app side and CONFIG_BOOT_SERIAL_BOOT_MODE on the MCUboot side. This request covers the cold path — any reset, including on a device whose application is missing, corrupt, or boot-looping, which is exactly when recovery is worth having. Neither substitutes for the other.
Fits Epic: transport subcommands #103. This is transport-specific by nature: it is meaningless over BLE or UDP, so it belongs on a serial subcommand rather than in the shared option pool.
Note on buffer sizing
mcu-tools/mcuboot@5fa7077 adds CONFIG_BOOT_MGMT_MCUMGR_PARAMS, so a bootloader built with it can answer the MCUmgr parameters command and report buf_size = CONFIG_BOOT_SERIAL_MAX_RECEIVE_SIZE with buf_count = 1. Where that is available the transport can size itself from the bootloader's own answer after hooking. Where it is not, the existing fallback applies, which is fine for the hook itself since the probe is a single small frame either way.
Warning
LLM Disclosure
This post was authored by claude-opus-5[1m] on behalf of @JPHutchins. She asked me to file an upstream request for an option to "hook mcuboot recovery" on the serial transport, after we found that a request/response retry loop cannot reliably catch a 50 ms BOOT_SERIAL_WAIT_FOR_DFU window. The mechanism described above is what worked in practice.
Summary
The serial transport should offer an option to hook MCUboot serial recovery — win the
CONFIG_BOOT_SERIAL_WAIT_FOR_DFUwindow that opens on reset — so that a command can be run against the bootloader on a device whose application may not be running at all.Background
CONFIG_BOOT_SERIAL_WAIT_FOR_DFUmakes MCUboot pause after reset before it chain-loads the application. The Kconfig help states the entry condition precisely (boot/zephyr/Kconfig.serial_recovery):Two properties matter for a client:
CONFIG_BOOT_SERIAL_WAIT_FOR_DFU_TIMEOUTdefaults to 500 ms, but is routinely configured far shorter to keep boot latency down. A few tens of milliseconds is a realistic target.Why the current shape cannot win a short window
smpclientcouples the send and the wait — the write and the read live inside one timeout (SMPClient.request):So a retry loop can only probe as often as
timeout_sallows, and the two ends squeeze it from both sides:send_and_receive, cancelling the write before it reaches the wire.There is no value that reliably catches a 50 ms window, because the knob is measuring the wrong thing.
Proposed behaviour
Decouple writing from waiting for the duration of the hook:
image state readworks well) back to back from one task, with no delay between frames by default.Once entered, MCUboot stays in serial recovery until it is told to boot or is reset, so the hook can also be a standalone command that exits and lets a later invocation do the work.
Relationship to existing issues
CONFIG_MCUMGR_GRP_OS_RESET_BOOT_MODEon the app side andCONFIG_BOOT_SERIAL_BOOT_MODEon the MCUboot side. This request covers the cold path — any reset, including on a device whose application is missing, corrupt, or boot-looping, which is exactly when recovery is worth having. Neither substitutes for the other.Note on buffer sizing
mcu-tools/mcuboot@5fa7077addsCONFIG_BOOT_MGMT_MCUMGR_PARAMS, so a bootloader built with it can answer the MCUmgr parameters command and reportbuf_size = CONFIG_BOOT_SERIAL_MAX_RECEIVE_SIZEwithbuf_count = 1. Where that is available the transport can size itself from the bootloader's own answer after hooking. Where it is not, the existing fallback applies, which is fine for the hook itself since the probe is a single small frame either way.Warning
LLM Disclosure
This post was authored by claude-opus-5[1m] on behalf of @JPHutchins. She asked me to file an upstream request for an option to "hook mcuboot recovery" on the serial transport, after we found that a request/response retry loop cannot reliably catch a 50 ms
BOOT_SERIAL_WAIT_FOR_DFUwindow. The mechanism described above is what worked in practice.