firmware.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. #!/usr/bin/env python3
  2. import dfudfuse
  3. import usb.core
  4. import usb.util
  5. import argparse
  6. import sys
  7. import parse
  8. class Firmware:
  9. def __init__(self, vid, pid, cfg, intf, alternate):
  10. self.mmaps = list()
  11. self.usbdev = usb.core.find(idVendor = vid, idProduct = pid)
  12. if self.usbdev is not None:
  13. self.dfu = dfuse.DfuDevice(self.usbdev)
  14. mmap_str = usb.util.get_string(self.usbdev, self.dfu.cfg[(0,0)].iInterface)
  15. mmap = parse.parse('{name}/{address:x}/{regions}',mmap_str)
  16. self.address = mmap['address']
  17. for m in mmap['regions'].split(','):
  18. map = dict(zip(['sectors','sec_size','unit','flag'], parse.parse('{:d}*{:d}{:1}{:1}', m)))
  19. self.mmaps.append(map)
  20. for _,alt in self.dfu.alternates():
  21. if alt.configuration == cfg and alt.bInterfaceNumber == intf and alt.bAlternateSetting == alternate:
  22. self.dfu.set_alternate(alt)
  23. status = self.dfu.get_status()
  24. if status[1] == dfuse.DfuState.DFU_ERROR:
  25. # print("Error cleared: %r" % (status,))
  26. self.dfu.clear_status() # Clear left-over errors
  27. return
  28. raise ValueError('No DfuSe compatible device found, check device information options (see --help)')
  29. def erase(self, address):
  30. print ("Erasing. Please wait this might be long ...")
  31. """
  32. dfu.erase(args.erase)
  33. status = dfu.wait_while_state(dfuse.DfuState.DFU_DOWNLOAD_BUSY)
  34. if status[1] != dfuse.DfuState.DFU_DOWNLOAD_IDLE:
  35. raise RuntimeError("An error occured. Device Status: %r" % status)
  36. """
  37. for i in range(0, 1280):
  38. print("Erasing page %r" % i)
  39. self.dfu.erase(address + i * size)
  40. status = self.dfu.wait_while_state(dfuse.DfuState.DFU_DOWNLOAD_BUSY)
  41. if status[1] != dfuse.DfuState.DFU_DOWNLOAD_IDLE:
  42. raise RuntimeError("An error occured. Device Status: %r" % status)
  43. print ("Done !")
  44. def leave_dfu(args):
  45. dfu = find_device(args)
  46. dfu.leave()
  47. status = dfu.get_status()
  48. # if status[0] > 0:
  49. # raise RuntimeError("An error occured. Status: %r" % status)
  50. def flash(dfufile):
  51. if (dfufile.devInfo['vid'] != dfu.dev.idVendor or dfufile.devInfo['pid'] != self.dfu.dev.idProduct):
  52. raise ValueError("Vendor/Product id mismatch: [%.4x:%.4x] (file) [%.4x:%.4x] (device). Trying running with --force" % ( \
  53. dfufile.devInfo['vid'], \
  54. dfufile.devInfo['vid'], \
  55. self.dfu.dev.idVendor, \
  56. self.dfu.dev.idProduct))
  57. targets = [t for t in dfufile.targets if t['alternate'] == self.dfu.intf.bAlternateSetting]
  58. if len(targets) == 0:
  59. raise ValueError("No file target matches the device. Check the --alt setting")
  60. print ("Flashing. Please wait this might be long ...")
  61. for t in targets:
  62. print(self.dfu.alternates()[0][0])
  63. return
  64. print ("Found target %r" % t['name'])
  65. for idx, image in enumerate(t['elements']):
  66. print("Flashing image %d at 0x%.8X" % (idx, image['address']))
  67. print("Flashing ...")
  68. transfer_size = 1024
  69. self.dfu.set_address(image['address'])
  70. status = self.dfu.wait_while_state(dfuse.DfuState.DFU_DOWNLOAD_BUSY)
  71. if status[1] != dfuse.DfuState.DFU_DOWNLOAD_IDLE:
  72. raise RuntimeError("An error occured. Device Status: %r" % status)
  73. data = image['data']
  74. blocks = [data[i:i + transfer_size] for i in range(0, len(data), transfer_size)]
  75. for blocknum, block in enumerate(blocks):
  76. print("Flashing block %r" % blocknum)
  77. self.dfu.write(blocknum, block)
  78. status = self.dfu.wait_while_state(dfuse.DfuState.DFU_DOWNLOAD_BUSY)
  79. if status[1] != dfuse.DfuState.DFU_DOWNLOAD_IDLE:
  80. raise RuntimeError("An error occured. Device Status: %r" % status)
  81. print("Done")
  82. return
  83. status = self.dfu.wait_while_state(dfuse.DfuState.DFU_DOWNLOAD_BUSY)
  84. if status[1] != dfuse.DfuState.DFU_IDLE and status[1] != dfuse.DfuState.DFU_DOWNLOAD_IDLE:
  85. raise RuntimeError("An error occured. Status: %r" % status)
  86. print ("Done !")