Merge branch 'feature/dfu_build_flash_s2' into 'master'

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

Closes IDF-579

See merge request espressif/esp-idf!8294
This commit is contained in:
Angus Gratton 2020-05-04 14:57:51 +08:00
commit f9552baf97
32 changed files with 624 additions and 21 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
for e in ['esp32s2.rst',
'hw-reference/esp32s2/**',
'api-guides/dfu.rst',
'api-guides/ulps2_instruction_set.rst',
'api-reference/peripherals/hmac.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>
:esp32: Build System (Legacy GNU Make) <build-system-legacy>
Deep Sleep Wake Stubs <deep-sleep-stub>
:esp32s2: Device Firmware Upgrade through USB <dfu>
Error Handling <error-handling>
:esp32: ESP-BLE-MESH <esp-ble-mesh/ble-mesh-index>
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-dfu-util-notes
---

View File

@ -15,15 +15,15 @@ To compile with ESP-IDF you need to get the following packages:
- 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::
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::
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::
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::
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::
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::
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::
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::
brew install cmake ninja
brew install cmake ninja dfu-util
- If you have MacPorts, you can run::
sudo port install cmake ninja
sudo port install cmake ninja dfu-util
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::
brew install cmake ninja
brew install cmake ninja dfu-util
- 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.

View File

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

View File

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

View File

@ -13,15 +13,15 @@
- 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::
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::
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::
使用 ESP-IDF 需要 CMake 3.5 或以上版本。较早版本的 Linux 可能需要升级才能向后移植仓库,或安装 "cmake3" 软件包,而不是安装 "cmake"。

View File

@ -11,15 +11,15 @@ Linux 平台工具链的标准设置
- 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::
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::
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::
使用 ESP-IDF 需要 CMake 3.5 或以上版本。较早版本的 Linux 可能需要升级才能向后移植仓库,或安装 "cmake3" 软件包,而不是安装 "cmake"。

View File

@ -31,11 +31,11 @@ MacPorts 需要完整的 XCode 软件,而 homebrew 只需要安装 XCode 命
- 若有 HomeBrew您可以运行::
brew install cmake ninja
brew install cmake ninja dfu-util
- 若有 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_您可以运行::
brew install cmake ninja
brew install cmake ninja dfu-util
- 若有 MacPorts_您可以运行::
sudo port install cmake ninja
sudo port install cmake ninja dfu-util
- 若以上均不适用,请访问 CMake_ 和 Ninja_ 主页,查询有关 Mac OS 平台的下载安装问题。

View File

@ -304,3 +304,11 @@ test_sysviewtrace_proc:
script:
- cd ${IDF_PATH}/tools/esp_app_trace/test/sysview
- ${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_generation.py
tools/mass_mfg/mfg_gen.py
tools/mkdfu.py
tools/set-submodules-to-github.sh
tools/test_check_kconfigs.py
tools/test_idf_monitor/run_test_idf_monitor.py
tools/test_idf_py/test_idf_py.py
tools/test_idf_size/test.sh
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/unit_test.py
tools/windows/eclipse_make.sh

View File

@ -707,6 +707,16 @@ endmenu\n" >> ${IDF_PATH}/Kconfig
bin_header_match build/bootloader/bootloader.bin "021f"
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"
if [ -n "${FAILURES}" ]; then
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(targets)
include(ldgen)
include(dfu)
include(version)
__build_init("${idf_path}")

View File

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

View File

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

@ -270,6 +270,13 @@ def get_sdkconfig_value(sdkconfig_file, key):
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):
"""
If CMakeCache.txt doesn't exist, and IDF_TARGET is not set in the environment, guess the value from

251
tools/mkdfu.py Executable file
View File

@ -0,0 +1,251 @@
#!/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.
#
# 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.
# 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).
from collections import namedtuple
from future.utils import iteritems
import argparse
import hashlib
import json
import os
import struct
import zlib
try:
import typing
except ImportError:
# Only used for type annotations
pass
try:
from itertools import izip as zip
except ImportError:
# Python 3
pass
# CPIO ("new ASCII") format related things
CPIO_MAGIC = b"070701"
CPIO_STRUCT = b"=6s" + b"8s" * 13
CPIOHeader = namedtuple(
"CPIOHeader",
[
"magic",
"ino",
"mode",
"uid",
"gid",
"nlink",
"mtime",
"filesize",
"devmajor",
"devminor",
"rdevmajor",
"rdevminor",
"namesize",
"check",
],
)
CPIO_TRAILER = "TRAILER!!!"
def make_cpio_header(
filename_len, file_len, is_trailer=False
): # type: (int, int, bool) -> CPIOHeader
""" Returns CPIOHeader for the given file name and file size """
def as_hex(val): # type: (int) -> bytes
return "{:08x}".format(val).encode("ascii")
hex_0 = as_hex(0)
mode = hex_0 if is_trailer else as_hex(0o0100644)
nlink = as_hex(1) if is_trailer else hex_0
return CPIOHeader(
magic=CPIO_MAGIC,
ino=hex_0,
mode=mode,
uid=hex_0,
gid=hex_0,
nlink=nlink,
mtime=hex_0,
filesize=as_hex(file_len),
devmajor=hex_0,
devminor=hex_0,
rdevmajor=hex_0,
rdevminor=hex_0,
namesize=as_hex(filename_len),
check=hex_0,
)
# DFU format related things
# Structure of one entry in dfuinfo0.dat
DFUINFO_STRUCT = b"<I I 64s 16s"
DFUInfo = namedtuple("DFUInfo", ["address", "flags", "name", "md5"])
DFUINFO_FILE = "dfuinfo0.dat"
# Structure which gets added at the end of the entire DFU file
DFUSUFFIX_STRUCT = b"<H H H H 3s B"
DFUSuffix = namedtuple(
"DFUSuffix", ["bcd_device", "pid", "vid", "bcd_dfu", "sig", "len"]
)
ESPRESSIF_VID = 12346
# TODO: set PID based on the chip type (add a command line argument)
DFUSUFFIX_DEFAULT = DFUSuffix(0xFFFF, 0xFFFF, ESPRESSIF_VID, 0x0100, b"UFD", 16)
# This CRC32 gets added after DFUSUFFIX_STRUCT
DFUCRC_STRUCT = b"<I"
def dfu_crc(data, crc=0): # type: (bytes, int) -> int
""" Calculate CRC32/JAMCRC of data, with an optional initial value """
uint32_max = 0xFFFFFFFF
return uint32_max - (zlib.crc32(data, crc) & uint32_max)
def pad_bytes(b, multiple, padding=b"\x00"): # type: (bytes, int, bytes) -> bytes
""" Pad 'b' to a length divisible by 'multiple' """
padded_len = (len(b) + multiple - 1) // multiple * multiple
return b + padding * (padded_len - len(b))
class EspDfuWriter(object):
def __init__(self, dest_file): # type: (typing.BinaryIO) -> None
self.dest = dest_file
self.entries = [] # type: typing.List[bytes]
self.index = [] # type: typing.List[DFUInfo]
def add_file(self, flash_addr, path): # type: (int, str) -> None
""" Add file to be written into flash at given address """
with open(path, "rb") as f:
self._add_cpio_flash_entry(os.path.basename(path), flash_addr, f.read())
def finish(self): # type: () -> None
""" Write DFU file """
# Prepare and add dfuinfo0.dat file
dfuinfo = b"".join([struct.pack(DFUINFO_STRUCT, *item) for item in self.index])
self._add_cpio_entry(DFUINFO_FILE, dfuinfo, first=True)
# Add CPIO archive trailer
self._add_cpio_entry(CPIO_TRAILER, b"", trailer=True)
# Combine all the entries and pad the file
out_data = b"".join(self.entries)
cpio_block_size = 10240
out_data = pad_bytes(out_data, cpio_block_size)
# Add DFU suffix and CRC
out_data += struct.pack(DFUSUFFIX_STRUCT, *DFUSUFFIX_DEFAULT)
out_data += struct.pack(DFUCRC_STRUCT, dfu_crc(out_data))
# Finally write the entire binary
self.dest.write(out_data)
def _add_cpio_flash_entry(
self, filename, flash_addr, data
): # type: (str, int, bytes) -> None
md5 = hashlib.md5()
md5.update(data)
self.index.append(
DFUInfo(
address=flash_addr,
flags=0,
name=filename.encode("utf-8"),
md5=md5.digest(),
)
)
self._add_cpio_entry(filename, data)
def _add_cpio_entry(
self, filename, data, first=False, trailer=False
): # type: (str, bytes, bool, bool) -> None
filename_b = filename.encode("utf-8") + b"\x00"
cpio_header = make_cpio_header(len(filename_b), len(data), is_trailer=trailer)
entry = pad_bytes(
struct.pack(CPIO_STRUCT, *cpio_header) + filename_b, 4
) + pad_bytes(data, 4)
if not first:
self.entries.append(entry)
else:
self.entries.insert(0, entry)
def action_write(args):
writer = EspDfuWriter(args['output_file'])
for addr, f in args['files']:
print('Adding {} at {:#x}'.format(f, addr))
writer.add_file(addr, f)
writer.finish()
print('"{}" has been written. You may proceed with DFU flashing.'.format(args['output_file'].name))
def main():
parser = argparse.ArgumentParser()
# Provision to add "info" command
subparsers = parser.add_subparsers(dest="command")
write_parser = subparsers.add_parser("write")
write_parser.add_argument("-o", "--output-file",
help='Filename for storing the output DFU image',
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()
def check_file(file_name):
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__":
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