#!/usr/bin/env python3 # Written by Antonio Galea - 2010/11/18 # Distributed under Gnu LGPL 3.0 # see http://www.gnu.org/licenses/lgpl-3.0.txt import sys, struct, zlib, os import binascii from optparse import OptionParser try: from intelhex import IntelHex except ImportError: IntelHex = None DEFAULT_DEVICE = "0x0483:0xdf11" DEFAULT_NAME = b"ST..." # Prefix and Suffix sizes are derived from ST's DfuSe File Format Specification (UM0391), DFU revision 1.1a PREFIX_SIZE = 11 SUFFIX_SIZE = 16 def named(tuple, names): return dict(list(zip(names.split(), tuple))) def consume(fmt, data, names): n = struct.calcsize(fmt) return named(struct.unpack(fmt, data[:n]), names), data[n:] def cstring(bytestring): return bytestring.partition(b"\0")[0] def compute_crc(data): return 0xFFFFFFFF & -zlib.crc32(data) - 1 def parse(file, dump_images=False): print('File: "%s"' % file) data = open(file, "rb").read() crc = compute_crc(data[:-4]) prefix, data = consume("<5sBIB", data, "signature version size targets") print( "%(signature)s v%(version)d, image size: %(size)d, targets: %(targets)d" % prefix ) for t in range(prefix["targets"]): tprefix, data = consume( "<6sBI255s2I", data, "signature altsetting named name size elements" ) tprefix["num"] = t if tprefix["named"]: tprefix["name"] = cstring(tprefix["name"]) else: tprefix["name"] = "" print( '%(signature)s %(num)d, alt setting: %(altsetting)s, name: "%(name)s", size: %(size)d, elements: %(elements)d' % tprefix ) tsize = tprefix["size"] target, data = data[:tsize], data[tsize:] for e in range(tprefix["elements"]): eprefix, target = consume("<2I", target, "address size") eprefix["num"] = e print(" %(num)d, address: 0x%(address)08x, size: %(size)d" % eprefix) esize = eprefix["size"] image, target = target[:esize], target[esize:] if dump_images: out = "%s.target%d.image%d.bin" % (file, t, e) open(out, "wb").write(image) print(' DUMPED IMAGE TO "%s"' % out) if len(target): print("target %d: PARSE ERROR" % t) suffix = named( struct.unpack("<4H3sBI", data[:SUFFIX_SIZE]), "device product vendor dfu ufd len crc", ) print( "usb: %(vendor)04x:%(product)04x, device: 0x%(device)04x, dfu: 0x%(dfu)04x, %(ufd)s, %(len)d, 0x%(crc)08x" % suffix ) if crc != suffix["crc"]: print("CRC ERROR: computed crc32 is 0x%08x" % crc) data = data[SUFFIX_SIZE:] if data: print("PARSE ERROR") def checkbin(binfile): data = open(binfile, "rb").read() if len(data) < SUFFIX_SIZE: return crc = compute_crc(data[:-4]) suffix = named( struct.unpack("<4H3sBI", data[-SUFFIX_SIZE:]), "device product vendor dfu ufd len crc", ) if crc == suffix["crc"] and suffix["ufd"] == b"UFD": print( "usb: %(vendor)04x:%(product)04x, device: 0x%(device)04x, dfu: 0x%(dfu)04x, %(ufd)s, %(len)d, 0x%(crc)08x" % suffix ) print("It looks like the file %s has a DFU suffix!" % binfile) print("Please remove any DFU suffix and retry.") sys.exit(1) def build(file, targets, name=DEFAULT_NAME, device=DEFAULT_DEVICE): data = b"" for t, target in enumerate(targets): tdata = b"" for image in target: tdata += ( struct.pack("<2I", image["address"], len(image["data"])) + image["data"] ) ealt = image["alt"] tdata = ( struct.pack( "<6sBI255s2I", b"Target", ealt, 1, name, len(tdata), len(target) ) + tdata ) data += tdata data = ( struct.pack( "<5sBIB", b"DfuSe", 1, PREFIX_SIZE + len(data) + SUFFIX_SIZE, len(targets) ) + data ) v, d = [int(x, 0) & 0xFFFF for x in device.split(":", 1)] data += struct.pack("<4H3sB", 0, d, v, 0x011A, b"UFD", SUFFIX_SIZE) crc = compute_crc(data) data += struct.pack("