mirror of
https://github.com/espressif/esptool.git
synced 2025-10-19 02:43:00 +08:00
feat(espefuse): Allow filtering efuses based on command line arguments
This commit is contained in:
@@ -3,12 +3,16 @@
|
|||||||
Summary
|
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:
|
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 <filtering-eFuses>` section.
|
||||||
- ``--file`` - File to save the efuse summary. Usage ``--file efuses.json``.
|
- ``--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 <filtering-eFuses>` section.
|
||||||
|
|
||||||
Text Format Summary
|
Text Format Summary
|
||||||
-------------------
|
-------------------
|
||||||
@@ -112,3 +116,31 @@ Save Json Format Summary To File
|
|||||||
|
|
||||||
=== Run "summary" command ===
|
=== Run "summary" command ===
|
||||||
Saving efuse values to efuses.json
|
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)
|
||||||
|
@@ -182,7 +182,7 @@ def add_common_commands(subparsers, efuses):
|
|||||||
summary_cmd.add_argument(
|
summary_cmd.add_argument(
|
||||||
"--format",
|
"--format",
|
||||||
help="Select the summary format",
|
help="Select the summary format",
|
||||||
choices=["summary", "json"],
|
choices=["summary", "json", "value_only"],
|
||||||
default="summary",
|
default="summary",
|
||||||
)
|
)
|
||||||
summary_cmd.add_argument(
|
summary_cmd.add_argument(
|
||||||
@@ -191,6 +191,11 @@ def add_common_commands(subparsers, efuses):
|
|||||||
type=argparse.FileType("w"),
|
type=argparse.FileType("w"),
|
||||||
default=sys.stdout,
|
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 = subparsers.add_parser(
|
||||||
"execute_scripts", help="Executes scripts to burn at one time."
|
"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):
|
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"
|
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 = {}
|
json_efuse = {}
|
||||||
|
summary_efuse = []
|
||||||
if args.file != sys.stdout:
|
if args.file != sys.stdout:
|
||||||
print("Saving efuse values to " + args.file.name)
|
print("Saving efuse values to " + args.file.name)
|
||||||
if human_output:
|
if human_output and not value_only:
|
||||||
print(
|
summary_efuse.append(
|
||||||
ROW_FORMAT.replace("-50", "-12")
|
ROW_FORMAT.replace("-50", "-12")
|
||||||
% (
|
% (
|
||||||
"EFUSE_NAME (Block)",
|
"EFUSE_NAME (Block)",
|
||||||
@@ -261,13 +273,12 @@ def summary(esp, efuses, args):
|
|||||||
"[Meaningful Value]",
|
"[Meaningful Value]",
|
||||||
"[Readable/Writeable]",
|
"[Readable/Writeable]",
|
||||||
"(Hex Value)",
|
"(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()):
|
for category in sorted(set(e.category for e in efuses), key=lambda c: c.title()):
|
||||||
if human_output:
|
if human_output and not value_only:
|
||||||
print("%s fuses:" % category.title(), file=args.file)
|
summary_efuse.append(f"{category.title()} fuses:")
|
||||||
for e in (e for e in efuses if e.category == category):
|
for e in (e for e in efuses if e.category == category):
|
||||||
if e.efuse_type.startswith("bytes"):
|
if e.efuse_type.startswith("bytes"):
|
||||||
raw = ""
|
raw = ""
|
||||||
@@ -296,8 +307,12 @@ def summary(esp, efuses, args):
|
|||||||
value = "".join(v)
|
value = "".join(v)
|
||||||
else:
|
else:
|
||||||
value = value.replace("0", "?")
|
value = value.replace("0", "?")
|
||||||
if human_output:
|
if (
|
||||||
print(
|
human_output
|
||||||
|
and (not do_filtering or e.name in args.efuses_to_show)
|
||||||
|
and not value_only
|
||||||
|
):
|
||||||
|
summary_efuse.append(
|
||||||
ROW_FORMAT
|
ROW_FORMAT
|
||||||
% (
|
% (
|
||||||
e.get_info(),
|
e.get_info(),
|
||||||
@@ -306,18 +321,20 @@ def summary(esp, efuses, args):
|
|||||||
value,
|
value,
|
||||||
perms,
|
perms,
|
||||||
raw,
|
raw,
|
||||||
),
|
)
|
||||||
file=args.file,
|
|
||||||
)
|
)
|
||||||
desc_len = len(e.description[50:])
|
desc_len = len(e.description[50:])
|
||||||
if desc_len:
|
if desc_len:
|
||||||
desc_len += 50
|
desc_len += 50
|
||||||
for i in range(50, desc_len, 50):
|
for i in range(50, desc_len, 50):
|
||||||
print(
|
summary_efuse.append(
|
||||||
"%-50s %-50s" % ("", e.description[i : (50 + i)]),
|
f"{'':<50} {e.description[i : (50 + i)]:<50}"
|
||||||
file=args.file,
|
|
||||||
)
|
)
|
||||||
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] = {
|
json_efuse[e.name] = {
|
||||||
"name": e.name,
|
"name": e.name,
|
||||||
"value": base_value if readable else value,
|
"value": base_value if readable else value,
|
||||||
@@ -331,19 +348,26 @@ def summary(esp, efuses, args):
|
|||||||
"efuse_type": e.efuse_type,
|
"efuse_type": e.efuse_type,
|
||||||
"bit_len": e.bit_len,
|
"bit_len": e.bit_len,
|
||||||
}
|
}
|
||||||
if human_output:
|
if human_output and not value_only:
|
||||||
print("", file=args.file)
|
# Remove empty category if efuses are filtered and there are none to show
|
||||||
if human_output:
|
if do_filtering and summary_efuse[-1] == f"{category.title()} fuses:":
|
||||||
print(efuses.summary(), file=args.file)
|
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()
|
warnings = efuses.get_coding_scheme_warnings()
|
||||||
if warnings:
|
if warnings:
|
||||||
print(
|
summary_efuse.append(
|
||||||
"WARNING: Coding scheme has encoding bit error warnings", file=args.file
|
"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:
|
if args.file != sys.stdout:
|
||||||
args.file.close()
|
args.file.close()
|
||||||
print("Done")
|
print("Done")
|
||||||
if args.format == "json":
|
elif args.format == "json":
|
||||||
json.dump(json_efuse, args.file, sort_keys=True, indent=4)
|
json.dump(json_efuse, args.file, sort_keys=True, indent=4)
|
||||||
print("")
|
print("")
|
||||||
|
|
||||||
|
@@ -184,6 +184,15 @@ class TestReadCommands(EfuseTestCase):
|
|||||||
def test_summary_json(self):
|
def test_summary_json(self):
|
||||||
self.espefuse_py("summary --format json")
|
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(
|
@pytest.mark.skipif(
|
||||||
arg_chip == "esp32p4", reason="No Custom MAC Address defined yet"
|
arg_chip == "esp32p4", reason="No Custom MAC Address defined yet"
|
||||||
)
|
)
|
||||||
|
Reference in New Issue
Block a user