adafruit / circuitpython

CircuitPython - a Python implementation for teaching coding with microcontrollers
https://circuitpython.org
Other
4.09k stars 1.21k forks source link

dfu.py doesn't generate valid DFU images #2742

Closed xobs closed 4 years ago

xobs commented 4 years ago

In trying to add support for Fomu, I found a script called dfu.py that seems to indicate that it can be used to create standard USB DFU images. However, the output does not appear to be valid.

For comparison with the standard dfu tools:

$ cp firmware.bin firmware-dfu-suffix.dfu
$ dfu-suffix -a firmware-dfu-suffix.dfu -p 70bl -v 1209
$  ../../../tools/dfu.py -b 0:firmware.bin -D 0x1209:0x70b1 firmware-python.dfu
$ ls -l *.dfu
-rwxrwxrwx 1 xobs xobs 307000 Mar 31 10:38 firmware-dfu-suffix.dfu
-rwxrwxrwx 1 xobs xobs 307293 Mar 31 10:39 firmware-python.dfu
$ hexdump -C firmware.bin | head
00000000  6f 00 40 00 17 01 fe ef  13 01 81 ff 17 35 fc ef  |o.@..........5..|
00000010  13 05 45 ff 73 10 55 30  17 55 fc ef 13 05 85 05  |..E.s.U0.U......|
00000020  97 85 fc ef 93 85 85 79  63 08 b5 00 23 20 05 00  |.......yc...# ..|
00000030  13 05 45 00 6f f0 5f ff  97 22 04 00 93 82 82 73  |..E.o._..".....s|
00000040  17 03 fc ef 13 03 03 fc  97 53 fc ef 93 83 83 02  |.........S......|
00000050  03 ae 02 00 23 20 c3 01  93 82 42 00 13 03 43 00  |....# ....B...C.|
00000060  e3 68 73 fe 37 15 00 00  13 05 05 88 73 10 45 30  |.hs.7.......s.E0|
00000070  ef 60 12 0d 6f 00 00 00  13 17 85 01 93 57 85 01  |.`..o........W..|
00000080  b7 06 01 00 b3 e7 e7 00  93 86 06 f0 13 57 85 40  |.............W.@|
00000090  33 77 d7 00 b3 e7 e7 00  13 15 85 00 37 07 ff 00  |3w..........7...|
$ hexdump -C firmware-dfu-suffix.dfu | head
00000000  6f 00 40 00 17 01 fe ef  13 01 81 ff 17 35 fc ef  |o.@..........5..|
00000010  13 05 45 ff 73 10 55 30  17 55 fc ef 13 05 85 05  |..E.s.U0.U......|
00000020  97 85 fc ef 93 85 85 79  63 08 b5 00 23 20 05 00  |.......yc...# ..|
00000030  13 05 45 00 6f f0 5f ff  97 22 04 00 93 82 82 73  |..E.o._..".....s|
00000040  17 03 fc ef 13 03 03 fc  97 53 fc ef 93 83 83 02  |.........S......|
00000050  03 ae 02 00 23 20 c3 01  93 82 42 00 13 03 43 00  |....# ....B...C.|
00000060  e3 68 73 fe 37 15 00 00  13 05 05 88 73 10 45 30  |.hs.7.......s.E0|
00000070  ef 60 12 0d 6f 00 00 00  13 17 85 01 93 57 85 01  |.`..o........W..|
00000080  b7 06 01 00 b3 e7 e7 00  93 86 06 f0 13 57 85 40  |.............W.@|
00000090  33 77 d7 00 b3 e7 e7 00  13 15 85 00 37 07 ff 00  |3w..........7...|
$ hexdump -C firmware-python.dfu | head
00000000  44 66 75 53 65 01 4d b0  04 00 01 54 61 72 67 65  |DfuSe.M....Targe|
00000010  74 00 01 00 00 00 53 54  2e 2e 2e 00 00 00 00 00  |t.....ST........|
00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000110  00 00 00 00 00 30 af 04  00 01 00 00 00 00 00 00  |.....0..........|
00000120  00 28 af 04 00 6f 00 40  00 17 01 fe ef 13 01 81  |.(...o.@........|
00000130  ff 17 35 fc ef 13 05 45  ff 73 10 55 30 17 55 fc  |..5....E.s.U0.U.|
00000140  ef 13 05 85 05 97 85 fc  ef 93 85 85 79 63 08 b5  |............yc..|
00000150  00 23 20 05 00 13 05 45  00 6f f0 5f ff 97 22 04  |.# ....E.o._..".|
00000160  00 93 82 82 73 17 03 fc  ef 13 03 03 fc 97 53 fc  |....s.........S.|
$

You can see that it's adding 292 bytes to the start of the image, whereas the DFU standard says that DFU images should only have a 16-byte header appended as a suffix. This results in a nonstandard DFU image that can't be loaded with e.g. dfu-util.

xobs commented 4 years ago

In looking closer, it looks like dfu.py uses generates nonstandard DFU versions. The bcdDFU field is 01.1a, whereas the standard defines the bcdDFU field should be 01.00, at least according to the most recent spec I can find: https://www.usb.org/sites/default/files/DFU_1.1.pdf

Additionally, there is a lot of extra stuff that gets added.

With this patch I can get dfu.py to generate the same file as dfu-suffix:

diff --git a/tools/dfu.py b/tools/dfu.py
index 54b6024..b74b7d7 100755
--- a/tools/dfu.py
+++ b/tools/dfu.py
@@ -60,12 +60,13 @@ def build(file,targets,device=DEFAULT_DEVICE):
   for t,target in enumerate(targets):
     tdata = b''
     for image in target:
-      tdata += struct.pack('<2I',image['address'],len(image['data']))+image['data']
-    tdata = struct.pack('<6sBI255s2I',b'Target',0,1, b'ST...',len(tdata),len(target)) + tdata
+      tdata += image['data']
+#      tdata += struct.pack('<2I',image['address'],len(image['data']))+image['data']
+#    tdata = struct.pack('<6sBI255s2I',b'Target',0,1, b'ST...',len(tdata),len(target)) + tdata
     data += tdata
-  data  = struct.pack('<5sBIB',b'DfuSe',1,len(data)+11,len(targets)) + data
+#  data  = struct.pack('<5sBIB',b'DfuSe',1,len(data)+11,len(targets)) + data
   v,d=map(lambda x: int(x,0) & 0xFFFF, device.split(':',1))
-  data += struct.pack('<4H3sB',0,d,v,0x011a,b'UFD',16)
+  data += struct.pack('<4H3sB',0xffff,d,v,0x0100,b'UFD',16)
   crc   = compute_crc(data)
   data += struct.pack('<I',crc)
   open(file,'wb').write(data)
xobs commented 4 years ago

I added dfu-suffix.py in c91d364a58118100871acd5a195b73c3bbbe5141 that addresses this.

tannewt commented 4 years ago

@xobs updated dfu.py