1
1
#!/usr/bin/python
2
2
3
3
# Written by Antonio Galea - 2010/11/18
4
+ # Updated for DFU 1.1 by Sean Cross - 2020/03/31
4
5
# Distributed under Gnu LGPL 3.0
5
6
# see http://www.gnu.org/licenses/lgpl-3.0.txt
6
7
@@ -23,30 +24,7 @@ def parse(file,dump_images=False):
23
24
print ('File: "%s"' % file )
24
25
data = open (file ,'rb' ).read ()
25
26
crc = compute_crc (data [:- 4 ])
26
- prefix , data = consume ('<5sBIB' ,data ,'signature version size targets' )
27
- print ('%(signature)s v%(version)d, image size: %(size)d, targets: %(targets)d' % prefix )
28
- for t in range (prefix ['targets' ]):
29
- tprefix , data = consume ('<6sBI255s2I' ,data ,'signature altsetting named name size elements' )
30
- tprefix ['num' ] = t
31
- if tprefix ['named' ]:
32
- tprefix ['name' ] = cstring (tprefix ['name' ])
33
- else :
34
- tprefix ['name' ] = ''
35
- print ('%(signature)s %(num)d, alt setting: %(altsetting)s, name: "%(name)s", size: %(size)d, elements: %(elements)d' % tprefix )
36
- tsize = tprefix ['size' ]
37
- target , data = data [:tsize ], data [tsize :]
38
- for e in range (tprefix ['elements' ]):
39
- eprefix , target = consume ('<2I' ,target ,'address size' )
40
- eprefix ['num' ] = e
41
- print (' %(num)d, address: 0x%(address)08x, size: %(size)d' % eprefix )
42
- esize = eprefix ['size' ]
43
- image , target = target [:esize ], target [esize :]
44
- if dump_images :
45
- out = '%s.target%d.image%d.bin' % (file ,t ,e )
46
- open (out ,'wb' ).write (image )
47
- print (' DUMPED IMAGE TO "%s"' % out )
48
- if len (target ):
49
- print ("target %d: PARSE ERROR" % t )
27
+ data = data [len (data )- 16 :]
50
28
suffix = named (struct .unpack ('<4H3sBI' ,data [:16 ]),'device product vendor dfu ufd len crc' )
51
29
print ('usb: %(vendor)04x:%(product)04x, device: 0x%(device)04x, dfu: 0x%(dfu)04x, %(ufd)s, %(len)d, 0x%(crc)08x' % suffix )
52
30
if crc != suffix ['crc' ]:
@@ -55,61 +33,57 @@ def parse(file,dump_images=False):
55
33
if data :
56
34
print ("PARSE ERROR" )
57
35
58
- def build (file ,targets ,device = DEFAULT_DEVICE ):
59
- data = b''
60
- for t ,target in enumerate (targets ):
61
- tdata = b''
62
- for image in target :
63
- tdata += struct .pack ('<2I' ,image ['address' ],len (image ['data' ]))+ image ['data' ]
64
- tdata = struct .pack ('<6sBI255s2I' ,b'Target' ,0 ,1 , b'ST...' ,len (tdata ),len (target )) + tdata
65
- data += tdata
66
- data = struct .pack ('<5sBIB' ,b'DfuSe' ,1 ,len (data )+ 11 ,len (targets )) + data
36
+ def build (file ,data ,device = DEFAULT_DEVICE ):
37
+ # Parse the VID and PID from the `device` argument
67
38
v ,d = map (lambda x : int (x ,0 ) & 0xFFFF , device .split (':' ,1 ))
68
- data += struct .pack ('<4H3sB' ,0 ,d ,v ,0x011a ,b'UFD' ,16 )
39
+
40
+ # Generate the DFU suffix, consisting of these fields:
41
+ # Field name | Length | Description
42
+ # ================+=========+================================
43
+ # bcdDevice | 2 | The release number of this firmware (0xffff - don't care)
44
+ # idProduct | 2 | PID of this device
45
+ # idVendor | 2 | VID of this device
46
+ # bcdDFU | 2 | Version of this DFU spec (0x01 0x00)
47
+ # ucDfuSignature | 3 | The characters 'DFU', printed in reverse order
48
+ # bLength | 1 | The length of this suffix (16 bytes)
49
+ # dwCRC | 4 | A CRC32 of the data, including this suffix
50
+ data += struct .pack ('<4H3sB' ,0xffff ,d ,v ,0x0100 ,b'UFD' ,16 )
69
51
crc = compute_crc (data )
52
+ # Append the CRC32 of the entire block
70
53
data += struct .pack ('<I' ,crc )
71
54
open (file ,'wb' ).write (data )
72
55
73
56
if __name__ == "__main__" :
74
57
usage = """
75
58
%prog [-d|--dump] infile.dfu
76
- %prog {-b|--build} address: file.bin [-b address:file.bin ...] [{-D|--device}=vendor:device] outfile.dfu"""
59
+ %prog {-b|--build} file.bin [{-D|--device}=vendor:device] outfile.dfu"""
77
60
parser = OptionParser (usage = usage )
78
- parser .add_option ("-b" , "--build" , action = "append " , dest = "binfiles " ,
79
- help = "build a DFU file from given BINFILES " , metavar = "BINFILES " )
61
+ parser .add_option ("-b" , "--build" , action = "store " , dest = "binfile " ,
62
+ help = "build a DFU file from given BINFILE " , metavar = "BINFILE " )
80
63
parser .add_option ("-D" , "--device" , action = "store" , dest = "device" ,
81
64
help = "build for DEVICE, defaults to %s" % DEFAULT_DEVICE , metavar = "DEVICE" )
82
65
parser .add_option ("-d" , "--dump" , action = "store_true" , dest = "dump_images" ,
83
66
default = False , help = "dump contained images to current directory" )
84
67
(options , args ) = parser .parse_args ()
85
68
86
- if options .binfiles and len (args )== 1 :
87
- target = []
88
- for arg in options .binfiles :
89
- try :
90
- address ,binfile = arg .split (':' ,1 )
91
- except ValueError :
92
- print ("Address:file couple '%s' invalid." % arg )
93
- sys .exit (1 )
94
- try :
95
- address = int (address ,0 ) & 0xFFFFFFFF
96
- except ValueError :
97
- print ("Address %s invalid." % address )
98
- sys .exit (1 )
99
- if not os .path .isfile (binfile ):
100
- print ("Unreadable file '%s'." % binfile )
101
- sys .exit (1 )
102
- target .append ({ 'address' : address , 'data' : open (binfile ,'rb' ).read () })
69
+ if options .binfile and len (args )== 1 :
70
+ binfile = options .binfile
71
+ if not os .path .isfile (binfile ):
72
+ print ("Unreadable file '%s'." % binfile )
73
+ sys .exit (1 )
74
+ target = open (binfile ,'rb' ).read ()
103
75
outfile = args [0 ]
104
76
device = DEFAULT_DEVICE
77
+ # If a device is specified, parse the pair into a VID:PID pair
78
+ # in order to validate them.
105
79
if options .device :
106
80
device = options .device
107
81
try :
108
82
v ,d = map (lambda x : int (x ,0 ) & 0xFFFF , device .split (':' ,1 ))
109
83
except :
110
84
print ("Invalid device '%s'." % device )
111
85
sys .exit (1 )
112
- build (outfile ,[ target ] ,device )
86
+ build (outfile ,target ,device )
113
87
elif len (args )== 1 :
114
88
infile = args [0 ]
115
89
if not os .path .isfile (infile ):
0 commit comments