You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

112 lines
5.2 KiB

  1. """Compile and flash QMK Firmware
  2. You can compile a keymap already in the repo or using a QMK Configurator export.
  3. A bootloader must be specified.
  4. """
  5. from argcomplete.completers import FilesCompleter
  6. from milc import cli
  7. import qmk.path
  8. from qmk.decorators import automagic_keyboard, automagic_keymap
  9. from qmk.commands import compile_configurator_json, create_make_command, parse_configurator_json, build_environment
  10. from qmk.keyboard import keyboard_completer, keyboard_folder
  11. from qmk.flashers import flasher
  12. def print_bootloader_help():
  13. """Prints the available bootloaders listed in docs.qmk.fm.
  14. """
  15. cli.log.info('Here are the available bootloaders:')
  16. cli.echo('\tavrdude')
  17. cli.echo('\tbootloadhid')
  18. cli.echo('\tdfu')
  19. cli.echo('\tdfu-util')
  20. cli.echo('\tmdloader')
  21. cli.echo('\tst-flash')
  22. cli.echo('\tst-link-cli')
  23. cli.log.info('Enhanced variants for split keyboards:')
  24. cli.echo('\tavrdude-split-left')
  25. cli.echo('\tavrdude-split-right')
  26. cli.echo('\tdfu-ee')
  27. cli.echo('\tdfu-split-left')
  28. cli.echo('\tdfu-split-right')
  29. cli.echo('\tdfu-util-split-left')
  30. cli.echo('\tdfu-util-split-right')
  31. cli.echo('\tuf2-split-left')
  32. cli.echo('\tuf2-split-right')
  33. cli.echo('For more info, visit https://docs.qmk.fm/#/flashing')
  34. @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.')
  35. @cli.argument('-b', '--bootloaders', action='store_true', help='List the available bootloaders.')
  36. @cli.argument('-bl', '--bootloader', default='flash', help='The flash command, corresponding to qmk\'s make options of bootloaders.')
  37. @cli.argument('-m', '--mcu', help='The MCU name. Required for HalfKay, HID, USBAspLoader and ISP flashing.')
  38. @cli.argument('-km', '--keymap', help='The keymap to build a firmware for. Use this if you dont have a configurator file. Ignored when a configurator file is supplied.')
  39. @cli.argument('-kb', '--keyboard', type=keyboard_folder, completer=keyboard_completer, help='The keyboard to build a firmware for. Use this if you dont have a configurator file. Ignored when a configurator file is supplied.')
  40. @cli.argument('-n', '--dry-run', arg_only=True, action='store_true', help="Don't actually build, just show the make command to be run.")
  41. @cli.argument('-j', '--parallel', type=int, default=1, help="Set the number of parallel make jobs; 0 means unlimited.")
  42. @cli.argument('-e', '--env', arg_only=True, action='append', default=[], help="Set a variable to be passed to make. May be passed multiple times.")
  43. @cli.argument('-c', '--clean', arg_only=True, action='store_true', help="Remove object files before compiling.")
  44. @cli.subcommand('QMK Flash.')
  45. @automagic_keyboard
  46. @automagic_keymap
  47. def flash(cli):
  48. """Compile and or flash QMK Firmware or keyboard/layout
  49. If a binary firmware is supplied, try to flash that.
  50. If a Configurator JSON export is supplied this command will create a new keymap. Keymap and Keyboard arguments
  51. will be ignored.
  52. If no file is supplied, keymap and keyboard are expected.
  53. If bootloader is omitted the make system will use the configured bootloader for that keyboard.
  54. """
  55. if cli.args.filename and cli.args.filename.suffix in ['.bin', '.hex']:
  56. # Try to flash binary firmware
  57. cli.echo('Flashing binary firmware...\nPlease reset your keyboard into bootloader mode now!\nPress Ctrl-C to exit.\n')
  58. try:
  59. err, msg = flasher(cli.args.mcu, cli.args.filename)
  60. if err:
  61. cli.log.error(msg)
  62. return False
  63. except KeyboardInterrupt:
  64. cli.log.info('Ctrl-C was pressed, exiting...')
  65. return True
  66. if cli.args.bootloaders:
  67. # Provide usage and list bootloaders
  68. cli.print_help()
  69. print_bootloader_help()
  70. return False
  71. # Build the environment vars
  72. envs = build_environment(cli.args.env)
  73. # Determine the compile command
  74. commands = []
  75. if cli.args.filename:
  76. # If a configurator JSON was provided generate a keymap and compile it
  77. user_keymap = parse_configurator_json(cli.args.filename)
  78. commands = [compile_configurator_json(user_keymap, cli.args.bootloader, parallel=cli.config.flash.parallel, clean=cli.args.clean, **envs)]
  79. elif cli.config.flash.keyboard and cli.config.flash.keymap:
  80. # Generate the make command for a specific keyboard/keymap.
  81. if cli.args.clean:
  82. commands.append(create_make_command(cli.config.flash.keyboard, cli.config.flash.keymap, 'clean', **envs))
  83. commands.append(create_make_command(cli.config.flash.keyboard, cli.config.flash.keymap, cli.args.bootloader, parallel=cli.config.flash.parallel, **envs))
  84. if not commands:
  85. cli.log.error('You must supply a configurator export, both `--keyboard` and `--keymap`, or be in a directory for a keyboard or keymap.')
  86. cli.print_help()
  87. return False
  88. cli.log.info('Compiling keymap with {fg_cyan}%s', ' '.join(commands[-1]))
  89. if not cli.args.dry_run:
  90. cli.echo('\n')
  91. for command in commands:
  92. ret = cli.run(command, capture_output=False)
  93. if ret.returncode:
  94. return ret.returncode