diff --git a/builddefs/xap.mk b/builddefs/xap.mk index c2ccf145418..e599c812211 100644 --- a/builddefs/xap.mk +++ b/builddefs/xap.mk @@ -4,11 +4,7 @@ # XAP embedded info.json $(KEYMAP_OUTPUT)/src/info_json_gz.h: $(INFO_JSON_FILES) @$(SILENT) || printf "$(MSG_GENERATING) $@" | $(AWK_CMD) - mkdir -p $(KEYMAP_OUTPUT)/src - $(eval CMD=$(QMK_BIN) info -f json -kb $(KEYBOARD) -km $(KEYMAP) | gzip -c9 > $(KEYMAP_OUTPUT)/src/info.json.gz \ - && cd $(KEYMAP_OUTPUT)/src >/dev/null 2>&1 \ - && xxd -i info.json.gz info_json_gz.h \ - && cd - >/dev/null 2>&1) + $(eval CMD=$(QMK_BIN) xap-generate-info-h -o "$(KEYMAP_OUTPUT)/src/info_json_gz.h" -kb $(KEYBOARD) -km $(KEYMAP)) @$(BUILD_CMD) XAP_FILES := $(shell ls -1 data/xap/* | sort | xargs echo) diff --git a/lib/python/qmk/cli/format/text.py b/lib/python/qmk/cli/format/text.py index 6dd45118965..fa86b4379a1 100644 --- a/lib/python/qmk/cli/format/text.py +++ b/lib/python/qmk/cli/format/text.py @@ -6,19 +6,13 @@ from subprocess import DEVNULL from milc import cli from qmk.path import normpath - - -def _get_chunks(it, size): - """Break down a collection into smaller parts - """ - it = iter(it) - return iter(lambda: tuple(islice(it, size)), ()) +from qmk.commands import get_chunks def dos2unix_run(files): """Spawn multiple dos2unix subprocess avoiding too long commands on formatting everything """ - for chunk in _get_chunks(files, 10): + for chunk in get_chunks(files, 10): dos2unix = cli.run(['dos2unix', *chunk]) if dos2unix.returncode: diff --git a/lib/python/qmk/cli/xap/generate_qmk.py b/lib/python/qmk/cli/xap/generate_qmk.py index 0cb2fec1954..ff43e2863d3 100755 --- a/lib/python/qmk/cli/xap/generate_qmk.py +++ b/lib/python/qmk/cli/xap/generate_qmk.py @@ -1,11 +1,19 @@ """This script generates the XAP protocol generated sources to be compiled into QMK firmware. """ +import json +import gzip + from milc import cli from qmk.path import normpath +from qmk.info import info_json +from qmk.commands import get_chunks, dump_lines +from qmk.keyboard import keyboard_completer, keyboard_folder from qmk.xap.gen_firmware.inline_generator import generate_inline from qmk.xap.gen_firmware.header_generator import generate_header +from qmk.constants import GPL2_HEADER_C_LIKE, GENERATED_HEADER_C_LIKE + @cli.argument('-o', '--output', type=normpath, help='File to write to') @cli.subcommand('Generates the XAP protocol include.', hidden=False if cli.config.user.developer else True) @@ -16,9 +24,56 @@ def xap_generate_qmk_inc(cli): @cli.argument('-o', '--output', type=normpath, help='File to write to') -@cli.argument('-kb', '--keyboard', help='Name of the keyboard') +@cli.argument('-kb', '--keyboard', type=keyboard_folder, completer=keyboard_completer, help='Name of the keyboard') @cli.subcommand('Generates the XAP protocol include.', hidden=False if cli.config.user.developer else True) def xap_generate_qmk_h(cli): """Generates the XAP protocol header file, generated during normal build. """ + # Determine our keyboard + if not cli.args.keyboard: + cli.log.error('Missing parameter: --keyboard') + cli.subcommands['xap-generate-qmk-h'].print_help() + return False generate_header(cli.args.output, cli.args.keyboard) + + +@cli.argument('-o', '--output', type=normpath, help='File to write to') +@cli.argument('-kb', '--keyboard', type=keyboard_folder, completer=keyboard_completer, help='Name of the keyboard') +@cli.argument('-km', '--keymap', help='The keymap\'s name') +@cli.subcommand('Generates the XAP info.json payload include.', hidden=False if cli.config.user.developer else True) +def xap_generate_info_h(cli): + """Generates the XAP info.json payload header file, generated during normal build. + """ + # Determine our keyboard + if not cli.args.keyboard: + cli.log.error('Missing parameter: --keyboard') + cli.subcommands['xap-generate-info-h'].print_help() + return False + + # TODO: merge in keymap level content + # Build the info.json file + kb_info_json = info_json(cli.args.keyboard) + + # Minify + str_data = json.dumps(kb_info_json, separators=(',', ':')) + + # Compress + compressed = gzip.compress(str_data.encode("utf-8"), compresslevel=9) + + # split into lines to match xxd output + hex_array = ["0x{:02X}".format(b) for b in compressed] + data_len = len(hex_array) + + data = "" + for chunk in get_chunks(hex_array, 12): + data += f' {", ".join(chunk)},\n' + + lines = [GPL2_HEADER_C_LIKE, GENERATED_HEADER_C_LIKE, '#pragma once', ''] + + # Gen output file + lines.append('unsigned char info_json_gz[] = {') + lines.append(data) + lines.append('};') + lines.append(f'unsigned int info_json_gz_len = {data_len};') + + dump_lines(cli.args.output, lines) diff --git a/lib/python/qmk/commands.py b/lib/python/qmk/commands.py index 5216bcdba52..56b2ccc50cf 100644 --- a/lib/python/qmk/commands.py +++ b/lib/python/qmk/commands.py @@ -6,6 +6,7 @@ import shutil from pathlib import Path from subprocess import DEVNULL from time import strftime +from itertools import islice from milc import cli import jsonschema @@ -360,3 +361,25 @@ def in_virtualenv(): """ active_prefix = getattr(sys, "base_prefix", None) or getattr(sys, "real_prefix", None) or sys.prefix return active_prefix != sys.prefix + + +def get_chunks(it, size): + """Break down a collection into smaller parts + """ + it = iter(it) + return iter(lambda: tuple(islice(it, size)), ()) + + +def dump_lines(output_file, lines): + """Handle dumping to stdout or file + Creates parent folders if required + """ + generated = '\n'.join(lines) + if output_file: + if output_file.name == '-': + print(generated) + else: + output_file.parent.mkdir(parents=True, exist_ok=True) + if output_file.exists(): + output_file.replace(output_file.parent / (output_file.name + '.bak')) + output_file.write_text(generated)