Add build system support for programming ESP32-S2 using DFU utils

This commit is contained in:
Roland Dobai 2020-04-06 16:41:44 +02:00
parent 2aaab7eeef
commit ab9f714248
32 changed files with 444 additions and 53 deletions

View file

@ -159,6 +159,7 @@ def update_exclude_patterns(tags):
# note: in toctrees, these also need to be marked with a :esp32: filter # note: in toctrees, these also need to be marked with a :esp32: filter
for e in ['esp32s2.rst', for e in ['esp32s2.rst',
'hw-reference/esp32s2/**', 'hw-reference/esp32s2/**',
'api-guides/dfu.rst',
'api-guides/ulps2_instruction_set.rst', 'api-guides/ulps2_instruction_set.rst',
'api-reference/peripherals/hmac.rst', 'api-reference/peripherals/hmac.rst',
'api-reference/peripherals/temp_sensor.rst']: 'api-reference/peripherals/temp_sensor.rst']:

View file

@ -0,0 +1,99 @@
***********************************************
Device Firmware Upgrade through USB
***********************************************
.. only:: esp32
.. note::
Device Firmware Upgrade through USB is not supported with ESP32 chips.
Device Firmware Upgrade (DFU) is a mechanism for upgrading the firmware of devices through Universal Serial Bus (USB).
DFU is supported by ESP32-S2 chips. The necessary connections for the USB peripheral are shown in the following table.
+------+-------------+
| GPIO | USB |
+======+=============+
| 19 | D- (green) |
+------+-------------+
| 20 | D+ (white) |
+------+-------------+
| GND | GND (black) |
+------+-------------+
| | +5V (red) |
+------+-------------+
The software requirements of DFU are included in :ref:`get-started-get-prerequisites` of the Getting Started Guide.
Section :ref:`api_guide_dfu_build` describes how to build firmware for DFU with ESP-IDF and
Section :ref:`api_guide_dfu_flash` deals with flashing the firmware.
.. _api_guide_dfu_build:
Building the DFU Image
======================
The DFU image can be created by running::
idf.py dfu
which creates ``dfu.bin`` in the build directory.
.. note::
Don't forget to set the target chip by ``idf.py set-target`` before running ``idf.py dfu``. Otherwise, you might
create an image for a different chip or receive an error message something like ``unknown target 'dfu'``.
.. _api_guide_dfu_flash:
Flashing the Chip with the DFU Image
====================================
The DFU image is downloaded into the chip by running::
idf.py dfu-flash
which relies on `dfu-util <http://dfu-util.sourceforge.net/>`_. Please see :ref:`get-started-get-prerequisites` for
installing ``dfu-util``. ``dfu-util`` needs additional setup for :ref:`api_guide_dfu_flash_win` or setting up an
:ref:`api_guide_dfu_flash_udev`. Mac OS users should be able to use ``dfu-util`` without further setup.
See :ref:`api_guide_dfu_flash_errors` and their solutions.
.. _api_guide_dfu_flash_udev:
udev rule (Linux only)
----------------------
udev is a device manager for the Linux kernel. It allows us to run ``dfu-util`` (and ``idf.py dfu-flash``) without
``sudo`` for gaining access to the chip.
Create file ``/etc/udev/rules.d/40-dfuse.rules`` with the following content::
SUBSYSTEMS=="usb", ATTRS{idVendor}=="303a", ATTRS{idProduct}=="00??", GROUP="plugdev", MODE="0666"
.. note::
Please check the output of command ``groups``. The user has to be a member of the `GROUP` specified above. You may
use some other existing group for this purpose (e.g. `uucp` on some systems instead of `plugdev`) or create a new
group for this purpose.
Restart your computer so the previous setting could take into affect or run ``sudo udevadm trigger`` to force
manually udev to trigger your new rule.
.. _api_guide_dfu_flash_win:
USB drivers (Windows only)
--------------------------
``dfu-util`` uses `libusb` to access the device. You have to register on Windows the device with the `WinUSB` driver.
Please see the `libusb wiki <https://github.com/libusb/libusb/wiki/Windows#How_to_use_libusb_on_Windows>`_ for more
details.
.. _api_guide_dfu_flash_errors:
Common errors
-------------
- ``dfu-util: command not found`` might indicate that the tool hasn't been installed or is not available from the terminal.
An easy way of checking the tool is running ``dfu-util --version``. Please see :ref:`get-started-get-prerequisites` for
installing ``dfu-util``.
- The reason for ``No DFU capable USB device available`` could be that the USB driver wasn't properly installed on
Windows (see :ref:`api_guide_dfu_flash_win`) or udev rule was not setup on Linux
(see :ref:`api_guide_dfu_flash_udev`).

View file

@ -11,6 +11,7 @@ API Guides
Build System <build-system> Build System <build-system>
:esp32: Build System (Legacy GNU Make) <build-system-legacy> :esp32: Build System (Legacy GNU Make) <build-system-legacy>
Deep Sleep Wake Stubs <deep-sleep-stub> Deep Sleep Wake Stubs <deep-sleep-stub>
:esp32s2: Device Firmware Upgrade through USB <dfu>
Error Handling <error-handling> Error Handling <error-handling>
:esp32: ESP-BLE-MESH <esp-ble-mesh/ble-mesh-index> :esp32: ESP-BLE-MESH <esp-ble-mesh/ble-mesh-index>
ESP-MESH (Wi-Fi) <mesh> ESP-MESH (Wi-Fi) <mesh>

View file

@ -47,4 +47,9 @@ On Linux and macOS, it is recommended to install ninja using the OS-specific pac
.. tool-ccache-notes .. tool-ccache-notes
---
.. tool-dfu-util-notes
--- ---

View file

@ -15,15 +15,15 @@ To compile with ESP-IDF you need to get the following packages:
- CentOS 7:: - CentOS 7::
sudo yum install git wget ncurses-devel flex bison gperf python pyserial python-pyelftools cmake ninja-build ccache sudo yum install git wget ncurses-devel flex bison gperf python pyserial python-pyelftools cmake ninja-build ccache dfu-util
- Ubuntu and Debian:: - Ubuntu and Debian::
sudo apt-get install git wget libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-click python-cryptography python-future python-pyparsing python-pyelftools cmake ninja-build ccache libffi-dev libssl-dev sudo apt-get install git wget libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-click python-cryptography python-future python-pyparsing python-pyelftools cmake ninja-build ccache libffi-dev libssl-dev dfu-util
- Arch:: - Arch::
sudo pacman -S --needed gcc git make ncurses flex bison gperf python-pyserial python-click python-cryptography python-future python-pyparsing python-pyelftools cmake ninja ccache sudo pacman -S --needed gcc git make ncurses flex bison gperf python-pyserial python-click python-cryptography python-future python-pyparsing python-pyelftools cmake ninja ccache dfu-util
.. note:: .. note::
CMake version 3.5 or newer is required for use with ESP-IDF. Older Linux distributions may require updating, enabling of a "backports" repository, or installing of a "cmake3" package rather than "cmake". CMake version 3.5 or newer is required for use with ESP-IDF. Older Linux distributions may require updating, enabling of a "backports" repository, or installing of a "cmake3" package rather than "cmake".

View file

@ -11,15 +11,15 @@ To compile with ESP-IDF you need to get the following packages:
- CentOS 7:: - CentOS 7::
sudo yum install git wget flex bison gperf python cmake ninja-build ccache sudo yum install git wget flex bison gperf python cmake ninja-build ccache dfu-util
- Ubuntu and Debian:: - Ubuntu and Debian::
sudo apt-get install git wget flex bison gperf python python-pip python-setuptools cmake ninja-build ccache libffi-dev libssl-dev sudo apt-get install git wget flex bison gperf python python-pip python-setuptools cmake ninja-build ccache libffi-dev libssl-dev dfu-util
- Arch:: - Arch::
sudo pacman -S --needed gcc git make flex bison gperf python-pip cmake ninja ccache sudo pacman -S --needed gcc git make flex bison gperf python-pip cmake ninja ccache dfu-util
.. note:: .. note::
CMake version 3.5 or newer is required for use with ESP-IDF. Older Linux distributions may require updating, enabling of a "backports" repository, or installing of a "cmake3" package rather than "cmake". CMake version 3.5 or newer is required for use with ESP-IDF. Older Linux distributions may require updating, enabling of a "backports" repository, or installing of a "cmake3" package rather than "cmake".

View file

@ -31,11 +31,11 @@ Install Prerequisites
- If you have HomeBrew, you can run:: - If you have HomeBrew, you can run::
brew install cmake ninja brew install cmake ninja dfu-util
- If you have MacPorts, you can run:: - If you have MacPorts, you can run::
sudo port install cmake ninja sudo port install cmake ninja dfu-util
Compile the Toolchain from Source Compile the Toolchain from Source
================================= =================================

View file

@ -21,11 +21,11 @@ ESP-IDF will use the version of Python installed by default on macOS.
- If you have HomeBrew_, you can run:: - If you have HomeBrew_, you can run::
brew install cmake ninja brew install cmake ninja dfu-util
- If you have MacPorts_, you can run:: - If you have MacPorts_, you can run::
sudo port install cmake ninja sudo port install cmake ninja dfu-util
- Otherwise, consult the CMake_ and Ninja_ home pages for macOS installation downloads. - Otherwise, consult the CMake_ and Ninja_ home pages for macOS installation downloads.

View file

@ -0,0 +1 @@
.. include:: ../../en/api-guides/dfu.rst

View file

@ -12,6 +12,7 @@ API 指南
严重错误 <fatal-errors> 严重错误 <fatal-errors>
Event Handling <event-handling> Event Handling <event-handling>
Deep Sleep Wake Stubs <deep-sleep-stub> Deep Sleep Wake Stubs <deep-sleep-stub>
:esp32s2: Device Firmware Upgrade through USB <dfu>
ESP32 Core Dump <core_dump> ESP32 Core Dump <core_dump>
Flash Encryption <../security/flash-encryption> Flash Encryption <../security/flash-encryption>
FreeRTOS SMP Changes <freertos-smp> FreeRTOS SMP Changes <freertos-smp>

View file

@ -49,4 +49,9 @@ On Linux and macOS, it is recommended to install ninja using the OS package mana
.. tool-ccache-notes .. tool-ccache-notes
---
.. tool-dfu-util-notes
--- ---

View file

@ -13,15 +13,15 @@
- CentOS 7:: - CentOS 7::
sudo yum install git wget ncurses-devel flex bison gperf python pyserial python-pyelftools cmake ninja-build ccache sudo yum install git wget ncurses-devel flex bison gperf python pyserial python-pyelftools cmake ninja-build ccache dfu-util
- Ubuntu 和 Debian:: - Ubuntu 和 Debian::
sudo apt-get install git wget libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-click python-cryptography python-future python-pyparsing python-pyelftools cmake ninja-build ccache libffi-dev libssl-dev sudo apt-get install git wget libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-click python-cryptography python-future python-pyparsing python-pyelftools cmake ninja-build ccache libffi-dev libssl-dev dfu-util
- Arch:: - Arch::
sudo pacman -S --needed gcc git make ncurses flex bison gperf python-pyserial python-click python-cryptography python-future python-pyparsing python-pyelftools cmake ninja ccache sudo pacman -S --needed gcc git make ncurses flex bison gperf python-pyserial python-click python-cryptography python-future python-pyparsing python-pyelftools cmake ninja ccache dfu-util
.. note:: .. note::
使用 ESP-IDF 需要 CMake 3.5 或以上版本。较早版本的 Linux 可能需要升级才能向后移植仓库,或安装 "cmake3" 软件包,而不是安装 "cmake"。 使用 ESP-IDF 需要 CMake 3.5 或以上版本。较早版本的 Linux 可能需要升级才能向后移植仓库,或安装 "cmake3" 软件包,而不是安装 "cmake"。

View file

@ -11,15 +11,15 @@ Linux 平台工具链的标准设置
- CentOS 7:: - CentOS 7::
sudo yum install git wget flex bison gperf python cmake ninja-build ccache sudo yum install git wget flex bison gperf python cmake ninja-build ccache dfu-util
- Ubuntu 和 Debian:: - Ubuntu 和 Debian::
sudo apt-get install git wget flex bison gperf python python-pip python-setuptools cmake ninja-build ccache libffi-dev libssl-dev sudo apt-get install git wget flex bison gperf python python-pip python-setuptools cmake ninja-build ccache libffi-dev libssl-dev dfu-util
- Arch:: - Arch::
sudo pacman -S --needed gcc git make flex bison gperf python-pip python-pyserial cmake ninja ccache sudo pacman -S --needed gcc git make flex bison gperf python-pip python-pyserial cmake ninja ccache dfu-util
.. note:: .. note::
使用 ESP-IDF 需要 CMake 3.5 或以上版本。较早版本的 Linux 可能需要升级才能向后移植仓库,或安装 "cmake3" 软件包,而不是安装 "cmake"。 使用 ESP-IDF 需要 CMake 3.5 或以上版本。较早版本的 Linux 可能需要升级才能向后移植仓库,或安装 "cmake3" 软件包,而不是安装 "cmake"。

View file

@ -31,11 +31,11 @@ MacPorts 需要完整的 XCode 软件,而 homebrew 只需要安装 XCode 命
- 若有 HomeBrew您可以运行:: - 若有 HomeBrew您可以运行::
brew install cmake ninja brew install cmake ninja dfu-util
- 若有 MacPorts您可以运行:: - 若有 MacPorts您可以运行::
sudo port install cmake ninja sudo port install cmake ninja dfu-util
从源代码编译工具链 从源代码编译工具链
================================= =================================

View file

@ -21,11 +21,11 @@ ESP-IDF 将使用 Mac OS 上默认安装的 Python 版本。
- 若有 HomeBrew_您可以运行:: - 若有 HomeBrew_您可以运行::
brew install cmake ninja brew install cmake ninja dfu-util
- 若有 MacPorts_您可以运行:: - 若有 MacPorts_您可以运行::
sudo port install cmake ninja sudo port install cmake ninja dfu-util
- 若以上均不适用,请访问 CMake_ 和 Ninja_ 主页,查询有关 Mac OS 平台的下载安装问题。 - 若以上均不适用,请访问 CMake_ 和 Ninja_ 主页,查询有关 Mac OS 平台的下载安装问题。

View file

@ -304,3 +304,11 @@ test_sysviewtrace_proc:
script: script:
- cd ${IDF_PATH}/tools/esp_app_trace/test/sysview - cd ${IDF_PATH}/tools/esp_app_trace/test/sysview
- ${IDF_PATH}/tools/ci/multirun_with_pyenv.sh ./test.sh - ${IDF_PATH}/tools/ci/multirun_with_pyenv.sh ./test.sh
test_mkdfu:
extends: .host_test_template
variables:
LC_ALL: C.UTF-8
script:
- cd ${IDF_PATH}/tools/test_mkdfu
- ${IDF_PATH}/tools/ci/multirun_with_pyenv.sh ./test_mkdfu.py

View file

@ -85,12 +85,14 @@ tools/ldgen/ldgen.py
tools/ldgen/test/test_fragments.py tools/ldgen/test/test_fragments.py
tools/ldgen/test/test_generation.py tools/ldgen/test/test_generation.py
tools/mass_mfg/mfg_gen.py tools/mass_mfg/mfg_gen.py
tools/mkdfu.py
tools/set-submodules-to-github.sh tools/set-submodules-to-github.sh
tools/test_check_kconfigs.py tools/test_check_kconfigs.py
tools/test_idf_monitor/run_test_idf_monitor.py tools/test_idf_monitor/run_test_idf_monitor.py
tools/test_idf_py/test_idf_py.py tools/test_idf_py/test_idf_py.py
tools/test_idf_size/test.sh tools/test_idf_size/test.sh
tools/test_idf_tools/test_idf_tools.py tools/test_idf_tools/test_idf_tools.py
tools/test_mkdfu/test_mkdfu.py
tools/unit-test-app/tools/get_available_configs.sh tools/unit-test-app/tools/get_available_configs.sh
tools/unit-test-app/unit_test.py tools/unit-test-app/unit_test.py
tools/windows/eclipse_make.sh tools/windows/eclipse_make.sh

View file

@ -700,6 +700,16 @@ endmenu\n" >> ${IDF_PATH}/Kconfig
bin_header_match build/bootloader/bootloader.bin "021f" bin_header_match build/bootloader/bootloader.bin "021f"
rm sdkconfig rm sdkconfig
print_status "DFU build works"
rm -f -r build sdkconfig
idf.py dfu &> tmp.log
grep "command \"dfu\" is not known to idf.py and is not a Ninja target" tmp.log || (tail -n 100 tmp.log ; failure "DFU build should fail for default chip target")
idf.py set-target esp32s2
idf.py dfu &> tmp.log
grep "build/dfu.bin\" has been written. You may proceed with DFU flashing." tmp.log || (tail -n 100 tmp.log ; failure "DFU build should succeed for esp32s2")
rm tmp.log
assert_built ${APP_BINS} ${BOOTLOADER_BINS} ${PARTITION_BIN} "dfu.bin"
print_status "All tests completed" print_status "All tests completed"
if [ -n "${FAILURES}" ]; then if [ -n "${FAILURES}" ]; then
echo "Some failures were detected:" echo "Some failures were detected:"

26
tools/cmake/dfu.cmake Normal file
View file

@ -0,0 +1,26 @@
# Add DFU build and flashing related targets
#
function(__add_dfu_targets)
idf_build_get_property(target IDF_TARGET)
if(NOT "${target}" STREQUAL "esp32s2")
return()
endif()
idf_build_get_property(python PYTHON)
idf_build_get_property(idf_path IDF_PATH)
add_custom_target(dfu
COMMAND ${python} ${idf_path}/tools/mkdfu.py write
-o "${CMAKE_CURRENT_BINARY_DIR}/dfu.bin"
--json "${CMAKE_CURRENT_BINARY_DIR}/flasher_args.json"
DEPENDS gen_project_binary bootloader
VERBATIM
USES_TERMINAL)
add_custom_target(dfu-flash
COMMAND dfu-util
-D "${CMAKE_CURRENT_BINARY_DIR}/dfu.bin"
VERBATIM
USES_TERMINAL)
endfunction()

View file

@ -43,6 +43,7 @@ if(NOT __idf_env_set)
include(utilities) include(utilities)
include(targets) include(targets)
include(ldgen) include(ldgen)
include(dfu)
include(version) include(version)
__build_init("${idf_path}") __build_init("${idf_path}")

View file

@ -486,6 +486,9 @@ macro(project project_name)
unset(idf_size) unset(idf_size)
# Add DFU build and flash targets
__add_dfu_targets()
idf_build_executable(${project_elf}) idf_build_executable(${project_elf})
__project_info("${test_components}") __project_info("${test_components}")

View file

@ -447,7 +447,7 @@ def init_cli(verbose_output=None):
def _print_closing_message(self, args, actions): def _print_closing_message(self, args, actions):
# print a closing message of some kind # print a closing message of some kind
# #
if "flash" in str(actions): if "flash" in str(actions) or "dfu" in str(actions):
print("Done") print("Done")
return return

View file

@ -0,0 +1,39 @@
from idf_py_actions.tools import is_target_supported, ensure_build_directory, run_target
from idf_py_actions.errors import FatalError
def action_extensions(base_actions, project_path):
SUPPORTED_TARGETS = ['esp32s2']
def dfu_target(target_name, ctx, args):
ensure_build_directory(args, ctx.info_name)
run_target(target_name, args)
def dfu_flash_target(target_name, ctx, args):
ensure_build_directory(args, ctx.info_name)
try:
run_target(target_name, args)
except FatalError:
# Cannot capture the error from dfu-util here so the best advise is:
print('Please have a look at the "Device Firmware Upgrade through USB" chapter in API Guides of the '
'ESP-IDF documentation for solving common dfu-util issues.')
raise
dfu_actions = {
"actions": {
"dfu": {
"callback": dfu_target,
"short_help": "Build the DFU binary",
"dependencies": ["all"],
},
"dfu-flash": {
"callback": dfu_flash_target,
"short_help": "Flash the DFU binary",
"order_dependencies": ["dfu"],
},
}
}
return dfu_actions if is_target_supported(project_path, SUPPORTED_TARGETS) else {}

View file

@ -269,6 +269,13 @@ def get_sdkconfig_value(sdkconfig_file, key):
return value return value
def is_target_supported(project_path, supported_targets):
"""
Returns True if the active target is supported, or False otherwise.
"""
return get_sdkconfig_value(os.path.join(project_path, "sdkconfig"), 'CONFIG_IDF_TARGET') in supported_targets
def _guess_or_check_idf_target(args, prog_name, cache): def _guess_or_check_idf_target(args, prog_name, cache):
""" """
If CMakeCache.txt doesn't exist, and IDF_TARGET is not set in the environment, guess the value from If CMakeCache.txt doesn't exist, and IDF_TARGET is not set in the environment, guess the value from

View file

@ -1,16 +1,31 @@
#!/usr/bin/env python #!/usr/bin/env python
# #
# Copyright 2020 Espressif Systems (Shanghai) PTE LTD
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# This program creates archives compatible with ESP32-S* ROM DFU implementation. # This program creates archives compatible with ESP32-S* ROM DFU implementation.
# #
# The archives are in CPIO format. Each file which needs to be flashed is added to the archive # The archives are in CPIO format. Each file which needs to be flashed is added to the archive
# as a separate file. In addition to that, a special index file, 'dfuinfo0.dat', is created. # as a separate file. In addition to that, a special index file, 'dfuinfo0.dat', is created.
# This file must be the first one in the archive. It contains binary structures describing each # This file must be the first one in the archive. It contains binary structures describing each
# subsequent file (for example, where the file needs to be flashed/loaded). # subsequent file (for example, where the file needs to be flashed/loaded).
#
import argparse
from collections import namedtuple from collections import namedtuple
from future.utils import iteritems
import argparse
import hashlib import hashlib
import json
import os import os
import struct import struct
import zlib import zlib
@ -21,6 +36,12 @@ except ImportError:
# Only used for type annotations # Only used for type annotations
pass pass
try:
from itertools import izip as zip
except ImportError:
# Python 3
pass
# CPIO ("new ASCII") format related things # CPIO ("new ASCII") format related things
CPIO_MAGIC = b"070701" CPIO_MAGIC = b"070701"
CPIO_STRUCT = b"=6s" + b"8s" * 13 CPIO_STRUCT = b"=6s" + b"8s" * 13
@ -166,46 +187,64 @@ class EspDfuWriter(object):
def action_write(args): def action_write(args):
writer = EspDfuWriter(args.output_file) writer = EspDfuWriter(args['output_file'])
for addr, file in args.files: for addr, f in args['files']:
writer.add_file(addr, file) print('Adding {} at {:#x}'.format(f, addr))
writer.add_file(addr, f)
writer.finish() writer.finish()
print('"{}" has been written. You may proceed with DFU flashing.'.format(args['output_file'].name))
class WriteArgsAction(argparse.Action):
""" Helper for argparse to parse <address, filename> argument pairs """
def __init__(self, *args, **kwargs):
super(WriteArgsAction, self).__init__(*args, **kwargs)
def __call__(self, parser, namespace, values, option_string=None):
# TODO: add validation
addr = 0
result = []
for i, value in enumerate(values):
if i % 2 == 0:
addr = int(value, 0)
else:
result.append((addr, value))
setattr(namespace, self.dest, result)
def main(): def main():
parser = argparse.ArgumentParser("mkdfu") parser = argparse.ArgumentParser()
# Provision to add "info" command # Provision to add "info" command
subparsers = parser.add_subparsers(dest="command") subparsers = parser.add_subparsers(dest="command")
write_parser = subparsers.add_parser("write") write_parser = subparsers.add_parser("write")
write_parser.add_argument("-o", "--output-file", type=argparse.FileType("wb")) write_parser.add_argument("-o", "--output-file",
write_parser.add_argument( help='Filename for storing the output DFU image',
"files", metavar="<address> <file>", action=WriteArgsAction, nargs="+" required=True,
) type=argparse.FileType("wb"))
write_parser.add_argument("--json",
help='Optional file for loading "flash_files" dictionary with <address> <file> items')
write_parser.add_argument("files",
metavar="<address> <file>", help='Add <file> at <address>',
nargs="*")
args = parser.parse_args() args = parser.parse_args()
print(repr(args))
if args.command == "write": def check_file(file_name):
action_write(args) if not os.path.isfile(file_name):
raise RuntimeError('{} is not a regular file!'.format(file_name))
return file_name
files = []
if args.files:
files += [(int(addr, 0), check_file(f_name)) for addr, f_name in zip(args.files[::2], args.files[1::2])]
if args.json:
json_dir = os.path.dirname(os.path.abspath(args.json))
def process_json_file(path):
'''
The input path is relative to json_dir. This function makes it relative to the current working
directory.
'''
return check_file(os.path.relpath(os.path.join(json_dir, path), start=os.curdir))
with open(args.json) as f:
files += [(int(addr, 0),
process_json_file(f_name)) for addr, f_name in iteritems(json.load(f)['flash_files'])]
files = sorted([(addr, f_name) for addr, f_name in iteritems(dict(files))],
key=lambda x: x[0]) # remove possible duplicates and sort based on the address
cmd_args = {'output_file': args.output_file,
'files': files,
}
{'write': action_write
}[args.command](cmd_args)
if __name__ == "__main__": if __name__ == "__main__":

BIN
tools/test_mkdfu/1/1.bin Normal file

Binary file not shown.

BIN
tools/test_mkdfu/1/2.bin Normal file

Binary file not shown.

BIN
tools/test_mkdfu/1/3.bin Normal file

Binary file not shown.

BIN
tools/test_mkdfu/1/dfu.bin Normal file

Binary file not shown.

View file

@ -0,0 +1,7 @@
{
"flash_files" : {
"0x8000" : "2.bin",
"0x1000" : "1.bin",
"0x10000" : "3.bin"
}
}

99
tools/test_mkdfu/test_mkdfu.py Executable file
View file

@ -0,0 +1,99 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright 2020 Espressif Systems (Shanghai) CO LTD
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import unicode_literals
import filecmp
import os
import pexpect
import shutil
import sys
import tempfile
import time
import unittest
current_dir = os.path.dirname(os.path.realpath(__file__))
mkdfu_path = os.path.join(current_dir, '..', 'mkdfu.py')
class TestHelloWorldExample(unittest.TestCase):
def common_test(self, add_args):
with tempfile.NamedTemporaryFile(delete=False) as f:
self.addCleanup(os.unlink, f.name)
cmd = ' '.join([sys.executable, mkdfu_path, 'write',
'-o', f.name,
add_args])
p = pexpect.spawn(cmd, timeout=10)
self.addCleanup(p.terminate, force=True)
p.expect_exact(['Adding 1/bootloader.bin at 0x1000',
'Adding 1/partition-table.bin at 0x8000',
'Adding 1/hello-world.bin at 0x10000',
'"{}" has been written. You may proceed with DFU flashing.'.format(f.name)])
# Need to wait for the process to end because the output file is closed when mkdfu exits.
# Do non-blocking wait instead of the blocking p.wait():
for _ in range(10):
if not p.isalive():
break
time.sleep(0.5)
else:
p.terminate()
self.assertTrue(filecmp.cmp(f.name, os.path.join(current_dir, '1','dfu.bin')), 'Output files are different')
def test_with_json(self):
self.common_test(' '.join(['--json', os.path.join(current_dir, '1', 'flasher_args.json')]))
def test_without_json(self):
self.common_test(' '.join(['0x1000', os.path.join(current_dir, '1', '1.bin'),
'0x8000', os.path.join(current_dir, '1', '2.bin'),
'0x10000', os.path.join(current_dir, '1', '3.bin')
]))
def test_filenames(self):
temp_dir = tempfile.mkdtemp(prefix='very_long_directory_name' * 8)
self.addCleanup(shutil.rmtree, temp_dir, ignore_errors=True)
with tempfile.NamedTemporaryFile(dir=temp_dir, delete=False) as f:
output = f.name
with tempfile.NamedTemporaryFile(prefix='ľščťžýáíéěř\u0420\u043e\u0441\u0441\u0438\u044f',
dir=temp_dir,
delete=False) as f:
bootloader = f.name
shutil.copyfile(os.path.join(current_dir, '1', '1.bin'), bootloader)
cmd = ' '.join([sys.executable, mkdfu_path, 'write',
'-o', output,
' '.join(['0x1000', bootloader,
'0x8000', os.path.join(current_dir, '1', '2.bin'),
'0x10000', os.path.join(current_dir, '1', '3.bin')
])
])
p = pexpect.spawn(cmd, timeout=10, encoding='utf-8')
self.addCleanup(p.terminate, force=True)
p.expect_exact(['Adding {} at 0x1000'.format(bootloader),
'Adding 1/2.bin at 0x8000',
'Adding 1/3.bin at 0x10000',
'"{}" has been written. You may proceed with DFU flashing.'.format(output)])
if __name__ == '__main__':
unittest.main()

View file

@ -483,6 +483,43 @@
} }
} }
] ]
},
{
"description": "dfu-util (Device Firmware Upgrade Utilities)",
"export_paths": [
[
"dfu-util-0.9-win64"
]
],
"export_vars": {},
"info_url": "http://dfu-util.sourceforge.net/",
"install": "never",
"license": "GPL-2.0-only",
"name": "dfu-util",
"platform_overrides": [
{
"install": "always",
"platforms": [
"win64"
]
}
],
"version_cmd": [
"dfu-util",
"--version"
],
"version_regex": "dfu-util ([0-9.]+)",
"versions": [
{
"name": "0.9",
"status": "recommended",
"win64": {
"sha256": "5816d7ec68ef3ac07b5ac9fb9837c57d2efe45b6a80a2f2bbe6b40b1c15c470e",
"size": 735635,
"url": "https://dl.espressif.com/dl/dfu-util-0.9-win64.zip"
}
}
]
} }
], ],
"version": 1 "version": 1