summaryrefslogtreecommitdiff
path: root/tools/pydfu.py
diff options
context:
space:
mode:
Diffstat (limited to 'tools/pydfu.py')
-rwxr-xr-xtools/pydfu.py234
1 files changed, 117 insertions, 117 deletions
diff --git a/tools/pydfu.py b/tools/pydfu.py
index a6210c603..5ee942c17 100755
--- a/tools/pydfu.py
+++ b/tools/pydfu.py
@@ -24,34 +24,34 @@ import zlib
# VID/PID
__VID = 0x0483
-__PID = 0xdf11
+__PID = 0xDF11
# USB request __TIMEOUT
__TIMEOUT = 4000
# DFU commands
-__DFU_DETACH = 0
-__DFU_DNLOAD = 1
-__DFU_UPLOAD = 2
+__DFU_DETACH = 0
+__DFU_DNLOAD = 1
+__DFU_UPLOAD = 2
__DFU_GETSTATUS = 3
__DFU_CLRSTATUS = 4
-__DFU_GETSTATE = 5
-__DFU_ABORT = 6
+__DFU_GETSTATE = 5
+__DFU_ABORT = 6
# DFU status
-__DFU_STATE_APP_IDLE = 0x00
-__DFU_STATE_APP_DETACH = 0x01
-__DFU_STATE_DFU_IDLE = 0x02
-__DFU_STATE_DFU_DOWNLOAD_SYNC = 0x03
-__DFU_STATE_DFU_DOWNLOAD_BUSY = 0x04
-__DFU_STATE_DFU_DOWNLOAD_IDLE = 0x05
-__DFU_STATE_DFU_MANIFEST_SYNC = 0x06
-__DFU_STATE_DFU_MANIFEST = 0x07
-__DFU_STATE_DFU_MANIFEST_WAIT_RESET = 0x08
-__DFU_STATE_DFU_UPLOAD_IDLE = 0x09
-__DFU_STATE_DFU_ERROR = 0x0a
+__DFU_STATE_APP_IDLE = 0x00
+__DFU_STATE_APP_DETACH = 0x01
+__DFU_STATE_DFU_IDLE = 0x02
+__DFU_STATE_DFU_DOWNLOAD_SYNC = 0x03
+__DFU_STATE_DFU_DOWNLOAD_BUSY = 0x04
+__DFU_STATE_DFU_DOWNLOAD_IDLE = 0x05
+__DFU_STATE_DFU_MANIFEST_SYNC = 0x06
+__DFU_STATE_DFU_MANIFEST = 0x07
+__DFU_STATE_DFU_MANIFEST_WAIT_RESET = 0x08
+__DFU_STATE_DFU_UPLOAD_IDLE = 0x09
+__DFU_STATE_DFU_ERROR = 0x0A
-_DFU_DESCRIPTOR_TYPE = 0x21
+_DFU_DESCRIPTOR_TYPE = 0x21
# USB device handle
@@ -63,10 +63,13 @@ __verbose = None
__DFU_INTERFACE = 0
import inspect
-if 'length' in inspect.getargspec(usb.util.get_string).args:
+
+if "length" in inspect.getargspec(usb.util.get_string).args:
# PyUSB 1.0.0.b1 has the length argument
def get_string(dev, index):
return usb.util.get_string(dev, 255, index)
+
+
else:
# PyUSB 1.0.0.b2 dropped the length argument
def get_string(dev, index):
@@ -78,7 +81,7 @@ def init():
global __dev
devices = get_dfu_devices(idVendor=__VID, idProduct=__PID)
if not devices:
- raise ValueError('No DFU device found')
+ raise ValueError("No DFU device found")
if len(devices) > 1:
raise ValueError("Multiple DFU devices found")
__dev = devices[0]
@@ -93,14 +96,12 @@ def init():
def clr_status():
"""Clears any error status (perhaps left over from a previous session)."""
- __dev.ctrl_transfer(0x21, __DFU_CLRSTATUS, 0, __DFU_INTERFACE,
- None, __TIMEOUT)
+ __dev.ctrl_transfer(0x21, __DFU_CLRSTATUS, 0, __DFU_INTERFACE, None, __TIMEOUT)
def get_status():
"""Get the status of the last operation."""
- stat = __dev.ctrl_transfer(0xA1, __DFU_GETSTATUS, 0, __DFU_INTERFACE,
- 6, 20000)
+ stat = __dev.ctrl_transfer(0xA1, __DFU_GETSTATUS, 0, __DFU_INTERFACE, 6, 20000)
# print (__DFU_STAT[stat[4]], stat)
return stat[4]
@@ -108,8 +109,7 @@ def get_status():
def mass_erase():
"""Performs a MASS erase (i.e. erases the entire device."""
# Send DNLOAD with first byte=0x41
- __dev.ctrl_transfer(0x21, __DFU_DNLOAD, 0, __DFU_INTERFACE,
- "\x41", __TIMEOUT)
+ __dev.ctrl_transfer(0x21, __DFU_DNLOAD, 0, __DFU_INTERFACE, "\x41", __TIMEOUT)
# Execute last command
if get_status() != __DFU_STATE_DFU_DOWNLOAD_BUSY:
@@ -166,22 +166,23 @@ def write_memory(addr, buf, progress=None, progress_addr=0, progress_size=0):
while xfer_bytes < xfer_total:
if __verbose and xfer_count % 512 == 0:
- print ("Addr 0x%x %dKBs/%dKBs..." % (xfer_base + xfer_bytes,
- xfer_bytes // 1024,
- xfer_total // 1024))
+ print(
+ "Addr 0x%x %dKBs/%dKBs..."
+ % (xfer_base + xfer_bytes, xfer_bytes // 1024, xfer_total // 1024)
+ )
if progress and xfer_count % 2 == 0:
- progress(progress_addr, xfer_base + xfer_bytes - progress_addr,
- progress_size)
+ progress(progress_addr, xfer_base + xfer_bytes - progress_addr, progress_size)
# Set mem write address
- set_address(xfer_base+xfer_bytes)
+ set_address(xfer_base + xfer_bytes)
# Send DNLOAD with fw data
# the "2048" is the DFU transfer size supported by the ST DFU bootloader
# TODO: this number should be extracted from the USB config descriptor
- chunk = min(2048, xfer_total-xfer_bytes)
- __dev.ctrl_transfer(0x21, __DFU_DNLOAD, 2, __DFU_INTERFACE,
- buf[xfer_bytes:xfer_bytes + chunk], __TIMEOUT)
+ chunk = min(2048, xfer_total - xfer_bytes)
+ __dev.ctrl_transfer(
+ 0x21, __DFU_DNLOAD, 2, __DFU_INTERFACE, buf[xfer_bytes : xfer_bytes + chunk], __TIMEOUT
+ )
# Execute last command
if get_status() != __DFU_STATE_DFU_DOWNLOAD_BUSY:
@@ -203,7 +204,7 @@ def write_page(buf, xfer_offset):
xfer_base = 0x08000000
# Set mem write address
- set_address(xfer_base+xfer_offset)
+ set_address(xfer_base + xfer_offset)
# Send DNLOAD with fw data
__dev.ctrl_transfer(0x21, __DFU_DNLOAD, 2, __DFU_INTERFACE, buf, __TIMEOUT)
@@ -217,7 +218,7 @@ def write_page(buf, xfer_offset):
raise Exception("DFU: write memory failed")
if __verbose:
- print ("Write: 0x%x " % (xfer_base + xfer_offset))
+ print("Write: 0x%x " % (xfer_base + xfer_offset))
def exit_dfu():
@@ -227,8 +228,7 @@ def exit_dfu():
set_address(0x08000000)
# Send DNLOAD with 0 length to exit DFU
- __dev.ctrl_transfer(0x21, __DFU_DNLOAD, 0, __DFU_INTERFACE,
- None, __TIMEOUT)
+ __dev.ctrl_transfer(0x21, __DFU_DNLOAD, 0, __DFU_INTERFACE, None, __TIMEOUT)
try:
# Execute last command
@@ -256,7 +256,7 @@ def consume(fmt, data, names):
def cstring(string):
"""Extracts a null-terminated string from a byte array."""
- return string.decode('utf-8').split('\0', 1)[0]
+ return string.decode("utf-8").split("\0", 1)[0]
def compute_crc(data):
@@ -276,7 +276,7 @@ def read_dfu_file(filename):
"""
print("File: {}".format(filename))
- with open(filename, 'rb') as fin:
+ with open(filename, "rb") as fin:
data = fin.read()
crc = compute_crc(data[:-4])
elements = []
@@ -289,11 +289,12 @@ def read_dfu_file(filename):
# B uint8_t version 1
# I uint32_t size Size of the DFU file (not including suffix)
# B uint8_t targets Number of targets
- dfu_prefix, data = consume('<5sBIB', data,
- 'signature version size targets')
- print (" %(signature)s v%(version)d, image size: %(size)d, "
- "targets: %(targets)d" % dfu_prefix)
- for target_idx in range(dfu_prefix['targets']):
+ dfu_prefix, data = consume("<5sBIB", data, "signature version size targets")
+ print(
+ " %(signature)s v%(version)d, image size: %(size)d, "
+ "targets: %(targets)d" % dfu_prefix
+ )
+ for target_idx in range(dfu_prefix["targets"]):
# Decode the Image Prefix
#
# <6sBI255s2I
@@ -304,33 +305,33 @@ def read_dfu_file(filename):
# 255s char[255] name name of the target
# I uint32_t size size of image (not incl prefix)
# I uint32_t elements Number of elements in the image
- img_prefix, data = consume('<6sBI255s2I', data,
- 'signature altsetting named name '
- 'size elements')
- img_prefix['num'] = target_idx
- if img_prefix['named']:
- img_prefix['name'] = cstring(img_prefix['name'])
+ img_prefix, data = consume(
+ "<6sBI255s2I", data, "signature altsetting named name " "size elements"
+ )
+ img_prefix["num"] = target_idx
+ if img_prefix["named"]:
+ img_prefix["name"] = cstring(img_prefix["name"])
else:
- img_prefix['name'] = ''
- print(' %(signature)s %(num)d, alt setting: %(altsetting)s, '
- 'name: "%(name)s", size: %(size)d, elements: %(elements)d'
- % img_prefix)
+ img_prefix["name"] = ""
+ print(
+ " %(signature)s %(num)d, alt setting: %(altsetting)s, "
+ 'name: "%(name)s", size: %(size)d, elements: %(elements)d' % img_prefix
+ )
- target_size = img_prefix['size']
+ target_size = img_prefix["size"]
target_data, data = data[:target_size], data[target_size:]
- for elem_idx in range(img_prefix['elements']):
+ for elem_idx in range(img_prefix["elements"]):
# Decode target prefix
# < little endian
# I uint32_t element address
# I uint32_t element size
- elem_prefix, target_data = consume('<2I', target_data, 'addr size')
- elem_prefix['num'] = elem_idx
- print(' %(num)d, address: 0x%(addr)08x, size: %(size)d'
- % elem_prefix)
- elem_size = elem_prefix['size']
+ elem_prefix, target_data = consume("<2I", target_data, "addr size")
+ elem_prefix["num"] = elem_idx
+ print(" %(num)d, address: 0x%(addr)08x, size: %(size)d" % elem_prefix)
+ elem_size = elem_prefix["size"]
elem_data = target_data[:elem_size]
target_data = target_data[elem_size:]
- elem_prefix['data'] = elem_data
+ elem_prefix["data"] = elem_data
elements.append(elem_prefix)
if len(target_data):
@@ -345,11 +346,14 @@ def read_dfu_file(filename):
# 3s char[3] ufd 'UFD'
# B uint8_t len 16
# I uint32_t crc32
- dfu_suffix = named(struct.unpack('<4H3sBI', data[:16]),
- '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' % dfu_suffix)
- if crc != dfu_suffix['crc']:
+ dfu_suffix = named(
+ struct.unpack("<4H3sBI", data[:16]), "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" % dfu_suffix
+ )
+ if crc != dfu_suffix["crc"]:
print("CRC ERROR: computed crc32 is 0x%08x" % crc)
return
data = data[16:]
@@ -368,8 +372,7 @@ class FilterDFU(object):
def __call__(self, device):
for cfg in device:
for intf in cfg:
- return (intf.bInterfaceClass == 0xFE and
- intf.bInterfaceSubClass == 1)
+ return intf.bInterfaceClass == 0xFE and intf.bInterfaceSubClass == 1
def get_dfu_devices(*args, **kwargs):
@@ -378,8 +381,7 @@ def get_dfu_devices(*args, **kwargs):
refine the search.
"""
# convert to list for compatibility with newer pyusb
- return list(usb.core.find(*args, find_all=True,
- custom_match=FilterDFU(), **kwargs))
+ return list(usb.core.find(*args, find_all=True, custom_match=FilterDFU(), **kwargs))
def get_memory_layout(device):
@@ -394,25 +396,29 @@ def get_memory_layout(device):
cfg = device[0]
intf = cfg[(0, 0)]
mem_layout_str = get_string(device, intf.iInterface)
- mem_layout = mem_layout_str.split('/')
+ mem_layout = mem_layout_str.split("/")
result = []
for mem_layout_index in range(1, len(mem_layout), 2):
addr = int(mem_layout[mem_layout_index], 0)
- segments = mem_layout[mem_layout_index + 1].split(',')
- seg_re = re.compile(r'(\d+)\*(\d+)(.)(.)')
+ segments = mem_layout[mem_layout_index + 1].split(",")
+ seg_re = re.compile(r"(\d+)\*(\d+)(.)(.)")
for segment in segments:
seg_match = seg_re.match(segment)
num_pages = int(seg_match.groups()[0], 10)
page_size = int(seg_match.groups()[1], 10)
multiplier = seg_match.groups()[2]
- if multiplier == 'K':
+ if multiplier == "K":
page_size *= 1024
- if multiplier == 'M':
+ if multiplier == "M":
page_size *= 1024 * 1024
size = num_pages * page_size
last_addr = addr + size - 1
- result.append(named((addr, last_addr, size, num_pages, page_size),
- "addr last_addr size num_pages page_size"))
+ result.append(
+ named(
+ (addr, last_addr, size, num_pages, page_size),
+ "addr last_addr size num_pages page_size",
+ )
+ )
addr += size
return result
@@ -424,15 +430,19 @@ def list_dfu_devices(*args, **kwargs):
print("No DFU capable devices found")
return
for device in devices:
- print("Bus {} Device {:03d}: ID {:04x}:{:04x}"
- .format(device.bus, device.address,
- device.idVendor, device.idProduct))
+ print(
+ "Bus {} Device {:03d}: ID {:04x}:{:04x}".format(
+ device.bus, device.address, device.idVendor, device.idProduct
+ )
+ )
layout = get_memory_layout(device)
print("Memory Layout")
for entry in layout:
- print(" 0x{:x} {:2d} pages of {:3d}K bytes"
- .format(entry['addr'], entry['num_pages'],
- entry['page_size'] // 1024))
+ print(
+ " 0x{:x} {:2d} pages of {:3d}K bytes".format(
+ entry["addr"], entry["num_pages"], entry["page_size"] // 1024
+ )
+ )
def write_elements(elements, mass_erase_used, progress=None):
@@ -442,9 +452,9 @@ def write_elements(elements, mass_erase_used, progress=None):
mem_layout = get_memory_layout(__dev)
for elem in elements:
- addr = elem['addr']
- size = elem['size']
- data = elem['data']
+ addr = elem["addr"]
+ size = elem["size"]
+ data = elem["data"]
elem_size = size
elem_addr = addr
if progress:
@@ -453,18 +463,16 @@ def write_elements(elements, mass_erase_used, progress=None):
write_size = size
if not mass_erase_used:
for segment in mem_layout:
- if addr >= segment['addr'] and \
- addr <= segment['last_addr']:
+ if addr >= segment["addr"] and addr <= segment["last_addr"]:
# We found the page containing the address we want to
# write, erase it
- page_size = segment['page_size']
+ page_size = segment["page_size"]
page_addr = addr & ~(page_size - 1)
if addr + write_size > page_addr + page_size:
write_size = page_addr + page_size - addr
page_erase(page_addr)
break
- write_memory(addr, data[:write_size], progress,
- elem_addr, elem_size)
+ write_memory(addr, data[:write_size], progress, elem_addr, elem_size)
data = data[write_size:]
addr += write_size
size -= write_size
@@ -476,9 +484,12 @@ def cli_progress(addr, offset, size):
"""Prints a progress report suitable for use on the command line."""
width = 25
done = offset * width // size
- print("\r0x{:08x} {:7d} [{}{}] {:3d}% "
- .format(addr, size, '=' * done, ' ' * (width - done),
- offset * 100 // size), end="")
+ print(
+ "\r0x{:08x} {:7d} [{}{}] {:3d}% ".format(
+ addr, size, "=" * done, " " * (width - done), offset * 100 // size
+ ),
+ end="",
+ )
sys.stdout.flush()
if offset == size:
print("")
@@ -488,31 +499,19 @@ def main():
"""Test program for verifying this files functionality."""
global __verbose
# Parse CMD args
- parser = argparse.ArgumentParser(description='DFU Python Util')
- #parser.add_argument("path", help="file path")
+ parser = argparse.ArgumentParser(description="DFU Python Util")
+ # parser.add_argument("path", help="file path")
parser.add_argument(
- "-l", "--list",
- help="list available DFU devices",
- action="store_true",
- default=False
+ "-l", "--list", help="list available DFU devices", action="store_true", default=False
)
parser.add_argument(
- "-m", "--mass-erase",
- help="mass erase device",
- action="store_true",
- default=False
+ "-m", "--mass-erase", help="mass erase device", action="store_true", default=False
)
parser.add_argument(
- "-u", "--upload",
- help="read file from DFU device",
- dest="path",
- default=False
+ "-u", "--upload", help="read file from DFU device", dest="path", default=False
)
parser.add_argument(
- "-v", "--verbose",
- help="increase output verbosity",
- action="store_true",
- default=False
+ "-v", "--verbose", help="increase output verbosity", action="store_true", default=False
)
args = parser.parse_args()
@@ -525,7 +524,7 @@ def main():
init()
if args.mass_erase:
- print ("Mass erase...")
+ print("Mass erase...")
mass_erase()
if args.path:
@@ -541,5 +540,6 @@ def main():
print("No command specified")
-if __name__ == '__main__':
+
+if __name__ == "__main__":
main()