esptool_py: Adds funcs to read eFuses from Cmake during a build stage

Closes https://github.com/espressif/esp-idf/issues/10311
This commit is contained in:
KonstantinKondrashov 2023-01-04 00:30:38 +08:00
parent d9a80ec7cf
commit fd721c5b09
7 changed files with 147 additions and 5 deletions

View File

@ -0,0 +1,47 @@
cmake_minimum_required(VERSION 3.16)
# Executes a espefuse.py command and returns a cleaned log
function(espefuse_cmd cmd output_log)
set(SERIAL_TOOL ${ESPEFUSEPY})
if(${ESPEFUSEPY_OFFLINE})
set(VIRT_OPTION "--virt")
endif()
set(SERIAL_TOOL_ARGS ${VIRT_OPTION} "--chip;${IDF_TARGET};${cmd}")
set(SERIAL_TOOL_SILENT 1)
include(${esptool_py_dir}/run_serial_tool.cmake)
set(log ${SERIAL_TOOL_OUTPUT_LOG})
set(prefix_str " command ===")
string(FIND ${log} ${prefix_str} pos)
if(${pos} GREATER -1)
string(LENGTH ${prefix_str} len_of_prefix_str)
math(EXPR pos "${pos} + ${len_of_prefix_str}")
string(SUBSTRING ${log} ${pos} -1 final_log)
else()
set(final_log ${log})
endif()
set(${output_log} ${final_log} PARENT_SCOPE)
endfunction()
# Reads efuses "espefuse.py summary" and returns JSON string
function(espefuse_get_json_summary json_str)
espefuse_cmd("summary;--format;json" output_log)
set(${json_str} ${output_log} PARENT_SCOPE)
endfunction()
# See the esp-idf/docs/en/api-reference/system/efuse.rst "Get eFuses During Build".
#
# It takes the efuse json string and returns a value of property for a given efuse name
function(espefuse_get_efuse result efuse_json efuse_name efuse_property)
if(${CMAKE_VERSION} VERSION_LESS "3.19.0")
string(REGEX MATCH "\"${efuse_name}\":[ \t\n\r]*\{[^\}]*\}" cur_efuse ${efuse_json})
string(REGEX MATCH "\"${efuse_property}\":[ \t\n\r]*\"?([^,\"]*)\"?," ret_value ${cur_efuse})
set(${result} ${CMAKE_MATCH_1} PARENT_SCOPE)
else()
# The JSON feature has been supported by Cmake since 3.19.0
string(JSON cur_efuse GET ${efuse_json} ${efuse_name})
string(JSON ret_value GET ${cur_efuse} ${efuse_property})
set(${result} ${ret_value} PARENT_SCOPE)
endif()
endfunction()

View File

@ -494,3 +494,7 @@ if(NOT BOOTLOADER_BUILD)
esptool_py_custom_target(flash project "${flash_deps}")
endif()
# Adds espefuse functions for global use
idf_component_get_property(esptool_py_dir esptool_py COMPONENT_DIR)
include(${esptool_py_dir}/espefuse.cmake)

View File

@ -45,12 +45,20 @@ endif()
list(APPEND serial_tool_cmd ${SERIAL_TOOL_ARGS})
execute_process(COMMAND ${serial_tool_cmd}
WORKING_DIRECTORY "${WORKING_DIRECTORY}"
RESULT_VARIABLE result
if(${SERIAL_TOOL_SILENT})
execute_process(COMMAND ${serial_tool_cmd}
WORKING_DIRECTORY "${WORKING_DIRECTORY}"
RESULT_VARIABLE result
OUTPUT_VARIABLE SERIAL_TOOL_OUTPUT_LOG
)
else()
execute_process(COMMAND ${serial_tool_cmd}
WORKING_DIRECTORY "${WORKING_DIRECTORY}"
RESULT_VARIABLE result
)
endif()
if(${result})
# No way to have CMake silently fail, unfortunately
message(FATAL_ERROR "${SERIAL_TOOL} failed")
message(FATAL_ERROR "${SERIAL_TOOL} failed. \n${SERIAL_TOOL_OUTPUT_LOG}")
endif()

View File

@ -401,6 +401,53 @@ Thus, reading the eFuse ``USER_DATA`` block written as above gives the following
// id = 0x01
// b'001
Get eFuses During Build
-----------------------
There is a way to get the state of eFuses at the build stage of the project. There are two cmake functions for this:
* ``espefuse_get_json_summary()`` - It calls the ``espefuse.py summary --format json`` command and returns a json string (it is not stored in a file).
* ``espefuse_get_efuse()`` - It finds a given eFuse name in the json string and returns its property.
The json string has the following properties:
.. code-block:: json
{
"MAC": {
"bit_len": 48,
"block": 0,
"category": "identity",
"description": "Factory MAC Address",
"efuse_type": "bytes:6",
"name": "MAC",
"pos": 0,
"readable": true,
"value": "94:b9:7e:5a:6e:58 (CRC 0xe2 OK)",
"word": 1,
"writeable": true
},
}
These functions can be used from a top-level project ``CMakeLists.txt`` (:example_file:`get-started/hello_world/CMakeLists.txt`):
.. code-block:: cmake
# ...
project(hello_world)
espefuse_get_json_summary(efuse_json)
espefuse_get_efuse(ret_data ${efuse_json} "MAC" "value")
message("MAC:" ${ret_data})
The format of the ``value`` property is the same as shown in ``espefuse.py summary``.
.. code-block:: none
MAC:94:b9:7e:5a:6e:58 (CRC 0xe2 OK)
There is an example test :example_file:`system/efuse/CMakeLists.txt` which adds a custom target ``efuse-summary``. This allows you to run the ``idf.py efuse-summary`` command to read the required eFuses (specified in the ``efuse_names`` list) at any time, not just at project build time.
Debug eFuse & Unit tests
------------------------

View File

@ -4,3 +4,19 @@ cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(efuse)
idf_component_get_property(esptool_py_dir esptool_py COMPONENT_DIR)
set(efuse_names "MAC" "WR_DIS")
add_custom_target(efuse-summary
COMMAND ${CMAKE_COMMAND}
-D "IDF_PATH=${IDF_PATH}"
-D "esptool_py_dir=${esptool_py_dir}"
-D "ESPEFUSEPY=${ESPEFUSEPY}"
-D "ESPEFUSEPY_OFFLINE=${CONFIG_IDF_CI_BUILD}" # Only for CI tests. Do not establish a connection with the chip
-D "IDF_TARGET=${IDF_TARGET}"
-D "efuse_names=${efuse_names}"
-P get_efuse_summary.cmake
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
USES_TERMINAL
VERBATIM
)

View File

@ -0,0 +1,8 @@
cmake_minimum_required(VERSION 3.16)
include(${esptool_py_dir}/espefuse.cmake)
espefuse_get_json_summary(efuse_json)
foreach(name ${efuse_names})
espefuse_get_efuse(ret_data ${efuse_json} ${name} "value")
message(STATUS "FROM_CMAKE: ${name}: ${ret_data}")
endforeach()

View File

@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
import shutil
import subprocess
@ -71,3 +71,15 @@ def test_idf_build_with_env_var_sdkconfig_defaults(
with open(test_app_copy / 'sdkconfig') as fr:
assert 'CONFIG_BT_ENABLED=y' in fr.read()
@pytest.mark.usefixtures('test_app_copy')
@pytest.mark.test_app_copy('examples/system/efuse')
def test_efuse_symmary_cmake_functions(
idf_py: IdfPyFunc,
monkeypatch: MonkeyPatch
) -> None:
monkeypatch.setenv('IDF_CI_BUILD', '1')
output = idf_py('efuse-summary')
assert 'FROM_CMAKE: MAC: 00:00:00:00:00:00' in output.stdout
assert 'FROM_CMAKE: WR_DIS: 0' in output.stdout