update.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  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 a valid 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, major, minor = struct.unpack("2s2B", dat[upd_len-4:upd_len])
  44. if ((hw_model, upd_type, major, minor)
  45. == (usb.hw_model, req_type, version.major, version.minor)):
  46. # Match: Pull out the embedded update file.
  47. dat = dat[4:upd_len+4]
  48. break
  49. # Skip to the next catalogue entry.
  50. dat = dat[upd_len+4:]
  51. if not dat:
  52. print("%s: F%u v%u.%u %s update not found"
  53. % (filename, usb.hw_model,
  54. version.major, version.minor,
  55. 'bootloader' if args.bootloader else 'firmware'))
  56. return
  57. # Check the matching update file's footer.
  58. sig, maj, min, hw_model = struct.unpack("<2s2BH", dat[-8:-2])
  59. if len(dat) & 3 != 0 or sig != req_type or hw_model != usb.hw_model:
  60. print("%s: Bad update file" % (filename))
  61. return
  62. crc16 = crcmod.predefined.Crc('crc-ccitt-false')
  63. crc16.update(dat)
  64. if crc16.crcValue != 0:
  65. print("%s: Bad CRC" % (filename))
  66. return
  67. # Perform the update.
  68. print("Updating %s to v%u.%u..."
  69. % ("Bootloader" if args.bootloader else "Main Firmware", maj, min))
  70. if args.bootloader:
  71. ack = usb.update_bootloader(dat)
  72. if ack != 0:
  73. print("""\
  74. ** UPDATE FAILED: Please retry immediately or your Weazle may need
  75. full reflashing via a suitable programming adapter!""")
  76. return
  77. print("Done.")
  78. else:
  79. ack = usb.update_firmware(dat)
  80. if ack != 0:
  81. print("** UPDATE FAILED: Please retry!")
  82. return
  83. print("Done.")
  84. if usb.hw_model == 7:
  85. util.usb_reopen(usb, is_update=False)
  86. else:
  87. print("** Disconnect Greaseweazle and remove the Programming Jumper.")
  88. def main(argv):
  89. parser = util.ArgumentParser(allow_abbrev=False, usage='%(prog)s [options] [file]')
  90. parser.add_argument("file", nargs="?", help="update filename")
  91. parser.add_argument("--device", help="greaseweazle device name")
  92. parser.add_argument("--bootloader", action="store_true",
  93. help="update the bootloader (use with caution!)")
  94. parser.description = description
  95. parser.prog += ' ' + argv[1]
  96. args = parser.parse_args(argv[2:])
  97. try:
  98. usb = util.usb_open(args.device, is_update=not args.bootloader)
  99. update_firmware(usb, args)
  100. except USB.CmdError as error:
  101. print("Command Failed: %s" % error)
  102. if __name__ == "__main__":
  103. main(sys.argv)
  104. # Local variables:
  105. # python-indent: 4
  106. # End: