mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Add build system support for programming ESP32-S2 using DFU utils
This commit is contained in:
parent
2aaab7eeef
commit
ab9f714248
@ -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']:
|
||||
|
99
docs/en/api-guides/dfu.rst
Normal file
99
docs/en/api-guides/dfu.rst
Normal 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`).
|
@ -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>
|
||||
|
@ -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
|
||||
|
||||
|
||||
---
|
||||
|
@ -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".
|
||||
|
@ -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".
|
||||
|
@ -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
|
||||
=================================
|
||||
|
@ -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.
|
||||
|
||||
|
1
docs/zh_CN/api-guides/dfu.rst
Normal file
1
docs/zh_CN/api-guides/dfu.rst
Normal file
@ -0,0 +1 @@
|
||||
.. include:: ../../en/api-guides/dfu.rst
|
@ -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>
|
||||
|
@ -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
|
||||
|
||||
|
||||
---
|
||||
|
@ -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"。
|
||||
|
@ -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"。
|
||||
|
@ -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
|
||||
|
||||
从源代码编译工具链
|
||||
=================================
|
||||
|
@ -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 平台的下载安装问题。
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -700,6 +700,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
26
tools/cmake/dfu.cmake
Normal 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()
|
@ -43,6 +43,7 @@ if(NOT __idf_env_set)
|
||||
include(utilities)
|
||||
include(targets)
|
||||
include(ldgen)
|
||||
include(dfu)
|
||||
include(version)
|
||||
|
||||
__build_init("${idf_path}")
|
||||
|
@ -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}")
|
||||
|
@ -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
|
||||
|
||||
|
39
tools/idf_py_actions/dfu_ext.py
Normal file
39
tools/idf_py_actions/dfu_ext.py
Normal 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 {}
|
@ -269,6 +269,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
|
||||
|
103
tools/mkdfu.py
103
tools/mkdfu.py
@ -1,16 +1,31 @@
|
||||
#!/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).
|
||||
#
|
||||
|
||||
import argparse
|
||||
from collections import namedtuple
|
||||
from future.utils import iteritems
|
||||
import argparse
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
import struct
|
||||
import zlib
|
||||
@ -21,6 +36,12 @@ 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
|
||||
@ -166,46 +187,64 @@ class EspDfuWriter(object):
|
||||
|
||||
|
||||
def action_write(args):
|
||||
writer = EspDfuWriter(args.output_file)
|
||||
for addr, file in args.files:
|
||||
writer.add_file(addr, file)
|
||||
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()
|
||||
|
||||
|
||||
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)
|
||||
print('"{}" has been written. You may proceed with DFU flashing.'.format(args['output_file'].name))
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser("mkdfu")
|
||||
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", type=argparse.FileType("wb"))
|
||||
write_parser.add_argument(
|
||||
"files", metavar="<address> <file>", action=WriteArgsAction, nargs="+"
|
||||
)
|
||||
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()
|
||||
print(repr(args))
|
||||
if args.command == "write":
|
||||
action_write(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__":
|
||||
|
BIN
tools/test_mkdfu/1/1.bin
Normal file
BIN
tools/test_mkdfu/1/1.bin
Normal file
Binary file not shown.
BIN
tools/test_mkdfu/1/2.bin
Normal file
BIN
tools/test_mkdfu/1/2.bin
Normal file
Binary file not shown.
BIN
tools/test_mkdfu/1/3.bin
Normal file
BIN
tools/test_mkdfu/1/3.bin
Normal file
Binary file not shown.
BIN
tools/test_mkdfu/1/dfu.bin
Normal file
BIN
tools/test_mkdfu/1/dfu.bin
Normal file
Binary file not shown.
7
tools/test_mkdfu/1/flasher_args.json
Normal file
7
tools/test_mkdfu/1/flasher_args.json
Normal 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
99
tools/test_mkdfu/test_mkdfu.py
Executable 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()
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user