From 248dc9ad84e35e6bd03198faf56a41e339bc970c Mon Sep 17 00:00:00 2001 From: Konstantin Kondrashov Date: Fri, 19 Apr 2024 09:18:29 +0300 Subject: [PATCH 1/6] fix(espefuse): Fix efuse base addr for esp32c5 MP --- espefuse/efuse/esp32c5/mem_definition.py | 2 +- esptool/targets/esp32c5.py | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/espefuse/efuse/esp32c5/mem_definition.py b/espefuse/efuse/esp32c5/mem_definition.py index bb31cad75..9a9212681 100644 --- a/espefuse/efuse/esp32c5/mem_definition.py +++ b/espefuse/efuse/esp32c5/mem_definition.py @@ -20,7 +20,7 @@ class EfuseDefineRegisters(EfuseRegistersBase): EFUSE_MEM_SIZE = 0x01FC + 4 # EFUSE registers & command/conf values - DR_REG_EFUSE_BASE = 0x600B0800 + DR_REG_EFUSE_BASE = 0x600B4800 EFUSE_PGM_DATA0_REG = DR_REG_EFUSE_BASE EFUSE_CHECK_VALUE0_REG = DR_REG_EFUSE_BASE + 0x020 EFUSE_CLK_REG = DR_REG_EFUSE_BASE + 0x1C8 diff --git a/esptool/targets/esp32c5.py b/esptool/targets/esp32c5.py index d4517af91..fc2db6c0d 100644 --- a/esptool/targets/esp32c5.py +++ b/esptool/targets/esp32c5.py @@ -13,6 +13,8 @@ class ESP32C5ROM(ESP32C6ROM): CHIP_NAME = "ESP32-C5" IMAGE_CHIP_ID = 23 + EFUSE_BASE = 0x600B4800 + IROM_MAP_START = 0x42000000 IROM_MAP_END = 0x42800000 DROM_MAP_START = 0x42800000 From d4c8cb3551cee5c186cd901965739292ceb1dbf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Radim=20Karni=C5=A1?= Date: Mon, 22 Apr 2024 15:28:59 +0200 Subject: [PATCH 2/6] feat(esploader): Enable context manager for esp instances --- esptool/loader.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/esptool/loader.py b/esptool/loader.py index af4dc54af..2b2785db4 100644 --- a/esptool/loader.py +++ b/esptool/loader.py @@ -181,7 +181,8 @@ class ESPLoader(object): Don't instantiate this base class directly, either instantiate a subclass or call cmds.detect_chip() which will interrogate the chip and return the - appropriate subclass instance. + appropriate subclass instance. You can also use a context manager as + "with detect_chip() as esp:" to ensure the serial port is closed when done. """ @@ -281,7 +282,8 @@ def __init__(self, port=DEFAULT_PORT, baud=ESP_ROM_BAUD, trace_enabled=False): """Base constructor for ESPLoader bootloader interaction Don't call this constructor, either instantiate a specific - ROM class directly, or use cmds.detect_chip(). + ROM class directly, or use cmds.detect_chip(). You can use the with + statement to ensure the serial port is closed when done. This base class has all of the instance methods for bootloader functionality supported across various chips & stub @@ -365,6 +367,12 @@ def __init__(self, port=DEFAULT_PORT, baud=ESP_ROM_BAUD, trace_enabled=False): # need to set the property back to None or it will continue to fail self._port.write_timeout = None + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, traceback): + self._port.close() + @property def serial_port(self): return self._port.port From bb52d36278e51cb2fc0ae38ae5e20760e7f39563 Mon Sep 17 00:00:00 2001 From: Jan Beran Date: Mon, 22 Apr 2024 14:43:50 +0200 Subject: [PATCH 3/6] feat(espefuse): Allow filtering efuses based on command line arguments --- docs/en/espefuse/summary-cmd.rst | 36 ++++++++++++++- espefuse/efuse/base_operations.py | 74 ++++++++++++++++++++----------- test/test_espefuse.py | 9 ++++ 3 files changed, 92 insertions(+), 27 deletions(-) diff --git a/docs/en/espefuse/summary-cmd.rst b/docs/en/espefuse/summary-cmd.rst index 5e5d46962..195083ebd 100644 --- a/docs/en/espefuse/summary-cmd.rst +++ b/docs/en/espefuse/summary-cmd.rst @@ -3,12 +3,16 @@ Summary ======= -The ``espefuse.py summary`` command reads all eFuses from the chip and outputs them in text or json format. It is also possible to save it to a file. +The ``espefuse.py summary`` command reads the eFuses from the chip and outputs them in text or json format. It is also possible to save it to a file. The command also supports eFuse filtering by name. Optional arguments: -- ``--format`` - Select the summary format: ``summary`` - text format (default option), ``json`` - json format. Usage ``--format json``. +- ``--format`` - Select the summary format: + - ``summary`` - text format (default option). + - ``json`` - json format. Usage ``--format json``. + - ``value_only`` - only the value of the eFuse specified as an argument will be displayed. For more information, refer to the :ref:`Filtering eFuses ` section. - ``--file`` - File to save the efuse summary. Usage ``--file efuses.json``. +- List of eFuses to filter. For more information, refer to the :ref:`Filtering eFuses ` section. Text Format Summary ------------------- @@ -112,3 +116,31 @@ Save Json Format Summary To File === Run "summary" command === Saving efuse values to efuses.json + +.. _filtering-eFuses: + +Filtering Efuses and Displaying Only the Value +---------------------------------------------- + +The ``espefuse.py summary`` command supports filtering eFuses by name. The eFuses to filter needs to be specified as positional arguments. If no eFuses are specified, complete summary will be displayed. Example: + +.. code-block:: none + + > espefuse.py summary ABS_DONE_0 BLOCK1 + + === Run "summary" command === + EFUSE_NAME (Block) Description = [Meaningful Value] [Readable/Writeable] (Hex Value) + ---------------------------------------------------------------------------------------- + Security fuses: + ABS_DONE_0 (BLOCK0) Secure boot V1 is enabled for bootloader image = False R/W (0b0) + BLOCK1 (BLOCK1) Flash encryption key + = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 R/W + +If ``--format value_only`` is specified, only the value of the eFuse specified as an argument will be displayed. Only one eFuse can be specified as an argument for this format. Example: + +.. code-block:: none + + > espefuse.py summary --format value_only MAC + + === Run "summary" command === + 00:00:00:00:00:00 (CRC 0x00 OK) diff --git a/espefuse/efuse/base_operations.py b/espefuse/efuse/base_operations.py index ccf7efe21..8ee667810 100644 --- a/espefuse/efuse/base_operations.py +++ b/espefuse/efuse/base_operations.py @@ -182,7 +182,7 @@ def check_efuse_name(efuse_name, efuse_list): summary_cmd.add_argument( "--format", help="Select the summary format", - choices=["summary", "json"], + choices=["summary", "json", "value_only"], default="summary", ) summary_cmd.add_argument( @@ -191,6 +191,11 @@ def check_efuse_name(efuse_name, efuse_list): type=argparse.FileType("w"), default=sys.stdout, ) + summary_cmd.add_argument( + "efuses_to_show", + help="The efuses to show. If not provided, all efuses will be shown.", + nargs="*", + ) execute_scripts = subparsers.add_parser( "execute_scripts", help="Executes scripts to burn at one time." @@ -245,14 +250,21 @@ def add_show_sensitive_info_option(p): def summary(esp, efuses, args): - """Print a human-readable summary of efuse contents""" + """Print a human-readable or json summary of efuse contents""" ROW_FORMAT = "%-50s %-50s%s = %s %s %s" - human_output = args.format == "summary" + human_output = args.format in ["summary", "value_only"] + value_only = args.format == "value_only" + if value_only and len(args.efuses_to_show) != 1: + raise esptool.FatalError( + "The 'value_only' format can be used exactly for one efuse." + ) + do_filtering = bool(args.efuses_to_show) json_efuse = {} + summary_efuse = [] if args.file != sys.stdout: print("Saving efuse values to " + args.file.name) - if human_output: - print( + if human_output and not value_only: + summary_efuse.append( ROW_FORMAT.replace("-50", "-12") % ( "EFUSE_NAME (Block)", @@ -261,13 +273,12 @@ def summary(esp, efuses, args): "[Meaningful Value]", "[Readable/Writeable]", "(Hex Value)", - ), - file=args.file, + ) ) - print("-" * 88, file=args.file) + summary_efuse.append("-" * 88) for category in sorted(set(e.category for e in efuses), key=lambda c: c.title()): - if human_output: - print("%s fuses:" % category.title(), file=args.file) + if human_output and not value_only: + summary_efuse.append(f"{category.title()} fuses:") for e in (e for e in efuses if e.category == category): if e.efuse_type.startswith("bytes"): raw = "" @@ -296,8 +307,12 @@ def summary(esp, efuses, args): value = "".join(v) else: value = value.replace("0", "?") - if human_output: - print( + if ( + human_output + and (not do_filtering or e.name in args.efuses_to_show) + and not value_only + ): + summary_efuse.append( ROW_FORMAT % ( e.get_info(), @@ -306,18 +321,20 @@ def summary(esp, efuses, args): value, perms, raw, - ), - file=args.file, + ) ) desc_len = len(e.description[50:]) if desc_len: desc_len += 50 for i in range(50, desc_len, 50): - print( - "%-50s %-50s" % ("", e.description[i : (50 + i)]), - file=args.file, + summary_efuse.append( + f"{'':<50} {e.description[i : (50 + i)]:<50}" ) - if args.format == "json": + elif human_output and value_only and e.name in args.efuses_to_show: + summary_efuse.append(f"{value}") + elif args.format == "json" and ( + not do_filtering or e.name in args.efuses_to_show + ): json_efuse[e.name] = { "name": e.name, "value": base_value if readable else value, @@ -331,19 +348,26 @@ def summary(esp, efuses, args): "efuse_type": e.efuse_type, "bit_len": e.bit_len, } - if human_output: - print("", file=args.file) - if human_output: - print(efuses.summary(), file=args.file) + if human_output and not value_only: + # Remove empty category if efuses are filtered and there are none to show + if do_filtering and summary_efuse[-1] == f"{category.title()} fuses:": + summary_efuse.pop() + else: + summary_efuse.append("") + if human_output and not value_only: + summary_efuse.append(efuses.summary()) warnings = efuses.get_coding_scheme_warnings() if warnings: - print( - "WARNING: Coding scheme has encoding bit error warnings", file=args.file + summary_efuse.append( + "WARNING: Coding scheme has encoding bit error warnings" ) + if human_output: + for line in summary_efuse: + print(line, file=args.file) if args.file != sys.stdout: args.file.close() print("Done") - if args.format == "json": + elif args.format == "json": json.dump(json_efuse, args.file, sort_keys=True, indent=4) print("") diff --git a/test/test_espefuse.py b/test/test_espefuse.py index 78ddffeef..2388dc94f 100755 --- a/test/test_espefuse.py +++ b/test/test_espefuse.py @@ -184,6 +184,15 @@ def test_summary(self): def test_summary_json(self): self.espefuse_py("summary --format json") + def test_summary_filter(self): + self.espefuse_py("summary MAC") + self.espefuse_py("summary --format value_only MAC") + self.espefuse_py( + "summary --format value_only MAC WR_DIS", + check_msg="The 'value_only' format can be used exactly for one efuse.", + ret_code=2, + ) + @pytest.mark.skipif( arg_chip == "esp32p4", reason="No Custom MAC Address defined yet" ) From 9f46568a86a54412906b1e6de9f6c0e7afb21b68 Mon Sep 17 00:00:00 2001 From: Green <77177015+GreenDiscord@users.noreply.github.com> Date: Fri, 26 Apr 2024 17:10:05 +0100 Subject: [PATCH 4/6] docs(flashing): Fixed a typo in /docs/en/esptool/flashing-firmware.rst Updated the text in this file to fix a typo which was decives, that is now devices. --- docs/en/esptool/flashing-firmware.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/esptool/flashing-firmware.rst b/docs/en/esptool/flashing-firmware.rst index 6c4276b05..78a6c575d 100644 --- a/docs/en/esptool/flashing-firmware.rst +++ b/docs/en/esptool/flashing-firmware.rst @@ -8,7 +8,7 @@ Flashing Firmware Esptool is used under the hood of many development frameworks for Espressif SoCs, such as `ESP-IDF `_, `Arduino `_, or `PlatformIO `_. After the resulting firmware binary files are compiled, esptool is used to flash these into the device. -Sometimes there might be a need to comfortably flash a bigger amount of decives with the same binaries or to share flashing instructions with a third party. +Sometimes there might be a need to comfortably flash a bigger amount of devices with the same binaries or to share flashing instructions with a third party. It is possible to compile the firmware just once and then repeatedly use esptool (manually or :ref:`in a custom script `) to flash the files. Sharing these instructions and below mentioned assets with a third party (for example a manufacturer) should suffice to allow reproducible and quick flashing of your application into an Espressif chip. From 88f6186ae05ab0daede6d727684461fa20435c6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Radim=20Karni=C5=A1?= Date: Mon, 29 Apr 2024 12:44:18 +0200 Subject: [PATCH 5/6] ci(hsm_tests): Run tests in a virtual env --- .gitlab-ci.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 3dcc5f068..c8d89690c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -144,8 +144,10 @@ host_tests_hsm: PYTEST_ADDOPTS: "-sv --junitxml=test/report.xml --color=yes" before_script: - apt-get update - - apt-get install -y python3 python3-pip softhsm2 + - apt-get install -y python3 python3-pip python3-venv softhsm2 - ./ci/setup_softhsm2.sh || exit 1 + - python3 -m venv esptoolenv + - source esptoolenv/bin/activate - pip3 install -e .[dev,hsm] --prefer-binary script: - coverage run --parallel-mode -m pytest ${CI_PROJECT_DIR}/test/test_espsecure_hsm.py From 1deb1c65c140363bbfa16fbd889cff8e6d33b8c0 Mon Sep 17 00:00:00 2001 From: BoryaGames Date: Fri, 3 May 2024 13:25:25 +0500 Subject: [PATCH 6/6] change(detect_chip): Fixed a spelling mistake Closes https://github.com/espressif/esptool/pull/977 --- esptool/cmds.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esptool/cmds.py b/esptool/cmds.py index 701dc3ea8..7c770e42f 100644 --- a/esptool/cmds.py +++ b/esptool/cmds.py @@ -116,7 +116,7 @@ def detect_chip( else: err_msg = f"Unexpected chip ID value {chip_id}." except (UnsupportedCommandError, struct.error, FatalError) as e: - # UnsupportedCommmanddError: ESP8266/ESP32 ROM + # UnsupportedCommandError: ESP8266/ESP32 ROM # struct.error: ESP32-S2 # FatalError: ESP8266/ESP32 STUB print(" Unsupported detection protocol, switching and trying again...")