diff --git a/components/esptool_py/espefuse.cmake b/components/esptool_py/espefuse.cmake new file mode 100644 index 0000000000..d8c7d04256 --- /dev/null +++ b/components/esptool_py/espefuse.cmake @@ -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() diff --git a/components/esptool_py/project_include.cmake b/components/esptool_py/project_include.cmake index 57ef7b1a88..709c007960 100644 --- a/components/esptool_py/project_include.cmake +++ b/components/esptool_py/project_include.cmake @@ -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) diff --git a/components/esptool_py/run_serial_tool.cmake b/components/esptool_py/run_serial_tool.cmake index 93abb87fdc..31c7339fec 100644 --- a/components/esptool_py/run_serial_tool.cmake +++ b/components/esptool_py/run_serial_tool.cmake @@ -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() diff --git a/docs/en/api-reference/system/efuse.rst b/docs/en/api-reference/system/efuse.rst index e9c12805c0..b516710b07 100644 --- a/docs/en/api-reference/system/efuse.rst +++ b/docs/en/api-reference/system/efuse.rst @@ -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 ------------------------ diff --git a/examples/system/efuse/CMakeLists.txt b/examples/system/efuse/CMakeLists.txt index c9a6b5f6c7..56d50e5bdb 100644 --- a/examples/system/efuse/CMakeLists.txt +++ b/examples/system/efuse/CMakeLists.txt @@ -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 + ) diff --git a/examples/system/efuse/get_efuse_summary.cmake b/examples/system/efuse/get_efuse_summary.cmake new file mode 100644 index 0000000000..ecb0d2133c --- /dev/null +++ b/examples/system/efuse/get_efuse_summary.cmake @@ -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() diff --git a/tools/test_build_system/test_common.py b/tools/test_build_system/test_common.py index 2ed04639d2..af43c89108 100644 --- a/tools/test_build_system/test_common.py +++ b/tools/test_build_system/test_common.py @@ -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