5      Copyright (C) Dean Camera, 2021. 
   7   dean [at] fourwalledcubicle [dot] com 
  12     Front-end programmer for the LUFA HID class bootloader. 
  15         python hid_bootloader_loader.py <Device> <Input>.hex 
  18         python hid_bootloader_loader.py at90usb1287 Mouse.hex 
  20     Requires the hidapi (https://pypi.python.org/pypi/hidapi) and 
  21     IntelHex (https://pypi.python.org/pypi/IntelHex) libraries. 
  26 from intelhex 
import IntelHex
 
  29 # Device information table 
  30 device_info_map 
= dict() 
  31 device_info_map
['at90usb1287'] = {'page_size': 256, 'flash_kb': 128} 
  32 device_info_map
['at90usb1286'] = {'page_size': 256, 'flash_kb': 128} 
  33 device_info_map
['at90usb647']  = {'page_size': 256, 'flash_kb': 64} 
  34 device_info_map
['at90usb646']  = {'page_size': 256, 'flash_kb': 64} 
  35 device_info_map
['atmega32u4']  = {'page_size': 128, 'flash_kb': 32} 
  36 device_info_map
['atmega32u2']  = {'page_size': 128, 'flash_kb': 32} 
  37 device_info_map
['atmega16u4']  = {'page_size': 128, 'flash_kb': 16} 
  38 device_info_map
['atmega16u2']  = {'page_size': 128, 'flash_kb': 16} 
  39 device_info_map
['at90usb162']  = {'page_size': 128, 'flash_kb': 16} 
  40 device_info_map
['atmega8u2']   = {'page_size': 128, 'flash_kb': 8} 
  41 device_info_map
['at90usb82']   = {'page_size': 128, 'flash_kb': 8} 
  44 def get_hid_device_handle(): 
  45     all_hid_devices 
= hid
.enumerate() 
  47     lufa_hid_devices 
= [d 
for d 
in all_hid_devices 
if d
['vendor_id'] == 0x03EB and d
['product_id'] == 0x2067] 
  49     if len(lufa_hid_devices
) is 0: 
  52     device_handle 
= hid
.device() 
  53     device_handle
.open_path(lufa_hid_devices
[0]['path']) 
  57 def send_page_data(hid_device
, address
, data
): 
  58     # Bootloader page data should be the HID Report ID (always zero) followed 
  59     # by the starting address to program, then one device's flash page worth 
  61     output_report_data 
= bytearray(65) 
  62     output_report_data
[0] = 0 
  63     output_report_data
[1] = address 
& 0xFF 
  64     output_report_data
[2] = address 
>> 8 
  65     output_report_data
[3 : ] = data
 
  67     hid_device
.write(output_report_data
) 
  70 def program_device(hex_data
, device_info
): 
  71     hid_device 
= get_hid_device_handle() 
  73     if hid_device 
is None: 
  74         print("No valid HID device found.") 
  78         print("Connected to bootloader.", flush
=True) 
  80         # Program in all data from the loaded HEX file, in a number of device 
  82         for addr 
in range(0, hex_data
.maxaddr(), device_info
['page_size']): 
  83             # Compute the address range of the current page in the device 
  84             current_page_range 
= range(addr
, addr
+device_info
['page_size']) 
  86             # Extract the data from the hex file at the specified start page 
  87             # address and convert it to a regular list of bytes 
  88             page_data 
= [hex_data
[i
] for i 
in current_page_range
] 
  90             print("Writing address 0x%04X-0x%04X" % 
(current_page_range
[0], current_page_range
[-1]), flush
=True) 
  92             # Devices with more than 64KB of flash should shift down the page 
  93             # address so that it is 16-bit (page size is guaranteed to be 
  94             # >= 256 bytes so no non-zero address bits are discarded) 
  95             if device_info
['flash_kb'] < 64: 
  96                 send_page_data(hid_device
, addr
, page_data
) 
  98                 send_page_data(hid_device
, addr 
>> 8, page_data
) 
 100         # Once programming is complete, start the application via a dummy page 
 101         # program to the page address 0xFFFF 
 102         print("Programming complete, starting application.", flush
=True) 
 103         send_page_data(hid_device
, 0xFFFF, [0] * device_info
['page_size']) 
 109 if __name__ 
== '__main__': 
 110     if len(sys
.argv
) != 3: 
 112         print("\t{} device file.hex".format(sys
.argv
[0])) 
 115     # Load the specified HEX file 
 117         hex_data 
= IntelHex(sys
.argv
[2]) 
 119         print("Could not open the specified HEX file.") 
 122     # Retrieve the device information entry for the specified device 
 124         device_info 
= device_info_map
[sys
.argv
[1]] 
 126         print("Unknown device name specified.") 
 129     program_device(hex_data
, device_info
)