You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
148 lines
5.8 KiB
148 lines
5.8 KiB
#!/usr/bin/env python3 |
|
import dfuse |
|
import usb.core |
|
import usb.util |
|
import argparse |
|
import sys |
|
|
|
def find_device(args): |
|
usbdev = usb.core.find(idVendor=args.vid, idProduct=args.pid) |
|
|
|
if usbdev is not None: |
|
dfu = dfuse.DfuDevice(usbdev) |
|
for _,alt in dfu.alternates(): |
|
if alt.configuration == args.cfg and alt.bInterfaceNumber == args.intf and alt.bAlternateSetting == args.alt: |
|
dfu.set_alternate(alt) |
|
status = dfu.get_status() |
|
if status[1] == dfuse.DfuState.DFU_ERROR: |
|
print("Error cleared: %r" % (status,)) |
|
dfu.clear_status() # Clear left-over errors |
|
return dfu |
|
|
|
raise ValueError('No DfuSe compatible device found, check device information options (see --help)') |
|
|
|
|
|
def list_dfu(args): |
|
usbdev = usb.core.find(idVendor=args.vid, idProduct=args.pid) |
|
|
|
if usbdev is None: |
|
raise ValueError('No STM32 DfuSe device found.') |
|
|
|
dfu = dfuse.DfuDevice(usbdev) |
|
for name, alt in dfu.alternates(): |
|
print ("Device: [%.4x:%.4x] Cfg: %d Intf: %d Alt: %d '%s'" % ( \ |
|
alt.device.idVendor, \ |
|
alt.device.idProduct, \ |
|
alt.configuration, \ |
|
alt.bInterfaceNumber, \ |
|
alt.bAlternateSetting, \ |
|
name)) |
|
|
|
def leave_dfu(args): |
|
dfu = find_device(args) |
|
dfu.leave() |
|
status = dfu.get_status() |
|
if status[0] > 0: |
|
raise RuntimeError("An error occured. Status: %r" % status) |
|
|
|
def erase(args): |
|
dfu = find_device(args) |
|
|
|
print ("Erasing. Please wait this might be long ...") |
|
dfu.erase(args.erase) |
|
status = dfu.wait_while_state(dfuse.DfuState.DFU_DOWNLOAD_BUSY) |
|
|
|
if status[1] != dfuse.DfuState.DFU_DOWNLOAD_IDLE: |
|
raise RuntimeError("An error occured. Device Status: %r" % status) |
|
|
|
print ("Done !") |
|
|
|
def flash(args): |
|
dfufile = args.flash[0] |
|
dfu = find_device(args) |
|
|
|
if (dfufile.devInfo['vid'] != dfu.dev.idVendor or dfufile.devInfo['pid'] != dfu.dev.idProduct) and not args.force: |
|
raise ValueError("Vendor/Product id mismatch: [%.4x:%.4x] (file) [%.4x:%.4x] (device). Trying running with --force" % ( \ |
|
dfufile.devInfo['vid'], \ |
|
dfufile.devInfo['vid'], \ |
|
dfu.dev.idVendor, \ |
|
dfu.dev.idProduct)) |
|
|
|
targets = [t for t in dfufile.targets if t['alternate'] == dfu.intf.bAlternateSetting] |
|
|
|
if len(targets) == 0: |
|
raise ValueError("No file target matches the device. Check the --alt setting") |
|
|
|
|
|
print ("Flashing. Please wait this might be long ...") |
|
for t in targets: |
|
print ("Found target %r" % t['name']) |
|
for idx, image in enumerate(t['elements']): |
|
print("Flashing image %d at 0x%.8X" % (idx, image['address'])) |
|
|
|
print("Erasing ...") |
|
dfu.erase(image['address']) |
|
status = dfu.wait_while_state(dfuse.DfuState.DFU_DOWNLOAD_BUSY) |
|
if status[1] != dfuse.DfuState.DFU_DOWNLOAD_IDLE: |
|
raise RuntimeError("An error occured. Device Status: %r" % status) |
|
|
|
print("Flashing ...") |
|
transfer_size = 1024 |
|
dfu.set_address(image['address']) |
|
status = dfu.wait_while_state(dfuse.DfuState.DFU_DOWNLOAD_BUSY) |
|
if status[1] != dfuse.DfuState.DFU_DOWNLOAD_IDLE: |
|
raise RuntimeError("An error occured. Device Status: %r" % status) |
|
|
|
data = image['data'] |
|
blocks = [data[i:i + transfer_size] for i in range(0, len(data), transfer_size)] |
|
for blocknum, block in enumerate(blocks): |
|
print("Flashing block %r" % blocknum) |
|
dfu.write(blocknum, block) |
|
status = dfu.wait_while_state(dfuse.DfuState.DFU_DOWNLOAD_BUSY) |
|
if status[1] != dfuse.DfuState.DFU_DOWNLOAD_IDLE: |
|
raise RuntimeError("An error occured. Device Status: %r" % status) |
|
|
|
print("Done") |
|
|
|
|
|
return |
|
|
|
status = dfu.wait_while_state(dfuse.DfuState.DFU_DOWNLOAD_BUSY) |
|
|
|
if status[1] != dfuse.DfuState.DFU_IDLE and status[1] != dfuse.DfuState.DFU_DOWNLOAD_IDLE: |
|
raise RuntimeError("An error occured. Status: %r" % status) |
|
|
|
print ("Done !") |
|
|
|
parser = argparse.ArgumentParser(description="DfuSe flashing util for STM32") |
|
|
|
action = parser.add_mutually_exclusive_group(required = True) |
|
action.add_argument('--list', action='store_true', help='List available DfuSe interfaces') |
|
action.add_argument('--leave', action='store_true', help='Leave DFU mode') |
|
action.add_argument('--flash', nargs=1, action='store', help='Flash a DfuSe file', metavar='FILE', type=dfuse.DfuFile) |
|
action.add_argument('--erase', action='store', help='Erase page at ADDRESS (must be page aligned)', metavar=('ADDRESS'), type=int) |
|
|
|
devinfo = parser.add_argument_group('Device information') |
|
devinfo.add_argument('--vid', action='store', type=int, default=0x0483, help='Device\'s USB vendor id, defaults to 0x0483') |
|
devinfo.add_argument('--pid', action='store', type=int, default=0xdf11, help='Device\'s USB product id, defaults to 0xdf11') |
|
devinfo.add_argument('--cfg', action='store', type=int, default=0, help='Device\'s configuration number, default to 0') |
|
devinfo.add_argument('--intf', action='store', type=int, default=0, help='Device\'s interface number, defaults to 0') |
|
devinfo.add_argument('--alt', action='store', type=int, default=0, help='Device\'s alternate setting number, defaults to 0') |
|
|
|
others = parser.add_argument_group('Other Options') |
|
others.add_argument('--force', '-f', action='store_true', help='Bypass sanity checks') |
|
|
|
args = parser.parse_args() |
|
|
|
#try: |
|
if args.list: |
|
list_dfu(args) |
|
elif args.leave: |
|
leave_dfu(args) |
|
elif args.erase is not None: |
|
erase(args) |
|
elif args.flash is not None: |
|
flash(args) |
|
#except Exception as e: |
|
# print(e, file=sys.stderr) |
|
# sys.exit(-1)
|
|
|