feat(cmds): Polish the public API, unify arg names, pack some args

BREAKING CHANGE
This commit is contained in:
Radim Karniš
2025-02-26 11:05:07 +01:00
parent 063d9d5fba
commit 37a13a94c8
6 changed files with 107 additions and 70 deletions

View File

@@ -303,7 +303,7 @@ The output of the command will be in ``raw`` format and gaps between individual
**RAW options:**
* The ``--fill-flash-size SIZE`` option will pad the merged binary with `0xFF` bytes to the full flash specified size, for example ``--fill-flash-size 4MB`` will create a 4MB binary file.
* The ``--pad-to-size SIZE`` option will pad the merged binary with `0xFF` bytes to the full flash specified size, for example ``--pad-to-size 4MB`` will create a 4MB binary file.
* The ``--target-offset 0xNNN`` option will create a merged binary that should be flashed at the specified offset, instead of at offset 0x0.

View File

@@ -153,3 +153,21 @@ The esptool ``v5`` has switched to using `Click <https://click.palletsprojects.c
1. Remove the old shell completion code from your scripts and shell configuration files like ``.bashrc``, ``.zshrc``, ``.config/fish/config.fish``, etc.
2. Follow the new shell completion setup instructions in the :ref:`shell-completion` section of the :ref:`installation <installation>` guide.
``merge_bin`` ``--fill-flash-size`` Argument
********************************************
The ``--fill-flash-size`` option of the :ref:`merge_bin <merge-bin>` command has been renamed to ``--pad-to-size``. This change provides a more intuitive and descriptive name for the argument and is consistent with the naming scheme in other esptool image manipulation commands.
**Migration Steps:**
1. Rename the ``--fill-flash-size`` to ``--pad-to-size`` in any existing ``merge_bin`` commands in scripts/CI pipelines.
``write_flash`` ``--ignore-flash-encryption-efuse-setting`` Argument
********************************************************************
The ``--ignore-flash-encryption-efuse-setting`` option of the :ref:`write_flash <write-flash>` command has been renamed to ``--ignore-flash-enc-efuse``. This change shortens the argument name to improve readability and consistency with other esptool options.
**Migration Steps:**
1. Rename the ``--ignore-flash-encryption-efuse-setting`` to ``--ignore-flash-enc-efuse`` in any existing ``write_flash`` commands in scripts/CI pipelines.

View File

@@ -123,7 +123,7 @@ click.rich_click.OPTION_GROUPS = {
"name": "RAW options",
"options": [
"--target-offset",
"--fill-flash-size",
"--pad-to-size",
],
},
],
@@ -570,9 +570,9 @@ def write_mem_cli(ctx, address, value, mask):
"filename, separated by space.",
)
@click.option(
"--ignore-flash-encryption-efuse-setting",
"--ignore-flash-enc-efuse",
is_flag=True,
help="Ignore flash encryption efuse settings",
help="Ignore flash encryption eFuse settings",
)
@click.option(
"--force",
@@ -926,12 +926,12 @@ def read_flash_sfdp_cli(ctx, address, bytes, **kwargs):
help="Target offset where the output file will be flashed",
)
@click.option( # RAW only
"--fill-flash-size",
"--pad-to-size",
type=click.Choice(
["256KB", "512KB", "1MB", "2MB", "4MB", "8MB", "16MB", "32MB", "64MB", "128MB"]
),
help="If set, the final binary file will be padded with FF bytes up to this flash "
"size.",
help="If set, the final binary file will be padded with 0xFF bytes up to this flash"
" size.",
)
@add_spi_flash_options(allow_keep=True, auto_detect=False)
@click.pass_context

View File

@@ -102,7 +102,7 @@ def detect_chip(
connect_attempts: Number of connection attempts before failing.
Returns:
An instance of the detected chip class, initialized and ready for use.
An initialized instance of the detected chip class ready for use.
"""
inst = None
detect_port = ESPLoader(port, baud, trace_enabled=trace_enabled)
@@ -257,7 +257,7 @@ def dump_mem(
output: Path to output file for binary data. If None, returns the data.
Returns:
bytes | None: Memory dump as bytes if filename is None;
Memory dump as bytes if filename is None;
otherwise, returns None after writing to file.
"""
log.print(
@@ -429,14 +429,7 @@ def write_flash(
flash_freq: str = "keep",
flash_mode: str = "keep",
flash_size: str = "keep",
erase_all: bool = False,
encrypt: bool = False,
encrypt_files: list[tuple[int, BinaryIO]] | None = None,
compress: bool = False,
no_compress: bool = False,
force: bool = False,
ignore_flash_encryption_efuse_setting: bool = False,
no_progress: bool = False,
**kwargs,
) -> None:
"""
Write firmware or data to the SPI flash memory of an ESP device.
@@ -451,15 +444,29 @@ def write_flash(
(``"keep"`` to retain current).
flash_size: Flash size to set in the bootloader image header
(``"keep"`` to retain current).
erase_all: Erase the entire flash before writing.
encrypt: Encrypt all files during flashing.
encrypt_files: List of (address, file) tuples for files to encrypt individually.
compress: Compress data before flashing.
no_compress: Don't compress data before flashing.
force: Ignore safety checks (e.g., secure boot, flash size).
ignore_flash_encryption_efuse_setting: Ignore flash encryption efuse settings.
no_progress: Disable progress updates.
Keyword Args:
erase_all (bool): Erase the entire flash before writing.
encrypt (bool): Encrypt all files during flashing.
encrypt_files (list[tuple[int, BinaryIO]] | None): List of (address, file)
tuples for files to encrypt individually.
compress (bool): Compress data before flashing.
no_compress (bool): Don't compress data before flashing.
force (bool): Ignore safety checks (e.g., overwriting bootloader, flash size).
ignore_flash_enc_efuse (bool): Ignore flash encryption eFuse settings.
no_progress (bool): Disable progress updates.
"""
# Set default values of optional arguments
erase_all: bool = kwargs.get("erase_all", False)
encrypt: bool = kwargs.get("encrypt", False)
encrypt_files: list[tuple[int, BinaryIO]] | None = kwargs.get("encrypt_files", None)
compress: bool = kwargs.get("compress", False)
no_compress: bool = kwargs.get("no_compress", False)
force: bool = kwargs.get("force", False)
ignore_flash_enc_efuse: bool = kwargs.get("ignore_flash_enc_efuse", False)
no_progress: bool = kwargs.get("no_progress", False)
# set compress based on default behaviour:
# -> if either "compress" or "no_compress" is set, honour that
# -> otherwise, set "compress" unless the stub flasher is disabled
@@ -575,7 +582,7 @@ def write_flash(
do_write = False
if not do_write and not ignore_flash_encryption_efuse_setting:
if not do_write and not ignore_flash_enc_efuse:
raise FatalError(
"Can't perform encrypted flash write, "
"consult Flash Encryption documentation for more information"
@@ -1231,7 +1238,7 @@ def read_flash_sfdp(esp: ESPLoader, address: int, bytes: int = 1) -> None:
Args:
esp: Initiated esp object connected to a real device.
address: Starting address in the SFDP region to read from.
bytes: Number of bytes to read (1-4, default: 1).
bytes: Number of bytes to read (1-4).
"""
if not (1 <= bytes <= 4):
raise FatalError("Invalid number of bytes to read from SFDP (1-4).")
@@ -1270,7 +1277,7 @@ def read_flash(
no_progress: Disable printing progress.
Returns:
bytes | None: The read flash data as bytes if output is None; otherwise,
The read flash data as bytes if output is None; otherwise,
returns None after writing to file.
"""
_set_flash_parameters(esp, flash_size)
@@ -1557,7 +1564,7 @@ def run_stub(esp: ESPLoader) -> ESPLoader:
esp: Initiated esp object connected to a real device.
Returns:
ESPLoader: The esp instance, either as a stub child class in a state
The esp instance, either as a stub child class in a state
where the stub has been executed, or in its original state
if the stub loader is disabled or unsupported.
"""
@@ -1938,10 +1945,7 @@ def merge_bin(
flash_mode: str = "keep",
flash_size: str = "keep",
format: str = "raw",
target_offset: int = 0,
fill_flash_size: str | None = None,
chunk_size: int | None = None,
md5_disable: bool = False,
**kwargs,
) -> None:
"""
Merge multiple binary files into a single output file for flashing to an ESP device.
@@ -1962,11 +1966,20 @@ def merge_bin(
flash_size: Flash size to set in the image header
(``"keep"`` to retain current).
format: Output format (``"raw"``, ``"uf2"``, or ``"hex"``).
target_offset: Starting offset for the merged output.
fill_flash_size: If specified, pad the output he given flash size.
chunk_size: Chunk size for UF2 format.
md5_disable: If True, disable MD5 checks in UF2 format.
Keyword Args:
target_offset (int): Starting offset for the merged output.
pad_to_size (str | None): If specified, pad the output to a specific flash size.
chunk_size (int | None): Chunk size for UF2 format.
md5_disable (bool): If True, disable MD5 checks in UF2 format.
"""
# Set default values of optional arguments
target_offset: int = kwargs.get("target_offset", 0)
pad_to_size: str | None = kwargs.get("pad_to_size", None)
chunk_size: int | None = kwargs.get("chunk_size", None)
md5_disable: bool = kwargs.get("md5_disable", False)
try:
chip_class = CHIP_DEFS[chip]
except KeyError:
@@ -2023,8 +2036,8 @@ def merge_bin(
chip_class, addr, flash_freq, flash_mode, flash_size, image
)
of.write(image)
if fill_flash_size:
pad_to(flash_size_bytes(fill_flash_size))
if pad_to_size:
pad_to(flash_size_bytes(pad_to_size))
log.print(
f"Wrote {of.tell():#x} bytes to file {output}, "
f"ready to flash to offset {target_offset:#x}"
@@ -2061,18 +2074,7 @@ def elf2image(
flash_freq: str | None = None,
flash_mode: str = "qio",
flash_size: str = "1MB",
version: int = 1,
min_rev: int = 0,
min_rev_full: int = 0,
max_rev_full: int = 65535,
secure_pad: bool = False,
secure_pad_v2: bool = False,
elf_sha256_offset: int | None = None,
append_digest: bool = True,
use_segments: bool = False,
flash_mmu_page_size: str | None = None,
pad_to_size: str | None = None,
ram_only_header: bool = False,
**kwargs,
) -> None:
"""
Convert an ELF file into a firmware image suitable for flashing onto an ESP device.
@@ -2084,19 +2086,36 @@ def elf2image(
flash_freq: Flash frequency to set in the image header.
flash_mode: Flash mode to set in the image header.
flash_size: Flash size to set in the image header.
version: ESP8266 only, firmware image version.
min_rev: Minimum chip revision required.
min_rev_full: Minimum full revision required.
max_rev_full: Maximum full revision allowed.
secure_pad: Enable secure padding, ESP32-only.
secure_pad_v2: Enable version 2 secure padding.
elf_sha256_offset: Offset for storing the ELF file's SHA-256 hash.
append_digest: Whether to append a digest to the firmware image.
use_segments: Use ELF segments instead of sections.
flash_mmu_page_size: MMU page size for flash mapping.
pad_to_size: Pad the final image to a specific flash size.
ram_only_header: Image will only contain RAM segments and no SHA-256 digest.
Keyword Args:
version (int): ESP8266-only, firmware image version.
min_rev (int): Minimum chip revision required in legacy format.
min_rev_full (int): Minimum chip revision required in extended format.
max_rev_full (int): Maximum chip revision allowed in extended format.
secure_pad (bool): ESP32-only, enable secure padding.
secure_pad_v2 (bool): Enable version 2 secure padding.
elf_sha256_offset (int): Offset for storing the ELF file's SHA-256 hash.
append_digest (bool): Whether to append a digest to the firmware image.
use_segments (bool): Use ELF segments instead of sections.
flash_mmu_page_size (str): MMU page size for flash mapping.
pad_to_size (str): Pad the final image to a specific flash size.
ram_only_header (bool): Include only RAM segments and no SHA-256 hash.
"""
# Set default values of optional arguments
version: int = kwargs.get("version", 1)
min_rev: int = kwargs.get("min_rev", 0)
min_rev_full: int = kwargs.get("min_rev_full", 0)
max_rev_full: int = kwargs.get("max_rev_full", 65535)
secure_pad: bool = kwargs.get("secure_pad", False)
secure_pad_v2: bool = kwargs.get("secure_pad_v2", False)
elf_sha256_offset: int | None = kwargs.get("elf_sha256_offset", None)
append_digest: bool = kwargs.get("append_digest", True)
use_segments: bool = kwargs.get("use_segments", False)
flash_mmu_page_size: str | None = kwargs.get("flash_mmu_page_size", None)
pad_to_size: str | None = kwargs.get("pad_to_size", None)
ram_only_header: bool = kwargs.get("ram_only_header", False)
e = ELFFile(input)
if chip == "auto": # Default to ESP8266 for backwards compatibility
chip = "esp8266"

View File

@@ -369,7 +369,7 @@ class TestFlashEncryption(EsptoolTestCase):
pytest.skip("Valid encryption key already programmed, aborting the test")
self.run_esptool(
"write_flash --encrypt --ignore-flash-encryption-efuse-setting "
"write_flash --encrypt --ignore-flash-enc-efuse "
"0x10000 images/ram_helloworld/helloworld-esp32.bin"
)
self.run_esptool("read_flash 0x10000 192 images/read_encrypted_flash.bin")
@@ -408,7 +408,7 @@ class TestFlashEncryption(EsptoolTestCase):
pytest.skip("Valid encryption key already programmed, aborting the test")
self.run_esptool(
"write_flash --encrypt --ignore-flash-encryption-efuse-setting "
"write_flash --encrypt --ignore-flash-enc-efuse "
"0x10000 images/ram_helloworld/helloworld-esp32_edit.bin"
)
self.run_esptool("read_flash 0x10000 192 images/read_encrypted_flash.bin")

View File

@@ -169,9 +169,9 @@ class TestMergeBin:
assert helloworld == merged[0xF000 : 0xF000 + len(helloworld)]
self.assertAllFF(merged[0x1000 + len(bootloader) : 0xF000])
def test_fill_flash_size(self):
def test_pad_to_size(self):
merged = self.run_merge_bin(
"esp32c3", [(0x0, "bootloader_esp32c3.bin")], ["--fill-flash-size", "4MB"]
"esp32c3", [(0x0, "bootloader_esp32c3.bin")], ["--pad-to-size", "4MB"]
)
bootloader = read_image("bootloader_esp32c3.bin")
@@ -179,14 +179,14 @@ class TestMergeBin:
assert bootloader == merged[: len(bootloader)]
self.assertAllFF(merged[len(bootloader) :])
def test_fill_flash_size_w_target_offset(self):
def test_pad_to_size_w_target_offset(self):
merged = self.run_merge_bin(
"esp32",
[
(0x1000, "bootloader_esp32.bin"),
(0x10000, "ram_helloworld/helloworld-esp32.bin"),
],
["--target-offset", "0x1000", "--fill-flash-size", "2MB"],
["--target-offset", "0x1000", "--pad-to-size", "2MB"],
)
# full length is without target-offset arg
@@ -215,7 +215,7 @@ class TestMergeBin:
merged = self.run_merge_bin(
"esp32",
[(0x1000, f.name), (0x10000, "ram_helloworld/helloworld-esp32.bin")],
["--target-offset", "0x1000", "--fill-flash-size", "2MB"],
["--target-offset", "0x1000", "--pad-to-size", "2MB"],
)
finally:
os.unlink(f.name)