diff --git a/builddefs/xap.mk b/builddefs/xap.mk index e599c812211..4f23c28467a 100644 --- a/builddefs/xap.mk +++ b/builddefs/xap.mk @@ -11,12 +11,12 @@ XAP_FILES := $(shell ls -1 data/xap/* | sort | xargs echo) $(KEYMAP_OUTPUT)/src/xap_generated.inl: $(XAP_FILES) @$(SILENT) || printf "$(MSG_GENERATING) $@" | $(AWK_CMD) - $(eval CMD=$(QMK_BIN) xap-generate-qmk-inc -o "$(KEYMAP_OUTPUT)/src/xap_generated.inl") + $(eval CMD=$(QMK_BIN) xap-generate-qmk-inc -o "$(KEYMAP_OUTPUT)/src/xap_generated.inl" -kb $(KEYBOARD) -km $(KEYMAP)) @$(BUILD_CMD) $(KEYMAP_OUTPUT)/src/xap_generated.h: $(XAP_FILES) @$(SILENT) || printf "$(MSG_GENERATING) $@" | $(AWK_CMD) - $(eval CMD=$(QMK_BIN) xap-generate-qmk-h -o "$(KEYMAP_OUTPUT)/src/xap_generated.h" -kb $(KEYBOARD)) + $(eval CMD=$(QMK_BIN) xap-generate-qmk-h -o "$(KEYMAP_OUTPUT)/src/xap_generated.h" -kb $(KEYBOARD) -km $(KEYMAP)) @$(BUILD_CMD) generated-files: $(KEYMAP_OUTPUT)/src/info_json_gz.h $(KEYMAP_OUTPUT)/src/xap_generated.inl $(KEYMAP_OUTPUT)/src/xap_generated.h diff --git a/lib/python/qmk/cli/xap/generate_qmk.py b/lib/python/qmk/cli/xap/generate_qmk.py index 26476dba46f..d4ebb7e9dbd 100755 --- a/lib/python/qmk/cli/xap/generate_qmk.py +++ b/lib/python/qmk/cli/xap/generate_qmk.py @@ -10,25 +10,43 @@ from qmk.xap.gen_firmware.header_generator import generate_header @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 protocol include.', hidden=False if cli.config.user.developer else True) def xap_generate_qmk_inc(cli): """Generates the XAP protocol inline codegen file, generated during normal build. """ - generate_inline(cli.args.output) + # Determine our keyboard/keymap + if not cli.args.keyboard: + cli.log.error('Missing parameter: --keyboard') + cli.subcommands['xap-generate-info-h'].print_help() + return False + if not cli.args.keymap: + cli.log.error('Missing parameter: --keymap') + cli.subcommands['xap-generate-info-h'].print_help() + return False + + generate_inline(cli.args.output, cli.args.keyboard, cli.args.keymap) @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 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 + # Determine our keyboard/keymap if not cli.args.keyboard: cli.log.error('Missing parameter: --keyboard') - cli.subcommands['xap-generate-qmk-h'].print_help() + cli.subcommands['xap-generate-info-h'].print_help() return False - generate_header(cli.args.output, cli.args.keyboard) + if not cli.args.keymap: + cli.log.error('Missing parameter: --keymap') + cli.subcommands['xap-generate-info-h'].print_help() + return False + + generate_header(cli.args.output, cli.args.keyboard, cli.args.keymap) @cli.argument('-o', '--output', type=normpath, help='File to write to') diff --git a/lib/python/qmk/xap/common.py b/lib/python/qmk/xap/common.py index 8d68de3fab2..c28f9bea2be 100755 --- a/lib/python/qmk/xap/common.py +++ b/lib/python/qmk/xap/common.py @@ -9,6 +9,8 @@ from jinja2 import Environment, FileSystemLoader, select_autoescape from qmk.constants import QMK_FIRMWARE from qmk.json_schema import json_load from qmk.decorators import lru_cache +from qmk.keymap import locate_keymap +from qmk.path import keyboard def _get_jinja2_env(data_templates_xap_subdir: str): @@ -33,7 +35,7 @@ def _merge_ordered_dicts(dicts): result = OrderedDict() def add_entry(target, k, v): - if k in target and isinstance(v, OrderedDict): + if k in target and isinstance(v, (OrderedDict, dict)): if "!reset!" in v: target[k] = v else: @@ -96,6 +98,44 @@ def latest_xap_defs(): return get_xap_defs('latest') +def _find_kb_spec(kb): + base_path = Path('keyboards') + keyboard_parent = keyboard(kb) + + for _ in range(5): + if keyboard_parent == base_path: + break + + spec = keyboard_parent / 'xap.json' + if spec.exists(): + return spec + + keyboard_parent = keyboard_parent.parent + + # Just return something we know doesn't exist + return keyboard(kb) / 'xap.json' + + +def _find_km_spec(kb, km): + return locate_keymap(kb, km).parent / 'xap.json' + + +def merge_xap_defs(kb, km): + """Gets the latest version of the XAP definitions and merges in optional keyboard/keymap specs + """ + definitions = [get_xap_defs('latest')] + + kb_xap = _find_kb_spec(kb) + if kb_xap.exists(): + definitions.append({'routes': {'0x02': hjson.load(kb_xap.open(encoding='utf-8'))}}) + + km_xap = _find_km_spec(kb, km) + if km_xap.exists(): + definitions.append({'routes': {'0x03': hjson.load(km_xap.open(encoding='utf-8'))}}) + + return _merge_ordered_dicts(definitions) + + @lru_cache(timeout=5) def get_xap_keycodes(xap_version): """Gets keycode data for the required version of the XAP definitions. diff --git a/lib/python/qmk/xap/gen_firmware/header_generator.py b/lib/python/qmk/xap/gen_firmware/header_generator.py index 0a9ba7beadd..bd54c93720d 100755 --- a/lib/python/qmk/xap/gen_firmware/header_generator.py +++ b/lib/python/qmk/xap/gen_firmware/header_generator.py @@ -7,7 +7,7 @@ from qmk.casing import to_snake from qmk.commands import dump_lines from qmk.git import git_get_version from qmk.constants import GPL2_HEADER_C_LIKE, GENERATED_HEADER_C_LIKE -from qmk.xap.common import latest_xap_defs, route_conditions +from qmk.xap.common import merge_xap_defs, route_conditions def _get_c_type(xap_type): @@ -233,10 +233,10 @@ def _append_internal_types(lines, container): lines.append(f'typedef {data_type} xap_{key}_t;') -def generate_header(output_file, keyboard): +def generate_header(output_file, keyboard, keymap): """Generates the XAP protocol header file, generated during normal build. """ - xap_defs = latest_xap_defs() + xap_defs = merge_xap_defs(keyboard, keymap) # Preamble lines = [GPL2_HEADER_C_LIKE, GENERATED_HEADER_C_LIKE, '#pragma once', ''] diff --git a/lib/python/qmk/xap/gen_firmware/inline_generator.py b/lib/python/qmk/xap/gen_firmware/inline_generator.py index 8aeb3560477..44170a18acd 100755 --- a/lib/python/qmk/xap/gen_firmware/inline_generator.py +++ b/lib/python/qmk/xap/gen_firmware/inline_generator.py @@ -3,7 +3,7 @@ from qmk.casing import to_snake from qmk.commands import dump_lines from qmk.constants import GPL2_HEADER_C_LIKE, GENERATED_HEADER_C_LIKE -from qmk.xap.common import latest_xap_defs, route_conditions +from qmk.xap.common import merge_xap_defs, route_conditions def _get_c_type(xap_type): @@ -268,10 +268,10 @@ def _append_broadcast_messages(lines, container): lines.append(f'void {name}(const void *data, size_t length){{ xap_broadcast({key}, data, length); }}') -def generate_inline(output_file): +def generate_inline(output_file, keyboard, keymap): """Generates the XAP protocol header file, generated during normal build. """ - xap_defs = latest_xap_defs() + xap_defs = merge_xap_defs(keyboard, keymap) # Preamble lines = [GPL2_HEADER_C_LIKE, GENERATED_HEADER_C_LIKE, '']