Skip to content

Commit 7283b99

Browse files
committed
Merge branch 'feature/dfu_select_device' into 'master'
Add ability to select a device for DFU flashing Closes IDF-1652 See merge request espressif/esp-idf!8956
2 parents 58e1100 + 0ff8ec6 commit 7283b99

File tree

7 files changed

+88
-11
lines changed

7 files changed

+88
-11
lines changed

docs/en/api-guides/dfu.rst

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,22 @@ which relies on `dfu-util <http://dfu-util.sourceforge.net/>`_. Please see :ref:
6464
installing ``dfu-util``. ``dfu-util`` needs additional setup for :ref:`api_guide_dfu_flash_win` or setting up an
6565
:ref:`api_guide_dfu_flash_udev`. Mac OS users should be able to use ``dfu-util`` without further setup.
6666

67+
If there are more boards with the same chip connected then ``idf.py dfu-list`` can be used to list the available
68+
devices, for example::
69+
70+
Found Runtime: [303a:0002] ver=0723, devnum=4, cfg=1, intf=2, path="1-10", alt=0, name="UNKNOWN", serial="0"
71+
Found Runtime: [303a:0002] ver=0723, devnum=6, cfg=1, intf=2, path="1-2", alt=0, name="UNKNOWN", serial="0"
72+
73+
Consequently, the desired device can be selected for flashing by the ``--path`` argument. For example, the devices
74+
listed above can be flashed individually by the following commands::
75+
76+
idf.py dfu-flash --path 1-10
77+
idf.py dfu-flash --path 1-2
78+
79+
.. note::
80+
The vendor and product identificators are set based on the selected chip target by the ``idf.py set-target``
81+
command and it is not selectable during the ``idf.py dfu-flash`` call.
82+
6783
See :ref:`api_guide_dfu_flash_errors` and their solutions.
6884

6985
.. _api_guide_dfu_flash_udev:

tools/cmake/dfu.cmake

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,12 @@
33

44
function(__add_dfu_targets)
55
idf_build_get_property(target IDF_TARGET)
6-
if(NOT "${target}" STREQUAL "esp32s2")
6+
if("${target}" STREQUAL "esp32")
77
return()
8+
elseif("${target}" STREQUAL "esp32s2")
9+
set(dfu_pid "2")
10+
else()
11+
message(FATAL_ERROR "DFU PID unknown for ${target}")
812
endif()
913

1014
idf_build_get_property(python PYTHON)
@@ -14,13 +18,21 @@ function(__add_dfu_targets)
1418
COMMAND ${python} ${idf_path}/tools/mkdfu.py write
1519
-o "${CMAKE_CURRENT_BINARY_DIR}/dfu.bin"
1620
--json "${CMAKE_CURRENT_BINARY_DIR}/flasher_args.json"
21+
--pid "${dfu_pid}"
1722
DEPENDS gen_project_binary bootloader
1823
VERBATIM
1924
USES_TERMINAL)
2025

26+
add_custom_target(dfu-list
27+
COMMAND ${CMAKE_COMMAND}
28+
-D ESP_DFU_LIST="1"
29+
-P ${idf_path}/tools/cmake/run_dfu_util.cmake
30+
USES_TERMINAL)
31+
2132
add_custom_target(dfu-flash
22-
COMMAND dfu-util
23-
-D "${CMAKE_CURRENT_BINARY_DIR}/dfu.bin"
24-
VERBATIM
33+
COMMAND ${CMAKE_COMMAND}
34+
-D ESP_DFU_BIN="${CMAKE_CURRENT_BINARY_DIR}/dfu.bin"
35+
-D ESP_DFU_PID="${dfu_pid}"
36+
-P ${idf_path}/tools/cmake/run_dfu_util.cmake
2537
USES_TERMINAL)
2638
endfunction()

tools/cmake/run_dfu_util.cmake

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# A CMake script to run dfu-util from within ninja or make
2+
# or another cmake-based build runner
3+
#
4+
# It is recommended to NOT USE this CMake script directly
5+
6+
cmake_minimum_required(VERSION 3.5)
7+
8+
set(TOOL "dfu-util")
9+
set(CMD "${TOOL}")
10+
11+
if(${ESP_DFU_LIST})
12+
list(APPEND CMD "--list")
13+
else()
14+
# The following works even when ESP_DFU_PID is not defined.
15+
list(APPEND CMD "-d" "303a:${ESP_DFU_PID}")
16+
17+
if(NOT $ENV{ESP_DFU_PATH} STREQUAL "")
18+
list(APPEND CMD "--path" $ENV{ESP_DFU_PATH})
19+
endif()
20+
list(APPEND CMD "-D" ${ESP_DFU_BIN})
21+
endif()
22+
23+
message("Command list: ${CMD}")
24+
execute_process(COMMAND ${CMD} RESULT_VARIABLE result)
25+
26+
if(${result})
27+
message(FATAL_ERROR "${TOOL} failed")
28+
endif()

tools/idf_py_actions/dfu_ext.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@ def dfu_target(target_name, ctx, args):
1010
ensure_build_directory(args, ctx.info_name)
1111
run_target(target_name, args)
1212

13-
def dfu_flash_target(target_name, ctx, args):
13+
def dfu_flash_target(target_name, ctx, args, path):
1414
ensure_build_directory(args, ctx.info_name)
1515

1616
try:
17-
run_target(target_name, args)
17+
run_target(target_name, args, {"ESP_DFU_PATH": path})
1818
except FatalError:
1919
# Cannot capture the error from dfu-util here so the best advise is:
2020
print('Please have a look at the "Device Firmware Upgrade through USB" chapter in API Guides of the '
@@ -28,10 +28,24 @@ def dfu_flash_target(target_name, ctx, args):
2828
"short_help": "Build the DFU binary",
2929
"dependencies": ["all"],
3030
},
31+
"dfu-list": {
32+
"callback": dfu_target,
33+
"short_help": "List DFU capable devices",
34+
"dependencies": [],
35+
},
3136
"dfu-flash": {
3237
"callback": dfu_flash_target,
3338
"short_help": "Flash the DFU binary",
3439
"order_dependencies": ["dfu"],
40+
"options": [
41+
{
42+
"names": ["--path"],
43+
"default": "",
44+
"help": "Specify path to DFU device. The default empty path works if there is just one "
45+
"ESP device with the same product identificator. See the device list for paths "
46+
"of available devices."
47+
}
48+
],
3549
},
3650
}
3751
}

tools/mkdfu.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,6 @@ def as_hex(val): # type: (int) -> bytes
107107
"DFUSuffix", ["bcd_device", "pid", "vid", "bcd_dfu", "sig", "len"]
108108
)
109109
ESPRESSIF_VID = 12346
110-
# TODO: set PID based on the chip type (add a command line argument)
111-
DFUSUFFIX_DEFAULT = DFUSuffix(0xFFFF, 0xFFFF, ESPRESSIF_VID, 0x0100, b"UFD", 16)
112110
# This CRC32 gets added after DFUSUFFIX_STRUCT
113111
DFUCRC_STRUCT = b"<I"
114112

@@ -126,8 +124,9 @@ def pad_bytes(b, multiple, padding=b"\x00"): # type: (bytes, int, bytes) -> byt
126124

127125

128126
class EspDfuWriter(object):
129-
def __init__(self, dest_file): # type: (typing.BinaryIO) -> None
127+
def __init__(self, dest_file, pid): # type: (typing.BinaryIO) -> None
130128
self.dest = dest_file
129+
self.pid = pid
131130
self.entries = [] # type: typing.List[bytes]
132131
self.index = [] # type: typing.List[DFUInfo]
133132

@@ -151,7 +150,8 @@ def finish(self): # type: () -> None
151150
out_data = pad_bytes(out_data, cpio_block_size)
152151

153152
# Add DFU suffix and CRC
154-
out_data += struct.pack(DFUSUFFIX_STRUCT, *DFUSUFFIX_DEFAULT)
153+
dfu_suffix = DFUSuffix(0xFFFF, self.pid, ESPRESSIF_VID, 0x0100, b"UFD", 16)
154+
out_data += struct.pack(DFUSUFFIX_STRUCT, *dfu_suffix)
155155
out_data += struct.pack(DFUCRC_STRUCT, dfu_crc(out_data))
156156

157157
# Finally write the entire binary
@@ -187,7 +187,7 @@ def _add_cpio_entry(
187187

188188

189189
def action_write(args):
190-
writer = EspDfuWriter(args['output_file'])
190+
writer = EspDfuWriter(args['output_file'], args['pid'])
191191
for addr, f in args['files']:
192192
print('Adding {} at {:#x}'.format(f, addr))
193193
writer.add_file(addr, f)
@@ -205,6 +205,10 @@ def main():
205205
help='Filename for storing the output DFU image',
206206
required=True,
207207
type=argparse.FileType("wb"))
208+
write_parser.add_argument("--pid",
209+
required=True,
210+
type=lambda h: int(h, 16),
211+
help='Hexa-decimal product indentificator')
208212
write_parser.add_argument("--json",
209213
help='Optional file for loading "flash_files" dictionary with <address> <file> items')
210214
write_parser.add_argument("files",
@@ -241,6 +245,7 @@ def process_json_file(path):
241245

242246
cmd_args = {'output_file': args.output_file,
243247
'files': files,
248+
'pid': args.pid,
244249
}
245250

246251
{'write': action_write

tools/test_mkdfu/1/dfu.bin

0 Bytes
Binary file not shown.

tools/test_mkdfu/test_mkdfu.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ def common_test(self, add_args):
3535
self.addCleanup(os.unlink, f.name)
3636
cmd = ' '.join([sys.executable, mkdfu_path, 'write',
3737
'-o', f.name,
38+
'--pid', '2',
3839
add_args])
3940
p = pexpect.spawn(cmd, timeout=10)
4041
self.addCleanup(p.terminate, force=True)
@@ -81,6 +82,7 @@ def test_filenames(self):
8182

8283
cmd = ' '.join([sys.executable, mkdfu_path, 'write',
8384
'-o', output,
85+
'--pid', '2',
8486
' '.join(['0x1000', bootloader,
8587
'0x8000', os.path.join(current_dir, '1', '2.bin'),
8688
'0x10000', os.path.join(current_dir, '1', '3.bin')

0 commit comments

Comments
 (0)