update.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. # greaseweazle/tools/update.py
  2. #
  3. # Greaseweazle control script: Firmware Update.
  4. #
  5. # Written & released by Keir Fraser <keir.xen@gmail.com>
  6. #
  7. # This is free and unencumbered software released into the public domain.
  8. # See the file COPYING for more details, or visit <http://unlicense.org>.
  9. description = "Update the Greaseweazle device firmware to current version."
  10. import sys, serial, struct, os
  11. import crcmod.predefined
  12. from greaseweazle.tools import util
  13. from greaseweazle import version
  14. from greaseweazle import usb as USB
  15. # update_firmware:
  16. # Updates the Greaseweazle firmware using the specified Update File.
  17. def update_firmware(usb, args):
  18. req_type = b'BL' if args.bootloader else b'GW'
  19. filename = args.file
  20. if filename is None:
  21. # Get the absolute path to the root Greaseweazle folder.
  22. path = os.path.dirname(os.path.abspath(__file__))
  23. for _ in range(3):
  24. path = os.path.join(path, os.pardir)
  25. path = os.path.normpath(path)
  26. filename = os.path.join(path, "Greaseweazle-v%d.%d.upd"
  27. % (version.major, version.minor))
  28. # Read and verify the entire update catalogue.
  29. with open(filename, "rb") as f:
  30. dat = f.read()
  31. if struct.unpack('4s', dat[:4])[0] != b'GWUP':
  32. print('%s: Not an UPD file' % (filename))
  33. return
  34. crc32 = crcmod.predefined.Crc('crc-32-mpeg')
  35. crc32.update(dat)
  36. if crc32.crcValue != 0:
  37. print('%s: UPD file is corrupt' % (filename))
  38. return
  39. dat = dat[4:-4]
  40. # Search the catalogue for a match on our Weazle's hardware type.
  41. while dat:
  42. upd_len, hw_model = struct.unpack("<2H", dat[:4])
  43. upd_type, = struct.unpack("2s", dat[upd_len-4:upd_len-2])
  44. if hw_model == usb.hw_model and upd_type == req_type:
  45. # Match: Pull out the embedded update file.
  46. dat = dat[4:upd_len+4]
  47. break
  48. # Skip to the next catalogue entry.
  49. dat = dat[upd_len+4:]
  50. if not dat:
  51. print("%s: No match for F%u hardware" % (filename, usb.hw_model))
  52. return
  53. # Check the matching update file's footer.
  54. sig, maj, min, hw_model = struct.unpack("<2s2BH", dat[-8:-2])
  55. if len(dat) & 3 != 0 or sig != req_type or hw_model != usb.hw_model:
  56. print("%s: Bad update file" % (filename))
  57. return
  58. crc16 = crcmod.predefined.Crc('crc-ccitt-false')
  59. crc16.update(dat)
  60. if crc16.crcValue != 0:
  61. print("%s: Bad CRC" % (filename))
  62. return
  63. # Perform the update.
  64. print("Updating %s to v%u.%u..."
  65. % ("Bootloader" if args.bootloader else "Main Firmware", maj, min))
  66. if args.bootloader:
  67. ack = usb.update_bootloader(dat)
  68. if ack != 0:
  69. print("""\
  70. ** UPDATE FAILED: Please retry immediately or your Weazle may need
  71. full reflashing via a suitable programming adapter!""")
  72. return
  73. print("Done.")
  74. else:
  75. ack = usb.update_firmware(dat)
  76. if ack != 0:
  77. print("** UPDATE FAILED: Please retry!")
  78. return
  79. print("Done.")
  80. if usb.hw_model == 7:
  81. util.usb_reopen(usb, is_update=False)
  82. else:
  83. print("** Disconnect Greaseweazle and remove the Programming Jumper.")
  84. def main(argv):
  85. parser = util.ArgumentParser(allow_abbrev=False)
  86. parser.add_argument("file", nargs="?", help="update filename")
  87. parser.add_argument("device", nargs="?", help="serial device")
  88. parser.add_argument("--bootloader", action="store_true",
  89. help="update the bootloader (use with caution!)")
  90. parser.description = description
  91. parser.prog += ' ' + argv[1]
  92. args = parser.parse_args(argv[2:])
  93. try:
  94. usb = util.usb_open(args.device, is_update=not args.bootloader)
  95. update_firmware(usb, args)
  96. except USB.CmdError as error:
  97. print("Command Failed: %s" % error)
  98. if __name__ == "__main__":
  99. main(sys.argv)
  100. # Local variables:
  101. # python-indent: 4
  102. # End: