Skip to content

feat: add boot_mode to os_management ResetWriteRequest (closes #58)#59

Merged
JPHutchins merged 1 commit into
mainfrom
feat/#58/os-reset-boot-mode
Jun 3, 2026
Merged

feat: add boot_mode to os_management ResetWriteRequest (closes #58)#59
JPHutchins merged 1 commit into
mainfrom
feat/#58/os-reset-boot-mode

Conversation

@JPHutchins
Copy link
Copy Markdown
Owner

Summary

Adds the optional boot_mode field to smp.os_management.ResetWriteRequest, so a client can request a reboot into the bootloader (e.g. MCUboot serial recovery) rather than a normal reboot. Resolves #58.

  • New BootMode(IntEnum)NORMAL = 0, BOOTLOADER = 1 — mirroring Zephyr's enum BOOT_MODE_TYPES in include/zephyr/retention/bootmode.h.
  • ResetWriteRequest.boot_mode is encoded into the reset command's CBOR map under the key boot_mode only when set, exactly like the existing force field.
  • Known values surface as BootMode members; any other value in [0, 255] is accepted as a plain int (the server casts to uint8_t). Out-of-range values (< 0 or > 255) raise ValidationError, keeping the library's "impossible to create an invalid SMP message" contract intact.

Protocol provenance

I tracked down when this entered the protocol: boot_mode was added to the SMP OS management reset command in Zephyr v4.2.0 via zephyrproject-rtos/zephyr#91510 (commit 0adcf2e, merged 2025-06-18); it is not present in v4.1.0. Server-side it is gated by CONFIG_MCUMGR_GRP_OS_RESET_BOOT_MODE (depends on CONFIG_RETENTION_BOOT_MODE). The os_mgmt.c handler decodes the CBOR key string "boot_mode" as an unsigned int, validates <= UCHAR_MAX, casts to uint8_t, and passes it to bootmode_set(). BOOT_MODE_TYPE_BOOTLOADER (1) is what an MCUboot built with CONFIG_BOOT_SERIAL_BOOT_MODE checks to enter serial recovery on the next boot.

Design notes

  • Union[BootMode, Annotated[int, Field(ge=0, le=255)], None] with union_mode="left_to_right". This mirrors the existing house pattern at smp/header.py:103 (Annotated[Union[GroupId, UserGroupId, int], Field(union_mode="left_to_right")]). Left-to-right is load-bearing: under the default smart union, 0/1 would deserialize to plain int instead of BootMode members.
  • No wire format change for existing callers: when boot_mode is unset it is excluded from the CBOR map (exclude_unset/exclude_none), so an empty reset request still serializes to a0.

Testing

  • New tests in tests/test_os_management.py cover: boot_mode 0/1 → BootMode members, unknown-but-valid int passthrough, force + boot_mode together, enum-member construction matching the raw-int payload byte-for-byte, and rejection of -1/256.
  • Full suite: 40976 passed, 100% coverage (incl. smp/os_management.py), black/isort/flake8/mypy all clean.

🤖 Generated with Claude Code

Model the optional `boot_mode` field on `ResetWriteRequest` so a client can
request a reboot into the bootloader (e.g. MCUboot serial recovery) rather
than a normal reboot.

The field is encoded into the reset command's CBOR map under the key
`boot_mode` only when set, matching the existing `force` handling. Values are
modeled with a `BootMode(IntEnum)` (`NORMAL = 0`, `BOOTLOADER = 1`) mirroring
Zephyr's `enum BOOT_MODE_TYPES` in `include/zephyr/retention/bootmode.h`.
Because the server casts the value to a `uint8_t`, the field accepts any value
in `[0, 255]` (known values surface as `BootMode` members; the range guard
keeps invalid messages unconstructable per the library's contract).

This field was added to the SMP OS management group in Zephyr v4.2.0
(zephyrproject-rtos/zephyr#91510), gated by `CONFIG_MCUMGR_GRP_OS_RESET_BOOT_MODE`
(depends on `CONFIG_RETENTION_BOOT_MODE`).

Unblocks intercreate/smpclient#112 and intercreate/smpmgr#100.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings June 3, 2026 01:51
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds support for Zephyr’s optional OS-management reset command parameter boot_mode by extending smp.os_management.ResetWriteRequest, enabling clients to request rebooting into a bootloader/recovery mode while preserving existing wire behavior when the field is unset.

Changes:

  • Introduces BootMode(IntEnum) with NORMAL=0 and BOOTLOADER=1 to represent known reset boot modes.
  • Adds optional ResetWriteRequest.boot_mode with validation for uint8 range [0, 255] and left-to-right union decoding so 0/1 deserialize to BootMode members.
  • Adds tests covering known enum values, unknown passthrough ints, combined force + boot_mode, enum-member construction equivalence, and out-of-range validation failures.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
smp/os_management.py Adds BootMode enum and boot_mode field on ResetWriteRequest with range validation and union decoding behavior.
tests/test_os_management.py Adds test coverage ensuring correct (de)serialization and validation behavior for the new boot_mode field.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@JPHutchins JPHutchins merged commit 178089e into main Jun 3, 2026
38 checks passed
@JPHutchins JPHutchins deleted the feat/#58/os-reset-boot-mode branch June 3, 2026 01:57
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.

os_management: add boot_mode field to ResetWriteRequest (reboot to bootloader)

2 participants