3      Copyright (C) Dean Camera, 2016. 
   5   dean [at] fourwalledcubicle [dot] com 
  10     Front-end programmer for the LUFA HID class bootloader. 
  13         python hid_bootloader_loader.py <Device> <Input>.hex 
  16         python hid_bootloader_loader.py at90usb1287 Mouse.hex 
  18     Requires the pywinusb (https://pypi.python.org/pypi/pywinusb/) and 
  19     IntelHex (http://bialix.com/intelhex/) libraries. 
  23 from pywinusb 
import hid
 
  24 from intelhex 
import IntelHex
 
  27 # Device information table 
  28 device_info_map 
= dict() 
  29 device_info_map
['at90usb1287'] = {'page_size': 256, 'flash_kb': 128} 
  30 device_info_map
['at90usb1286'] = {'page_size': 256, 'flash_kb': 128} 
  31 device_info_map
['at90usb647']  = {'page_size': 256, 'flash_kb': 64} 
  32 device_info_map
['at90usb646']  = {'page_size': 256, 'flash_kb': 64} 
  33 device_info_map
['atmega32u4']  = {'page_size': 128, 'flash_kb': 32} 
  34 device_info_map
['atmega32u2']  = {'page_size': 128, 'flash_kb': 32} 
  35 device_info_map
['atmega16u4']  = {'page_size': 128, 'flash_kb': 16} 
  36 device_info_map
['atmega16u2']  = {'page_size': 128, 'flash_kb': 16} 
  37 device_info_map
['at90usb162']  = {'page_size': 128, 'flash_kb': 16} 
  38 device_info_map
['atmega8u2']   = {'page_size': 128, 'flash_kb': 8} 
  39 device_info_map
['at90usb82']   = {'page_size': 128, 'flash_kb': 8} 
  42 def get_hid_device_handle(): 
  43     hid_device_filter 
= hid
.HidDeviceFilter(vendor_id
=0x03EB, 
  46     valid_hid_devices 
= hid_device_filter
.get_devices() 
  48     if len(valid_hid_devices
) is 0: 
  51         return valid_hid_devices
[0] 
  54 def send_page_data(hid_device
, address
, data
): 
  55     # Bootloader page data should be the HID Report ID (always zero) followed 
  56     # by the starting address to program, then one device's flash page worth 
  58     output_report_data 
= [0] 
  59     output_report_data
.extend([address 
& 0xFF, address 
>> 8]) 
  60     output_report_data
.extend(data
) 
  62     hid_device
.send_output_report(output_report_data
) 
  65 def program_device(hex_data
, device_info
): 
  66     hid_device 
= get_hid_device_handle() 
  68     if hid_device 
is None: 
  69         print("No valid HID device found.") 
  74         print("Connected to bootloader.") 
  76         # Program in all data from the loaded HEX file, in a number of device 
  78         for addr 
in range(0, hex_data
.maxaddr(), device_info
['page_size']): 
  79             # Compute the address range of the current page in the device 
  80             current_page_range 
= range(addr
, addr
+device_info
['page_size']) 
  82             # Extract the data from the hex file at the specified start page 
  83             # address and convert it to a regular list of bytes 
  84             page_data 
= [hex_data
[i
] for i 
in current_page_range
] 
  86             print("Writing address 0x%04X-0x%04X" % 
(current_page_range
[0], current_page_range
[-1])) 
  88             # Devices with more than 64KB of flash should shift down the page 
  89             # address so that it is 16-bit (page size is guaranteed to be 
  90             # >= 256 bytes so no non-zero address bits are discarded) 
  91             if device_info
['flash_kb'] < 64: 
  92                 send_page_data(hid_device
, addr
, page_data
) 
  94                 send_page_data(hid_device
, addr 
>> 8, page_data
) 
  96         # Once programming is complete, start the application via a dummy page 
  97         # program to the page address 0xFFFF 
  98         print("Programming complete, starting application.") 
  99         send_page_data(hid_device
, 0xFFFF, [0] * device_info
['page_size']) 
 105 if __name__ 
== '__main__': 
 106     # Load the specified HEX file 
 108         hex_data 
= IntelHex(sys
.argv
[2]) 
 110         print("Could not open the specified HEX file.") 
 113     # Retrieve the device information entry for the specified device 
 115         device_info 
= device_info_map
[sys
.argv
[1]] 
 117         print("Unknown device name specified.") 
 120     program_device(hex_data
, device_info
)