nRF5340 / NCS 3.3.x–3.4.x: MCUboot erases an encrypted staged image instead of swapping it — secure boot + image encryption cannot complete an OTA (+3 related bootloader defects, bench-measured)

What this ticket reports

We ship a battery-powered nRF5340 product using the nRF Connect SDK's documented production security configuration: immutable bootloader (NSIB/b0) + upgradable MCUboot in s0/s1, signed and encrypted application images, and firmware-over-BLE (SMP/mcumgr) as the only update path for fielded units.

In this configuration, on NCS v3.3.x, no encrypted application OTA can ever complete: on the first boot after an update is staged and marked pending, MCUboot mis-classifies the encrypted image in the secondary slot, never schedules the swap, and then deliberately erases the staged image. The device boots the old firmware, and nothing is logged above DEBUG level.

We root-caused this to four distinct, individually measurable defects in the NCS MCUboot integration (three in Nordic-only [nrf noup] code, one shared with upstream mcu-tools/mcuboot). This ticket documents each defect with measurements, explains how they interlock, reports which of them NCS 3.4.0 does and does not fix, and attaches a minimal bench-proven patch set. The specific requests are listed at the end; the headline one is that the 3.4.0 fix for defect 1 is compile-time unavailable to Partition-Manager-based projects, which leaves fielded products with no supported configuration in which encrypted OTA works.

Environment

  • nRF5340 (QKAA), custom board derived from nrf5340dk_nrf5340_cpuapp
  • NCS v3.3.1. We verified v3.3.2, v3.3.3 and v3.3.4 all pin the identical sdk-mcuboot revision (3de5b4df, "v2.3.0-dev"), so everything below applies to the whole 3.3.x line.
  • Sysbuild + static Partition Manager layout (pm_static.yml, attached); app-core secondary slot in external QSPI NOR (MX25R6435F), size 0xd3000 (864,256 bytes)
  • SB_CONFIG_SECURE_BOOT_APPCORE=y (b0 + s0/s1), SB_CONFIG_BOOT_ENCRYPTION=y (ECIES-P256 key exchange, AES-128-CTR payload), SB_CONFIG_MCUBOOT_MODE_SWAP_USING_MOVE=y
  • SB_CONFIG_MCUBOOT_NRF53_MULTI_IMAGE_UPDATE=y — network-core update via PCD, sharing the same external secondary slot
  • CONFIG_UPDATEABLE_IMAGE_NUMBER=3 as sysbuild derives it: image 0 = app core, image 1 = net core, image 2 = s0/s1 (MCUboot self-update). This value cannot be lowered from the project — see "Defect 2" below, which also explains why.
  • The application arms a task watchdog with a 10.5 s hardware fallback window (CONFIG_TASK_WDT + CONFIG_TASK_WDT_HW_FALLBACK). This is relevant because the nRF5340 WDT deliberately survives warm resets and cannot be stopped, and a field OTA reboot (sys_reboot after the mcumgr upload + test mark) is a warm reset — so MCUboot runs the entire swap with the application's watchdog counting down underneath it.

Summary of the failure chain

Staging an encrypted app image triggers the following chain. (Defects are numbered by how we isolated them, not by the order they fire; on a stock build the watchdog cuts the boot at the first operation that exceeds its window, so the individual timings below were measured on boots where the watchdog was not armed — see "How we measured".)

  1. Defect 1 — the NSIB slot-disambiguation code reads the staged image's reset vector from the secondary slot without decrypting it, concludes the (perfectly valid) image belongs to no slot, and returns before the slot is marked as assigned.
  2. Defect 3 — the "unusable slot" cleanup then erases the staged image: 15.8 s of blocking erase over external QSPI in one unfed call, followed by a second 17.9 s erase of the same physical area on behalf of image 2.
  3. Defect 2 — independently, image 2's swap-state scan never returns when anything is staged in the shared secondary, because it reads a flash area backed by the powered-off network core (≥10.86 s observed before our watchdog cut the boot).
  4. Defect 4 — MCUboot never feeds the watchdog on any of these paths, nor on the ~60 s swap path itself. So with any application watchdog under ~60 s the device additionally takes a mid-operation DOG0 reset; without one, the staged image is simply erased and the boot proceeds normally.

Either way the update never happens and the old image keeps running. With all four fixes applied (attached patch), the full encrypted OTA chain works on our bench: swap in ~60.6 s, application self-confirm, persistence across resets, and watchdog-driven revert of a deliberately broken image.

How we measured

Everything below comes from the target hardware, not from reading code alone. Method: RTT attach over SWD immediately after releasing reset, so MCUboot's log is captured from its first instruction; warm resets issued over BLE/mcumgr exactly as a fielded unit experiences them; RESETREAS read and cleared around every experiment so each reset is attributed to its cause (DOG0 vs SREQ vs pin); and, where the stock DEBUG log was insufficient, temporary instrumentation compiled into MCUboot (entry/exit timestamps, and the actual header fields and addresses each decision reads). Timings longer than the 10.5 s watchdog window were captured on boots where the application watchdog had not yet been armed (power-on and debugger flash cycles rather than warm OTA resets), so each operation could run to completion; the DOG0 observations come from the warm-reset runs with the watchdog live. All timings are RTT timestamps, reproducible across runs. The attached logs are raw captures; PROOF.txt is the acceptance evidence for the full fix set.

Defect 1 (keystone): NSIB slot disambiguation reads the reset vector of an encrypted image as plaintext

boot/bootutil/src/loader.c, boot_validated_swap_type() — the downstream block introduced by [nrf noup] 977324e9 ("Rework CPUNET application update logic"). Because the s0/s1 self-update image shares the app's external secondary slot, this block reads the staged image's reset vector (offset ih_hdr_size + 4 in the secondary) to decide which image the staged binary belongs to. The read is raw flash — never decrypted. For an AES-CTR-encrypted image that word is ciphertext, so the range checks conclude "not intended for any image" and the function returns BOOT_SWAP_TYPE_NONE before sec_slot_mark_assigned() runs. The slot is left in the SEC_SLOT_TOUCHED state, which sec_slot_cleanup_if_unusable() then erases (defect 3).

Instrumented capture — the same boot, both images' classification of the shared secondary side by side:

img=0  magic=0x96f3b83d  ih_flags=0x4 (IMAGE_F_ENCRYPTED_AES128)  reset_addr=0x3ee3fbc2
  -> "not in primary [0x28000,0xfc000]" -> BOOT_SWAP_TYPE_NONE (never assigned)
img=1  magic=0x96f3b83d  ih_flags=0x100 (no ENCRYPTIONFLAGS bit -- unencrypted net-core image)  reset_addr=0x1023291
  -> assigned  (this is why only the encrypted app image ever fails)

(The primary span above is 0x1000 larger than the secondary because swap-using-move keeps the primary one sector larger.) Note the code has the encryption flag in hand at the moment of the bad read — hdr->ih_flags comes from the plaintext header it already parsed.

Suggested fix: skip the plaintext-only disambiguation when ih_flags & ENCRYPTIONFLAGS is set — the two-line guard in boot_validated_swap_type() in the attached patch. With it, the entire OTA chain works; bench-proven, logs attached.

Prior art: mcu-tools/mcuboot PR #2473 (closed unmerged), whose discussion notes that the reset-vector disambiguation "explicitly does not support encrypted images".

Defect 2: image-2 swap-state scan never returns when the network core is off (≥10.86 s observed)

boot_prepare_image_for_update()swap_status_source()boot_read_swap_state() for image index 2. Image 2's primary flash area resolves to mcuboot_primary_1 — the nordic_ram_flash_controller (PCD) staging area backed by the network core, which is held in FORCEOFF while MCUboot runs. The read blocks and was still blocked when our watchdog fired 10.86 s in (bisected with entry/exit timestamps; images 0 and 1 traverse the identical code in under 1 ms).

Trigger condition: image 2's secondary is the shared mcuboot_secondary, so staging any app image gives image 2's secondary "good magic" and sends its swap-state scan into the unbacked primary. Idle boots short-circuit before the read and look healthy — which is why this survives testing that never stages an image.

We also verified image 2 cannot be disabled from a project: CONFIG_UPDATEABLE_IMAGE_NUMBER is force-set by nrf/sysbuild/CMakeLists.txt (set_config_int), SB_CONFIG_MCUBOOT_ADDITIONAL_UPDATEABLE_IMAGES is Kconfig-pinned to range [1,1] when SECURE_BOOT_APPCORE is on, and forcing the count to 2 anyway produces an application-core LOCKUP (the image-ID plumbing assumes all three images exist).

Suggested fix: guard the swap-state read for net-core-backed areas (or for the NSIB-owned image) the way downgrade-prevention paths already are. Our patch skips image 2's update processing entirely in boot_prepare_image_for_update() — correct for products whose s0/s1 updates are delivered as signed app-style images, but a general fix belongs in the SDK.

Defect 3: sec_slot_cleanup_if_unusable() erases the whole external secondary in one unfed call — twice

Introduced by [nrf noup] 0751a63a. A single flash_area_erase(fa, 0, fa->fa_size) over our 844 KiB QSPI secondary measured 15.80 s for image 0 — then ran again for image 2 over the same shared physical area, 17.88 s. Each alone exceeds a 10.5 s watchdog window, so on watchdog-equipped products the erase itself is interrupted mid-flight, leaving a torn slot.

Independent of the watchdog interaction, note what this call destroys in the defect-1 scenario: a signature-valid, correctly staged application image, erased as a side effect of a mis-classification, partly on behalf of an image-2 slot that cannot function on this platform at all (defect 2).

Suggested fix: chunk the erase with MCUBOOT_WATCHDOG_FEED() between chunks (our patch uses 32 KB chunks in sec_slot_cleanup_if_unusable()), skip the redundant second erase of a shared area, and log a warning whenever a staged image is about to be destroyed — today the path is silent above DEBUG.

Defect 4: MCUBOOT_WATCHDOG_FEED() has no call sites on the swap path

The macro exists and is default y on Nordic SoCs (CONFIG_BOOT_WATCHDOG_FEED), but at 3de5b4df it is called from only four places: twice in boot/bootutil/src/bootutil_area.c, once at startup in boot/zephyr/main.c, and one copy loop in loader.c. There are zero feeds in swap_move.c — neither in the move-up loop, nor the sector-swap loop, nor swap_read_status_bytes(), which at BOOT_MAX_IMG_SECTORS=256 issues ~1000 single-byte reads over external QSPI — and zero in the image hash/decrypt chunk loop (bootutil_img_hash.c). Our encrypted swap takes ~60 s end to end; none of it feeds the watchdog.

This matters beyond our product: on nRF SoCs the watchdog survives warm resets and cannot be stopped, and a field OTA reboot is a warm reset, so any application watchdog shorter than the swap time will reset the device mid-swap. Swap-using-move tolerates the interruption and resumes — but with defects 1–3 in play, the interrupted operation was the erase of the staged image.

Suggested fix: feed coverage across the swap/validate path. Our patch adds four feed sites: swap_read_status_bytes(), both loops in swap_run(), and the hash chunk loop.

What NCS 3.4.0 changes — and what it does not

Before filing this we checked each defect against NCS v3.4.0 and current sdk-mcuboot main:

Defect NCS 3.3.x NCS 3.4.0 Remaining gap
1 — encrypted secondary read as plaintext Broken Fixed only outside Partition Manager. The reset-vector read is replaced by a plaintext-header check, CONFIG_MCUBOOT_CHECK_HEADER_LOAD_ADDRESS (uses ih_load_addr, works "even when the image is encrypted"). The new option is declared depends on !PARTITION_MANAGER_ENABLED — a project on a PM static layout (i.e. an existing fielded nRF5340 product with a frozen flash map) compiles the old path in 3.4.0 too.
2 — non-returning read of the net-core-backed area Broken Unchanged. 3.4.0 adds IS_NSIB_OWNED() guards elsewhere, but not around this read. Present in 3.4.0 and sdk-mcuboot main; we found no public report of it.
3 — monolithic unfed 15.8 s + 17.9 s erases Broken Unchanged. Same single-call flash_area_erase, still run per-image over the shared area. Present in 3.4.0 and sdk-mcuboot main; no public report found.
4 — no watchdog feeds on the swap path Broken Unchanged. swap_move.c in 3.4.0 and upstream main contains zero MCUBOOT_WATCHDOG_FEED occurrences. Upstream-shared code (mcu-tools/mcuboot).

So for a product already in the field on a Partition Manager layout — which cannot migrate its flash map because OTA is its only firmware path — upgrading to NCS 3.4.0 fixes none of the four defects.

Reproduction

Deterministic, every staged boot, no special timing needed:

  1. Build any application with the Environment configuration above (secure boot + encryption + swap-using-move + shared external secondary; a watchdog under ~60 s makes the failure louder but is not required).
  2. Upload any correctly signed+encrypted app image over SMP, mark it pending (test mode), and warm-reset.
  3. Observe via RTT on MCUboot: the image trailer is read as pending (the mcumgr "test" mark), but boot_validated_swap_type() returns BOOT_SWAP_TYPE_NONE because the staged image is classified as belonging to no slot; the secondary is erased and the old version boots. With a watchdog armed, RESETREAS additionally shows DOG0 partway through the erase; without one, the erase completes and the boot log looks normal at default log levels.

We have not attempted this on a stock nrf5340dk (its default layout has no external shared secondary). Defect 1 is layout-independent — a plaintext read of an encrypted secondary — and should reproduce on any secure-boot + encryption + multi-image build; defects 2 and 3 need the shared external secondary. We can put together a DK-based reduced case on request.

Attachments

  • ncs-3.3.1-mcuboot-secured-swap.patch — minimal 4-fix set, applies cleanly to sdk-mcuboot 3de5b4df (the whole 3.3.x line). With it applied, our full acceptance run passes: encrypted swap in, self-confirm, persistence across reset, and automatic revert of a deliberately broken image — timings and logs in PROOF.txt.
  • PROOF.txt — acceptance table, timings, RESETREAS trails, and the exact configuration used.
  • partitions.yml.txt — the static Partition Manager layout (renamed from .yml for upload).
  • rtt-keystone-encrypted-reset-vector.log — defect 1: ciphertext reset-vector classification, both images side by side.
  • rtt-img2-hang-bisect.log — defect 2: the ≥10.86 s block bisected to the image-2 swap-state read.
  • rtt-secondary-erase-timing.log — defect 3: the 15.80 s / 17.88 s erase pair.
  • rtt-row2-swap-pass.log, rtt-row3-revert.log — passing encrypted swap and passing revert with the patch set applied ("row 2" / "row 3" refer to the acceptance table in PROOF.txt).

What we are asking for

  1. Internal bug IDs for defects 1–4 (defects 2 and 3 appear publicly unreported as far as we can tell).
  2. A position on the Partition Manager gap for defect 1: is a PM-compatible fix planned, and is a backport of any fix to the 3.3.x line possible?
  3. Review of the attached minimal patch set — we would like to converge on something Nordic-blessed rather than maintain out-of-tree SDK patches.
  4. Whether you prefer the defect-4 watchdog feeds (upstream-shared files) as a direct mcu-tools/mcuboot PR.

app:
  address: 0x28200
  end_address: 0xfc000
  region: flash_primary
  size: 0xd3e00
app_image:
  address: 0x28200
  end_address: 0xfc000
  orig_span: &id001
  - app
  region: flash_primary
  size: 0xd3e00
  span: *id001
b0:
  address: 0x0
  end_address: 0x8000
  placement:
    after:
    - start
  region: flash_primary
  size: 0x8000
b0_container:
  address: 0x0
  end_address: 0x8000
  orig_span: &id002
  - b0
  region: flash_primary
  size: 0x8000
  span: *id002
ble_key_storage:
  address: 0xfe000
  end_address: 0x100000
  placement:
    after:
    - settings_storage
  region: flash_primary
  size: 0x2000
crash_record_sram:
  address: 0x2006fc00
  end_address: 0x20070000
  placement:
    before:
    - rpmsg_nrf53_sram
  region: sram_primary
  size: 0x400
external_flash:
  address: 0x113000
  end_address: 0x800000
  region: external_flash
  size: 0x6ed000
mcuboot:
  address: 0x8200
  end_address: 0x18000
  region: flash_primary
  size: 0xfe00
mcuboot_pad:
  address: 0x28000
  end_address: 0x28200
  placement:
    align:
      start: 0x4000
    before:
    - mcuboot_primary_app
  region: flash_primary
  size: 0x200
mcuboot_primary:
  address: 0x28000
  end_address: 0xfc000
  orig_span: &id003
  - mcuboot_pad
  - app
  region: flash_primary
  size: 0xd4000
  span: *id003
mcuboot_primary_1:
  address: 0x0
  device: nordic_ram_flash_controller
  end_address: 0x40000
  region: ram_flash
  size: 0x40000
mcuboot_primary_app:
  address: 0x28200
  end_address: 0xfc000
  orig_span: &id004
  - app
  region: flash_primary
  size: 0xd3e00
  span: *id004
mcuboot_secondary:
  address: 0x0
  device: DT_CHOSEN(nordic_pm_ext_flash)
  end_address: 0xd3000
  placement:
    align:
      start: 0x4
  region: external_flash
  size: 0xd3000
mcuboot_secondary_1:
  address: 0xd3000
  device: DT_CHOSEN(nordic_pm_ext_flash)
  end_address: 0x113000
  region: external_flash
  size: 0x40000
otp:
  address: 0xff8380
  end_address: 0xff83fc
  region: otp
  size: 0x7c
pcd_sram:
  address: 0x20000000
  end_address: 0x20002000
  placement:
    after:
    - start
  region: sram_primary
  size: 0x2000
provision:
  address: 0xff8100
  end_address: 0xff8380
  region: otp
  size: 0x280
ram_flash:
  address: 0x40000
  end_address: 0x40000
  region: ram_flash
  size: 0x0
rpmsg_nrf53_sram:
  address: 0x20070000
  end_address: 0x20080000
  placement:
    before:
    - end
  region: sram_primary
  size: 0x10000
s0:
  address: 0x8000
  end_address: 0x18000
  orig_span: &id005
  - s0_pad
  - s0_image
  region: flash_primary
  size: 0x10000
  span: *id005
s0_image:
  address: 0x8200
  end_address: 0x18000
  orig_span: &id006
  - mcuboot
  region: flash_primary
  size: 0xfe00
  span: *id006
s0_pad:
  address: 0x8000
  end_address: 0x8200
  placement:
    after:
    - b0_container
    align:
      start: 0x4000
  region: flash_primary
  size: 0x200
s1:
  address: 0x18000
  end_address: 0x28000
  orig_span: &id007
  - s1_pad
  - s1_image
  region: flash_primary
  size: 0x10000
  span: *id007
s1_image:
  address: 0x18200
  end_address: 0x28000
  region: flash_primary
  share_size:
  - s0_image
  size: 0xfe00
s1_pad:
  address: 0x18000
  end_address: 0x18200
  placement:
    after:
    - s0
    align:
      start: 0x4000
  region: flash_primary
  size: 0x200
settings_storage:
  address: 0xfc000
  end_address: 0xfe000
  placement:
    align:
      start: 0x4000
    before:
    - end
  region: flash_primary
  size: 0x2000
sram_primary:
  address: 0x20002000
  end_address: 0x2006fc00
  region: sram_primary
  size: 0x6dc00
 
 WARN probe_rs::rtt: Buffer for up channel 1 not initialized
 WARN probe_rs::rtt: Buffer for up channel 2 not initialized
 WARN probe_rs::rtt: Buffer for down channel 1 not initialized
 WARN probe_rs::rtt: Buffer for down channel 2 not initialized
Failed to create readline
O��)��pFG����  (  ]�E��]�1 dQ���??pQpQpQpQp  �%�%�%�%
22:02:33.177: k=0x3
22:02:33.177: I: Secondary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
22:02:33.177: I: Boot source: none
22:02:33.177: I: DIAG ncs img=1 magic=0x96f3b83d flags=0x100 reset_addr=0x1023291
22:02:33.177: I: DIAG ncs ASSIGNED img=1
22:02:33.177: I: Image index: 1, Swap type: none
22:02:33.177: I: DIAG skip prepare img=2
22:02:33.177: I: Bootloader chainload address offset: 0x28000
22:02:33.177: I: Image version: v0.1.2
22:02:33.177: I: Jumping to the first image slot
22:02:33.177: *** Booting MCUboot v2.3.0-dev-3de5b4df5f9f ***
22:02:33.177: *** Using nRF Connect SDK v3.3.1-1d7a0b0e49b8 ***
22:02:33.177: *** Using Zephyr OS v4.3.99-37e6c28576ee ***
22:02:33.177: I: Starting bootloader
22:02:33.177: I: Primary image: magic=unset, swap_type=0x1, cop[00:01:11.428,070] <inf> app: BleCore.cpp: onDisconnected() [2203]:: [XX:XX:XX:XX:XX:02 (public)] BLE device disconnected with reason 19
22:02:33.918: [00:01:11.428,100] <inf> app: DeviceStateManager.cpp: bleOnDisconnect() [ 280]:: Disconnected
22:02:33.918: [00:01:11.428,161] <wrn> app: GeneralFsm.hpp: setState() [  78]:: State: ACTIVE: CONNECTED => ACTIVE: WAIT CONN
22:02:33.918: [00:01:11.428,497] <inf> app: Application.cpp: handleNewState() [2295]:: Handling new device state...
22:02:33.918: [00:01:11.428,619] <inf> app: BleServerController.cpp: processIntCmd() [ 337]:: Starting advertising without whitelist
22:02:33.918: [00:01:11.428,649] <inf> app: BleCore.cpp: advertisingStart() [1101]:: Adv data size: 3; ScanRespPacketsData size: 1
22:02:33.918: [00:01:11.431,091] <inf> app: BleServerController.cpp: processIntCmd() [ 341]:: Advertising started
22:02:36.934: [00:01:15.348,785] <inf> app: BleCore.cpp: onConnected() [2178]:: New BLE connection established: [XX:XX:XX:XX:XX:02 (public)], MTU: 23 bytes
22:02:36.934: [00:01:15.349,304] <inf> app: ---- Basic nonce (len: 13): ----
22:02:36.934: [00:01:15.349,334] <inf> app: Content:
22:02:36.934:                               5b 1a a8 7d b0 00 29 1b  56 41 b7 e2 e4          |[..}..). VA...   
22:02:36.934: [00:01:15.349,365] <inf> app: ---- Basic nonce end  ----
22:02:36.934: [00:01:15.372,924] <inf> app: DeviceStateManager.cpp: bleOnConnect() [ 272]:: Connected
22:02:36.934: [00:01:15.372,985] <wrn> app: GeneralFsm.hpp: setState() [  78]:: State: ACTIVE: WAIT CONN => ACTIVE: CONNECTED
22:02:36.934: [00:01:15.373,443] <inf> app: BleCore.cpp: onDataLengthUpdated() [2269]:: LE data len updated: TX (len: 251 bytes time: 2120 us) RX (len: 251 bytes time: 2120 us)
22:02:36.934: [00:01:15.373,565] <inf> app: Application.cpp: handleNewState() [2295]:: Handling new device state...
22:02:36.934: [00:01:15.423,583] <inf> app: BleCore.cpp: mtuExchangeFuncful
22:02:36.939: 
22:02:37.781: *** Booting MCUboot v2.3.0-dev-3de5b4df5f9f ***
22:02:37.781: *** Using nRF Connect SDK v3.3.1-1d7a0b0e49b8 ***
22:02:37.781: *** Using Zephyr OS v4.3.99-37e6c28576ee ***
22:02:37.781: I: Starting bootloader
22:02:37.781: I: Primary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
22:02:37.781: I: Secondary image: magic=good, swap_type=0x2, copy_done=0x3, image_ok=0x3
22:02:37.781: I: Boot source: none
22:02:37.781: I: DIAG ncs img=0 magic=0x96f3b83d flags=0x4 reset_addr=0x3ee3fbc2
22:02:37.781: I: DIAG ncs RETURN-NONE img=0 reset_addr=0x3ee3fbc2 NOT in primary [0x28000,0xfc000]
22:02:37.781: I: Primary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
22:02:37.781: I: Secondary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
22:02:37.781: I: Boot source: none
22:02:37.781: I: DIAG ncs img=1 magic=0x96f3b83d flags=0x100 reset_addr=0x1023291
22:02:37.781: I: DIAG ncs ASSIGNED img=1
22:02:37.781: I: Image index: 1, Swap type: none
22:02:37.781: I: DIAG skip prepare img=2
22:02:37.781: I: DIAG enter sec_erase img=0
22:02:53.474: I: DIAG exit sec_erase img=0 rc=0
22:02:53.474: E: Erase secondary: img 0: 0
22:02:53.474: I: DIAG enter sec_erase img=2
22:03:11.339: I: DIAG exit sec_erase img=2 rc=0
22:03:11.339: E: Erase secondary: img 2: 0
22:03:12.582: I: Bootloader chainload address offset: 0x28000
22:03:12.582: I: Image version: v0.1.2
22:03:12.582: I: Jumping to the first image slot
22:03:13.838: *** Booting My Application v0.1.2-0d268237374f ***
22:03:13.838: *** Using nRF Connect SDK v3.3.1-1d7a0b0e49b8 ***
22:03:13.838: *** Using Zephyr OS v4.3.99-37e6c28576ee ***
22:03:13.838: [00:00:00.051,330] <wrn> app: main.cpp: main() [  47]:: nRF5340 app, last-good-ncs-2.6-95-g0d26823-d
22:03:13.838: [00:00:00.056,152] <wrn> app: GeneralFsm.hpp: setState() [  78]:: State: <UNDEFINED> => STANDBY
22:03:13.838: [00:00:00.056,213] <inf> app: Npm1300.cpp: init() [ 244]:: nRF Fuel Gauge version: 1.1.1
22:03:13.838: [00:00:00.056,793] <inf> app: Npm1300.cpp: initChargerState() [ 806]:: Charger init (regs: SET: 0x1; CLR: 0x1)
22:03:13.838: [00:00:00.057,617] <inf> app: Npm1300.cpp: controlCharger() [ 855]:: Charger disabled (regs: SET: 0x0; CLR: 0x0)
22:03:13.838: [00:00:00.559,600] <wrn> app: Npm1300.cpp: init() [ 283]:: (init) NPM1300 data: 4.174000V, -0.000000A, 25.617737°C
22:03:14.773: [00:00:01.061,523] <wrn> app: Npm1300.cpp: init() [ 283]:: (init) NPM1300 data: 4.174000V, -0.000000A, 25.617737°C
22:03:14.773: [00:00:01.063,690] <inf> app: Npm1300.cpp: controlCharger() [ 855]:: Charger enabled (regs: SET: 0x1; CLR: 0x1)
22:03:16.739: [00:00:02.978,881] <inf> app: AFE4403.cpp: findCapacitanceConfig() [2000]:: Finding feedback capacitor: Target: 5, Best: 5, Config: 0x00000000
22:03:16.861: [00:00:04.108,459] <inf> app: Application.cpp: initCrypto() [ 893]:: BLE session key: built-in default (no valid override)
22:03:16.861: [00:00:04.113,708] <inf> fs_nvs: 2 Sectors of 4096 bytes
22:03:16.861: [00:00:04.113,708] <inf> fs_nvs: alloc wra: 0, fe8
22:03:16.861: [00:00:04.113,708] <inf> fs_nvs: data wra: 0, 0
22:03:16.861: [00:00:04.113,800] <wrn> app: Application.cpp: initCrypto() [ 918]:: BLE app-layer encryption: ENCRYPTED
22:03:16.861: [00:00:04.113,861] <wrn> app: Application.cpp: init() [ 532]:: Charger interlock: ON
22:03:16.861: [00:00:04.113,922] <wrn> app: Application.cpp: init() [ 543]:: OTA version gate: OFF (factory default)
22:03:16.861: [00:00:04.113,983] <inf> app: LedFillCapSetting.cpp: init() [  59]:: LED fill cap: 30 %
22:03:16.861: [00:00:04.114,044] <inf> app: AutoAnimBrightSetting.cpp: init() [  61]:: Auto-animation brightness cap: 20 %
22:03:16.861: [00:00:04.115,417] <inf> app: BleCore.cpp: addService() [ 333]:: Adding chars...
22:03:16.861: [00:00:04.115,692] <inf> app: BleCore.cpp: addService() [ 
22:03:16.861: 
22:03:16.873: --- 1 messages dropped ---
22:03:16.873: [00:00:04.116,363] <inf> app: BleCore.cpp: addService() [ 333]:: Adding chars...
22:03:16.873: [00:00:04.116,424] <inf> app: BleCore.cpp: addService() [ 406]:: Adding descriptors...
22:03:16.873: [00:00:04.116,516] <inf> app: BleCore.cpp: addService() [ 406]:: Adding descriptors...
22:03:16.873: [00:00:04.116,668] <inf> app: BleCore.cpp: addService() [ 333]:: Adding chars...
22:03:16.873: [00:00:04.116,729] <inf> app: BleCore.cpp: addService() [ 406]:: Adding descriptors...
22:03:16.873: [00:00:04.116,821] <inf> app: BleCore.cpp: addService() [ 406]:: Adding descriptors...
22:03:16.873: [00:00:04.116,973] <inf> app: BleCore.cpp: addService() [ 333]:: Adding chars...
22:03:16.884: [00:00:04.139,373] <inf> bt_hci_core: HW Platform: Nordic Semiconductor (0x0002)
22:03:16.884: [00:00:04.139,404] <inf> bt_hci_core: HW Variant: nRF53x (0x0003)
22:03:16.884: [00:00:04.139,434] <inf> bt_hci_core: Firmware: Standard Bluetooth controller (0x00) Version 252.31313 Build 1865177321
22:03:16.884: [00:00:04.141,754] <inf> bt_hci_core: HCI transport: IPC
22:03:16.904: [00:00:04.141,876] <inf> bt_hci_core: Identity: XX:XX:XX:XX:XX:01 (random)
22:03:16.904: [00:00:04.141,906] <inf> bt_hci_core: HCI: version 6.3 (0x11) revision 0x201f, manufacturer 0x0059
22:03:16.904: [00:00:04.141,937] <inf> bt_hci_core: LMP: version 6.3 (0x11) subver 0x201f
22:03:16.904: [00:00:04.142,456] <wrn> app: GeneralFsm.hpp: setState() [  78]:: State: STANDBY => ACTIVE: WAIT CONN
22:03:16.904: [00:00:04.144,958] <wrn> app: BatteryStateMonitorTask.hpp: start() [ 284]:: Charger is connected
22:03:16.904: [00:00:04.144,989] <inf> app: BatteryStateMonitorTask.hpp: notifyObservers() [1139]:: charger: connected
22:03:16.904: [00:00:04.145,019] <inf> app: Application.cpp: handleChargerState() [1890]:: Handling new charger state...
22:03:16.904: [00:00:04.145,263] <inf> app: BatteryStateMonitorTask.hpp: notifyObservers() [1165]:: bat state: full
22:03:16.904: [00:00:04.145,294] <inf> app: Application.cpp: handleBatteryState() [2216]:: Handling new battery state...
22:03:16.904: [00:00:04.148,071] <err> app: Application.cpp: powerDownUnusedPeripherals() [1864]:: Failed to suspend LSM6DSM (err: -120)
22:03:17.018: [00:00:04.148,559] <wrn> app: Application.cpp: armTaskWatchdogs() [1656]:: Task watchdog armed
22:03:17.018: [00:00:04.148,590] <inf> app: Application.cpp: handleNewState() [2295]:: Handling new device state...
22:03:17.018: [00:00:04.148,712] <wrn> app: DisplayTask.hpp: evtHandler() [ 101]:: Activating LED boost conv
22:03:18.994: [00:00:05.236,785] <inf> app: BleServerController.cpp: processIntCmd() [ 337]:: Starting advertising without whitelist
22:03:18.994: [00:00:05.236,938] <inf> app: BleCore.cpp: advertisingStart() [1101]:: Adv data size: 3; ScanRespPacketsData size: 1
22:03:18.994: [00:00:05.238,586] <inf> mcuboot_util: Image index: 0, Swap type: none
22:03:18.994: [00:00:05.238,647] <inf> app: Application.cpp: confirmRunningImage() [2484]:: Running image already confirmed, nothing to do
22:03:18.994: [00:00:05.239,501] <inf> app: BleServerController.cpp: processIntCmd() [ 341]:: Advertising started
Received SIGTERM, exiting
Exited by user request
 
 WARN probe_rs::rtt: Buffer for up channel 1 not initialized
 WARN probe_rs::rtt: Buffer for up channel 2 not initialized
 WARN probe_rs::rtt: Buffer for down channel 1 not initialized
 WARN probe_rs::rtt: Buffer for down channel 2 not initialized
Failed to create readline
O��)��pFG����  (  ]�E��]�1 dQ���??pQpQpQpQp  �%�%�%�%
20:56:53.169:  exit swap_status_source (none)
20:56:53.169: I: Boot source: none
20:56:53.169: I: DIAG enter boot_swap_type_multi img=0
20:56:53.169: I: DIAG bstm: primary done, reading secondary
20:56:53.169: I: DIAG bstm: secondary state read done
20:56:53.169: I: Image index: 0, Swap type: none
20:56:53.169: I: DIAG enter swap_status_source img=1
20:56:53.169: I: Primary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
20:56:53.169: I: DIAG after read_swap_state PRIMARY
20:56:53.169: I: Secondary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
20:56:53.169: I: DIAG after read_swap_state SECONDARY
20:56:53.169: I: DIAG exit swap_status_source (none)
20:56:53.169: I: Boot source: none
20:56:53.169: I: DIAG enter boot_swap_type_multi img=1
20:56:53.912: [00:01:16.632,904] <inf> app: BleCore.cpp: onDisconnected() [2203]:: [XX:XX:XX:XX:XX:02 (public)] BLE device disconnected with reason 19
20:56:53.912: [00:01:16.632,965] <inf> app: DeviceStateManager.cpp: bleOnDisconnect() [ 280]:: Disconnected
20:56:53.912: [00:01:16.633,026] <wrn> app: GeneralFsm.hpp: setState() [  78]:: State: ACTIVE: CONNECTED => ACTIVE: WAIT CONN
20:56:53.912: [00:01:16.633,422] <inf> app: Application.cpp: handleNewState() [2295]:: Handling new device state...
20:56:53.912: [00:01:16.633,575] <inf> app: BleServerController.cpp: processIntCmd() [ 337]:: Starting advertising without whitelist
20:56:53.912: [00:01:16.633,636] <inf> app: BleCore.cpp: advertisingStart() [1101]:: Adv data size: 3; ScanRespPacketsData size: 1
20:56:53.912: [00:01:16.636,077] <inf> app: BleServerController.cpp: processIntCmd() [ 341]:: Advertising started
20:56:58.274: [00:01:21.899,780] <inf> app: BleCore.cpp: onConnected() [2178]:: New BLE connection established: [XX:XX:XX:XX:XX:02 (public)], MTU: 23 bytes
20:56:58.274: [00:01:21.900,421] <inf> app: ---- Basic nonce (len: 13): ----
20:56:58.274: [00:01:21.900,451] <inf> app: Content:
20:56:58.274:                               89 87 fc 7c 6a 31 98 e6  dd 8b 1e cd 34          |...|j1.. ....4   
20:56:58.274: [00:01:21.900,482] <inf> app: ---- Basic nonce end  ----
20:56:58.274: [00:01:21.925,354] <inf> app: DeviceStateManager.cpp: bleOnConnect() [ 272]:: Connected
20:56:58.274: [00:01:21.925,415] <wrn> app: GeneralFsm.hpp: setState() [  78]:: State: ACTIVE: WAIT CONN => ACTIVE: CONNECTED
20:56:58.274: [00:01:21.925,872] <inf> app: BleCore.cpp: onDataLengthUpdated() [2269]:: LE data len updated: TX (len: 251 bytes time: 2120 us) RX (len: 251 bytes time: 2120 us)
20:56:58.274: [00:01:21.925,964] <inf> app: Application.cpp: handleNewState() [2295]:: Handling new device state...
20:56:58.274: [00:01:21.973,205] <inf> app: BleCore.cpp: mtuExchangeFuncful
20:56:58.278: 
20:56:59.124: *** Booting MCUboot v2.3.0-dev-3de5b4df5f9f ***
20:56:59.124: *** Using nRF Connect SDK v3.3.1-1d7a0b0e49b8 ***
20:56:59.124: *** Using Zephyr OS v4.3.99-37e6c28576ee ***
20:56:59.124: I: Starting bootloader
20:56:59.124: I: DIAG enter swap_status_source img=0
20:56:59.124: I: Primary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
20:56:59.124: I: DIAG after read_swap_state PRIMARY
20:56:59.124: I: Secondary image: magic=good, swap_type=0x2, copy_done=0x3, image_ok=0x3
20:56:59.124: I: DIAG after read_swap_state SECONDARY
20:56:59.124: I: DIAG exit swap_status_source (none)
20:56:59.124: I: Boot source: none
20:56:59.124: I: DIAG enter swap_status_source img=1
20:56:59.124: I: Primary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
20:56:59.124: I: DIAG after read_swap_state PRIMARY
20:56:59.124: I: Secondary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
20:56:59.124: I: DIAG after read_swap_state SECONDARY
20:56:59.124: I: DIAG exit swap_status_source (none)
20:56:59.124: I: Boot source: none
20:56:59.124: I: DIAG enter boot_swap_type_multi img=1
20:56:59.124: I: DIAG bstm: primary done, reading secondary
20:56:59.124: I: DIAG bstm: secondary state read done
20:56:59.124: I: Image index: 1, Swap type: none
20:56:59.124: I: DIAG enter swap_status_source img=2
20:56:59.124: I: *** Booting MCUboot v2.3.0-dev-3de5b4df5f9f ***
20:57:09.986: *** Using nRF Connect SDK v3.3.1-1d7a0b0e49b8 ***
20:57:09.986: *** Using Zephyr OS v4.3.99-37e6c28576ee ***
20:57:09.986: I: Starting bootloader
20:57:09.986: I: DIAG enter swap_status_source img=0
20:57:09.986: I: Primary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
20:57:09.986: I: DIAG after read_swap_state PRIMARY
20:57:09.986: I: Secondary image: magic=good, swap_type=0x2, copy_done=0x3, image_ok=0x3
20:57:09.986: I: DIAG after read_swap_state SECONDARY
20:57:09.986: I: DIAG exit swap_status_source (none)
20:57:09.986: I: Boot source: none
20:57:09.986: I: DIAG enter boot_swap_type_multi img=0
20:57:09.986: I: DIAG bstm: primary done, reading secondary
20:57:09.986: I: DIAG bstm: secondary state read done
20:57:09.986: I: Image index: 0, Swap type: test
20:57:10.106: I: DIAG enter boot_swap_type_multi img=0
20:57:10.106: I: DIAG bstm: primary done, reading secondary
20:57:10.106: I: DIAG bstm: secondary state read done
20:57:10.106: I: Image index: 0, Swap type: none
20:57:10.106: I: DIAG enter swap_status_source img=1
20:57:10.106: I: Primary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
20:57:10.106: I: DIAG after read_swap_state PRIMARY
20:57:10.106: I: Secondary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
20:57:10.106: I: DIAG after read_swap_state SECONDARY
20:57:10.106: I: DIAG exit swap_status_source (none)
20:57:10.106: I: Boot source: none
20:57:10.106: I: DIAG enter boot_swap_type_multi img=1
20:57:10.106: I: DIAG bstm: primary done, reading secondary
20:57:10.106: I: DIAG bstm: secondary state read done
20:57:10.106: I: Image index: 1, Swap type: none
20:57:10.106: I: DIAG enter swap_status_source img=2
20:57:10.106: I: Primary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
20:57:10.106: I: DIAG after read_swap_state PRIMARY
20:57:10.106: I: Secondary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
20:57:10.106: I: DIAG after read_swap_state SECONDARY
20:57:10.106: I: DIAG exit swap_status_source (none)
20:57:10.106: I: Boot source: none
20:57:10.106: I: DIAG enter boot_swap_type_multi img=2
20:57:10.106: I: DI: Bootloader chainload address offset: 0x28000
20:57:11.346: I: Image version: v0.1.2
20:57:11.346: I: Jumping to the first image slot
20:57:12.603: *** Booting My Application v0.1.2-0d268237374f ***
20:57:12.603: *** Using nRF Connect SDK v3.3.1-1d7a0b0e49b8 ***
20:57:12.603: *** Using Zephyr OS v4.3.99-37e6c28576ee ***
20:57:12.603: [00:00:00.051,330] <wrn> app: main.cpp: main() [  47]:: nRF5340 app, last-good-ncs-2.6-95-g0d26823-d
20:57:12.603: [00:00:00.056,121] <wrn> app: GeneralFsm.hpp: setState() [  78]:: State: <UNDEFINED> => STANDBY
20:57:12.603: [00:00:00.056,182] <inf> app: Npm1300.cpp: init() [ 244]:: nRF Fuel Gauge version: 1.1.1
20:57:12.603: [00:00:00.056,762] <inf> app: Npm1300.cpp: initChargerState() [ 806]:: Charger init (regs: SET: 0x1; CLR: 0x1)
20:57:12.603: [00:00:00.057,556] <inf> app: Npm1300.cpp: controlCharger() [ 855]:: Charger disabled (regs: SET: 0x0; CLR: 0x0)
20:57:12.603: [00:00:00.559,539] <wrn> app: Npm1300.cpp: init() [ 283]:: (init) NPM1300 data: 4.174000V, -0.000000A, 25.927582°C
20:57:13.538: [00:00:01.061,462] <wrn> app: Npm1300.cpp: init() [ 283]:: (init) NPM1300 data: 4.174000V, -0.000000A, 25.927582°C
20:57:13.538: [00:00:01.063,629] <inf> app: Npm1300.cpp: controlCharger() [ 855]:: Charger enabled (regs: SET: 0x1; CLR: 0x1)
20:57:15.510: [00:00:02.978,546] <inf> app: AFE4403.cpp: findCapacitanceConfig() [2000]:: Finding feedback capacitor: Target: 5, Best: 5, Config: 0x00000000
20:57:15.631: [00:00:04.108,032] <inf> app: Application.cpp: initCrypto() [ 893]:: BLE session key: built-in default (no valid override)
20:57:15.631: [00:00:04.113,342] <inf> fs_nvs: 2 Sectors of 4096 bytes
20:57:15.631: [00:00:04.113,372] <inf> fs_nvs: alloc wra: 0, fe8
20:57:15.631: [00:00:04.113,372] <inf> fs_nvs: data wra: 0, 0
20:57:15.631: [00:00:04.113,464] <wrn> app: Application.cpp: initCrypto() [ 918]:: BLE app-layer encryption: ENCRYPTED
20:57:15.631: [00:00:04.113,525] <wrn> app: Application.cpp: init() [ 532]:: Charger interlock: ON
20:57:15.631: [00:00:04.113,586] <wrn> app: Application.cpp: init() [ 543]:: OTA version gate: OFF (factory default)
20:57:15.631: [00:00:04.113,647] <inf> app: LedFillCapSetting.cpp: init() [  59]:: LED fill cap: 30 %
20:57:15.631: [00:00:04.113,708] <inf> app: AutoAnimBrightSetting.cpp: init() [  61]:: Auto-animation brightness cap: 20 %
20:57:15.631: [00:00:04.115,081] <inf> app: BleCore.cpp: addService() [ 333]:: Adding chars...
20:57:15.631: [00:00:04.115,356] <inf> app: BleCore.cpp: addService() [ 
20:57:15.635: 
20:57:15.646: --- 1 messages dropped ---
20:57:15.646: [00:00:04.116,027] <inf> app: BleCore.cpp: addService() [ 333]:: Adding chars...
20:57:15.646: [00:00:04.116,088] <inf> app: BleCore.cpp: addService() [ 406]:: Adding descriptors...
20:57:15.646: [00:00:04.116,149] <inf> app: BleCore.cpp: addService() [ 406]:: Adding descriptors...
20:57:15.646: [00:00:04.116,333] <inf> app: BleCore.cpp: addService() [ 333]:: Adding chars...
20:57:15.658: [00:00:04.116,394] <inf> app: BleCore.cpp: addService() [ 406]:: Adding descriptors...
20:57:15.658: [00:00:04.116,455] <inf> app: BleCore.cpp: addService() [ 406]:: Adding descriptors...
20:57:15.658: [00:00:04.116,638] <inf> app: BleCore.cpp: addService() [ 333]:: Adding chars...
20:57:15.658: [00:00:04.138,916] <inf> bt_hci_core: HW Platform: Nordic Semiconductor (0x0002)
20:57:15.658: [00:00:04.138,946] <inf> bt_hci_core: HW Variant: nRF53x (0x0003)
20:57:15.658: [00:00:04.138,977] <inf> bt_hci_core: Firmware: Standard Bluetooth controller (0x00) Version 252.31313 Build 1865177321
20:57:15.658: [00:00:04.141,326] <inf> bt_hci_core: HCI transport: IPC
20:57:15.668: [00:00:04.141,448] <inf> bt_hci_core: Identity: XX:XX:XX:XX:XX:01 (random)
20:57:15.668: [00:00:04.141,479] <inf> bt_hci_core: HCI: version 6.3 (0x11) revision 0x201f, manufacturer 0x0059
20:57:15.668: [00:00:04.141,510] <inf> bt_hci_core: LMP: version 6.3 (0x11) subver 0x201f
20:57:15.668: [00:00:04.142,028] <wrn> app: GeneralFsm.hpp: setState() [  78]:: State: STANDBY => ACTIVE: WAIT CONN
20:57:15.681: [00:00:04.144,500] <wrn> app: BatteryStateMonitorTask.hpp: start() [ 284]:: Charger is connected
20:57:15.681: [00:00:04.144,531] <inf> app: BatteryStateMonitorTask.hpp: notifyObservers() [1139]:: charger: connected
20:57:15.681: [00:00:04.144,561] <inf> app: Application.cpp: handleChargerState() [1890]:: Handling new charger state...
20:57:15.681: [00:00:04.144,805] <inf> app: BatteryStateMonitorTask.hpp: notifyObservers() [1165]:: bat state: full
20:57:15.681: [00:00:04.144,836] <inf> app: Application.cpp: handleBatteryState() [2216]:: Handling new battery state...
20:57:15.681: [00:00:04.147,613] <err> app: Application.cpp: powerDownUnusedPeripherals() [1864]:: Failed to suspend LSM6DSM (err: -120)
20:57:15.690: [00:00:04.148,101] <wrn> app: Application.cpp: armTaskWatchdogs() [1656]:: Task watchdog armed
20:57:15.690: [00:00:04.148,132] <inf> app: Application.cpp: handleNewState() [2295]:: Handling new device state...
20:57:15.690: [00:00:04.148,254] <wrn> app: DisplayTask.hpp: evtHandler() [ 101]:: Activating LED boost conv
20:57:17.781: [00:00:05.236,236] <inf> app: BleServerController.cpp: processIntCmd() [ 337]:: Starting advertising without whitelist
20:57:17.781: [00:00:05.236,389] <inf> app: BleCore.cpp: advertisingStart() [1101]:: Adv data size: 3; ScanRespPacketsData size: 1
20:57:17.781: [00:00:05.236,633] <inf> mcuboot_util: DIAG enter boot_swap_type_multi img=0
20:57:17.781: [00:00:05.236,694] <inf> mcuboot_util: DIAG bstm: primary done, reading secondary
20:57:17.781: [00:00:05.238,006] <inf> mcuboot_util: DIAG bstm: secondary state read done
20:57:17.781: [00:00:05.238,006] <inf> mcuboot_util: Image index: 0, Swap type: none
20:57:17.781: [00:00:05.238,037] <inf> app: Application.cpp: confirmRunningImage() [2484]:: Running image already confirmed, nothing to do
20:57:17.781: [00:00:05.239,044] <inf> app: BleServerController.cpp: processIntCmd() [ 341]:: Advertising started
Received SIGTERM, exiting
Exited by user request
 
 WARN probe_rs::rtt: Buffer for up channel 1 not initialized
 WARN probe_rs::rtt: Buffer for up channel 2 not initialized
 WARN probe_rs::rtt: Buffer for down channel 1 not initialized
 WARN probe_rs::rtt: Buffer for down channel 2 not initialized
Failed to create readline
O��)��pFG����  (  ]�E��]�1 dQ���??pQpQpQpQp  �%�%�%�%
22:22:07.347: index: 0, Swap type: none
22:22:07.347: I: Primary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
22:22:07.347: I: Secondary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
22:22:07.347: I: Boot source: none
22:22:07.347: I: DIAG ncs img=1 magic=0x96f3b83d flags=0x100 reset_addr=0x1023291
22:22:07.347: I: DIAG ncs ASSIGNED img=1
22:22:07.347: I: Image index: 1, Swap type: none
22:22:07.347: I: DIAG skip prepare img=2
22:22:07.347: I: Bootloader chainload address offset: 0x28000
22:22:07.347: I: Image version: v0.1.2
22:22:07.347: I: Jumping to the first image slot
22:22:07.347: *** Booting MCUboot v2.3.0-dev-3de5b4df5f9f ***
22:22:07.347: *** Using nRF Connect SDK v3.3.1-1d7a0b0e49b8 ***
22:22:07.347: *** Using Zephyr OS v4.[00:01:10.080,718] <inf> app: BleCore.cpp: onConnected() [2178]:: New BLE connection established: [XX:XX:XX:XX:XX:02 (public)], MTU: 23 bytes
22:22:12.125: [00:01:10.081,359] <inf> app: ---- Basic nonce (len: 13): ----
22:22:12.125: [00:01:10.081,359] <inf> app: Content:
22:22:12.125:                               f6 de 97 c1 7b 74 67 fa  d6 b2 02 2f 83          |....{tg. .../.   
22:22:12.125: [00:01:10.081,420] <inf> app: ---- Basic nonce end  ----
22:22:12.125: [00:01:10.106,506] <inf> app: DeviceStateManager.cpp: bleOnConnect() [ 272]:: Connected
22:22:12.125: [00:01:10.106,567] <wrn> app: GeneralFsm.hpp: setState() [  78]:: State: ACTIVE: WAIT CONN => ACTIVE: CONNECTED
22:22:12.125: [00:01:10.107,025] <inf> app: BleCore.cpp: onDataLengthUpdated() [2269]:: LE data len updated: TX (len: 251 bytes time: 2120 us) RX (len: 251 bytes time: 2120 us)
22:22:12.125: [00:01:10.107,147] <inf> app: Application.cpp: handleNewState() [2295]:: Handling new device state...
22:22:12.125: [00:01:10.153,503] <inf> app: BleCore.cpp: mtuExchangeFuncful
22:22:12.125: 
22:22:12.858: *** Booting MCUboot v2.3.0-dev-3de5b4df5f9f ***
22:22:12.858: *** Using nRF Connect SDK v3.3.1-1d7a0b0e49b8 ***
22:22:12.858: *** Using Zephyr OS v4.3.99-37e6c28576ee ***
22:22:12.858: I: Starting bootloader
22:22:12.858: I: Primary image: magic=good, swap_type=0x4, copy_done=0x1, image_ok=0x1
22:22:12.858: I: Secondary image: magic=good, swap_type=0x2, copy_done=0x3, image_ok=0x3
22:22:12.858: I: Boot source: none
22:22:12.858: I: DIAG ncs img=0 magic=0x96f3b83d flags=0x4 reset_addr=0x3ee3fbc2
22:22:12.858: I: DIAG ncs ASSIGNED img=0
22:22:12.858: I: Image index: 0, Swap type: test
22:22:22.175: I: Primary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
22:22:22.175: I: Secondary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
22:22:22.175: I: Boot source: none
22:22:22.175: I: DIAG ncs img=1 magic=0x96f3b83d flags=0x100 reset_addr=0x1023291
22:22:22.175: I: DIAG ncs ASSIGNED img=1
22:22:22.175: I: Image index: 1, Swap type: none
22:22:22.175: I: DIAG skip prepare img=2
22:22:22.799: I: Starting swap using move algorithm.
22:23:23.393: I: Bootloader chainload address offset: 0x28000
22:23:23.393: I: Image version: v0.1.3
22:23:23.393: I: Jumping to the first image slot
22:23:24.630: *** Booting My Application v0.1.3-0d268237374f ***
22:23:24.630: *** Using nRF Connect SDK v3.3.1-1d7a0b0e49b8 ***
22:23:24.630: *** Using Zephyr OS v4.3.99-37e6c28576ee ***
22:23:24.630: [00:00:00.051,452] <wrn> app: main.cpp: main() [  47]:: nRF5340 app, last-good-ncs-2.6-95-g0d26823-d
22:23:24.630: [00:00:00.056,274] <wrn> app: GeneralFsm.hpp: setState() [  78]:: State: <UNDEFINED> => STANDBY
22:23:24.630: [00:00:00.056,335] <inf> app: Npm1300.cpp: init() [ 244]:: nRF Fuel Gauge version: 1.1.1
22:23:24.630: [00:00:00.056,915] <inf> app: Npm1300.cpp: initChargerState() [ 806]:: Charger init (regs: SET: 0x1; CLR: 0x1)
22:23:24.630: [00:00:00.057,739] <inf> app: Npm1300.cpp: controlCharger() [ 855]:: Charger disabled (regs: SET: 0x0; CLR: 0x0)
22:23:24.630: [00:00:00.559,692] <wrn> app: Npm1300.cpp: init() [ 283]:: (init) NPM1300 data: 4.174000V, -0.000000A, 25.205627°C
22:23:25.583: [00:00:01.061,645] <wrn> app: Npm1300.cpp: init() [ 283]:: (init) NPM1300 data: 4.174000V, -0.000000A, 25.205627°C
22:23:25.583: [00:00:01.063,812] <inf> app: Npm1300.cpp: controlCharger() [ 855]:: Charger enabled (regs: SET: 0x1; CLR: 0x1)
22:23:27.488: [00:00:02.979,125] <inf> app: AFE4403.cpp: findCapacitanceConfig() [2000]:: Finding feedback capacitor: Target: 5, Best: 5, Config: 0x00000000
22:23:27.653: [00:00:04.108,734] <inf> app: Application.cpp: initCrypto() [ 893]:: BLE session key: built-in default (no valid override)
22:23:27.653: [00:00:04.113,952] <inf> fs_nvs: 2 Sectors of 4096 bytes
22:23:27.653: [00:00:04.113,983] <inf> fs_nvs: alloc wra: 0, fe8
22:23:27.653: [00:00:04.113,983] <inf> fs_nvs: data wra: 0, 0
22:23:27.653: [00:00:04.114,074] <wrn> app: Application.cpp: initCrypto() [ 918]:: BLE app-layer encryption: ENCRYPTED
22:23:27.653: [00:00:04.114,135] <wrn> app: Application.cpp: init() [ 532]:: Charger interlock: ON
22:23:27.653: [00:00:04.114,196] <wrn> app: Application.cpp: init() [ 543]:: OTA version gate: OFF (factory default)
22:23:27.653: [00:00:04.114,257] <inf> app: LedFillCapSetting.cpp: init() [  59]:: LED fill cap: 30 %
22:23:27.653: [00:00:04.114,288] <inf> app: AutoAnimBrightSetting.cpp: init() [  61]:: Auto-animation brightness cap: 20 %
22:23:27.653: [00:00:04.115,692] <inf> app: BleCore.cpp: addService() [ 333]:: Adding chars...
22:23:27.653: [00:00:04.115,936] <inf> app: BleCore.cpp: addService() [ 
22:23:27.717: 
22:23:27.717: [00:00:04.142,761] <wrn> app: GeneralFsm.hpp: setState() [  78]:: State: STANDBY => ACTIVE: WAIT CONN
22:23:27.717: [00:00:04.145,263] <wrn> app: BatteryStateMonitorTask.hpp: start() [ 284]:: Charger is connected
22:23:27.717: [00:00:04.145,294] <inf> app: BatteryStateMonitorTask.hpp: notifyObservers() [1139]:: charger: connected
22:23:27.717: [00:00:04.145,324] <inf> app: Application.cpp: handleChargerState() [1890]:: Handling new charger state...
22:23:27.717: [00:00:04.145,568] <inf> app: BatteryStateMonitorTask.hpp: notifyObservers() [1165]:: bat state: full
22:23:27.717: [00:00:04.145,599] <inf> app: Application.cpp: handleBatteryState() [2216]:: Handling new battery state...
22:23:27.717: [00:00:04.148,406] <err> app: Application.cpp: powerDownUnusedPeripherals() [1864]:: Failed to suspend LSM6DSM (err: -120)
22:23:27.717: [00:00:04.148,895] <wrn> app: Application.cpp: armTaskWatchdogs() [1656]:: Task watchdog armed
Received SIGTERM, exiting
22:23:27.717: [00:00:04.148,925] <inf> app: Application.cpp: handleNewState() [2295]:: Handling new deviceExited by user request
 
### ROW 3 part 1: broken v0.1.3 swap-in (warm BLE reset)
 WARN probe_rs::rtt: Buffer for up channel 1 not initialized
 WARN probe_rs::rtt: Buffer for up channel 2 not initialized
 WARN probe_rs::rtt: Buffer for down channel 1 not initialized
 WARN probe_rs::rtt: Buffer for down channel 2 not initialized
Failed to create readline
O��)��pFG����  (  ]�E��]�1 dQ���??pQpQpQpQp  �%�%�%�%
22:26:31.574: index: 0, Swap type: none
22:26:31.574: I: Primary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
22:26:31.574: I: Secondary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
22:26:31.574: I: Boot source: none
22:26:31.574: I: DIAG ncs img=1 magic=0x96f3b83d flags=0x100 reset_addr=0x1023291
22:26:31.574: I: DIAG ncs ASSIGNED img=1
22:26:31.574: I: Image index: 1, Swap type: none
22:26:31.574: I: DIAG skip prepare img=2
22:26:31.574: I: Bootloader chainload address offset: 0x28000
22:26:31.574: I: Image version: v0.1.2
22:26:31.574: I: Jumping to the first image slot
22:26:31.574: *** Booting MCUboot v2.3.0-dev-3de5b4df5f9f ***
22:26:31.574: *** Using nRF Connect SDK v3.3.1-1d7a0b0e49b8 ***
22:26:31.574: *** Using Zephyr OS v4.[00:01:13.534,484] <inf> app: BleCore.cpp: onConnected() [2178]:: New BLE connection established: [XX:XX:XX:XX:XX:02 (public)], MTU: 23 bytes
22:26:35.527: [00:01:13.535,003] <inf> app: ---- Basic nonce (len: 13): ----
22:26:35.527: [00:01:13.535,034] <inf> app: Content:
22:26:35.527:                               dd 83 c4 46 1b cc 5a 84  14 93 04 67 a1          |...F..Z. ...g.   
22:26:35.527: [00:01:13.535,064] <inf> app: ---- Basic nonce end  ----
22:26:35.527: [00:01:13.558,624] <inf> app: DeviceStateManager.cpp: bleOnConnect() [ 272]:: Connected
22:26:35.527: [00:01:13.558,685] <wrn> app: GeneralFsm.hpp: setState() [  78]:: State: ACTIVE: WAIT CONN => ACTIVE: CONNECTED
22:26:35.527: [00:01:13.559,143] <inf> app: BleCore.cpp: onDataLengthUpdated() [2269]:: LE data len updated: TX (len: 251 bytes time: 2120 us) RX (len: 251 bytes time: 2120 us)
22:26:35.527: [00:01:13.559,234] <inf> app: Application.cpp: handleNewState() [2295]:: Handling new device state...
22:26:35.527: [00:01:13.607,666] <inf> app: BleCore.cpp: mtuExchangeFuncful
22:26:35.527: 
22:26:36.265: *** Booting MCUboot v2.3.0-dev-3de5b4df5f9f ***
22:26:36.265: *** Using nRF Connect SDK v3.3.1-1d7a0b0e49b8 ***
22:26:36.265: *** Using Zephyr OS v4.3.99-37e6c28576ee ***
22:26:36.265: I: Starting bootloader
22:26:36.265: I: Primary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
22:26:36.265: I: Secondary image: magic=good, swap_type=0x2, copy_done=0x3, image_ok=0x3
22:26:36.265: I: Boot source: none
22:26:36.265: I: DIAG ncs img=0 magic=0x96f3b83d flags=0x4 reset_addr=0x9769f57c
22:26:36.265: I: DIAG ncs ASSIGNED img=0
22:26:36.265: I: Image index: 0, Swap type: test
22:26:45.654: I: Primary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
22:26:45.654: I: Secondary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
22:26:45.654: I: Boot source: none
22:26:45.654: I: DIAG ncs img=1 magic=0x96f3b83d flags=0x100 reset_addr=0x1023291
22:26:45.654: I: DIAG ncs ASSIGNED img=1
22:26:45.654: I: Image index: 1, Swap type: none
22:26:45.654: I: DIAG skip prepare img=2
22:26:46.280: I: Starting swap using move algorithm.
22:27:46.775: I: Bootloader chainload address offset: 0x28000
22:27:46.775: I: Image version: v0.1.3
22:27:46.775: I: Jumping to the first image slot
22:27:48.048: *** Booting My Application v0.1.3-0d268237374f ***
22:27:48.048: *** Using nRF Connect SDK v3.3.1-1d7a0b0e49b8 ***
22:27:48.048: *** Using Zephyr OS v4.3.99-37e6c28576ee ***
22:27:48.048: [00:00:00.051,239] <wrn> app: main.cpp: main() [  47]:: nRF5340 app, last-good-ncs-2.6-95-g0d26823-d
22:27:48.048: [00:00:00.056,091] <wrn> app: GeneralFsm.hpp: setState() [  78]:: State: <UNDEFINED> => STANDBY
22:27:48.048: [00:00:00.056,152] <inf> app: Npm1300.cpp: init() [ 244]:: nRF Fuel Gauge version: 1.1.1
22:27:48.048: [00:00:00.056,732] <inf> app: Npm1300.cpp: initChargerState() [ 806]:: Charger init (regs: SET: 0x1; CLR: 0x1)
22:27:48.048: [00:00:00.057,525] <inf> app: Npm1300.cpp: controlCharger() [ 855]:: Charger disabled (regs: SET: 0x0; CLR: 0x0)
22:27:48.048: [00:00:00.559,448] <wrn> app: Npm1300.cpp: init() [ 283]:: (init) NPM1300 data: 4.174000V, -0.000000A, 25.000000°C
22:27:49.040: [00:00:01.061,431] <wrn> app: Npm1300.cpp: init() [ 283]:: (init) NPM1300 data: 4.174000V, -0.000000A, 25.000000°C
22:27:49.040: [00:00:01.063,568] <inf> app: Npm1300.cpp: controlCharger() [ 855]:: Charger enabled (regs: SET: 0x1; CLR: 0x1)
22:27:50.907: [00:00:02.978,759] <inf> app: AFE4403.cpp: findCapacitanceConfig() [2000]:: Finding feedback capacitor: Target: 5, Best: 5, Config: 0x00000000
22:27:51.034: [00:00:04.108,306] <inf> app: Application.cpp: initCrypto() [ 893]:: BLE session key: built-in default (no valid override)
22:27:51.034: [00:00:04.113,525] <inf> fs_nvs: 2 Sectors of 4096 bytes
22:27:51.034: [00:00:04.113,525] <inf> fs_nvs: alloc wra: 0, fe8
22:27:51.034: [00:00:04.113,525] <inf> fs_nvs: data wra: 0, 0
22:27:51.034: [00:00:04.113,616] <wrn> app: Application.cpp: initCrypto() [ 918]:: BLE app-layer encryption: ENCRYPTED
22:27:51.034: [00:00:04.113,677] <wrn> app: Application.cpp: init() [ 532]:: Charger interlock: ON
22:27:51.034: [00:00:04.113,769] <wrn> app: Application.cpp: init() [ 543]:: OTA version gate: OFF (factory default)
22:27:51.034: [00:00:04.113,800] <inf> app: LedFillCapSetting.cpp: init() [  59]:: LED fill cap: 30 %
22:27:51.034: [00:00:04.113,861] <inf> app: AutoAnimBrightSetting.cpp: init() [  61]:: Auto-animation brightness cap: 20 %
22:27:51.034: [00:00:04.115,234] <inf> app: BleCore.cpp: addService() [ 333]:: Adding chars...
22:27:51.034: [00:00:04.115,509] <inf> app: BleCore.cpp: addService() [  addService() [ 333]:: Adding chars...
22:27:51.043: [00:00:04.115,783] <inf> app: BleCore.cpp: addService() [ 406]:: Adding descriptors...
22:27:51.043: [00:00:04.115,875] <inf> app: BleCore.cpp: addService() [ 406]:: Adding descriptors...
22:27:51.064: [00:00:04.115,997] <inf> app: BleCore.cpp: addService() [ 406]:: Adding descriptors...
22:27:51.064: [00:00:04.116,210] <inf> app: BleCore.cpp: addService() [ 333]:: Adding chars...
22:27:51.064: [00:00:04.116,241] <inf> app: BleCore.cpp: addService() [ 406]:: Adding descriptors...
22:27:51.064: [00:00:04.116,333] <inf> app: BleCore.cpp: addService() [ 406]:: Adding descriptors...
22:27:51.064: [00:00:04.116,516] <inf> app: BleCore.cpp: addService() [ 333]:: Adding chars...
22:27:51.064: [00:00:04.116,577] <inf> app: BleCore.cpp: addService() [ 406]:: Adding descriptors...
22:27:51.064: [00:00:04.116,638] <inf> app: BleCore.cpp: addService() [ 406]:: Adding descriptors...
22:27:51.064: [00:00:04.116,821] <inf> app: BleCore.cpp: addService() [ 333]:: Adding chars...
22:27:51.064: [00:00:04.139,343] <inf> bt_hci_core: HW Platform: Nordic Semiconductor (0x0002)
22:27:51.064: [00:00:04.139,373] <inf> bt_hci_core: HW Variant: nRF53x (0x0003)
22:27:51.064: [00:00:04.139,404] <inf> bt_hci_core: Firmware: Standard Bluetooth controller (0x00) Version 252.31313 Build 1865177321
22:27:51.070: [00:00:04.141,998] <inf> bt_hci_core: HCI transport: IPC
22:27:51.093: [00:00:04.142,089] <inf> bt_hci_core: Identity: XX:XX:XX:XX:XX:01 (random)
22:27:51.093: [00:00:04.142,150] <inf> bt_hci_core: HCI: version 6.3 (0x11) revision 0x201f, manufacturer 0x0059
22:27:51.093: [00:00:04.142,181] <inf> bt_hci_core: LMP: version 6.3 (0x11) subver 0x201f
22:27:51.093: [00:00:04.142,669] <inf> app: DeviceStateManager.cpp: benchForceAdvertise() [ 150]:: BENCH BROKEN IMAGE v0.1.3 -- advertising deliberately disabled
22:27:51.093: [00:00:04.145,202] <wrn> app: BatteryStateMonitorTask.hpp: start() [ 284]:: Charger is connected
22:27:51.093: [00:00:04.145,233] <inf> app: BatteryStateMonitorTask.hpp: notifyObservers() [1139]:: charger: connected
22:27:51.093: [00:00:04.145,263] <inf> app: Application.cpp: handleChargerState() [1890]:: Handling new charger state...
22:27:51.093: [00:00:04.145,507] <inf> app: BatteryStateMonitorTask.hpp: notifyObservers() [1165]:: bat state: full
22:27:51.093: [00:00:04.145,538] <inf> app: Application.cpp: handleBatteryState() [2216]:: Handling new battery state...
22:27:51.102: [00:00:04.148,345] <err> app: Application.cpp: powerDownUnusedPeripherals() [1864]:: Failed to suspend LSM6DSM (err: -120)
22:27:51.102: [00:00:04.148,803] <wrn> app: Application.cpp: armTaskWatchdogs() [1656]:: Task watchdog armed
22:27:51.102: [00:00:04.148,925] <wrn> app: DisplayTask.hpp: evtHandler() [ 101]:: Activating LED boost conv
Received SIGTERM, exiting
Exited by user request

### ROW 3 part 2: manual probe-rs reset -> MCUboot REVERT to v0.1.2
 WARN probe_rs::rtt: Buffer for up channel 1 not initialized
 WARN probe_rs::rtt: Buffer for up channel 2 not initialized
 WARN probe_rs::rtt: Buffer for down channel 1 not initialized
 WARN probe_rs::rtt: Buffer for down channel 2 not initialized
Failed to create readline
*** Booting MCUboot v2.3.0-dev-3de5b4df5f9f ***
22:29:37.736: *** Using nRF Connect SDK v3.3.1-1d7a0b0e49b8 ***
22:29:37.736: *** Using Zephyr OS v4.3.99-37e6c28576ee ***
22:29:37.736: I: Starting bootloader
22:29:37.736: I: Primary image: magic=good, swap_type=0x2, copy_done=0x1, image_ok=0x3
22:29:37.736: I: Secondary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
22:29:37.736: I: Boot source: none
22:29:37.736: I: DIAG ncs img=0 magic=0x96f3b83d flags=0x4 reset_addr=0xa78fbdc3
22:29:37.736: I: DIAG ncs ASSIGNED img=0
22:29:37.736: I: Image index: 0, Swap type: revert
22:29:47.076: I: Primary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
22:29:47.076: I: Secondary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
22:29:47.076: I: Boot source: none
22:29:47.076: I: DIAG ncs img=1 magic=0x96f3b83d flags=0x100 reset_addr=0x1023291
22:29:47.076: I: DIAG ncs ASSIGNED img=1
22:29:47.076: I: Image index: 1, Swap type: none
22:29:47.076: I: DIAG skip prepare img=2
22:29:47.749: I: Starting swap using move algorithm.
22:29:47.749: I: Secondary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
22:30:48.389: I: Bootloader chainload address offset: 0x28000
22:30:48.389: I: Image version: v0.1.2
22:30:48.389: I: Jumping to the first image slot
22:30:49.539: *** Booting My Application v0.1.2-0d268237374f ***
22:30:49.555: *** Using nRF Connect SDK v3.3.1-1d7a0b0e49b8 ***
22:30:49.555: *** Using Zephyr OS v4.3.99-37e6c28576ee ***
22:30:49.555: [00:00:00.051,361] <wrn> app: main.cpp: main() [  47]:: nRF5340 app, last-good-ncs-2.6-95-g0d26823-d
22:30:49.555: [00:00:00.056,182] <wrn> app: GeneralFsm.hpp: setState() [  78]:: State: <UNDEFINED> => STANDBY
22:30:49.555: [00:00:00.056,213] <inf> app: Npm1300.cpp: init() [ 244]:: nRF Fuel Gauge version: 1.1.1
22:30:49.555: [00:00:00.056,823] <inf> app: Npm1300.cpp: initChargerState() [ 806]:: Charger init (regs: SET: 0x1; CLR: 0x1)
22:30:49.555: [00:00:00.057,617] <inf> app: Npm1300.cpp: controlCharger() [ 855]:: Charger disabled (regs: SET: 0x0; CLR: 0x0)
22:30:49.555: [00:00:00.559,600] <wrn> app: Npm1300.cpp: init() [ 283]:: (init) NPM1300 data: 4.174000V, -0.000000A, 25.308533°C
22:30:50.625: [00:00:01.061,523] <wrn> app: Npm1300.cpp: init() [ 283]:: (init) NPM1300 data: 4.174000V, -0.000000A, 25.308533°C
22:30:50.625: [00:00:01.063,690] <inf> app: Npm1300.cpp: controlCharger() [ 855]:: Charger enabled (regs: SET: 0x1; CLR: 0x1)
22:30:52.489: [00:00:02.978,881] <inf> app: AFE4403.cpp: findCapacitanceConfig() [2000]:: Finding feedback capacitor: Target: 5, Best: 5, Config: 0x00000000
22:30:52.714: [00:00:04.108,459] <inf> app: Application.cpp: initCrypto() [ 893]:: BLE session key: built-in default (no valid override)
22:30:52.714: [00:00:04.113,708] <inf> fs_nvs: 2 Sectors of 4096 bytes
22:30:52.714: [00:00:04.113,708] <inf> fs_nvs: alloc wra: 0, fe8
22:30:52.714: [00:00:04.113,708] <inf> fs_nvs: data wra: 0, 0
22:30:52.714: [00:00:04.113,800] <wrn> app: Application.cpp: initCrypto() [ 918]:: BLE app-layer encryption: ENCRYPTED
22:30:52.714: [00:00:04.113,861] <wrn> app: Application.cpp: init() [ 532]:: Charger interlock: ON
22:30:52.714: [00:00:04.113,952] <wrn> app: Application.cpp: init() [ 543]:: OTA version gate: OFF (factory default)
22:30:52.714: [00:00:04.113,983] <inf> app: LedFillCapSetting.cpp: init() [  59]:: LED fill cap: 30 %
22:30:52.714: [00:00:04.114,044] <inf> app: AutoAnimBrightSetting.cpp: init() [  61]:: Auto-animation brightness cap: 20 %
22:30:52.714: [00:00:04.115,417] <inf> app: BleCore.cpp: addService() [ 333]:: Adding chars...
22:30:52.714: [00:00:04.115,692] <inf> app: BleCore.cpp: addService() [ 
22:30:52.714: 
22:30:54.795: [00:00:05.236,602] <inf> app: BleServerController.cpp: processIntCmd() [ 337]:: Starting advertising without whitelist
22:30:54.795: [00:00:05.236,724] <inf> app: BleCore.cpp: advertisingStart() [1101]:: Adv data size: 3; ScanRespPacketsData size: 1
22:30:54.795: [00:00:05.238,403] <inf> mcuboot_util: Image index: 0, Swap type: none
22:30:54.795: [00:00:05.238,433] <inf> app: Application.cpp: confirmRunningImage() [2484]:: Running image already confirmed, nothing to do
22:30:54.795: [00:00:05.239,379] <inf> app: BleServerController.cpp: processIntCmd() [ 341]:: Advertising started
Received SIGTERM, exiting
Exited by user request
 
 WARN probe_rs::rtt: Buffer for up channel 1 not initialized
 WARN probe_rs::rtt: Buffer for up channel 2 not initialized
 WARN probe_rs::rtt: Buffer for down channel 1 not initialized
 WARN probe_rs::rtt: Buffer for down channel 2 not initialized
Failed to create readline
O��)��pFG����  (  ]�E��]�1 dQ���??pQpQpQpQp  �%�%�%�%
21:54:46.179: k=0x3
21:54:46.179: I: Secondary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
21:54:46.179: I: Boot source: none
21:54:46.179: I: Image index: 1, Swap type: none
21:54:46.179: I: DIAG skip prepare img=2
21:54:46.179: I: Bootloader chainload address offset: 0x28000
21:54:46.179: I: Image version: v0.1.2
21:54:46.179: I: Jumping to the first image slot
21:54:46.179: *** Booting MCUboot v2.3.0-dev-3de5b4df5f9f ***
21:54:46.179: *** Using nRF Connect SDK v3.3.1-1d7a0b0e49b8 ***
21:54:46.179: *** Using Zephyr OS v4.3.99-37e6c28576ee ***
21:54:46.179: I: Starting bootloader
21:54:46.179: I: Primary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
21:54:46.179: I: Secondary image: magic=unset, swap_type=0x1, copy_done=0x3, image_o[00:01:01.486,450] <inf> app: BleCore.cpp: onDisconnected() [2203]:: [XX:XX:XX:XX:XX:02 (public)] BLE device disconnected with reason 19
21:54:46.919: [00:01:01.486,480] <inf> app: DeviceStateManager.cpp: bleOnDisconnect() [ 280]:: Disconnected
21:54:46.919: [00:01:01.486,541] <wrn> app: GeneralFsm.hpp: setState() [  78]:: State: ACTIVE: CONNECTED => ACTIVE: WAIT CONN
21:54:46.919: [00:01:01.486,877] <inf> app: Application.cpp: handleNewState() [2295]:: Handling new device state...
21:54:46.919: [00:01:01.486,999] <inf> app: BleServerController.cpp: processIntCmd() [ 337]:: Starting advertising without whitelist
21:54:46.919: [00:01:01.487,030] <inf> app: BleCore.cpp: advertisingStart() [1101]:: Adv data size: 3; ScanRespPacketsData size: 1
21:54:46.919: [00:01:01.489,440] <inf> app: BleServerController.cpp: processIntCmd() [ 341]:: Advertising started
21:54:49.728: [00:01:05.181,030] <inf> app: BleCore.cpp: onConnected() [2178]:: New BLE connection established: [XX:XX:XX:XX:XX:02 (public)], MTU: 23 bytes
21:54:49.728: [00:01:05.181,549] <inf> app: ---- Basic nonce (len: 13): ----
21:54:49.728: [00:01:05.181,579] <inf> app: Content:
21:54:49.728:                               04 e4 55 b5 e9 2e 75 25  a9 1f 2d 83 27          |..U...u% ..-.'   
21:54:49.728: [00:01:05.181,610] <inf> app: ---- Basic nonce end  ----
21:54:49.728: [00:01:05.205,139] <inf> app: DeviceStateManager.cpp: bleOnConnect() [ 272]:: Connected
21:54:49.728: [00:01:05.205,200] <wrn> app: GeneralFsm.hpp: setState() [  78]:: State: ACTIVE: WAIT CONN => ACTIVE: CONNECTED
21:54:49.728: [00:01:05.205,627] <inf> app: Application.cpp: handleNewState() [2295]:: Handling new device state...
21:54:49.728: [00:01:05.206,207] <inf> app: BleCore.cpp: onDataLengthUpdated() [2269]:: LE data len updated: TX (len: 251 bytes time: 2120 us) RX (len: 251 bytes time: 2120 us)
21:54:49.728: [00:01:05.258,209] <inf> app: BleCore.cpp: mtuExchangeFuncful
21:54:49.728: 
21:54:50.567: *** Booting MCUboot v2.3.0-dev-3de5b4df5f9f ***
21:54:50.567: *** Using nRF Connect SDK v3.3.1-1d7a0b0e49b8 ***
21:54:50.567: *** Using Zephyr OS v4.3.99-37e6c28576ee ***
21:54:50.567: I: Starting bootloader
21:54:50.567: I: Primary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
21:54:50.567: I: Secondary image: magic=good, swap_type=0x2, copy_done=0x3, image_ok=0x3
21:54:50.567: I: Boot source: none
21:54:50.567: I: Primary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
21:54:50.567: I: Secondary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
21:54:50.567: I: Boot source: none
21:54:50.567: I: Image index: 1, Swap type: none
21:54:50.567: I: DIAG skip prepare img=2
21:54:50.567: I: DIAG enter sec_erase img=0 size=0xd3000
21:55:06.371: I: DIAG exit sec_erase img=0 rc=0
21:55:06.371: E: Erase secondary: img 0: 0
21:55:06.371: I: DIAG enter sec_erase img=2 size=0xd3000
21:55:24.246: I: DIAG exit sec_erase img=2 rc=0
21:55:24.246: E: Erase secondary: img 2: 0
21:55:25.388: I: Bootloader chainload address offset: 0x28000
21:55:25.388: I: Image version: v0.1.2
21:55:25.388: I: Jumping to the first image slot
21:55:26.643: *** Booting My Application v0.1.2-0d268237374f ***
21:55:26.643: *** Using nRF Connect SDK v3.3.1-1d7a0b0e49b8 ***
21:55:26.643: *** Using Zephyr OS v4.3.99-37e6c28576ee ***
21:55:26.643: [00:00:00.051,361] <wrn> app: main.cpp: main() [  47]:: nRF5340 app, last-good-ncs-2.6-95-g0d26823-d
21:55:26.643: [00:00:00.056,182] <wrn> app: GeneralFsm.hpp: setState() [  78]:: State: <UNDEFINED> => STANDBY
21:55:26.643: [00:00:00.056,243] <inf> app: Npm1300.cpp: init() [ 244]:: nRF Fuel Gauge version: 1.1.1
21:55:26.643: [00:00:00.056,823] <inf> app: Npm1300.cpp: initChargerState() [ 806]:: Charger init (regs: SET: 0x1; CLR: 0x1)
21:55:26.643: [00:00:00.057,647] <inf> app: Npm1300.cpp: controlCharger() [ 855]:: Charger disabled (regs: SET: 0x0; CLR: 0x0)
21:55:26.643: [00:00:00.559,631] <wrn> app: Npm1300.cpp: init() [ 283]:: (init) NPM1300 data: 4.174000V, -0.000000A, 25.617737°C
21:55:27.682: [00:00:01.061,553] <wrn> app: Npm1300.cpp: init() [ 283]:: (init) NPM1300 data: 4.174000V, -0.000000A, 25.617737°C
21:55:27.682: [00:00:01.063,720] <inf> app: Npm1300.cpp: controlCharger() [ 855]:: Charger enabled (regs: SET: 0x1; CLR: 0x1)
21:55:29.547: [00:00:02.978,912] <inf> app: AFE4403.cpp: findCapacitanceConfig() [2000]:: Finding feedback capacitor: Target: 5, Best: 5, Config: 0x00000000
21:55:29.773: [00:00:04.108,489] <inf> app: Application.cpp: initCrypto() [ 893]:: BLE session key: built-in default (no valid override)
21:55:29.773: [00:00:04.113,739] <inf> fs_nvs: 2 Sectors of 4096 bytes
21:55:29.773: [00:00:04.113,739] <inf> fs_nvs: alloc wra: 0, fe8
21:55:29.773: [00:00:04.113,739] <inf> fs_nvs: data wra: 0, 0
21:55:29.773: [00:00:04.113,830] <wrn> app: Application.cpp: initCrypto() [ 918]:: BLE app-layer encryption: ENCRYPTED
21:55:29.773: [00:00:04.113,891] <wrn> app: Application.cpp: init() [ 532]:: Charger interlock: ON
21:55:29.773: [00:00:04.113,983] <wrn> app: Application.cpp: init() [ 543]:: OTA version gate: OFF (factory default)
21:55:29.773: [00:00:04.114,013] <inf> app: LedFillCapSetting.cpp: init() [  59]:: LED fill cap: 30 %
21:55:29.773: [00:00:04.114,074] <inf> app: AutoAnimBrightSetting.cpp: init() [  61]:: Auto-animation brightness cap: 20 %
21:55:29.773: [00:00:04.115,447] <inf> app: BleCore.cpp: addService() [ 333]:: Adding chars...
21:55:29.773: [00:00:04.115,722] <inf> app: BleCore.cpp: addService() [ 
21:55:29.773: 
21:55:31.850: [00:00:05.236,846] <inf> app: BleServerController.cpp: processIntCmd() [ 337]:: Starting advertising without whitelist
21:55:31.850: [00:00:05.236,999] <inf> app: BleCore.cpp: advertisingStart() [1101]:: Adv data size: 3; ScanRespPacketsData size: 1
21:55:31.850: [00:00:05.238,677] <inf> mcuboot_util: Image index: 0, Swap type: none
21:55:31.850: [00:00:05.238,708] <inf> app: Application.cpp: confirmRunningImage() [2484]:: Running image already confirmed, nothing to do
21:55:31.850: [00:00:05.239,654] <inf> app: BleServerController.cpp: processIntCmd() [ 341]:: Advertising started
Received SIGTERM, exiting
Exited by user request
 ncs-3.3.1-mcuboot-secured-swap.patch 
# Secured-line swap-with-revert — hardware acceptance proof

Bench-proven on a single nRF5340 custom board, 2026-08-23. All three acceptance
rows PASS on the SECURED line (b0 + s0/s1, AES-128 encrypted images, MCUboot
swap-using-move) over the real field path — a warm mcumgr/BLE reset, not a pin
reset.

Every row below required the four SDK patches in
`ncs-3.3.1-mcuboot-secured-swap.patch`. Without them the encrypted secured
line can never complete an OTA: the staged image is silently erased on every
boot.

## 1. Acceptance table

| Row | Image | Boots | Advertises | Swap executes | Self-confirms | Persists / reverts | RESETREAS |
|---|---|---|---|---|---|---|---|
| 1 | baseline v0.1.2 (SWD-flashed) | yes | yes | n/a | n/a (wired flash, already confirmed) | `v0.1.2 [active,confirmed,bootable]` | `0x08` (SREQ only) |
| 2 | good v0.1.3 (BLE OTA, warm reset) | yes | yes | **yes**, `Swap type: test` | **yes** | **PASS** — 2nd reset still `v0.1.3 [active,confirmed,bootable]`, no revert | `0x08` |
| 3 | broken v0.1.3 (BLE OTA, warm reset) | yes | **no** (by design) | **yes**, `Swap type: test` | **no** (never reaches the confirm point) | **REVERTS** — `Swap type: revert` → `v0.1.2 [active,confirmed,bootable]`, advertising | `0x00` while broken image ran (no self-reset), `0x08` after manual reset |

No `DOG0` (watchdog) and no `LOCKUP` bit in RESETREAS in any row.

### Row 2 — good image swaps in, self-confirms, persists

MCUboot log (`run14b-artifacts/rtt-row2-swap-pass.log`):

```
22:22:12.858  I: Starting bootloader
22:22:12.858  I: DIAG ncs img=0 magic=0x96f3b83d flags=0x4 reset_addr=0x3ee3fbc2
22:22:12.858  I: DIAG ncs ASSIGNED img=0
22:22:12.858  I: Image index: 0, Swap type: test
22:22:22.799  I: Starting swap using move algorithm.
22:23:23.393  I: Image version: v0.1.3
22:23:23.393  I: Jumping to the first image slot
```

`flags=0x4` is `IMAGE_F_ENCRYPTED_AES128` and `reset_addr=0x3ee3fbc2` is
ciphertext, outside the valid primary range `[0x28000,0xfc000]`. Before the
keystone patch this exact input produced `RETURN-NONE` and the slot was erased;
with the patch it is `ASSIGNED` and the swap proceeds.

State after, read over BLE (mcumgr `image list`):

```
image 0 slot 0 v0.1.3 [active,confirmed,bootable]
image 0 slot 1 v0.1.2 [bootable]
```

`confirmed` is the application self-confirming via its
`confirmRunningImage()` path once advertising and the SMP transport
were up. The old image moved down to slot 1, which is swap-using-move
behaviour. A further reset left the state unchanged (persistence proven).

### Row 3 — broken image swaps in, never confirms, reverts

Swap-in and broken-image banner (`run14b-artifacts/rtt-row3-revert.log`):

```
22:26:36.265  I: Starting bootloader
22:26:36.265  I: DIAG ncs img=0 magic=0x96f3b83d flags=0x4 reset_addr=0x9769f57c
22:26:36.265  I: Image index: 0, Swap type: test
22:26:46.280  I: Starting swap using move algorithm.
22:27:46.775  I: Image version: v0.1.3
22:27:46.775  I: Jumping to the first image slot
22:27:51.093  <inf> app: benchForceAdvertise(): BENCH BROKEN IMAGE v0.1.3 -- advertising deliberately disabled
```

The broken image then ran for 62 s: header stayed `v0.1.3`, no BLE
advertising, and `RESETREAS` stayed `0x00000000` — it did **not** self-reset.
That is a known application-side gap (see section 4). Recovery therefore needed
an external reset. On that reset:

```
22:29:37.736  I: Starting bootloader
22:29:37.736  I: DIAG ncs img=0 magic=0x96f3b83d flags=0x4 reset_addr=0xa78fbdc3
22:29:37.736  I: Image index: 0, Swap type: revert
22:29:47.749  I: Starting swap using move algorithm.
22:30:48.389  I: Image version: v0.1.2
22:30:48.389  I: Jumping to the first image slot
```

End state, over BLE: `image 0 slot 0 v0.1.2 [active,confirmed,bootable]`,
the unit advertising and serviceable.

## 2. Timings (measured)

| Quantity | Value |
|---|---|
| App image OTA upload (462,492 B over BLE) | 38.3 s |
| Broken app image upload (462,667 B) | 38.6 s |
| Net-core image upload (145,499 B) | 12.2–12.5 s |
| Swap execution, good (`Starting swap using move` → `Jumping`) | 60.59 s |
| Swap execution, broken | 60.50 s |
| Revert swap execution | 60.64 s |
| Boot → new image running, good (bootloader start → jump) | 70.5 s |
| Boot → revert complete | 70.7 s |
| Baseline boot → BLE advertising | ~8–12 s |
| Secondary slot erase, 0xd3000 = 864,256 B (single unfed call) | 15.80 s (img 0), 17.88 s (img 2) |
| Image hash + decrypt, 462,224 B | 0.83 s |
| ECDSA signature verify | 0.315 s |
| Image-2 swap-state read hang (unpatched) | 10.86 s |
| Inherited application task watchdog window | 10.5 s (`CRV` 0x54000 @ 32768 Hz) |

The swap window is ~60 s, consistent with the ~58 s encrypted-swap figure
recorded in earlier encrypted-image testing on the same board.

## 3. Defect chain (four SDK defects, all in NCS v3.3.1 MCUboot)

1. **Encrypted reset-vector misread — the keystone.**
   `boot_validated_swap_type()` reads the secondary slot's reset vector as
   plaintext. For an AES-encrypted image it is ciphertext
   (`0x3ee3fbc2` / `0x9769f57c` / `0xa78fbdc3` observed) and never falls inside
   the primary range `[0x28000,0xfc000]`, so MCUboot concludes "not intended
   for any image" and returns `BOOT_SWAP_TYPE_NONE` before
   `sec_slot_mark_assigned()`. The plaintext net-core image
   (`flags=0x100`, `reset_addr=0x1023291`) passes, which is why only the
   encrypted app image ever failed. NCS v3.3.1 has no encryption guard
   anywhere in that block, although `ih_flags & ENCRYPTIONFLAGS` is available.
   Implication: `SB_CONFIG_SECURE_BOOT_APPCORE` + `SB_CONFIG_BOOT_ENCRYPTION`
   are effectively incompatible on nRF5340 in NCS v3.3.1 without this fix.

2. **Image-2 swap-state read blocks the boot.**
   Image 2 is the NSIB s0/s1 self-update slot. Its primary is
   `mcuboot_primary_1`, a `nordic_ram_flash_controller` (PCD/RAM-flash) area
   backed by the network core, which is held off during boot, so the read
   blocks — 10.86 s measured, versus <1 ms for images 0 and 1 through the same
   code. Its secondary is the *shared* `mcuboot_secondary`, so any staged app
   image gives image 2 "good magic" and triggers this on every staged boot.

3. **Whole-secondary erase in one unfed call.**
   `sec_slot_cleanup_if_unusable()` erases the entire external-QSPI secondary
   in a single `flash_area_erase` — 15.80 s and 17.88 s measured, each far
   beyond the 10.5 s watchdog window. It erases the shared area twice, once on
   behalf of unwired image 2, destroying a good staged app image. This is what
   made every failed attempt leave a torn slot.

4. **Missing watchdog feeds on the swap/validate path.**
   `CONFIG_BOOT_WATCHDOG_FEED` exists but upstream calls it from only three
   places, none on the swap or validate path, which runs for tens of seconds
   over external QSPI. The nRF watchdog survives `sys_reboot`, so MCUboot
   inherits the running 10.5 s application `task_wdt` across a warm reset —
   the real field OTA path.

Defects 2, 3 and 4 combine to reset the device mid-operation and erase the
staged image; defect 1 guarantees the image would have been rejected anyway.

## 4. Fix inventory

### Already in the application build (not SDK changes)

- `sysbuild/mcuboot.overlay` — external-flash (`mx25r64`) properties mirrored
  from the application overlay so MCUboot drives the external flash
  identically. Hardening only; bench-proven **not** to be the no-swap cause.
- `sysbuild/mcuboot.conf` — documentation block recording that
  `CONFIG_UPDATEABLE_IMAGE_NUMBER` cannot be lowered from the application
  repository (sysbuild's `set_config_int` overrides the fragment; the
  `SB_CONFIG` knob is Kconfig-pinned to `range [1,1]` under
  `SECURE_BOOT_APPCORE` and hard-fails configuration). The setting is left
  commented out deliberately.

### SDK patch, required (`ncs-3.3.1-mcuboot-secured-swap.patch`)

All four hunks are necessary; none is sufficient alone.

| Hunk | File | Fixes |
|---|---|---|
| 1 | `loader.c` `boot_validated_swap_type()` | defect 1 (keystone) |
| 2 | `loader.c` `boot_prepare_image_for_update()` | defect 2 |
| 3 | `loader.c` `sec_slot_cleanup_if_unusable()` | defect 3 |
| 4 | `swap_move.c` ×3, `bootutil_img_hash.c` ×1 | defect 4 |

Rejected during investigation: forcing MCUboot's image count to 2. It produced
the intended count but broke the application (no advertising, `RESETREAS`
showed `LOCKUP`).

### Additional observations for Nordic

- Defects 1–4 above, with the measured numbers.
- Shared-secondary coupling: marking image 0 pending also flips image 1's
  reported state in `image list`.
- `boot_read_image_headers()` swallows a failed read
  (`i > 0 && !require_all` → `rc 0`) and keeps a stale header — observed as a
  valid cached header alongside a fresh read of `ff ff ff ff`.
- `swap_read_status_bytes()` issues roughly 1000 single-byte `flash_area_read`
  calls over external QSPI (`BOOT_MAX_IMG_SECTORS=256`); should be batched.

### Application-side, not an SDK issue

A booted-but-never-advertising image does not self-reset, because the task
watchdog is fed unconditionally. Row 3 evidences this: `RESETREAS` stayed
`0x00000000` for 62 s while the broken image ran. MCUboot's revert is correct
and fires on the next reset, but on a fielded unit nothing generates that
reset. Tracked separately on our side.

## 5. Evidence index

| File | Contents |
|---|---|
| `ncs-3.3.1-mcuboot-secured-swap.patch` | the four-hunk SDK patch, applies cleanly to mcuboot @ `3de5b4df5f9f` |
| `run14b-artifacts/rtt-row2-swap-pass.log` | row 2: `ASSIGNED` → `Swap type: test` → swap → `v0.1.3` |
| `run14b-artifacts/rtt-row3-revert.log` | row 3: broken swap-in + banner, then `Swap type: revert` → `v0.1.2` |
| `run14b-artifacts/rtt-keystone-encrypted-reset-vector.log` | pre-fix capture: `RETURN-NONE`, ciphertext `reset_addr` vs primary range |
| `run14b-artifacts/rtt-secondary-erase-timing.log` | 15.80 s / 17.88 s erase measurement |
| `run14b-artifacts/rtt-img2-hang-bisect.log` | 10.86 s image-2 hang bisect |
| `run14b-artifacts/partitions.yml` | partition geometry |

Build outputs (merged hex images, DFU bundles, `mcuboot-zephyr.config`,
`app-zephyr.config`, `mcuboot-zephyr.dts`) were retained locally and are not
included here; the logs above are the primary evidence and can be supplied on
request.

## 6. Bench provenance

- One nRF5340 custom board (the bench unit), BLE OTA over a Linux host.
- Debug probe: CMSIS-DAP probe, `probe-rs` v0.32.0 at 500 kHz.
- Toolchain: NCS `v3.3.1-1d7a0b0e49b8`, toolchain bundle `911f4c5c26`;
  MCUboot `v2.3.0-dev-3de5b4df5f9f`.
- Line: secured — `SB_CONFIG_SECURE_BOOT_APPCORE`, `SB_CONFIG_BOOT_ENCRYPTION`
  (AES-128), `SB_CONFIG_MCUBOOT_MODE_SWAP_USING_MOVE`, development keys from a
  local key directory.
- Geometry: `b0` 0x0–0x8000, `s0` 0x8000–0x18000, `s1` 0x18000–0x28000,
  `mcuboot_primary` 0x28000–0xfc000, `mcuboot_secondary` 0x0–0xd3000 in
  external QSPI (primary minus one sector, the swap-using-move requirement).
- b0 provision written to OTP at `0xff8128` via an NVMC workaround
  (`probe-rs` 0.32 cannot program the OTP page; error 104).
- Bench overlays on all images: auto-advertise and charger-interlock-bypass
  fragments, plus an RTT console overlay (`CONFIG_SERIAL=n`, so RTT is the only
  console).

### Builds used

| Build | Version | MCUboot binary md5 (first 12) | Role |
|---|---|---|---|
| baseline build | 0.1.2+0 | `4723182e9a08` | baseline, carries all four SDK patches |
| good build | 0.1.3+0 | `a601e851b3f7` | good image: boots, advertises, self-confirms |
| broken build | 0.1.3+0 | `0efa90344afe` | broken image: boots, never advertises |

Only the app image is staged over BLE for these rows; the good and broken
images are app-image-only OTAs, which is the self-healing case under test.

Version note: MCUboot compares only major.minor.patch — `CONFIG_BOOT_VERSION_CMP_USE_BUILD_NUMBER`
is not set — so a `VERSION_TWEAK` bump is not an upgrade under
`MCUBOOT_DOWNGRADE_PREVENTION`. The test images use a PATCH bump
(0.1.2 → 0.1.3).

  • One correction to Defect 4 before anyone else trips over it: the feed-site inventory. A fresh grep at 3de5b4df shows six MCUBOOT_WATCHDOG_FEED() call sites, not four — we missed two in serial recovery: boot/boot_serial/src/boot_serial.c:1543 and boot/boot_serial/src/boot_serial_encryption.c:187, both compiled only under MCUBOOT_SERIAL. The precise claim is therefore: four call sites on the normal boot path (boot/bootutil/src/bootutil_area.c:266 and :343, boot/zephyr/main.c:756, and the copy loop at boot/bootutil/src/loader.c:1340) and zero on the swap/validate pathswap_move.c and the image hash/decrypt chunk loop still contain none. The measurements and the argument are unaffected.

Related