Skip to content

Commit

Permalink
feat(espefuse): Allow filtering efuses based on command line arguments
Browse files Browse the repository at this point in the history
  • Loading branch information
Jan Beran authored and radimkarnis committed Apr 23, 2024
1 parent d4c8cb3 commit bb52d36
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 27 deletions.
36 changes: 34 additions & 2 deletions docs/en/espefuse/summary-cmd.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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 <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 <filtering-eFuses>` section.

Text Format Summary
-------------------
Expand Down Expand Up @@ -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)
74 changes: 49 additions & 25 deletions espefuse/efuse/base_operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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."
Expand Down Expand Up @@ -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)",
Expand All @@ -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 = ""
Expand Down Expand Up @@ -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(),
Expand All @@ -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,
Expand All @@ -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("")

Expand Down
9 changes: 9 additions & 0 deletions test/test_espefuse.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)
Expand Down

0 comments on commit bb52d36

Please sign in to comment.