2019-10-04 23:38:34 -07:00
"""Compile and flash QMK Firmware
You can compile a keymap already in the repo or using a QMK Configurator export.
A bootloader must be specified.
"""
2021-04-14 19:00:22 -07:00
from argcomplete.completers import FilesCompleter
2022-10-20 14:35:27 +01:00
2019-11-20 14:54:18 -08:00
from milc import cli
2020-03-13 15:47:04 -07:00
import qmk.path
from qmk.decorators import automagic_keyboard , automagic_keymap
2022-10-20 14:35:27 +01:00
from qmk.commands import compile_configurator_json , create_make_command , parse_configurator_json , build_environment
2021-04-14 19:00:22 -07:00
from qmk.keyboard import keyboard_completer , keyboard_folder
2023-01-19 00:24:13 +00:00
from qmk.keymap import keymap_completer , locate_keymap
2022-08-20 06:39:19 +01:00
from qmk.flashers import flasher
2019-10-04 23:38:34 -07:00
2023-01-19 00:24:13 +00:00
def _is_keymap_target ( keyboard , keymap ):
if keymap == 'all' :
return True
if locate_keymap ( keyboard , keymap ):
return True
return False
2023-01-01 04:51:29 +00:00
def _list_bootloaders ():
2019-10-04 23:38:34 -07:00
"""Prints the available bootloaders listed in docs.qmk.fm.
"""
2023-01-01 04:51:29 +00:00
cli . print_help ()
2019-10-04 23:38:34 -07:00
cli . log . info ( 'Here are the available bootloaders:' )
2021-10-15 22:07:33 +01:00
cli . echo ( ' \t avrdude' )
cli . echo ( ' \t bootloadhid' )
2019-10-04 23:38:34 -07:00
cli . echo ( ' \t dfu' )
2021-10-15 22:07:33 +01:00
cli . echo ( ' \t dfu-util' )
cli . echo ( ' \t mdloader' )
cli . echo ( ' \t st-flash' )
cli . echo ( ' \t st-link-cli' )
cli . log . info ( 'Enhanced variants for split keyboards:' )
cli . echo ( ' \t avrdude-split-left' )
cli . echo ( ' \t avrdude-split-right' )
2019-10-04 23:38:34 -07:00
cli . echo ( ' \t dfu-ee' )
cli . echo ( ' \t dfu-split-left' )
cli . echo ( ' \t dfu-split-right' )
cli . echo ( ' \t dfu-util-split-left' )
cli . echo ( ' \t dfu-util-split-right' )
2022-05-30 23:04:50 +01:00
cli . echo ( ' \t uf2-split-left' )
cli . echo ( ' \t uf2-split-right' )
2019-10-04 23:38:34 -07:00
cli . echo ( 'For more info, visit https://docs.qmk.fm/#/flashing' )
2023-01-01 04:51:29 +00:00
return False
def _flash_binary ( filename , mcu ):
"""Try to flash binary firmware
"""
cli . echo ( 'Flashing binary firmware... \n Please reset your keyboard into bootloader mode now! \n Press Ctrl-C to exit. \n ' )
try :
err , msg = flasher ( mcu , filename )
if err :
cli . log . error ( msg )
return False
except KeyboardInterrupt :
cli . log . info ( 'Ctrl-C was pressed, exiting...' )
return True
2019-10-04 23:38:34 -07:00
2019-11-16 07:10:19 +00:00
2022-08-20 06:39:19 +01:00
@cli.argument ( 'filename' , nargs = '?' , arg_only = True , type = qmk . path . FileType ( 'r' ), completer = FilesCompleter ( '.json' ), help = 'A configurator export JSON to be compiled and flashed or a pre-compiled binary firmware file (bin/hex) to be flashed.' )
2020-03-13 15:47:04 -07:00
@cli.argument ( '-b' , '--bootloaders' , action = 'store_true' , help = 'List the available bootloaders.' )
@cli.argument ( '-bl' , '--bootloader' , default = 'flash' , help = 'The flash command, corresponding to qmk \' s make options of bootloaders.' )
2022-08-20 06:39:19 +01:00
@cli.argument ( '-m' , '--mcu' , help = 'The MCU name. Required for HalfKay, HID, USBAspLoader and ISP flashing.' )
2023-01-01 04:51:29 +00:00
@cli.argument ( '-kb' , '--keyboard' , type = keyboard_folder , completer = keyboard_completer , help = 'The keyboard to build a firmware for. Ignored when a configurator export is supplied.' )
@cli.argument ( '-km' , '--keymap' , completer = keymap_completer , help = 'The keymap to build a firmware for. Ignored when a configurator export is supplied.' )
2020-03-13 15:47:04 -07:00
@cli.argument ( '-n' , '--dry-run' , arg_only = True , action = 'store_true' , help = "Don't actually build, just show the make command to be run." )
2021-08-18 01:46:59 +03:00
@cli.argument ( '-j' , '--parallel' , type = int , default = 1 , help = "Set the number of parallel make jobs; 0 means unlimited." )
2021-01-16 15:13:04 -08:00
@cli.argument ( '-e' , '--env' , arg_only = True , action = 'append' , default = [], help = "Set a variable to be passed to make. May be passed multiple times." )
@cli.argument ( '-c' , '--clean' , arg_only = True , action = 'store_true' , help = "Remove object files before compiling." )
2019-10-04 23:38:34 -07:00
@cli.subcommand ( 'QMK Flash.' )
2020-03-13 15:47:04 -07:00
@automagic_keyboard
@automagic_keymap
2019-10-04 23:38:34 -07:00
def flash ( cli ):
"""Compile and or flash QMK Firmware or keyboard/layout
2022-08-20 06:39:19 +01:00
If a binary firmware is supplied, try to flash that.
2023-01-01 04:51:29 +00:00
If a Configurator export is supplied this command will create a new keymap, overwriting an existing keymap if one exists.
2019-10-04 23:38:34 -07:00
2023-01-01 04:51:29 +00:00
If a keyboard and keymap are provided this command will build a firmware based on that.
2019-10-04 23:38:34 -07:00
2020-03-13 15:47:04 -07:00
If bootloader is omitted the make system will use the configured bootloader for that keyboard.
2019-10-04 23:38:34 -07:00
"""
2023-01-01 04:51:29 +00:00
if cli . args . filename and cli . args . filename . suffix in [ '.bin' , '.hex' , '.uf2' ]:
return _flash_binary ( cli . args . filename , cli . args . mcu )
2022-08-20 06:39:19 +01:00
2022-10-20 14:35:27 +01:00
if cli . args . bootloaders :
2023-01-01 04:51:29 +00:00
return _list_bootloaders ()
2022-08-20 06:39:19 +01:00
2022-10-20 14:35:27 +01:00
# Build the environment vars
envs = build_environment ( cli . args . env )
2022-08-20 06:39:19 +01:00
2022-10-20 14:35:27 +01:00
# Determine the compile command
commands = []
2022-08-20 06:39:19 +01:00
2022-10-20 14:35:27 +01:00
if cli . args . filename :
# If a configurator JSON was provided generate a keymap and compile it
user_keymap = parse_configurator_json ( cli . args . filename )
commands = [ compile_configurator_json ( user_keymap , cli . args . bootloader , parallel = cli . config . flash . parallel , clean = cli . args . clean , ** envs )]
2022-08-20 06:39:19 +01:00
2022-10-20 14:35:27 +01:00
elif cli . config . flash . keyboard and cli . config . flash . keymap :
# Generate the make command for a specific keyboard/keymap.
2023-01-19 00:24:13 +00:00
if not _is_keymap_target ( cli . config . flash . keyboard , cli . config . flash . keymap ):
cli . log . error ( 'Invalid keymap argument.' )
cli . print_help ()
return False
2022-10-20 14:35:27 +01:00
if cli . args . clean :
commands . append ( create_make_command ( cli . config . flash . keyboard , cli . config . flash . keymap , 'clean' , ** envs ))
commands . append ( create_make_command ( cli . config . flash . keyboard , cli . config . flash . keymap , cli . args . bootloader , parallel = cli . config . flash . parallel , ** envs ))
2022-08-20 06:39:19 +01:00
2022-10-20 14:35:27 +01:00
if not commands :
cli . log . error ( 'You must supply a configurator export, both `--keyboard` and `--keymap`, or be in a directory for a keyboard or keymap.' )
cli . print_help ()
return False
2021-01-16 15:13:04 -08:00
2022-10-20 14:35:27 +01:00
cli . log . info ( 'Compiling keymap with {fg_cyan}%s ' , ' ' . join ( commands [ - 1 ]))
if not cli . args . dry_run :
cli . echo ( ' \n ' )
for command in commands :
ret = cli . run ( command , capture_output = False )
if ret . returncode :
return ret . returncode