From 431923f23c883811929f0715949dfea51fd52e0d Mon Sep 17 00:00:00 2001 From: Jan Beran Date: Mon, 23 Sep 2024 15:48:59 +0200 Subject: [PATCH] fix(uf2): Ignore ESPBAUD, ESPPORT when calling idf.py uf2[-app] --- components/esptool_py/project_include.cmake | 25 -------- tools/cmake/project.cmake | 27 +++++++++ tools/cmake/run_uf2_cmds.cmake | 27 +++++++++ tools/test_idf_py/test_idf_py.py | 65 ++++++++++++++++++++- 4 files changed, 116 insertions(+), 28 deletions(-) create mode 100644 tools/cmake/run_uf2_cmds.cmake diff --git a/components/esptool_py/project_include.cmake b/components/esptool_py/project_include.cmake index 0252810407..5a197b277f 100644 --- a/components/esptool_py/project_include.cmake +++ b/components/esptool_py/project_include.cmake @@ -11,7 +11,6 @@ set(ESPTOOLPY ${python} "$ENV{ESPTOOL_WRAPPER}" "${CMAKE_CURRENT_LIST_DIR}/espto set(ESPSECUREPY ${python} "${CMAKE_CURRENT_LIST_DIR}/esptool/espsecure.py") set(ESPEFUSEPY ${python} "${CMAKE_CURRENT_LIST_DIR}/esptool/espefuse.py") set(ESPMONITOR ${python} -m esp_idf_monitor) -set(ESPMKUF2 ${python} "${idf_path}/tools/mkuf2.py" write --chip ${chip_model}) set(ESPTOOLPY_CHIP "${chip_model}") if(NOT CONFIG_APP_BUILD_TYPE_RAM AND CONFIG_APP_BUILD_GENERATE_BINARIES) @@ -208,30 +207,6 @@ add_custom_target(erase_flash VERBATIM ) -set(UF2_ARGS --json "${CMAKE_CURRENT_BINARY_DIR}/flasher_args.json") - -add_custom_target(uf2 - COMMAND ${CMAKE_COMMAND} - -D "IDF_PATH=${idf_path}" - -D "SERIAL_TOOL=${ESPMKUF2}" - -D "SERIAL_TOOL_ARGS=${UF2_ARGS};-o;${CMAKE_CURRENT_BINARY_DIR}/uf2.bin" - -P run_serial_tool.cmake - WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} - USES_TERMINAL - VERBATIM - ) - -add_custom_target(uf2-app - COMMAND ${CMAKE_COMMAND} - -D "IDF_PATH=${idf_path}" - -D "SERIAL_TOOL=${ESPMKUF2}" - -D "SERIAL_TOOL_ARGS=${UF2_ARGS};-o;${CMAKE_CURRENT_BINARY_DIR}/uf2-app.bin;--bin;app" - -P run_serial_tool.cmake - WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} - USES_TERMINAL - VERBATIM - ) - add_custom_target(monitor COMMAND ${CMAKE_COMMAND} -D "IDF_PATH=${idf_path}" diff --git a/tools/cmake/project.cmake b/tools/cmake/project.cmake index d5e3da9455..47f15fee53 100644 --- a/tools/cmake/project.cmake +++ b/tools/cmake/project.cmake @@ -779,6 +779,33 @@ macro(project project_name) # Add DFU build and flash targets __add_dfu_targets() + # Add uf2 related targets + idf_build_get_property(idf_path IDF_PATH) + idf_build_get_property(python PYTHON) + + set(UF2_ARGS --json "${CMAKE_CURRENT_BINARY_DIR}/flasher_args.json") + set(UF2_CMD ${python} "${idf_path}/tools/mkuf2.py" write --chip ${chip_model}) + + add_custom_target(uf2 + COMMAND ${CMAKE_COMMAND} + -D "IDF_PATH=${idf_path}" + -D "UF2_CMD=${UF2_CMD}" + -D "UF2_ARGS=${UF2_ARGS};-o;${CMAKE_CURRENT_BINARY_DIR}/uf2.bin" + -P "${idf_path}/tools/cmake/run_uf2_cmds.cmake" + USES_TERMINAL + VERBATIM + ) + + add_custom_target(uf2-app + COMMAND ${CMAKE_COMMAND} + -D "IDF_PATH=${idf_path}" + -D "UF2_CMD=${UF2_CMD}" + -D "UF2_ARGS=${UF2_ARGS};-o;${CMAKE_CURRENT_BINARY_DIR}/uf2-app.bin;--bin;app" + -P "${idf_path}/tools/cmake/run_uf2_cmds.cmake" + USES_TERMINAL + VERBATIM + ) + idf_build_executable(${project_elf}) __project_info("${test_components}") diff --git a/tools/cmake/run_uf2_cmds.cmake b/tools/cmake/run_uf2_cmds.cmake new file mode 100644 index 0000000000..1ed4d5c0fc --- /dev/null +++ b/tools/cmake/run_uf2_cmds.cmake @@ -0,0 +1,27 @@ +# A CMake script to run dfu-util from within ninja or make +# or another cmake-based build runner +# +# It is recommended to NOT USE this CMake script directly + +cmake_minimum_required(VERSION 3.16) + +set(UF2_CMD "${UF2_CMD}") +set(UF2_ARGS "${UF2_ARGS}") + +if(NOT UF2_CMD) + message(FATAL_ERROR "UF2_CMD must be specified on the CMake command line.") +endif() + +if(NOT UF2_ARGS) + message(FATAL_ERROR "UF2_ARGS must be specified on the CMake command line.") +endif() + +set(uf2_cmd_with_args ${UF2_CMD}) +list(APPEND uf2_cmd_with_args ${UF2_ARGS}) + +execute_process(COMMAND ${uf2_cmd_with_args} + RESULT_VARIABLE result) + +if(${result}) + message(FATAL_ERROR "${UF2_CMD} failed") +endif() diff --git a/tools/test_idf_py/test_idf_py.py b/tools/test_idf_py/test_idf_py.py index 678d93a09b..82eec84ddc 100755 --- a/tools/test_idf_py/test_idf_py.py +++ b/tools/test_idf_py/test_idf_py.py @@ -1,13 +1,15 @@ #!/usr/bin/env python # -# SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: Apache-2.0 - import json import os import subprocess import sys -from unittest import TestCase, main, mock +from typing import List +from unittest import main +from unittest import mock +from unittest import TestCase import elftools.common.utils as ecu import jsonschema @@ -344,5 +346,62 @@ class TestFileArgumentExpansion(TestCase): self.assertIn('(expansion of @args_non_existent) could not be opened', cm.exception.output.decode('utf-8', 'ignore')) +class TestWrapperCommands(TestCase): + @classmethod + def setUpClass(cls): + cls.sample_project_dir = os.path.join(current_dir, '..', 'test_build_system', 'build_test_app') + os.chdir(cls.sample_project_dir) + super().setUpClass() + + def call_command(self, command: List[str]) -> str: + try: + output = subprocess.check_output( + command, + env=os.environ, + stderr=subprocess.STDOUT).decode('utf-8', 'ignore') + return output + except subprocess.CalledProcessError as e: + self.fail(f'Process should have exited normally, but it exited with a return code of {e.returncode}') + + @classmethod + def tearDownClass(cls): + subprocess.run([sys.executable, idf_py_path, 'fullclean'], stdout=subprocess.DEVNULL) + os.chdir(current_dir) + super().tearDownClass() + + +class TestUF2Commands(TestWrapperCommands): + """ + Test if uf2 commands are invoked as expected. + This test is not testing the functionality of mkuf2.py/idf.py uf2, but the invocation of the command from idf.py. + """ + + def test_uf2(self): + uf2_command = [sys.executable, idf_py_path, 'uf2'] + output = self.call_command(uf2_command) + self.assertIn('Executing:', output) + + def test_uf2_with_envvars(self): + # Values do not really matter, they should not be used. + os.environ['ESPBAUD'] = '115200' + os.environ['ESPPORT'] = '/dev/ttyUSB0' + self.test_uf2() + os.environ.pop('ESPBAUD') + os.environ.pop('ESPPORT') + + def test_uf2_app(self): + uf2_app_command = [sys.executable, idf_py_path, 'uf2-app'] + output = self.call_command(uf2_app_command) + self.assertIn('Executing:', output) + + def test_uf2_app_with_envvars(self): + # Values do not really matter, they should not be used. + os.environ['ESPBAUD'] = '115200' + os.environ['ESPPORT'] = '/dev/ttyUSB0' + self.test_uf2_app() + os.environ.pop('ESPBAUD') + os.environ.pop('ESPPORT') + + if __name__ == '__main__': main()