Skip to content

Commit e8db880

Browse files
committed
tools: rename dfu-suffix.py to dfu.py
dfu.py is unused in circuitpython, so rename dfu-suffix.py to replace it. Signed-off-by: Sean Cross <[email protected]>
1 parent 34ea140 commit e8db880

File tree

2 files changed

+29
-150
lines changed

2 files changed

+29
-150
lines changed

tools/dfu-suffix.py

Lines changed: 0 additions & 95 deletions
This file was deleted.

tools/dfu.py

100755100644
Lines changed: 29 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#!/usr/bin/python
22

33
# Written by Antonio Galea - 2010/11/18
4+
# Updated for DFU 1.1 by Sean Cross - 2020/03/31
45
# Distributed under Gnu LGPL 3.0
56
# see http://www.gnu.org/licenses/lgpl-3.0.txt
67

@@ -23,30 +24,7 @@ def parse(file,dump_images=False):
2324
print ('File: "%s"' % file)
2425
data = open(file,'rb').read()
2526
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:]
5028
suffix = named(struct.unpack('<4H3sBI',data[:16]),'device product vendor dfu ufd len crc')
5129
print ('usb: %(vendor)04x:%(product)04x, device: 0x%(device)04x, dfu: 0x%(dfu)04x, %(ufd)s, %(len)d, 0x%(crc)08x' % suffix)
5230
if crc != suffix['crc']:
@@ -55,61 +33,57 @@ def parse(file,dump_images=False):
5533
if data:
5634
print ("PARSE ERROR")
5735

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
6738
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)
6951
crc = compute_crc(data)
52+
# Append the CRC32 of the entire block
7053
data += struct.pack('<I',crc)
7154
open(file,'wb').write(data)
7255

7356
if __name__=="__main__":
7457
usage = """
7558
%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"""
7760
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")
8063
parser.add_option("-D", "--device", action="store", dest="device",
8164
help="build for DEVICE, defaults to %s" % DEFAULT_DEVICE, metavar="DEVICE")
8265
parser.add_option("-d", "--dump", action="store_true", dest="dump_images",
8366
default=False, help="dump contained images to current directory")
8467
(options, args) = parser.parse_args()
8568

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()
10375
outfile = args[0]
10476
device = DEFAULT_DEVICE
77+
# If a device is specified, parse the pair into a VID:PID pair
78+
# in order to validate them.
10579
if options.device:
10680
device=options.device
10781
try:
10882
v,d=map(lambda x: int(x,0) & 0xFFFF, device.split(':',1))
10983
except:
11084
print ("Invalid device '%s'." % device)
11185
sys.exit(1)
112-
build(outfile,[target],device)
86+
build(outfile,target,device)
11387
elif len(args)==1:
11488
infile = args[0]
11589
if not os.path.isfile(infile):

0 commit comments

Comments
 (0)