2017-11-17 11:40:34 -05:00
#!/usr/bin/env python
# Copyright 2017 Luiz Ribeiro <luizribeiro@gmail.com>, Sebastian Kaim <sebb@sebb767.de>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from __future__ import print_function
import os
import sys
import time
2019-02-22 20:50:58 +00:00
import argparse
2017-11-17 11:40:34 -05:00
import usb
2019-02-22 20:50:58 +00:00
def check_keyboard_normal_mode ( vendor , product ):
2017-11-17 11:40:34 -05:00
"""Returns a device if a ps2avrGB device in normal made (that is in keyboard mode) or None if it is not found."""
2019-02-22 20:50:58 +00:00
return usb . core . find ( idVendor = vendor , idProduct = product )
2017-11-17 11:40:34 -05:00
2019-02-22 20:50:58 +00:00
def check_keyboard_bootloader_mode ():
2017-11-17 11:40:34 -05:00
"""Returns True if a ps2avrGB device in bootloader (flashable) mode is found and False otherwise."""
return ( usb . core . find ( idVendor = 0x16c0 , idProduct = 0x05df ) is not None )
2019-02-22 20:50:58 +00:00
def flash_keyboard ( firmware_file ):
2017-11-17 11:40:34 -05:00
"""Calls bootloadHID to flash the given file to the device."""
print ( 'Flashing firmware to device ...' )
if os . system ( 'bootloadHID -r " %s "' % firmware_file ) == 0 :
print ( ' \n Done!' )
else :
print ( ' \n bootloadHID returned an error.' )
2019-02-22 20:50:58 +00:00
def print_device_info ( dev ):
2017-11-17 11:40:34 -05:00
"""Prints all infos for a given USB device"""
print ( 'Device Information:' )
2019-02-22 21:10:16 +00:00
print ( ' idVendor: %d (0x %04x )' % ( dev . idVendor , dev . idVendor ))
print ( ' idProduct: %d (0x %04x )' % ( dev . idProduct , dev . idProduct ))
2017-11-17 11:40:34 -05:00
print ( 'Manufacturer: %s ' % ( dev . iManufacturer ))
print ( 'Serial: %s ' % ( dev . iSerialNumber ))
print ( 'Product: %s ' % ( dev . iProduct ), end = ' \n\n ' )
2019-02-22 20:50:58 +00:00
def send_device_to_bootloader_mode ( dev ):
2017-11-17 11:40:34 -05:00
"""Tries to send a given ps2avrGB keyboard to bootloader mode to allow flashing."""
try :
dev . set_configuration ()
request_type = usb . util . build_request_type (
2019-02-22 20:50:58 +00:00
usb . util . CTRL_OUT ,
usb . util . CTRL_TYPE_CLASS ,
usb . util . CTRL_RECIPIENT_DEVICE )
2017-11-17 11:40:34 -05:00
USBRQ_HID_SET_REPORT = 0x09
HID_REPORT_OPTION = 0x0301
dev . ctrl_transfer ( request_type , USBRQ_HID_SET_REPORT , HID_REPORT_OPTION , 0 , [ 0 , 0 , 0xFF ] + [ 0 ] * 5 )
except usb . core . USBError :
# for some reason I keep getting USBError, but it works!
pass
2019-02-22 20:50:58 +00:00
def auto_int ( value ):
"""Helper for argparse to enable auto base detection"""
return int ( value , 0 )
2017-11-17 11:40:34 -05:00
2019-02-22 20:50:58 +00:00
parser = argparse . ArgumentParser ( description = 'Flash bootloadHID device' )
2019-02-22 21:10:16 +00:00
parser . add_argument ( '--vendor' , type = auto_int , default = 0x20A0 , help = 'Non bootloader idVendor to search for (default: 0x %(default)04x )' )
parser . add_argument ( '--product' , type = auto_int , default = 0x422D , help = 'Non bootloader idProduct to search for (default: 0x %(default)04x )' )
2019-02-22 20:50:58 +00:00
parser . add_argument ( 'firmware_hex' , type = argparse . FileType ( 'r' ), help = 'Firmware hex file to flash' )
args = parser . parse_args ()
2017-11-17 11:40:34 -05:00
2019-02-22 20:50:58 +00:00
kb = check_keyboard_normal_mode ( args . vendor , args . product )
2017-11-17 11:40:34 -05:00
if kb is not None :
2018-04-20 02:28:55 +10:00
print ( 'Found a keyboard in normal mode. Attempting to send it to bootloader mode ...' , end = '' )
2019-02-22 20:50:58 +00:00
send_device_to_bootloader_mode ( kb )
2017-11-17 11:40:34 -05:00
print ( ' done.' )
print ( "Hint: If your keyboard can't be set to bootloader mode automatically, plug it in while pressing the bootloader key to do so manually." )
print ( " You can find more infos about this here: https://github.com/qmk/qmk_firmware/tree/master/keyboards/ps2avrGB#setting-the-board-to-bootloader-mode" )
attempts = 12 # 60 seconds
found = False
for attempt in range ( 1 , attempts + 1 ):
print ( "Searching for keyboard in bootloader mode ( %i / %i ) ... " % ( attempt , attempts ), end = '' )
2019-02-22 20:50:58 +00:00
if check_keyboard_bootloader_mode ():
2017-11-17 11:40:34 -05:00
print ( 'Found' , end = ' \n\n ' )
2019-02-22 20:50:58 +00:00
flash_keyboard ( args . firmware_hex . name )
2017-11-17 11:40:34 -05:00
found = True
break
else :
print ( 'Nothing.' , end = '' )
if attempt != attempts : # no need to wait on the last attempt
print ( ' Sleeping 5 seconds.' , end = '' )
time . sleep ( 5 )
# print a newline
print ()
if not found :
print ( "Couldn't find a flashable keyboard. Aborting." )
sys . exit ( 2 )