First stab at codegen.
This commit is contained in:
parent
acb2f34c5c
commit
e3fe9fac60
8 changed files with 123 additions and 27 deletions
|
|
@ -224,6 +224,20 @@ $(INTERMEDIATE_OUTPUT)/src/keymap.h: $(KEYMAP_JSON)
|
|||
|
||||
generated-files: $(INTERMEDIATE_OUTPUT)/src/config.h $(INTERMEDIATE_OUTPUT)/src/keymap.c $(INTERMEDIATE_OUTPUT)/src/keymap.h
|
||||
|
||||
$(INTERMEDIATE_OUTPUT)/src/community_modules.h: $(KEYMAP_JSON)
|
||||
@$(SILENT) || printf "$(MSG_GENERATING) $@" | $(AWK_CMD)
|
||||
$(eval CMD=$(QMK_BIN) generate-community-modules-h --quiet --output $(INTERMEDIATE_OUTPUT)/src/community_modules.h $(KEYMAP_JSON))
|
||||
@$(BUILD_CMD)
|
||||
|
||||
$(INTERMEDIATE_OUTPUT)/src/community_modules.c: $(KEYMAP_JSON)
|
||||
@$(SILENT) || printf "$(MSG_GENERATING) $@" | $(AWK_CMD)
|
||||
$(eval CMD=$(QMK_BIN) generate-community-modules-c --quiet --output $(INTERMEDIATE_OUTPUT)/src/community_modules.c $(KEYMAP_JSON))
|
||||
@$(BUILD_CMD)
|
||||
|
||||
SRC += $(INTERMEDIATE_OUTPUT)/src/community_modules.c
|
||||
|
||||
generated-files: $(INTERMEDIATE_OUTPUT)/src/community_modules.h $(INTERMEDIATE_OUTPUT)/src/community_modules.c
|
||||
|
||||
endif
|
||||
|
||||
include $(BUILDDEFS_PATH)/converters.mk
|
||||
|
|
|
|||
|
|
@ -71,6 +71,12 @@
|
|||
"config": {"$ref": "qmk.keyboard.v1"},
|
||||
"notes": {
|
||||
"type": "string"
|
||||
},
|
||||
"modules": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ subcommands = [
|
|||
'qmk.cli.generate.api',
|
||||
'qmk.cli.generate.autocorrect_data',
|
||||
'qmk.cli.generate.compilation_database',
|
||||
'qmk.cli.generate.community_modules',
|
||||
'qmk.cli.generate.config_h',
|
||||
'qmk.cli.generate.develop_pr_list',
|
||||
'qmk.cli.generate.dfu_header',
|
||||
|
|
|
|||
75
lib/python/qmk/cli/generate/community_modules.py
Normal file
75
lib/python/qmk/cli/generate/community_modules.py
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
from argcomplete.completers import FilesCompleter
|
||||
|
||||
from milc import cli
|
||||
from milc.attrdict import AttrDict
|
||||
|
||||
import qmk.path
|
||||
from qmk.commands import dump_lines, parse_configurator_json
|
||||
from qmk.constants import GPL2_HEADER_C_LIKE, GENERATED_HEADER_C_LIKE
|
||||
|
||||
class ModuleAPI(AttrDict):
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__()
|
||||
for key, value in kwargs.items():
|
||||
self[key] = value
|
||||
|
||||
MODULE_API_LIST = [
|
||||
ModuleAPI(ret_type='void', name='keyboard_pre_init', args='void', call_params='', ret_val=None),
|
||||
ModuleAPI(ret_type='void', name='keyboard_post_init', args='void', call_params='', ret_val=None),
|
||||
ModuleAPI(ret_type='void', name='housekeeping_task', args='void', call_params='', ret_val=None),
|
||||
ModuleAPI(ret_type='bool', name='process_record', args='uint16_t keycode, keyrecord_t *record', call_params='keycode, record', ret_val='true'),
|
||||
]
|
||||
|
||||
@cli.argument('-o', '--output', arg_only=True, type=qmk.path.normpath, help='File to write to')
|
||||
@cli.argument('-q', '--quiet', arg_only=True, action='store_true', help="Quiet mode, only output error messages")
|
||||
@cli.argument('filename', type=qmk.path.FileType('r'), arg_only=True, completer=FilesCompleter('.json'), help='Configurator JSON file')
|
||||
@cli.subcommand('Creates a community_modules.h from a keymap.json file.')
|
||||
def generate_community_modules_h(cli):
|
||||
"""Creates a community_modules.h from a keymap.json file
|
||||
"""
|
||||
if cli.args.output and cli.args.output.name == '-':
|
||||
cli.args.output = None
|
||||
|
||||
lines = [GPL2_HEADER_C_LIKE, GENERATED_HEADER_C_LIKE, '#pragma once', '']
|
||||
keymap_json = parse_configurator_json(cli.args.filename)
|
||||
if keymap_json and 'modules' in keymap_json:
|
||||
for module in keymap_json['modules']:
|
||||
for api in MODULE_API_LIST:
|
||||
lines.append(f'{api.ret_type} {api.name}_{module}({api.args});')
|
||||
dump_lines(cli.args.output, lines, cli.args.quiet)
|
||||
|
||||
@cli.argument('-o', '--output', arg_only=True, type=qmk.path.normpath, help='File to write to')
|
||||
@cli.argument('-q', '--quiet', arg_only=True, action='store_true', help="Quiet mode, only output error messages")
|
||||
@cli.argument('filename', type=qmk.path.FileType('r'), arg_only=True, completer=FilesCompleter('.json'), help='Configurator JSON file')
|
||||
@cli.subcommand('Creates a community_modules.c from a keymap.json file.')
|
||||
def generate_community_modules_c(cli):
|
||||
"""Creates a community_modules.c from a keymap.json file
|
||||
"""
|
||||
if cli.args.output and cli.args.output.name == '-':
|
||||
cli.args.output = None
|
||||
|
||||
lines = [GPL2_HEADER_C_LIKE, GENERATED_HEADER_C_LIKE, '#include QMK_KEYBOARD_H', '#include "community_modules.h"']
|
||||
keymap_json = parse_configurator_json(cli.args.filename)
|
||||
if keymap_json and 'modules' in keymap_json:
|
||||
for module in keymap_json['modules']:
|
||||
for api in MODULE_API_LIST:
|
||||
lines.append('')
|
||||
lines.append(f'__attribute__((weak)) {api.ret_type} {api.name}_{module}({api.args}) {{ ')
|
||||
if api.ret_val:
|
||||
lines.append(f' return {api.ret_val};')
|
||||
lines.append('}')
|
||||
|
||||
for api in MODULE_API_LIST:
|
||||
lines.append('')
|
||||
lines.append(f'{api.ret_type} {api.name}_modules({api.args}) {{')
|
||||
if api.ret_type == 'bool':
|
||||
lines.append(' return true')
|
||||
for module in keymap_json['modules']:
|
||||
if api.ret_type == 'bool':
|
||||
lines.append(f' && {api.name}_{module}({api.call_params})')
|
||||
else:
|
||||
lines.append(f' {api.name}_{module}({api.call_params});')
|
||||
if api.ret_type == 'bool':
|
||||
lines.append(' ;')
|
||||
lines.append('}')
|
||||
dump_lines(cli.args.output, lines, cli.args.quiet)
|
||||
|
|
@ -55,6 +55,7 @@ def process_mapping_rule(kb_info_json, rules_key, info_dict):
|
|||
def generate_rules_mk(cli):
|
||||
"""Generates a rules.mk file from info.json.
|
||||
"""
|
||||
user_keymap = None
|
||||
converter = None
|
||||
# Determine our keyboard/keymap
|
||||
if cli.args.filename:
|
||||
|
|
@ -99,6 +100,14 @@ def generate_rules_mk(cli):
|
|||
if converter:
|
||||
rules_mk_lines.append(generate_rule('CONVERT_TO', converter))
|
||||
|
||||
if user_keymap and 'modules' in user_keymap:
|
||||
for module in user_keymap['modules']:
|
||||
rules_mk_lines.append('')
|
||||
rules_mk_lines.append(f'COMMUNITY_MODULES += {module}')
|
||||
rules_mk_lines.append(f'OPT_DEFS += -DMODULE_{module.upper()}=TRUE')
|
||||
rules_mk_lines.append(f'VPATH += modules/{module}')
|
||||
rules_mk_lines.append(f'include modules/{module}/rules.mk')
|
||||
|
||||
# Show the results
|
||||
dump_lines(cli.args.output, rules_mk_lines)
|
||||
|
||||
|
|
|
|||
|
|
@ -334,33 +334,6 @@ def write_json(keyboard, keymap, layout, layers, macros=None):
|
|||
return write_file(keymap_file, keymap_content)
|
||||
|
||||
|
||||
def write(keymap_json):
|
||||
"""Generate the `keymap.c` and write it to disk.
|
||||
|
||||
Returns the filename written to.
|
||||
|
||||
`keymap_json` should be a dict with the following keys:
|
||||
keyboard
|
||||
The name of the keyboard
|
||||
|
||||
keymap
|
||||
The name of the keymap
|
||||
|
||||
layout
|
||||
The LAYOUT macro this keymap uses.
|
||||
|
||||
layers
|
||||
An array of arrays describing the keymap. Each item in the inner array should be a string that is a valid QMK keycode.
|
||||
|
||||
macros
|
||||
A list of macros for this keymap.
|
||||
"""
|
||||
keymap_content = generate_c(keymap_json)
|
||||
keymap_file = qmk.path.keymaps(keymap_json['keyboard'])[0] / keymap_json['keymap'] / 'keymap.c'
|
||||
|
||||
return write_file(keymap_file, keymap_content)
|
||||
|
||||
|
||||
def locate_keymap(keyboard, keymap, force_layout=None):
|
||||
"""Returns the path to a keymap for a specific keyboard.
|
||||
"""
|
||||
|
|
|
|||
17
modules/hello_world/hello_world.c
Normal file
17
modules/hello_world/hello_world.c
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
// Copyright 2025 Nick Brassel (@tzarc)
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#include QMK_KEYBOARD_H
|
||||
|
||||
static uint32_t init_timestamp = 0;
|
||||
|
||||
void keyboard_post_init_hello_world(void) {
|
||||
init_timestamp = timer_read32();
|
||||
}
|
||||
|
||||
void housekeeping_task_hello_world(void) {
|
||||
static bool welcomed = false;
|
||||
if(!welcomed && timer_elapsed32(init_timestamp) > 1000) {
|
||||
welcomed = true;
|
||||
print("Hello, world! I'm a QMK based keyboard!\n");
|
||||
}
|
||||
}
|
||||
1
modules/hello_world/rules.mk
Normal file
1
modules/hello_world/rules.mk
Normal file
|
|
@ -0,0 +1 @@
|
|||
SRC += hello_world.c
|
||||
Loading…
Reference in a new issue