diff options
author | Zach White <skullydazed@gmail.com> | 2021-08-16 15:33:30 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-08-16 23:33:30 +0100 |
commit | 8d9bfdc25437bb401985ba93b47edae2126e7fac (patch) | |
tree | 2439e7adde0bafd6af9a403c92c1a89384c3f6ea | |
parent | fac717c11cfa27780f2f9098383673784174141a (diff) | |
download | qmk_firmware-8d9bfdc25437bb401985ba93b47edae2126e7fac.tar.gz qmk_firmware-8d9bfdc25437bb401985ba93b47edae2126e7fac.zip |
Add a lot more data to info.json (#13366)
* add some split data to info.json
* add tags
* add half of config_options.md to info.json
* add support for designating master split
* sort out split transport and primary
* fix bad data in UNUSED_PINS
* fixup custom transport
* wip
* allow for setting split right half keyboard matrix
* add SPLIT_USB_DETECT
* minor cleanup
* fix an erroneous message
* rework split.usb_detect
* adding missing rgblight vars to info.json
* add mouse_key to info.json
* add all remaining options from docs/config_options.md
* fix audio voices
* qmk info: Change text output to use dotted notation
* tweak layout output
* resolve alias names
* break out some functions to make flake8 happy
* add a field for bootloader instructions
* qmk generate-info-json: add a write-to-file argument
Adds an argument that instructs qmk generate-info-json to write the output to a file instead of just to the terminal.
* -arg_only, +action
Because it was never my intention that one would have to specify a value for the argument that enables writing the file.
* Bring qmk generate-info-json inline with other generate commands
* pytest fixup
* fix esca/getawayvan
* fix data driven errors for bpiphany converters
* features.force_nkro -> usb.force_nkro
* split.primary->split.main
* fix esca/getawayvan_f042
* fix the bpiphany converters for real
* fix bpiphany/tiger_lily
* Apply suggestions from code review
Co-authored-by: Nick Brassel <nick@tzarc.org>
* fix generate-api errors
* fix matrix pin extraction for split boards
* fix ploopyco/trackball_nano/rev1_001
Co-authored-by: James Young <18669334+noroadsleft@users.noreply.github.com>
Co-authored-by: Nick Brassel <nick@tzarc.org>
-rw-r--r-- | data/mappings/info_config.json | 56 | ||||
-rw-r--r-- | data/mappings/info_rules.json | 14 | ||||
-rw-r--r-- | data/schemas/keyboard.jsonschema | 220 | ||||
-rw-r--r-- | keyboards/bpiphany/frosty_flake/config.h | 5 | ||||
-rw-r--r-- | keyboards/bpiphany/tiger_lily/config.h | 5 | ||||
-rw-r--r-- | keyboards/cest73/tkm/config.h | 2 | ||||
-rw-r--r-- | keyboards/esca/getawayvan/config.h | 1 | ||||
-rw-r--r-- | keyboards/esca/getawayvan_f042/config.h | 1 | ||||
-rw-r--r-- | keyboards/handwired/tennie/config.h | 2 | ||||
-rw-r--r-- | keyboards/mesa/mesa_tkl/config.h | 2 | ||||
-rw-r--r-- | keyboards/ploopyco/trackball_nano/rev1_001/config.h | 2 | ||||
-rwxr-xr-x | lib/python/qmk/cli/generate/config_h.py | 140 | ||||
-rwxr-xr-x | lib/python/qmk/cli/generate/info_json.py | 40 | ||||
-rwxr-xr-x | lib/python/qmk/cli/generate/rules_mk.py | 11 | ||||
-rwxr-xr-x | lib/python/qmk/cli/info.py | 53 | ||||
-rw-r--r-- | lib/python/qmk/info.py | 184 | ||||
-rw-r--r-- | lib/python/qmk/json_schema.py | 15 |
17 files changed, 654 insertions, 99 deletions
diff --git a/data/mappings/info_config.json b/data/mappings/info_config.json index b949b1332..18477f912 100644 --- a/data/mappings/info_config.json +++ b/data/mappings/info_config.json | |||
@@ -1,21 +1,46 @@ | |||
1 | # This file maps keys between `config.h` and `info.json`. It is used by QMK | 1 | # This file maps keys between `config.h` and `info.json`. It is used by QMK |
2 | # to correctly and consistently map back and forth between the two systems. | 2 | # to correctly and consistently map back and forth between the two systems. |
3 | { | 3 | { |
4 | # Format: | 4 | # Format: |
5 | # <config.h key>: {"info_key": <info.json key>, ["value_type": <value_type>], ["to_json": <true/false>], ["to_c": <true/false>]} | 5 | # <config.h key>: {"info_key": <info.json key>, ["value_type": <value_type>], ["to_json": <true/false>], ["to_c": <true/false>]} |
6 | # value_type: one of "array", "array.int", "int", "hex", "list", "mapping" | 6 | # value_type: one of "array", "array.int", "bool", "int", "hex", "list", "mapping" |
7 | # to_json: Default `true`. Set to `false` to exclude this mapping from info.json | 7 | # to_json: Default `true`. Set to `false` to exclude this mapping from info.json |
8 | # to_c: Default `true`. Set to `false` to exclude this mapping from config.h | 8 | # to_c: Default `true`. Set to `false` to exclude this mapping from config.h |
9 | # warn_duplicate: Default `true`. Set to `false` to turn off warning when a value exists in both places | 9 | # warn_duplicate: Default `true`. Set to `false` to turn off warning when a value exists in both places |
10 | "DEBOUNCE": {"info_key": "debounce", "value_type": "int"} | 10 | "AUDIO_VOICES": {"info_key": "audio.voices", "value_type": "bool"}, |
11 | "BACKLIGHT_BREATHING": {"info_key": "backlight.breathing", "value_type": "bool"}, | ||
12 | "BREATHING_PERIOD": {"info_key": "backlight.breathing_period", "value_type": "int"}, | ||
13 | "BACKLIGHT_PIN": {"info_key": "backlight.pin"}, | ||
14 | "COMBO_COUNT": {"info_key": "combo.count", "value_type": "int"}, | ||
15 | "COMBO_TERM": {"info_key": "combo.term", "value_type": "int"}, | ||
16 | "DEBOUNCE": {"info_key": "debounce", "value_type": "int"}, | ||
11 | "DEVICE_VER": {"info_key": "usb.device_ver", "value_type": "hex"}, | 17 | "DEVICE_VER": {"info_key": "usb.device_ver", "value_type": "hex"}, |
12 | "DESCRIPTION": {"info_key": "keyboard_folder", "to_json": false}, | 18 | "DESCRIPTION": {"info_key": "keyboard_folder", "to_json": false}, |
13 | "DIODE_DIRECTION": {"info_key": "diode_direction"}, | 19 | "DIODE_DIRECTION": {"info_key": "diode_direction"}, |
20 | "FORCE_NKRO": {"info_key": "usb.force_nkro", "value_type": "bool"}, | ||
21 | "IGNORE_MOD_TAP_INTERRUPT": {"info_key": "tapping.ignore_mod_tap_interrupt", "value_type": "bool"}, | ||
22 | "IGNORE_MOD_TAP_INTERRUPT_PER_KEY": {"info_key": "tapping.ignore_mod_tap_interrupt_per_key", "value_type": "bool"}, | ||
14 | "LAYOUTS": {"info_key": "layout_aliases", "value_type": "mapping"}, | 23 | "LAYOUTS": {"info_key": "layout_aliases", "value_type": "mapping"}, |
24 | "LEADER_PER_KEY_TIMING": {"info_key": "leader_key.timing", "value_type": "bool"}, | ||
25 | "LEADER_KEY_STRICT_KEY_PROCESSING": {"info_key": "leader_key.strict_processing", "value_type": "bool"}, | ||
26 | "LEADER_TIMEOUT": {"info_key": "leader_key.timeout", "value_type": "int"}, | ||
15 | "LED_CAPS_LOCK_PIN": {"info_key": "indicators.caps_lock"}, | 27 | "LED_CAPS_LOCK_PIN": {"info_key": "indicators.caps_lock"}, |
16 | "LED_NUM_LOCK_PIN": {"info_key": "indicators.num_lock"}, | 28 | "LED_NUM_LOCK_PIN": {"info_key": "indicators.num_lock"}, |
17 | "LED_SCROLL_LOCK_PIN": {"info_key": "indicators.scroll_lock"}, | 29 | "LED_SCROLL_LOCK_PIN": {"info_key": "indicators.scroll_lock"}, |
18 | "MANUFACTURER": {"info_key": "manufacturer"}, | 30 | "MANUFACTURER": {"info_key": "manufacturer"}, |
31 | "MATRIX_HAS_GHOST": {"info_key": "matrix_pins.ghost", "value_type": "bool"}, | ||
32 | "MATRIX_IO_DELAY": {"info_key": "matrix_pins.io_delay", "value_type": "int"}, | ||
33 | "MOUSEKEY_DELAY": {"info_key": "mousekey.delay", "value_type": "int"}, | ||
34 | "MOUSEKEY_INTERVAL": {"info_key": "mousekey.interval", "value_type": "int"}, | ||
35 | "MOUSEKEY_MAX_SPEED": {"info_key": "mousekey.max_speed", "value_type": "int"}, | ||
36 | "MOUSEKEY_TIME_TO_MAX": {"info_key": "mousekey.time_to_max", "value_type": "int"}, | ||
37 | "MOUSEKEY_WHEEL_DELAY": {"info_key": "mousekey.wheel_delay", "value_type": "int"}, | ||
38 | "ONESHOT_TIMEOUT": {"info_key": "oneshot.timeout", "value_type": "int"}, | ||
39 | "ONESHOT_TAP_TOGGLE": {"info_key": "oneshot.tap_toggle", "value_type": "int"}, | ||
40 | "PERMISSIVE_HOLD": {"info_key": "tapping.permissive_hold", "value_type": "bool"}, | ||
41 | "PERMISSIVE_HOLD_PER_KEY": {"info_key": "tapping.permissive_hold_per_key", "value_type": "bool"}, | ||
42 | "RETRO_TAPPING": {"info_key": "tapping.retro", "value_type": "bool"}, | ||
43 | "RETRO_TAPPING_PER_KEY": {"info_key": "tapping.retro_per_key", "value_type": "bool"}, | ||
19 | "RGB_DI_PIN": {"info_key": "rgblight.pin"}, | 44 | "RGB_DI_PIN": {"info_key": "rgblight.pin"}, |
20 | "RGBLED_NUM": {"info_key": "rgblight.led_count", "value_type": "int"}, | 45 | "RGBLED_NUM": {"info_key": "rgblight.led_count", "value_type": "int"}, |
21 | "RGBLED_SPLIT": {"info_key": "rgblight.split_count", "value_type": "array.int"}, | 46 | "RGBLED_SPLIT": {"info_key": "rgblight.split_count", "value_type": "array.int"}, |
@@ -30,17 +55,40 @@ | |||
30 | "RGBLIGHT_EFFECT_SNAKE": {"info_key": "rgblight.animations.snake", "value_type": "bool"}, | 55 | "RGBLIGHT_EFFECT_SNAKE": {"info_key": "rgblight.animations.snake", "value_type": "bool"}, |
31 | "RGBLIGHT_EFFECT_STATIC_GRADIENT": {"info_key": "rgblight.animations.static_gradient", "value_type": "bool"}, | 56 | "RGBLIGHT_EFFECT_STATIC_GRADIENT": {"info_key": "rgblight.animations.static_gradient", "value_type": "bool"}, |
32 | "RGBLIGHT_EFFECT_TWINKLE": {"info_key": "rgblight.animations.twinkle"}, | 57 | "RGBLIGHT_EFFECT_TWINKLE": {"info_key": "rgblight.animations.twinkle"}, |
58 | "RGBLIGHT_LAYER_BLINK": {"info_key": "rgblight.layers.blink", "value_type": "bool"}, | ||
59 | "RGBLIGHT_LAYERS": {"info_key": "rgblight.layers.enabled", "value_type": "bool"}, | ||
60 | "RGBLIGHT_LAYERS_OVERRIDE_RGB_OFF": {"info_key": "rgblight.layers.override_rgb", "value_type": "bool"}, | ||
33 | "RGBLIGHT_LIMIT_VAL": {"info_key": "rgblight.max_brightness", "value_type": "int"}, | 61 | "RGBLIGHT_LIMIT_VAL": {"info_key": "rgblight.max_brightness", "value_type": "int"}, |
62 | "RGBLIGHT_MAX_LAYERS": {"info_key": "rgblight.layers.max", "value_type": "int"}, | ||
34 | "RGBLIGHT_HUE_STEP": {"info_key": "rgblight.hue_steps", "value_type": "int"}, | 63 | "RGBLIGHT_HUE_STEP": {"info_key": "rgblight.hue_steps", "value_type": "int"}, |
35 | "RGBLIGHT_SAT_STEP": {"info_key": "rgblight.saturation_steps", "value_type": "int"}, | 64 | "RGBLIGHT_SAT_STEP": {"info_key": "rgblight.saturation_steps", "value_type": "int"}, |
36 | "RGBLIGHT_VAL_STEP": {"info_key": "rgblight.brightness_steps", "value_type": "int"}, | 65 | "RGBLIGHT_VAL_STEP": {"info_key": "rgblight.brightness_steps", "value_type": "int"}, |
37 | "RGBLIGHT_SLEEP": {"info_key": "rgblight.sleep", "value_type": "bool"}, | 66 | "RGBLIGHT_SLEEP": {"info_key": "rgblight.sleep", "value_type": "bool"}, |
38 | "RGBLIGHT_SPLIT": {"info_key": "rgblight.split", "value_type": "bool"}, | 67 | "RGBLIGHT_SPLIT": {"info_key": "rgblight.split", "value_type": "bool"}, |
68 | "RGBW": {"info_key": "rgblight.rgbw", "value_type": "bool"}, | ||
39 | "PRODUCT": {"info_key": "keyboard_folder", "to_json": false}, | 69 | "PRODUCT": {"info_key": "keyboard_folder", "to_json": false}, |
40 | "PRODUCT_ID": {"info_key": "usb.pid", "value_type": "hex"}, | 70 | "PRODUCT_ID": {"info_key": "usb.pid", "value_type": "hex"}, |
41 | "VENDOR_ID": {"info_key": "usb.vid", "value_type": "hex"}, | 71 | "VENDOR_ID": {"info_key": "usb.vid", "value_type": "hex"}, |
42 | "QMK_ESC_OUTPUT": {"info_key": "qmk_lufa_bootloader.esc_output"}, | 72 | "QMK_ESC_OUTPUT": {"info_key": "qmk_lufa_bootloader.esc_output"}, |
43 | "QMK_ESC_INPUT": {"info_key": "qmk_lufa_bootloader.esc_input"}, | 73 | "QMK_ESC_INPUT": {"info_key": "qmk_lufa_bootloader.esc_input"}, |
74 | "QMK_KEYS_PER_SCAN": {"info_key": "qmk.keys_per_scan", "value_type": "int"}, | ||
44 | "QMK_LED": {"info_key": "qmk_lufa_bootloader.led"}, | 75 | "QMK_LED": {"info_key": "qmk_lufa_bootloader.led"}, |
45 | "QMK_SPEAKER": {"info_key": "qmk_lufa_bootloader.speaker"} | 76 | "QMK_SPEAKER": {"info_key": "qmk_lufa_bootloader.speaker"}, |
77 | "SPLIT_MODS_ENABLE": {"info_key": "split.transport.sync_modifiers", "value_type": "bool"}, | ||
78 | "SPLIT_TRANSPORT_MIRROR": {"info_key": "split.transport.sync_matrix_state", "value_type": "bool"}, | ||
79 | "SPLIT_USB_DETECT": {"info_key": "split.usb_detect.enabled", "value_type": "bool"}, | ||
80 | "SPLIT_USB_TIMEOUT": {"info_key": "split.usb_detect.timeout", "value_type": "int"}, | ||
81 | "SPLIT_USB_TIMEOUT_POLL": {"info_key": "split.usb_detect.polling_interval", "value_type": "int"}, | ||
82 | "SOFT_SERIAL_PIN": {"info_key": "split.soft_serial_pin"}, | ||
83 | "SOFT_SERIAL_SPEED": {"info_key": "split.soft_serial_speed"}, | ||
84 | "TAP_CODE_DELAY": {"info_key": "qmk.tap_keycode_delay", "value_type": "int"}, | ||
85 | "TAP_HOLD_CAPS_DELAY": {"info_key": "qmk.tap_capslock_delay", "value_type": "int"}, | ||
86 | "TAPPING_FORCE_HOLD": {"info_key": "tapping.force_hold", "value_type": "bool"}, | ||
87 | "TAPPING_FORCE_HOLD_PER_KEY": {"info_key": "tapping.force_hold_per_key", "value_type": "bool"}, | ||
88 | "TAPPING_TERM": {"info_key": "tapping.term", "value_type": "int"}, | ||
89 | "TAPPING_TERM_PER_KEY": {"info_key": "tapping.term_per_key", "value_type": "bool"}, | ||
90 | "TAPPING_TOGGLE": {"info_key": "tapping.toggle", "value_type": "int"}, | ||
91 | "USB_MAX_POWER_CONSUMPTION": {"info_key": "usb.max_power", "value_type": "int"}, | ||
92 | "USB_POLLING_INTERVAL_MS": {"info_key": "usb.polling_interval", "value_type": "int"}, | ||
93 | "USB_SUSPEND_WAKEUP_DELAY": {"info_key": "usb.suspend_wakeup_delay", "value_type": "int"}, | ||
46 | } | 94 | } |
diff --git a/data/mappings/info_rules.json b/data/mappings/info_rules.json index 97f772c4d..aea67e04c 100644 --- a/data/mappings/info_rules.json +++ b/data/mappings/info_rules.json | |||
@@ -1,15 +1,25 @@ | |||
1 | # This file maps keys between `rules.mk` and `info.json`. It is used by QMK | 1 | # This file maps keys between `rules.mk` and `info.json`. It is used by QMK |
2 | # to correctly and consistently map back and forth between the two systems. | 2 | # to correctly and consistently map back and forth between the two systems. |
3 | { | 3 | { |
4 | # Format: | 4 | # Format: |
5 | # <rules.mk key>: {"info_key": <info.json key>, ["value_type": <value_type>], ["to_json": <true/false>], ["to_c": <true/false>]} | 5 | # <rules.mk key>: {"info_key": <info.json key>, ["value_type": <value_type>], ["to_json": <true/false>], ["to_c": <true/false>]} |
6 | # value_type: one of "array", "array.int", "int", "list", "hex", "mapping" | 6 | # value_type: one of "array", "array.int", "bool", "int", "list", "hex", "mapping" |
7 | # to_json: Default `true`. Set to `false` to exclude this mapping from info.json | 7 | # to_json: Default `true`. Set to `false` to exclude this mapping from info.json |
8 | # to_c: Default `true`. Set to `false` to exclude this mapping from rules.mk | 8 | # to_c: Default `true`. Set to `false` to exclude this mapping from rules.mk |
9 | # warn_duplicate: Default `true`. Set to `false` to turn off warning when a value exists in both places | 9 | # warn_duplicate: Default `true`. Set to `false` to turn off warning when a value exists in both places |
10 | "BOARD": {"info_key": "board"}, | 10 | "BOARD": {"info_key": "board"}, |
11 | "BOOTLOADER": {"info_key": "bootloader", "warn_duplicate": false}, | 11 | "BOOTLOADER": {"info_key": "bootloader", "warn_duplicate": false}, |
12 | "BLUETOOTH": {"info_key": "bluetooth.driver"}, | ||
13 | "FIRMWARE_FORMAT": {"info_key": "build.firmware_format"}, | ||
14 | "KEYBOARD_SHARED_EP": {"info_key": "usb.shared_endpoint.keyboard", "value_type": "bool"}, | ||
15 | "MOUSE_SHARED_EP": {"info_key": "usb.shared_endpoint.mouse", "value_type": "bool"}, | ||
12 | "LAYOUTS": {"info_key": "community_layouts", "value_type": "list"}, | 16 | "LAYOUTS": {"info_key": "community_layouts", "value_type": "list"}, |
13 | "LED_MATRIX_DRIVER": {"info_key": "led_matrix.driver"}, | 17 | "LED_MATRIX_DRIVER": {"info_key": "led_matrix.driver"}, |
18 | "LTO_ENABLE": {"info_key": "build.lto", "value_type": "bool"}, | ||
14 | "MCU": {"info_key": "processor", "warn_duplicate": false}, | 19 | "MCU": {"info_key": "processor", "warn_duplicate": false}, |
20 | "MOUSEKEY_ENABLE": {"info_key": "mouse_key.enabled", "value_type": "bool"}, | ||
21 | "NO_USB_STARTUP_CHECK": {"info_key": "usb.no_startup_check", "value_type": "bool"}, | ||
22 | "SPLIT_KEYBOARD": {"info_key": "split.enabled", "value_type": "bool"}, | ||
23 | "SPLIT_TRANSPORT": {"info_key": "split.transport.protocol", "value_type": "str", "to_c": false}, | ||
24 | "WAIT_FOR_USB": {"info_key": "usb.wait_for", "value_type": "bool"} | ||
15 | } | 25 | } |
diff --git a/data/schemas/keyboard.jsonschema b/data/schemas/keyboard.jsonschema index 3a3fa4b73..78c9a8d36 100644 --- a/data/schemas/keyboard.jsonschema +++ b/data/schemas/keyboard.jsonschema | |||
@@ -15,6 +15,40 @@ | |||
15 | "type": "string", | 15 | "type": "string", |
16 | "enum": ["cortex-m0", "cortex-m0plus", "cortex-m3", "cortex-m4", "MKL26Z64", "MK20DX128", "MK20DX256", "MK66F18", "STM32F042", "STM32F072", "STM32F103", "STM32F303", "STM32F401", "STM32F407", "STM32F411", "STM32F446", "STM32G431", "STM32G474", "STM32L412", "STM32L422", "STM32L433", "STM32L443", "atmega16u2", "atmega32u2", "atmega16u4", "atmega32u4", "at90usb162", "at90usb646", "at90usb647", "at90usb1286", "at90usb1287", "atmega32a", "atmega328p", "atmega328", "attiny85", "unknown"] | 16 | "enum": ["cortex-m0", "cortex-m0plus", "cortex-m3", "cortex-m4", "MKL26Z64", "MK20DX128", "MK20DX256", "MK66F18", "STM32F042", "STM32F072", "STM32F103", "STM32F303", "STM32F401", "STM32F407", "STM32F411", "STM32F446", "STM32G431", "STM32G474", "STM32L412", "STM32L422", "STM32L433", "STM32L443", "atmega16u2", "atmega32u2", "atmega16u4", "atmega32u4", "at90usb162", "at90usb646", "at90usb647", "at90usb1286", "at90usb1287", "atmega32a", "atmega328p", "atmega328", "attiny85", "unknown"] |
17 | }, | 17 | }, |
18 | "audio": { | ||
19 | "type": "object", | ||
20 | "additionalProperties": false, | ||
21 | "properties": { | ||
22 | "pins": {"$ref": "qmk.definitions.v1#/mcu_pin_array"}, | ||
23 | "voices": {"type": "boolean"} | ||
24 | } | ||
25 | }, | ||
26 | "backlight": { | ||
27 | "type": "object", | ||
28 | "additionalProperties": false, | ||
29 | "properties": { | ||
30 | "breathing": {"type": "boolean"}, | ||
31 | "breathing_period": {"$ref": "qmk.definitions.v1#/unsigned_int_8"}, | ||
32 | "levels": { | ||
33 | "type": "number", | ||
34 | "min": 1, | ||
35 | "max": 31, | ||
36 | "multipleOf": 1 | ||
37 | }, | ||
38 | "pin": {"$ref": "qmk.definitions.v1#/mcu_pin"} | ||
39 | } | ||
40 | }, | ||
41 | "bluetooth": { | ||
42 | "type": "object", | ||
43 | "additionalProperties": false, | ||
44 | "properties": { | ||
45 | "driver": { | ||
46 | "type": "string", | ||
47 | "enum": ["AdafruitBLE", "RN42"] | ||
48 | }, | ||
49 | "lto": {"type": "boolean"}, | ||
50 | } | ||
51 | }, | ||
18 | "board": { | 52 | "board": { |
19 | "type": "string", | 53 | "type": "string", |
20 | "minLength": 2, | 54 | "minLength": 2, |
@@ -22,13 +56,39 @@ | |||
22 | }, | 56 | }, |
23 | "bootloader": { | 57 | "bootloader": { |
24 | "type": "string", | 58 | "type": "string", |
25 | "enum": ["atmel-dfu", "bootloadHID", "caterina", "halfkay", "kiibohd", "lufa-dfu", "lufa-ms", "micronucleus", "qmk-dfu", "qmk-hid", "stm32-dfu", "stm32duino", "unknown", "USBasp", "tinyuf2"] | 59 | "enum": ["atmel-dfu", "bootloadHID", "caterina", "halfkay", "kiibohd", "lufa-dfu", "lufa-ms", "micronucleus", "qmk-dfu", "qmk-hid", "stm32-dfu", "stm32duino", "unknown", "USBasp", "tinyuf2"], |
60 | }, | ||
61 | "bootloader_instructions": { | ||
62 | "type": "string", | ||
63 | "description": "Instructions for putting the keyboard into a mode that allows for firmware flashing." | ||
64 | }, | ||
65 | "build": { | ||
66 | "type": "object", | ||
67 | "additionalProperties": false, | ||
68 | "properties": { | ||
69 | "debounce_type": { | ||
70 | "type": "string", | ||
71 | "enum": ["custom", "eager_pk", "eager_pr", "sym_defer_pk", "sym_eager_pk"] | ||
72 | }, | ||
73 | "firmware_format": { | ||
74 | "type": "string", | ||
75 | "enum": ["bin", "hex", "uf2"] | ||
76 | }, | ||
77 | "lto": {"type": "boolean"}, | ||
78 | } | ||
26 | }, | 79 | }, |
27 | "diode_direction": { | 80 | "diode_direction": { |
28 | "type": "string", | 81 | "type": "string", |
29 | "enum": ["COL2ROW", "ROW2COL"] | 82 | "enum": ["COL2ROW", "ROW2COL"] |
30 | }, | 83 | }, |
31 | "debounce": {"$ref": "qmk.definitions.v1#/unsigned_int"}, | 84 | "debounce": {"$ref": "qmk.definitions.v1#/unsigned_int"}, |
85 | "combo": { | ||
86 | "type": "object", | ||
87 | "properties": { | ||
88 | "count": {"$ref": "qmk.definitions.v1#/unsigned_int"}, | ||
89 | "term": {"$ref": "qmk.definitions.v1#/unsigned_int"} | ||
90 | } | ||
91 | }, | ||
32 | "community_layouts": { | 92 | "community_layouts": { |
33 | "type": "array", | 93 | "type": "array", |
34 | "items": {"$ref": "qmk.definitions.v1#/filename"} | 94 | "items": {"$ref": "qmk.definitions.v1#/filename"} |
@@ -90,16 +150,47 @@ | |||
90 | } | 150 | } |
91 | } | 151 | } |
92 | }, | 152 | }, |
153 | "leader_key": { | ||
154 | "type": "object", | ||
155 | "properties": { | ||
156 | "timing": {"type": "boolean"}, | ||
157 | "strict_processing": {"type": "boolean"}, | ||
158 | "timeout": {"$ref": "qmk.definitions.v1#/unsigned_int"} | ||
159 | } | ||
160 | }, | ||
93 | "matrix_pins": { | 161 | "matrix_pins": { |
94 | "type": "object", | 162 | "type": "object", |
95 | "additionalProperties": false, | 163 | "additionalProperties": false, |
96 | "properties": { | 164 | "properties": { |
165 | "custom": {"type": "boolean"}, | ||
166 | "custom_lite": {"type": "boolean"}, | ||
167 | "ghost": {"type": "boolean"}, | ||
168 | "io_delay": {"$ref": "qmk.definitions.v1#/unsigned_int"}, | ||
97 | "direct": { | 169 | "direct": { |
98 | "type": "array", | 170 | "type": "array", |
99 | "items": {$ref": "qmk.definitions.v1#/mcu_pin_array"} | 171 | "items": {"$ref": "qmk.definitions.v1#/mcu_pin_array"} |
100 | }, | 172 | }, |
101 | "cols": {"$ref": "qmk.definitions.v1#/mcu_pin_array"}, | 173 | "cols": {"$ref": "qmk.definitions.v1#/mcu_pin_array"}, |
102 | "rows": {"$ref": "qmk.definitions.v1#/mcu_pin_array"} | 174 | "rows": {"$ref": "qmk.definitions.v1#/mcu_pin_array"}, |
175 | "unused": {"$ref": "qmk.definitions.v1#/mcu_pin_array"} | ||
176 | } | ||
177 | }, | ||
178 | "mouse_key": { | ||
179 | "type": "object", | ||
180 | "properties": { | ||
181 | "enabled": {"type": "boolean"}, | ||
182 | "delay": {"$ref": "qmk.definitions.v1#/unsigned_int_8"} | ||
183 | "interval": {"$ref": "qmk.definitions.v1#/unsigned_int_8"} | ||
184 | "max_speed": {"$ref": "qmk.definitions.v1#/unsigned_int_8"} | ||
185 | "time_to_max": {"$ref": "qmk.definitions.v1#/unsigned_int_8"} | ||
186 | "wheel_delay": {"$ref": "qmk.definitions.v1#/unsigned_int_8"} | ||
187 | } | ||
188 | }, | ||
189 | "oneshot": { | ||
190 | "type": "object", | ||
191 | "properties": { | ||
192 | "tap_toggle": {"$ref": "qmk.definitions.v1#/unsigned_int"}, | ||
193 | "timeout": {"$ref": "qmk.definitions.v1#/unsigned_int"} | ||
103 | } | 194 | } |
104 | }, | 195 | }, |
105 | "rgblight": { | 196 | "rgblight": { |
@@ -114,9 +205,25 @@ | |||
114 | }, | 205 | }, |
115 | "brightness_steps": {"$ref": "qmk.definitions.v1#/unsigned_int"}, | 206 | "brightness_steps": {"$ref": "qmk.definitions.v1#/unsigned_int"}, |
116 | "hue_steps": {"$ref": "qmk.definitions.v1#/unsigned_int"}, | 207 | "hue_steps": {"$ref": "qmk.definitions.v1#/unsigned_int"}, |
208 | "layers": { | ||
209 | "type": "object", | ||
210 | "additionalProperties": false, | ||
211 | "properties": { | ||
212 | "blink": {"type": "boolean"}, | ||
213 | "enabled": {"type": "boolean"}, | ||
214 | "max": { | ||
215 | "type": "number", | ||
216 | "min": 1, | ||
217 | "max": 32, | ||
218 | "multipleOf": 1 | ||
219 | }, | ||
220 | "override_rgb": {"type": "boolean"} | ||
221 | } | ||
222 | }, | ||
117 | "led_count": {"$ref": "qmk.definitions.v1#/unsigned_int"}, | 223 | "led_count": {"$ref": "qmk.definitions.v1#/unsigned_int"}, |
118 | "max_brightness": {"$ref": "qmk.definitions.v1#/unsigned_int_8"}, | 224 | "max_brightness": {"$ref": "qmk.definitions.v1#/unsigned_int_8"}, |
119 | "pin": {"$ref": "qmk.definitions.v1#/mcu_pin"}, | 225 | "pin": {"$ref": "qmk.definitions.v1#/mcu_pin"}, |
226 | "rgbw": {"type": "boolean"}, | ||
120 | "saturation_steps": {"$ref": "qmk.definitions.v1#/unsigned_int"}, | 227 | "saturation_steps": {"$ref": "qmk.definitions.v1#/unsigned_int"}, |
121 | "sleep": {"type": "boolean"}, | 228 | "sleep": {"type": "boolean"}, |
122 | "split": {"type": "boolean"}, | 229 | "split": {"type": "boolean"}, |
@@ -128,13 +235,118 @@ | |||
128 | } | 235 | } |
129 | } | 236 | } |
130 | }, | 237 | }, |
238 | "split": { | ||
239 | "type": "object", | ||
240 | "additionalProperties": false, | ||
241 | "properties": { | ||
242 | "enabled": {"type": "boolean"}, | ||
243 | "matrix_grid": { | ||
244 | "type": "array", | ||
245 | "items": {"$ref": "qmk.definitions.v1#/mcu_pin"} | ||
246 | }, | ||
247 | "matrix_pins": { | ||
248 | "type": "object", | ||
249 | "additionalProperties": false, | ||
250 | "properties": { | ||
251 | "right": { | ||
252 | "type": "object", | ||
253 | "additionalProperties": false, | ||
254 | "properties": { | ||
255 | "direct": { | ||
256 | "type": "array", | ||
257 | "items": {"$ref": "qmk.definitions.v1#/mcu_pin_array"} | ||
258 | }, | ||
259 | "cols": {"$ref": "qmk.definitions.v1#/mcu_pin_array"}, | ||
260 | "rows": {"$ref": "qmk.definitions.v1#/mcu_pin_array"}, | ||
261 | "unused": {"$ref": "qmk.definitions.v1#/mcu_pin_array"} | ||
262 | } | ||
263 | } | ||
264 | } | ||
265 | }, | ||
266 | "main": { | ||
267 | "type": "string", | ||
268 | "enum": ["eeprom", "left", "matrix_grid", "pin", "right"] | ||
269 | }, | ||
270 | "soft_serial_pin": {"$ref": "qmk.definitions.v1#/mcu_pin"}, | ||
271 | "soft_serial_speed": { | ||
272 | "type": "number", | ||
273 | "min": 0, | ||
274 | "max": 5, | ||
275 | "multipleOf": 1 | ||
276 | }, | ||
277 | "transport": { | ||
278 | "type": "object", | ||
279 | "additionalProperties": false, | ||
280 | "properties": { | ||
281 | "protocol": { | ||
282 | "type": "string", | ||
283 | "enum": ["custom", "i2c", "serial", "serial_usart"] | ||
284 | }, | ||
285 | "sync_matrix_state": {"type": "boolean"}, | ||
286 | "sync_modifiers": {"type": "boolean"} | ||
287 | } | ||
288 | }, | ||
289 | "usb_detect": { | ||
290 | "type": "object", | ||
291 | "additionalProperties": false, | ||
292 | "properties": { | ||
293 | "enabled": {"type": "boolean"}, | ||
294 | "polling_interval": {"$ref": "qmk.definitions.v1#/unsigned_int"}, | ||
295 | "timeout": {"$ref": "qmk.definitions.v1#/unsigned_int"} | ||
296 | } | ||
297 | } | ||
298 | } | ||
299 | }, | ||
300 | "tags": { | ||
301 | "type": "array", | ||
302 | "items": {"type": "string"} | ||
303 | }, | ||
304 | "tapping": { | ||
305 | "type": "object", | ||
306 | "properties": { | ||
307 | "force_hold": {"type": "boolean"}, | ||
308 | "force_hold_per_key": {"type": "boolean"}, | ||
309 | "ignore_mod_tap_interrupt": {"type": "boolean"}, | ||
310 | "ignore_mod_tap_interrupt_per_key": {"type": "boolean"}, | ||
311 | "permissive_hold": {"type": "boolean"}, | ||
312 | "permissive_hold_per_key": {"type": "boolean"}, | ||
313 | "retro": {"type": "boolean"}, | ||
314 | "retro_per_key": {"type": "boolean"}, | ||
315 | "term": {"$ref": "qmk.definitions.v1#/unsigned_int"}, | ||
316 | "term_per_key": {"type": "boolean"}, | ||
317 | "toggle": {"$ref": "qmk.definitions.v1#/unsigned_int"}, | ||
318 | } | ||
319 | }, | ||
131 | "usb": { | 320 | "usb": { |
132 | "type": "object", | 321 | "type": "object", |
133 | "additionalProperties": false, | 322 | "additionalProperties": false, |
134 | "properties": { | 323 | "properties": { |
135 | "device_ver": {"$ref": "qmk.definitions.v1#/hex_number_4d"}, | 324 | "device_ver": {"$ref": "qmk.definitions.v1#/hex_number_4d"}, |
325 | "force_nkro": {"type": "boolean"}, | ||
136 | "pid": {"$ref": "qmk.definitions.v1#/hex_number_4d"}, | 326 | "pid": {"$ref": "qmk.definitions.v1#/hex_number_4d"}, |
137 | "vid": {"$ref": "qmk.definitions.v1#/hex_number_4d"} | 327 | "vid": {"$ref": "qmk.definitions.v1#/hex_number_4d"}, |
328 | "max_power": {"$ref": "qmk.definitions.v1#/unsigned_int_8"}, | ||
329 | "no_startup_check": {"type": "boolean"}, | ||
330 | "polling_interval": {"$ref": "qmk.definitions.v1#/unsigned_int_8"}, | ||
331 | "shared_endpoint": { | ||
332 | "type": "object", | ||
333 | "additionalProperties": false, | ||
334 | "properties": { | ||
335 | "keyboard": {"type": "boolean"}, | ||
336 | "mouse": {"type": "boolean"} | ||
337 | } | ||
338 | }, | ||
339 | "suspend_wakeup_delay": {"$ref": "qmk.definitions.v1#/unsigned_int_8"}, | ||
340 | "wait_for": {"type": "boolean"}, | ||
341 | } | ||
342 | }, | ||
343 | "qmk": { | ||
344 | "type": "object", | ||
345 | "additionalProperties": false, | ||
346 | "properties": { | ||
347 | "keys_per_scan": {"$ref": "qmk.definitions.v1#/unsigned_int_8"}, | ||
348 | "tap_keycode_delay": {"$ref": "qmk.definitions.v1#/unsigned_int_8"}, | ||
349 | "tap_capslock_delay": {"$ref": "qmk.definitions.v1#/unsigned_int_8"}, | ||
138 | } | 350 | } |
139 | }, | 351 | }, |
140 | "qmk_lufa_bootloader": { | 352 | "qmk_lufa_bootloader": { |
diff --git a/keyboards/bpiphany/frosty_flake/config.h b/keyboards/bpiphany/frosty_flake/config.h index 344db5f0d..ae19184a6 100644 --- a/keyboards/bpiphany/frosty_flake/config.h +++ b/keyboards/bpiphany/frosty_flake/config.h | |||
@@ -40,7 +40,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
40 | 40 | ||
41 | /* | 41 | /* |
42 | * Keyboard Matrix Assignments | 42 | * Keyboard Matrix Assignments |
43 | * | ||
44 | * MATRIX_ROW_PINS and MATRIX_COL_PINS aren't actually used and are included | ||
45 | * for data driven compatibility. | ||
43 | */ | 46 | */ |
47 | #define MATRIX_COL_PINS { B0, B3, B2, B1, B6, B4, B5, C7 } | ||
48 | #define MATRIX_ROW_PINS { NO_PIN, NO_PIN, NO_PIN, NO_PIN, NO_PIN, NO_PIN, NO_PIN, NO_PIN, NO_PIN, NO_PIN, NO_PIN, NO_PIN, NO_PIN, NO_PIN, NO_PIN, NO_PIN, NO_PIN, NO_PIN } | ||
44 | #define UNUSED_PINS { C0, C1, C2, C3, C4, D2, D7 } | 49 | #define UNUSED_PINS { C0, C1, C2, C3, C4, D2, D7 } |
45 | 50 | ||
46 | /* Debounce reduces chatter (unintended double-presses) - set 0 if debouncing is not needed */ | 51 | /* Debounce reduces chatter (unintended double-presses) - set 0 if debouncing is not needed */ |
diff --git a/keyboards/bpiphany/tiger_lily/config.h b/keyboards/bpiphany/tiger_lily/config.h index a86cffd16..d3e2464be 100644 --- a/keyboards/bpiphany/tiger_lily/config.h +++ b/keyboards/bpiphany/tiger_lily/config.h | |||
@@ -40,7 +40,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
40 | 40 | ||
41 | /* | 41 | /* |
42 | * Keyboard Matrix Assignments | 42 | * Keyboard Matrix Assignments |
43 | * | ||
44 | * MATRIX_ROW_PINS and MATRIX_COL_PINS aren't actually used and are included | ||
45 | * for data driven compatibility. | ||
43 | */ | 46 | */ |
47 | #define MATRIX_ROW_PINS { C2, B3, B4, B2, B1, C7, B6, B5 } | ||
48 | #define MATRIX_COL_PINS { NO_PIN, NO_PIN, NO_PIN, NO_PIN, NO_PIN, NO_PIN, NO_PIN, NO_PIN, NO_PIN, NO_PIN, NO_PIN, NO_PIN, NO_PIN, NO_PIN, NO_PIN, NO_PIN, NO_PIN, NO_PIN } | ||
44 | #define UNUSED_PINS { B0, C4, D3 } | 49 | #define UNUSED_PINS { B0, C4, D3 } |
45 | 50 | ||
46 | #define LED_NUM_LOCK_PIN C5 | 51 | #define LED_NUM_LOCK_PIN C5 |
diff --git a/keyboards/cest73/tkm/config.h b/keyboards/cest73/tkm/config.h index deef979b2..e925f3971 100644 --- a/keyboards/cest73/tkm/config.h +++ b/keyboards/cest73/tkm/config.h | |||
@@ -34,7 +34,7 @@ | |||
34 | #define MATRIX_ROW_PINS { B0, B1, B2, B3, B4, B5, B6, B7, C6, C7, D0 } | 34 | #define MATRIX_ROW_PINS { B0, B1, B2, B3, B4, B5, B6, B7, C6, C7, D0 } |
35 | /* column handy ruler: c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 */ | 35 | /* column handy ruler: c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 */ |
36 | #define MATRIX_COL_PINS { D1, D2, D3, D4, D5, D6, D7, F0, F1, F4 } | 36 | #define MATRIX_COL_PINS { D1, D2, D3, D4, D5, D6, D7, F0, F1, F4 } |
37 | #define UNUSED_PINS { AF } | 37 | #define UNUSED_PINS { } |
38 | 38 | ||
39 | //NOTE: if D6 pin shows any issues in exploatation the LED on the Teensy is to be removed | 39 | //NOTE: if D6 pin shows any issues in exploatation the LED on the Teensy is to be removed |
40 | 40 | ||
diff --git a/keyboards/esca/getawayvan/config.h b/keyboards/esca/getawayvan/config.h index e9fbc6b40..3b718c583 100644 --- a/keyboards/esca/getawayvan/config.h +++ b/keyboards/esca/getawayvan/config.h | |||
@@ -35,7 +35,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
35 | #define MATRIX_ROW_PINS { A9, A8, A3, A5 } | 35 | #define MATRIX_ROW_PINS { A9, A8, A3, A5 } |
36 | #define DIODE_DIRECTION COL2ROW | 36 | #define DIODE_DIRECTION COL2ROW |
37 | 37 | ||
38 | #define BACKLIGHT_PIN | ||
39 | #define BACKLIGHT_LEVELS 6 | 38 | #define BACKLIGHT_LEVELS 6 |
40 | 39 | ||
41 | #define GRAVE_ESC_CTRL_OVERRIDE | 40 | #define GRAVE_ESC_CTRL_OVERRIDE |
diff --git a/keyboards/esca/getawayvan_f042/config.h b/keyboards/esca/getawayvan_f042/config.h index f83ec7434..8921e9db4 100644 --- a/keyboards/esca/getawayvan_f042/config.h +++ b/keyboards/esca/getawayvan_f042/config.h | |||
@@ -34,7 +34,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
34 | #define MATRIX_ROW_PINS { A9, A8, A3, A5 } | 34 | #define MATRIX_ROW_PINS { A9, A8, A3, A5 } |
35 | #define DIODE_DIRECTION COL2ROW | 35 | #define DIODE_DIRECTION COL2ROW |
36 | 36 | ||
37 | #define BACKLIGHT_PIN | ||
38 | #define BACKLIGHT_LEVELS 6 | 37 | #define BACKLIGHT_LEVELS 6 |
39 | 38 | ||
40 | #define GRAVE_ESC_CTRL_OVERRIDE | 39 | #define GRAVE_ESC_CTRL_OVERRIDE |
diff --git a/keyboards/handwired/tennie/config.h b/keyboards/handwired/tennie/config.h index fee1258df..b1bddac45 100644 --- a/keyboards/handwired/tennie/config.h +++ b/keyboards/handwired/tennie/config.h | |||
@@ -42,7 +42,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
42 | */ | 42 | */ |
43 | #define MATRIX_ROW_PINS { C6, D4, D0} | 43 | #define MATRIX_ROW_PINS { C6, D4, D0} |
44 | #define MATRIX_COL_PINS { D7, E6, B4, B5 } | 44 | #define MATRIX_COL_PINS { D7, E6, B4, B5 } |
45 | #define UNUSED_PINS { B1, B2, B3, B6, F4, F5, F6, F7 D1} | 45 | #define UNUSED_PINS { B1, B2, B3, B6, F4, F5, F6, F7, D1} |
46 | 46 | ||
47 | /* COL2ROW, ROW2COL */ | 47 | /* COL2ROW, ROW2COL */ |
48 | #define DIODE_DIRECTION COL2ROW | 48 | #define DIODE_DIRECTION COL2ROW |
diff --git a/keyboards/mesa/mesa_tkl/config.h b/keyboards/mesa/mesa_tkl/config.h index f4c26e2a0..23da260bc 100644 --- a/keyboards/mesa/mesa_tkl/config.h +++ b/keyboards/mesa/mesa_tkl/config.h | |||
@@ -42,7 +42,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
42 | */ | 42 | */ |
43 | #define MATRIX_ROW_PINS { D2, D1, D0, B0, C6, C7 } | 43 | #define MATRIX_ROW_PINS { D2, D1, D0, B0, C6, C7 } |
44 | #define MATRIX_COL_PINS { D3, D5, D4, D6, D7, B4, B5, B6, F7, F6, F5, F4, F1, F0, B1, B2, B3 } | 44 | #define MATRIX_COL_PINS { D3, D5, D4, D6, D7, B4, B5, B6, F7, F6, F5, F4, F1, F0, B1, B2, B3 } |
45 | #define UNUSED_PINS { B7 E6 } | 45 | #define UNUSED_PINS { B7, E6 } |
46 | 46 | ||
47 | /* COL2ROW, ROW2COL*/ | 47 | /* COL2ROW, ROW2COL*/ |
48 | #define DIODE_DIRECTION COL2ROW | 48 | #define DIODE_DIRECTION COL2ROW |
diff --git a/keyboards/ploopyco/trackball_nano/rev1_001/config.h b/keyboards/ploopyco/trackball_nano/rev1_001/config.h index 63780ef04..6d265d723 100644 --- a/keyboards/ploopyco/trackball_nano/rev1_001/config.h +++ b/keyboards/ploopyco/trackball_nano/rev1_001/config.h | |||
@@ -29,7 +29,7 @@ | |||
29 | * ROW2COL = ROW = Anode (+), COL = Cathode (-, marked on diode) | 29 | * ROW2COL = ROW = Anode (+), COL = Cathode (-, marked on diode) |
30 | * | 30 | * |
31 | */ | 31 | */ |
32 | #define DIRECT_PINS {} | 32 | #define DIRECT_PINS {{NO_PIN}} |
33 | 33 | ||
34 | // These pins are not broken out, and cannot be used normally. | 34 | // These pins are not broken out, and cannot be used normally. |
35 | // They are set as output and pulled high, by default | 35 | // They are set as output and pulled high, by default |
diff --git a/lib/python/qmk/cli/generate/config_h.py b/lib/python/qmk/cli/generate/config_h.py index 54cd5b96a..c0c148f1c 100755 --- a/lib/python/qmk/cli/generate/config_h.py +++ b/lib/python/qmk/cli/generate/config_h.py | |||
@@ -12,7 +12,7 @@ from qmk.keyboard import keyboard_completer, keyboard_folder | |||
12 | from qmk.path import is_keyboard, normpath | 12 | from qmk.path import is_keyboard, normpath |
13 | 13 | ||
14 | 14 | ||
15 | def direct_pins(direct_pins): | 15 | def direct_pins(direct_pins, postfix): |
16 | """Return the config.h lines that set the direct pins. | 16 | """Return the config.h lines that set the direct pins. |
17 | """ | 17 | """ |
18 | rows = [] | 18 | rows = [] |
@@ -24,81 +24,60 @@ def direct_pins(direct_pins): | |||
24 | col_count = len(direct_pins[0]) | 24 | col_count = len(direct_pins[0]) |
25 | row_count = len(direct_pins) | 25 | row_count = len(direct_pins) |
26 | 26 | ||
27 | return """ | 27 | return f""" |
28 | #ifndef MATRIX_COLS | 28 | #ifndef MATRIX_COLS{postfix} |
29 | # define MATRIX_COLS %s | 29 | # define MATRIX_COLS{postfix} {col_count} |
30 | #endif // MATRIX_COLS | 30 | #endif // MATRIX_COLS{postfix} |
31 | 31 | ||
32 | #ifndef MATRIX_ROWS | 32 | #ifndef MATRIX_ROWS{postfix} |
33 | # define MATRIX_ROWS %s | 33 | # define MATRIX_ROWS{postfix} {row_count} |
34 | #endif // MATRIX_ROWS | 34 | #endif // MATRIX_ROWS{postfix} |
35 | 35 | ||
36 | #ifndef DIRECT_PINS | 36 | #ifndef DIRECT_PINS{postfix} |
37 | # define DIRECT_PINS {%s} | 37 | # define DIRECT_PINS{postfix} {{ {", ".join(rows)} }} |
38 | #endif // DIRECT_PINS | 38 | #endif // DIRECT_PINS{postfix} |
39 | """ % (col_count, row_count, ','.join(rows)) | 39 | """ |
40 | 40 | ||
41 | 41 | ||
42 | def pin_array(define, pins): | 42 | def pin_array(define, pins, postfix): |
43 | """Return the config.h lines that set a pin array. | 43 | """Return the config.h lines that set a pin array. |
44 | """ | 44 | """ |
45 | pin_num = len(pins) | 45 | pin_num = len(pins) |
46 | pin_array = ', '.join(map(str, [pin or 'NO_PIN' for pin in pins])) | 46 | pin_array = ', '.join(map(str, [pin or 'NO_PIN' for pin in pins])) |
47 | 47 | ||
48 | return f""" | 48 | return f""" |
49 | #ifndef {define}S | 49 | #ifndef {define}S{postfix} |
50 | # define {define}S {pin_num} | 50 | # define {define}S{postfix} {pin_num} |
51 | #endif // {define}S | 51 | #endif // {define}S{postfix} |
52 | 52 | ||
53 | #ifndef {define}_PINS | 53 | #ifndef {define}_PINS{postfix} |
54 | # define {define}_PINS {{ {pin_array} }} | 54 | # define {define}_PINS{postfix} {{ {pin_array} }} |
55 | #endif // {define}_PINS | 55 | #endif // {define}_PINS{postfix} |
56 | """ | 56 | """ |
57 | 57 | ||
58 | 58 | ||
59 | def matrix_pins(matrix_pins): | 59 | def matrix_pins(matrix_pins, postfix=''): |
60 | """Add the matrix config to the config.h. | 60 | """Add the matrix config to the config.h. |
61 | """ | 61 | """ |
62 | pins = [] | 62 | pins = [] |
63 | 63 | ||
64 | if 'direct' in matrix_pins: | 64 | if 'direct' in matrix_pins: |
65 | pins.append(direct_pins(matrix_pins['direct'])) | 65 | pins.append(direct_pins(matrix_pins['direct'], postfix)) |
66 | 66 | ||
67 | if 'cols' in matrix_pins: | 67 | if 'cols' in matrix_pins: |
68 | pins.append(pin_array('MATRIX_COL', matrix_pins['cols'])) | 68 | pins.append(pin_array('MATRIX_COL', matrix_pins['cols'], postfix)) |
69 | 69 | ||
70 | if 'rows' in matrix_pins: | 70 | if 'rows' in matrix_pins: |
71 | pins.append(pin_array('MATRIX_ROW', matrix_pins['rows'])) | 71 | pins.append(pin_array('MATRIX_ROW', matrix_pins['rows'], postfix)) |
72 | 72 | ||
73 | return '\n'.join(pins) | 73 | return '\n'.join(pins) |
74 | 74 | ||
75 | 75 | ||
76 | @cli.argument('-o', '--output', arg_only=True, type=normpath, help='File to write to') | 76 | def generate_config_items(kb_info_json, config_h_lines): |
77 | @cli.argument('-q', '--quiet', arg_only=True, action='store_true', help="Quiet mode, only output error messages") | 77 | """Iterate through the info_config map to generate basic config values. |
78 | @cli.argument('-kb', '--keyboard', type=keyboard_folder, completer=keyboard_completer, help='Keyboard to generate config.h for.') | ||
79 | @cli.subcommand('Used by the make system to generate info_config.h from info.json', hidden=True) | ||
80 | @automagic_keyboard | ||
81 | @automagic_keymap | ||
82 | def generate_config_h(cli): | ||
83 | """Generates the info_config.h file. | ||
84 | """ | 78 | """ |
85 | # Determine our keyboard(s) | ||
86 | if not cli.config.generate_config_h.keyboard: | ||
87 | cli.log.error('Missing parameter: --keyboard') | ||
88 | cli.subcommands['info'].print_help() | ||
89 | return False | ||
90 | |||
91 | if not is_keyboard(cli.config.generate_config_h.keyboard): | ||
92 | cli.log.error('Invalid keyboard: "%s"', cli.config.generate_config_h.keyboard) | ||
93 | return False | ||
94 | |||
95 | # Build the info_config.h file. | ||
96 | kb_info_json = dotty(info_json(cli.config.generate_config_h.keyboard)) | ||
97 | info_config_map = json_load(Path('data/mappings/info_config.json')) | 79 | info_config_map = json_load(Path('data/mappings/info_config.json')) |
98 | 80 | ||
99 | config_h_lines = ['/* This file was generated by `qmk generate-config-h`. Do not edit or copy.' ' */', '', '#pragma once'] | ||
100 | |||
101 | # Iterate through the info_config map to generate basic things | ||
102 | for config_key, info_dict in info_config_map.items(): | 81 | for config_key, info_dict in info_config_map.items(): |
103 | info_key = info_dict['info_key'] | 82 | info_key = info_dict['info_key'] |
104 | key_type = info_dict.get('value_type', 'str') | 83 | key_type = info_dict.get('value_type', 'str') |
@@ -135,9 +114,78 @@ def generate_config_h(cli): | |||
135 | config_h_lines.append(f'# define {config_key} {config_value}') | 114 | config_h_lines.append(f'# define {config_key} {config_value}') |
136 | config_h_lines.append(f'#endif // {config_key}') | 115 | config_h_lines.append(f'#endif // {config_key}') |
137 | 116 | ||
117 | |||
118 | def generate_split_config(kb_info_json, config_h_lines): | ||
119 | """Generate the config.h lines for split boards.""" | ||
120 | if 'primary' in kb_info_json['split']: | ||
121 | if kb_info_json['split']['primary'] in ('left', 'right'): | ||
122 | config_h_lines.append('') | ||
123 | config_h_lines.append('#ifndef MASTER_LEFT') | ||
124 | config_h_lines.append('# ifndef MASTER_RIGHT') | ||
125 | if kb_info_json['split']['primary'] == 'left': | ||
126 | config_h_lines.append('# define MASTER_LEFT') | ||
127 | elif kb_info_json['split']['primary'] == 'right': | ||
128 | config_h_lines.append('# define MASTER_RIGHT') | ||
129 | config_h_lines.append('# endif // MASTER_RIGHT') | ||
130 | config_h_lines.append('#endif // MASTER_LEFT') | ||
131 | elif kb_info_json['split']['primary'] == 'pin': | ||
132 | config_h_lines.append('') | ||
133 | config_h_lines.append('#ifndef SPLIT_HAND_PIN') | ||
134 | config_h_lines.append('# define SPLIT_HAND_PIN') | ||
135 | config_h_lines.append('#endif // SPLIT_HAND_PIN') | ||
136 | elif kb_info_json['split']['primary'] == 'matrix_grid': | ||
137 | config_h_lines.append('') | ||
138 | config_h_lines.append('#ifndef SPLIT_HAND_MATRIX_GRID') | ||
139 | config_h_lines.append('# define SPLIT_HAND_MATRIX_GRID {%s}' % (','.join(kb_info_json["split"]["matrix_grid"],))) | ||
140 | config_h_lines.append('#endif // SPLIT_HAND_MATRIX_GRID') | ||
141 | elif kb_info_json['split']['primary'] == 'eeprom': | ||
142 | config_h_lines.append('') | ||
143 | config_h_lines.append('#ifndef EE_HANDS') | ||
144 | config_h_lines.append('# define EE_HANDS') | ||
145 | config_h_lines.append('#endif // EE_HANDS') | ||
146 | |||
147 | if 'protocol' in kb_info_json['split'].get('transport', {}): | ||
148 | if kb_info_json['split']['transport']['protocol'] == 'i2c': | ||
149 | config_h_lines.append('') | ||
150 | config_h_lines.append('#ifndef USE_I2C') | ||
151 | config_h_lines.append('# define USE_I2C') | ||
152 | config_h_lines.append('#endif // USE_I2C') | ||
153 | |||
154 | if 'right' in kb_info_json['split'].get('matrix_pins', {}): | ||
155 | config_h_lines.append(matrix_pins(kb_info_json['split']['matrix_pins']['right'], '_RIGHT')) | ||
156 | |||
157 | |||
158 | @cli.argument('-o', '--output', arg_only=True, type=normpath, help='File to write to') | ||
159 | @cli.argument('-q', '--quiet', arg_only=True, action='store_true', help="Quiet mode, only output error messages") | ||
160 | @cli.argument('-kb', '--keyboard', type=keyboard_folder, completer=keyboard_completer, help='Keyboard to generate config.h for.') | ||
161 | @cli.subcommand('Used by the make system to generate info_config.h from info.json', hidden=True) | ||
162 | @automagic_keyboard | ||
163 | @automagic_keymap | ||
164 | def generate_config_h(cli): | ||
165 | """Generates the info_config.h file. | ||
166 | """ | ||
167 | # Determine our keyboard(s) | ||
168 | if not cli.config.generate_config_h.keyboard: | ||
169 | cli.log.error('Missing parameter: --keyboard') | ||
170 | cli.subcommands['info'].print_help() | ||
171 | return False | ||
172 | |||
173 | if not is_keyboard(cli.config.generate_config_h.keyboard): | ||
174 | cli.log.error('Invalid keyboard: "%s"', cli.config.generate_config_h.keyboard) | ||
175 | return False | ||
176 | |||
177 | # Build the info_config.h file. | ||
178 | kb_info_json = dotty(info_json(cli.config.generate_config_h.keyboard)) | ||
179 | config_h_lines = ['/* This file was generated by `qmk generate-config-h`. Do not edit or copy.' ' */', '', '#pragma once'] | ||
180 | |||
181 | generate_config_items(kb_info_json, config_h_lines) | ||
182 | |||
138 | if 'matrix_pins' in kb_info_json: | 183 | if 'matrix_pins' in kb_info_json: |
139 | config_h_lines.append(matrix_pins(kb_info_json['matrix_pins'])) | 184 | config_h_lines.append(matrix_pins(kb_info_json['matrix_pins'])) |
140 | 185 | ||
186 | if 'split' in kb_info_json: | ||
187 | generate_split_config(kb_info_json, config_h_lines) | ||
188 | |||
141 | # Show the results | 189 | # Show the results |
142 | config_h = '\n'.join(config_h_lines) | 190 | config_h = '\n'.join(config_h_lines) |
143 | 191 | ||
diff --git a/lib/python/qmk/cli/generate/info_json.py b/lib/python/qmk/cli/generate/info_json.py index 8931b68b6..284d1a851 100755 --- a/lib/python/qmk/cli/generate/info_json.py +++ b/lib/python/qmk/cli/generate/info_json.py | |||
@@ -4,15 +4,17 @@ Compile an info.json for a particular keyboard and pretty-print it. | |||
4 | """ | 4 | """ |
5 | import json | 5 | import json |
6 | 6 | ||
7 | from jsonschema import Draft7Validator, validators | 7 | from argcomplete.completers import FilesCompleter |
8 | from jsonschema import Draft7Validator, RefResolver, validators | ||
8 | from milc import cli | 9 | from milc import cli |
10 | from pathlib import Path | ||
9 | 11 | ||
10 | from qmk.decorators import automagic_keyboard, automagic_keymap | 12 | from qmk.decorators import automagic_keyboard, automagic_keymap |
11 | from qmk.info import info_json | 13 | from qmk.info import info_json |
12 | from qmk.json_encoders import InfoJSONEncoder | 14 | from qmk.json_encoders import InfoJSONEncoder |
13 | from qmk.json_schema import load_jsonschema | 15 | from qmk.json_schema import compile_schema_store |
14 | from qmk.keyboard import keyboard_completer, keyboard_folder | 16 | from qmk.keyboard import keyboard_completer, keyboard_folder |
15 | from qmk.path import is_keyboard | 17 | from qmk.path import is_keyboard, normpath |
16 | 18 | ||
17 | 19 | ||
18 | def pruning_validator(validator_class): | 20 | def pruning_validator(validator_class): |
@@ -34,15 +36,19 @@ def pruning_validator(validator_class): | |||
34 | def strip_info_json(kb_info_json): | 36 | def strip_info_json(kb_info_json): |
35 | """Remove the API-only properties from the info.json. | 37 | """Remove the API-only properties from the info.json. |
36 | """ | 38 | """ |
39 | schema_store = compile_schema_store() | ||
37 | pruning_draft_7_validator = pruning_validator(Draft7Validator) | 40 | pruning_draft_7_validator = pruning_validator(Draft7Validator) |
38 | schema = load_jsonschema('keyboard') | 41 | schema = schema_store['qmk.keyboard.v1'] |
39 | validator = pruning_draft_7_validator(schema).validate | 42 | resolver = RefResolver.from_schema(schema_store['qmk.keyboard.v1'], store=schema_store) |
43 | validator = pruning_draft_7_validator(schema, resolver=resolver).validate | ||
40 | 44 | ||
41 | return validator(kb_info_json) | 45 | return validator(kb_info_json) |
42 | 46 | ||
43 | 47 | ||
44 | @cli.argument('-kb', '--keyboard', type=keyboard_folder, completer=keyboard_completer, help='Keyboard to show info for.') | 48 | @cli.argument('-kb', '--keyboard', type=keyboard_folder, completer=keyboard_completer, help='Keyboard to show info for.') |
45 | @cli.argument('-km', '--keymap', help='Show the layers for a JSON keymap too.') | 49 | @cli.argument('-km', '--keymap', help='Show the layers for a JSON keymap too.') |
50 | @cli.argument('-o', '--output', arg_only=True, completer=FilesCompleter, help='Write the output the specified file, overwriting if necessary.') | ||
51 | @cli.argument('-ow', '--overwrite', arg_only=True, action='store_true', help='Overwrite the existing info.json. (Overrides the location of --output)') | ||
46 | @cli.subcommand('Generate an info.json file for a keyboard.', hidden=False if cli.config.user.developer else True) | 52 | @cli.subcommand('Generate an info.json file for a keyboard.', hidden=False if cli.config.user.developer else True) |
47 | @automagic_keyboard | 53 | @automagic_keyboard |
48 | @automagic_keymap | 54 | @automagic_keymap |
@@ -59,9 +65,29 @@ def generate_info_json(cli): | |||
59 | cli.log.error('Invalid keyboard: "%s"', cli.config.generate_info_json.keyboard) | 65 | cli.log.error('Invalid keyboard: "%s"', cli.config.generate_info_json.keyboard) |
60 | return False | 66 | return False |
61 | 67 | ||
68 | if cli.args.overwrite: | ||
69 | output_path = (Path('keyboards') / cli.config.generate_info_json.keyboard / 'info.json').resolve() | ||
70 | |||
71 | if cli.args.output: | ||
72 | cli.log.warning('Overwriting user supplied --output with %s', output_path) | ||
73 | |||
74 | cli.args.output = output_path | ||
75 | |||
62 | # Build the info.json file | 76 | # Build the info.json file |
63 | kb_info_json = info_json(cli.config.generate_info_json.keyboard) | 77 | kb_info_json = info_json(cli.config.generate_info_json.keyboard) |
64 | strip_info_json(kb_info_json) | 78 | strip_info_json(kb_info_json) |
79 | info_json_text = json.dumps(kb_info_json, indent=4, cls=InfoJSONEncoder) | ||
80 | |||
81 | if cli.args.output: | ||
82 | # Write to a file | ||
83 | output_path = normpath(cli.args.output) | ||
84 | |||
85 | if output_path.exists(): | ||
86 | cli.log.warning('Overwriting output file %s', output_path) | ||
87 | |||
88 | output_path.write_text(info_json_text + '\n') | ||
89 | cli.log.info('Wrote info.json to %s.', output_path) | ||
65 | 90 | ||
66 | # Display the results | 91 | else: |
67 | print(json.dumps(kb_info_json, indent=2, cls=InfoJSONEncoder)) | 92 | # Display the results |
93 | print(info_json_text) | ||
diff --git a/lib/python/qmk/cli/generate/rules_mk.py b/lib/python/qmk/cli/generate/rules_mk.py index 41c94e16b..2712b81cb 100755 --- a/lib/python/qmk/cli/generate/rules_mk.py +++ b/lib/python/qmk/cli/generate/rules_mk.py | |||
@@ -76,6 +76,17 @@ def generate_rules_mk(cli): | |||
76 | enabled = 'yes' if enabled else 'no' | 76 | enabled = 'yes' if enabled else 'no' |
77 | rules_mk_lines.append(f'{feature}_ENABLE ?= {enabled}') | 77 | rules_mk_lines.append(f'{feature}_ENABLE ?= {enabled}') |
78 | 78 | ||
79 | # Set SPLIT_TRANSPORT, if needed | ||
80 | if kb_info_json.get('split', {}).get('transport', {}).get('protocol') == 'custom': | ||
81 | rules_mk_lines.append('SPLIT_TRANSPORT ?= custom') | ||
82 | |||
83 | # Set CUSTOM_MATRIX, if needed | ||
84 | if kb_info_json.get('matrix_pins', {}).get('custom'): | ||
85 | if kb_info_json.get('matrix_pins', {}).get('custom_lite'): | ||
86 | rules_mk_lines.append('CUSTOM_MATRIX ?= lite') | ||
87 | else: | ||
88 | rules_mk_lines.append('CUSTOM_MATRIX ?= yes') | ||
89 | |||
79 | # Show the results | 90 | # Show the results |
80 | rules_mk = '\n'.join(rules_mk_lines) + '\n' | 91 | rules_mk = '\n'.join(rules_mk_lines) + '\n' |
81 | 92 | ||
diff --git a/lib/python/qmk/cli/info.py b/lib/python/qmk/cli/info.py index 337b494a9..3131d4b53 100755 --- a/lib/python/qmk/cli/info.py +++ b/lib/python/qmk/cli/info.py | |||
@@ -24,19 +24,15 @@ def show_keymap(kb_info_json, title_caps=True): | |||
24 | keymap_path = locate_keymap(cli.config.info.keyboard, cli.config.info.keymap) | 24 | keymap_path = locate_keymap(cli.config.info.keyboard, cli.config.info.keymap) |
25 | 25 | ||
26 | if keymap_path and keymap_path.suffix == '.json': | 26 | if keymap_path and keymap_path.suffix == '.json': |
27 | if title_caps: | ||
28 | cli.echo('{fg_blue}Keymap "%s"{fg_reset}:', cli.config.info.keymap) | ||
29 | else: | ||
30 | cli.echo('{fg_blue}keymap_%s{fg_reset}:', cli.config.info.keymap) | ||
31 | |||
32 | keymap_data = json.load(keymap_path.open(encoding='utf-8')) | 27 | keymap_data = json.load(keymap_path.open(encoding='utf-8')) |
33 | layout_name = keymap_data['layout'] | 28 | layout_name = keymap_data['layout'] |
29 | layout_name = kb_info_json.get('layout_aliases', {}).get(layout_name, layout_name) # Resolve alias names | ||
34 | 30 | ||
35 | for layer_num, layer in enumerate(keymap_data['layers']): | 31 | for layer_num, layer in enumerate(keymap_data['layers']): |
36 | if title_caps: | 32 | if title_caps: |
37 | cli.echo('{fg_cyan}Layer %s{fg_reset}:', layer_num) | 33 | cli.echo('{fg_cyan}Keymap %s Layer %s{fg_reset}:', cli.config.info.keymap, layer_num) |
38 | else: | 34 | else: |
39 | cli.echo('{fg_cyan}layer_%s{fg_reset}:', layer_num) | 35 | cli.echo('{fg_cyan}keymap.%s.layer.%s{fg_reset}:', cli.config.info.keymap, layer_num) |
40 | 36 | ||
41 | print(render_layout(kb_info_json['layouts'][layout_name]['layout'], cli.config.info.ascii, layer)) | 37 | print(render_layout(kb_info_json['layouts'][layout_name]['layout'], cli.config.info.ascii, layer)) |
42 | 38 | ||
@@ -45,7 +41,7 @@ def show_layouts(kb_info_json, title_caps=True): | |||
45 | """Render the layouts with info.json labels. | 41 | """Render the layouts with info.json labels. |
46 | """ | 42 | """ |
47 | for layout_name, layout_art in render_layouts(kb_info_json, cli.config.info.ascii).items(): | 43 | for layout_name, layout_art in render_layouts(kb_info_json, cli.config.info.ascii).items(): |
48 | title = layout_name.title() if title_caps else layout_name | 44 | title = f'Layout {layout_name.title()}' if title_caps else f'layouts.{layout_name}' |
49 | cli.echo('{fg_cyan}%s{fg_reset}:', title) | 45 | cli.echo('{fg_cyan}%s{fg_reset}:', title) |
50 | print(layout_art) # Avoid passing dirty data to cli.echo() | 46 | print(layout_art) # Avoid passing dirty data to cli.echo() |
51 | 47 | ||
@@ -93,15 +89,6 @@ def print_friendly_output(kb_info_json): | |||
93 | aliases = [f'{key}={value}' for key, value in kb_info_json['layout_aliases'].items()] | 89 | aliases = [f'{key}={value}' for key, value in kb_info_json['layout_aliases'].items()] |
94 | cli.echo('{fg_blue}Layout aliases:{fg_reset} %s' % (', '.join(aliases),)) | 90 | cli.echo('{fg_blue}Layout aliases:{fg_reset} %s' % (', '.join(aliases),)) |
95 | 91 | ||
96 | if cli.config.info.layouts: | ||
97 | show_layouts(kb_info_json, True) | ||
98 | |||
99 | if cli.config.info.matrix: | ||
100 | show_matrix(kb_info_json, True) | ||
101 | |||
102 | if cli.config_source.info.keymap and cli.config_source.info.keymap != 'config_file': | ||
103 | show_keymap(kb_info_json, True) | ||
104 | |||
105 | 92 | ||
106 | def print_text_output(kb_info_json): | 93 | def print_text_output(kb_info_json): |
107 | """Print the info.json in a plain text format. | 94 | """Print the info.json in a plain text format. |
@@ -122,6 +109,24 @@ def print_text_output(kb_info_json): | |||
122 | show_keymap(kb_info_json, False) | 109 | show_keymap(kb_info_json, False) |
123 | 110 | ||
124 | 111 | ||
112 | def print_dotted_output(kb_info_json, prefix=''): | ||
113 | """Print the info.json in a plain text format with dot-joined keys. | ||
114 | """ | ||
115 | for key in sorted(kb_info_json): | ||
116 | new_prefix = f'{prefix}.{key}' if prefix else key | ||
117 | |||
118 | if key in ['parse_errors', 'parse_warnings']: | ||
119 | continue | ||
120 | elif key == 'layouts' and prefix == '': | ||
121 | cli.echo('{fg_blue}layouts{fg_reset}: %s', ', '.join(sorted(kb_info_json['layouts'].keys()))) | ||
122 | elif isinstance(kb_info_json[key], dict): | ||
123 | print_dotted_output(kb_info_json[key], new_prefix) | ||
124 | elif isinstance(kb_info_json[key], list): | ||
125 | cli.echo('{fg_blue}%s{fg_reset}: %s', new_prefix, ', '.join(map(str, sorted(kb_info_json[key])))) | ||
126 | else: | ||
127 | cli.echo('{fg_blue}%s{fg_reset}: %s', new_prefix, kb_info_json[key]) | ||
128 | |||
129 | |||
125 | def print_parsed_rules_mk(keyboard_name): | 130 | def print_parsed_rules_mk(keyboard_name): |
126 | rules = rules_mk(keyboard_name) | 131 | rules = rules_mk(keyboard_name) |
127 | for k in sorted(rules.keys()): | 132 | for k in sorted(rules.keys()): |
@@ -162,10 +167,22 @@ def info(cli): | |||
162 | # Output in the requested format | 167 | # Output in the requested format |
163 | if cli.args.format == 'json': | 168 | if cli.args.format == 'json': |
164 | print(json.dumps(kb_info_json, cls=InfoJSONEncoder)) | 169 | print(json.dumps(kb_info_json, cls=InfoJSONEncoder)) |
170 | return True | ||
165 | elif cli.args.format == 'text': | 171 | elif cli.args.format == 'text': |
166 | print_text_output(kb_info_json) | 172 | print_dotted_output(kb_info_json) |
173 | title_caps = False | ||
167 | elif cli.args.format == 'friendly': | 174 | elif cli.args.format == 'friendly': |
168 | print_friendly_output(kb_info_json) | 175 | print_friendly_output(kb_info_json) |
176 | title_caps = True | ||
169 | else: | 177 | else: |
170 | cli.log.error('Unknown format: %s', cli.args.format) | 178 | cli.log.error('Unknown format: %s', cli.args.format) |
171 | return False | 179 | return False |
180 | |||
181 | if cli.config.info.layouts: | ||
182 | show_layouts(kb_info_json, title_caps) | ||
183 | |||
184 | if cli.config.info.matrix: | ||
185 | show_matrix(kb_info_json, title_caps) | ||
186 | |||
187 | if cli.config_source.info.keymap and cli.config_source.info.keymap != 'config_file': | ||
188 | show_keymap(kb_info_json, title_caps) | ||
diff --git a/lib/python/qmk/info.py b/lib/python/qmk/info.py index 858fbab33..b6f2ecf64 100644 --- a/lib/python/qmk/info.py +++ b/lib/python/qmk/info.py | |||
@@ -61,8 +61,8 @@ def info_json(keyboard): | |||
61 | 61 | ||
62 | # Merge in the data from info.json, config.h, and rules.mk | 62 | # Merge in the data from info.json, config.h, and rules.mk |
63 | info_data = merge_info_jsons(keyboard, info_data) | 63 | info_data = merge_info_jsons(keyboard, info_data) |
64 | info_data = _extract_config_h(info_data) | ||
65 | info_data = _extract_rules_mk(info_data) | 64 | info_data = _extract_rules_mk(info_data) |
65 | info_data = _extract_config_h(info_data) | ||
66 | 66 | ||
67 | # Ensure that we have matrix row and column counts | 67 | # Ensure that we have matrix row and column counts |
68 | info_data = _matrix_size(info_data) | 68 | info_data = _matrix_size(info_data) |
@@ -161,10 +161,9 @@ def _extract_pins(pins): | |||
161 | return [_pin_name(pin) for pin in pins.split(',')] | 161 | return [_pin_name(pin) for pin in pins.split(',')] |
162 | 162 | ||
163 | 163 | ||
164 | def _extract_direct_matrix(info_data, direct_pins): | 164 | def _extract_direct_matrix(direct_pins): |
165 | """ | 165 | """ |
166 | """ | 166 | """ |
167 | info_data['matrix_pins'] = {} | ||
168 | direct_pin_array = [] | 167 | direct_pin_array = [] |
169 | 168 | ||
170 | while direct_pins[-1] != '}': | 169 | while direct_pins[-1] != '}': |
@@ -188,12 +187,157 @@ def _extract_direct_matrix(info_data, direct_pins): | |||
188 | return direct_pin_array | 187 | return direct_pin_array |
189 | 188 | ||
190 | 189 | ||
190 | def _extract_audio(info_data, config_c): | ||
191 | """Populate data about the audio configuration | ||
192 | """ | ||
193 | audio_pins = [] | ||
194 | |||
195 | for pin in 'B5', 'B6', 'B7', 'C4', 'C5', 'C6': | ||
196 | if config_c.get(f'{pin}_AUDIO'): | ||
197 | audio_pins.append(pin) | ||
198 | |||
199 | if audio_pins: | ||
200 | info_data['audio'] = {'pins': audio_pins} | ||
201 | |||
202 | |||
203 | def _extract_split_main(info_data, config_c): | ||
204 | """Populate data about the split configuration | ||
205 | """ | ||
206 | # Figure out how the main half is determined | ||
207 | if config_c.get('SPLIT_HAND_PIN') is True: | ||
208 | if 'split' not in info_data: | ||
209 | info_data['split'] = {} | ||
210 | |||
211 | if 'main' in info_data['split']: | ||
212 | _log_warning(info_data, 'Split main hand is specified in both config.h (SPLIT_HAND_PIN) and info.json (split.main) (Value: %s), the config.h value wins.' % info_data['split']['main']) | ||
213 | |||
214 | info_data['split']['main'] = 'pin' | ||
215 | |||
216 | if config_c.get('SPLIT_HAND_MATRIX_GRID'): | ||
217 | if 'split' not in info_data: | ||
218 | info_data['split'] = {} | ||
219 | |||
220 | if 'main' in info_data['split']: | ||
221 | _log_warning(info_data, 'Split main hand is specified in both config.h (SPLIT_HAND_MATRIX_GRID) and info.json (split.main) (Value: %s), the config.h value wins.' % info_data['split']['main']) | ||
222 | |||
223 | info_data['split']['main'] = 'matrix_grid' | ||
224 | info_data['split']['matrix_grid'] = _extract_pins(config_c['SPLIT_HAND_MATRIX_GRID']) | ||
225 | |||
226 | if config_c.get('EE_HANDS') is True: | ||
227 | if 'split' not in info_data: | ||
228 | info_data['split'] = {} | ||
229 | |||
230 | if 'main' in info_data['split']: | ||
231 | _log_warning(info_data, 'Split main hand is specified in both config.h (EE_HANDS) and info.json (split.main) (Value: %s), the config.h value wins.' % info_data['split']['main']) | ||
232 | |||
233 | info_data['split']['main'] = 'eeprom' | ||
234 | |||
235 | if config_c.get('MASTER_RIGHT') is True: | ||
236 | if 'split' not in info_data: | ||
237 | info_data['split'] = {} | ||
238 | |||
239 | if 'main' in info_data['split']: | ||
240 | _log_warning(info_data, 'Split main hand is specified in both config.h (MASTER_RIGHT) and info.json (split.main) (Value: %s), the config.h value wins.' % info_data['split']['main']) | ||
241 | |||
242 | info_data['split']['main'] = 'right' | ||
243 | |||
244 | if config_c.get('MASTER_LEFT') is True: | ||
245 | if 'split' not in info_data: | ||
246 | info_data['split'] = {} | ||
247 | |||
248 | if 'main' in info_data['split']: | ||
249 | _log_warning(info_data, 'Split main hand is specified in both config.h (MASTER_LEFT) and info.json (split.main) (Value: %s), the config.h value wins.' % info_data['split']['main']) | ||
250 | |||
251 | info_data['split']['main'] = 'left' | ||
252 | |||
253 | |||
254 | def _extract_split_transport(info_data, config_c): | ||
255 | # Figure out the transport method | ||
256 | if config_c.get('USE_I2C') is True: | ||
257 | if 'split' not in info_data: | ||
258 | info_data['split'] = {} | ||
259 | |||
260 | if 'transport' not in info_data['split']: | ||
261 | info_data['split']['transport'] = {} | ||
262 | |||
263 | if 'protocol' in info_data['split']['transport']: | ||
264 | _log_warning(info_data, 'Split transport is specified in both config.h (USE_I2C) and info.json (split.transport.protocol) (Value: %s), the config.h value wins.' % info_data['split']['transport']) | ||
265 | |||
266 | info_data['split']['transport']['protocol'] = 'i2c' | ||
267 | |||
268 | elif 'protocol' not in info_data.get('split', {}).get('transport', {}): | ||
269 | if 'split' not in info_data: | ||
270 | info_data['split'] = {} | ||
271 | |||
272 | if 'transport' not in info_data['split']: | ||
273 | info_data['split']['transport'] = {} | ||
274 | |||
275 | info_data['split']['transport']['protocol'] = 'serial' | ||
276 | |||
277 | |||
278 | def _extract_split_right_pins(info_data, config_c): | ||
279 | # Figure out the right half matrix pins | ||
280 | row_pins = config_c.get('MATRIX_ROW_PINS_RIGHT', '').replace('{', '').replace('}', '').strip() | ||
281 | col_pins = config_c.get('MATRIX_COL_PINS_RIGHT', '').replace('{', '').replace('}', '').strip() | ||
282 | unused_pin_text = config_c.get('UNUSED_PINS_RIGHT') | ||
283 | unused_pins = unused_pin_text.replace('{', '').replace('}', '').strip() if isinstance(unused_pin_text, str) else None | ||
284 | direct_pins = config_c.get('DIRECT_PINS_RIGHT', '').replace(' ', '')[1:-1] | ||
285 | |||
286 | if row_pins and col_pins: | ||
287 | if info_data.get('split', {}).get('matrix_pins', {}).get('right') in info_data: | ||
288 | _log_warning(info_data, 'Right hand matrix data is specified in both info.json and config.h, the config.h values win.') | ||
289 | |||
290 | if 'split' not in info_data: | ||
291 | info_data['split'] = {} | ||
292 | |||
293 | if 'matrix_pins' not in info_data['split']: | ||
294 | info_data['split']['matrix_pins'] = {} | ||
295 | |||
296 | if 'right' not in info_data['split']['matrix_pins']: | ||
297 | info_data['split']['matrix_pins']['right'] = {} | ||
298 | |||
299 | info_data['split']['matrix_pins']['right'] = { | ||
300 | 'cols': _extract_pins(col_pins), | ||
301 | 'rows': _extract_pins(row_pins), | ||
302 | } | ||
303 | |||
304 | if direct_pins: | ||
305 | if info_data.get('split', {}).get('matrix_pins', {}).get('right', {}): | ||
306 | _log_warning(info_data, 'Right hand matrix data is specified in both info.json and config.h, the config.h values win.') | ||
307 | |||
308 | if 'split' not in info_data: | ||
309 | info_data['split'] = {} | ||
310 | |||
311 | if 'matrix_pins' not in info_data['split']: | ||
312 | info_data['split']['matrix_pins'] = {} | ||
313 | |||
314 | if 'right' not in info_data['split']['matrix_pins']: | ||
315 | info_data['split']['matrix_pins']['right'] = {} | ||
316 | |||
317 | info_data['split']['matrix_pins']['right']['direct'] = _extract_direct_matrix(direct_pins) | ||
318 | |||
319 | if unused_pins: | ||
320 | if 'split' not in info_data: | ||
321 | info_data['split'] = {} | ||
322 | |||
323 | if 'matrix_pins' not in info_data['split']: | ||
324 | info_data['split']['matrix_pins'] = {} | ||
325 | |||
326 | if 'right' not in info_data['split']['matrix_pins']: | ||
327 | info_data['split']['matrix_pins']['right'] = {} | ||
328 | |||
329 | info_data['split']['matrix_pins']['right']['unused'] = _extract_pins(unused_pins) | ||
330 | |||
331 | |||
191 | def _extract_matrix_info(info_data, config_c): | 332 | def _extract_matrix_info(info_data, config_c): |
192 | """Populate the matrix information. | 333 | """Populate the matrix information. |
193 | """ | 334 | """ |
194 | row_pins = config_c.get('MATRIX_ROW_PINS', '').replace('{', '').replace('}', '').strip() | 335 | row_pins = config_c.get('MATRIX_ROW_PINS', '').replace('{', '').replace('}', '').strip() |
195 | col_pins = config_c.get('MATRIX_COL_PINS', '').replace('{', '').replace('}', '').strip() | 336 | col_pins = config_c.get('MATRIX_COL_PINS', '').replace('{', '').replace('}', '').strip() |
337 | unused_pin_text = config_c.get('UNUSED_PINS') | ||
338 | unused_pins = unused_pin_text.replace('{', '').replace('}', '').strip() if isinstance(unused_pin_text, str) else None | ||
196 | direct_pins = config_c.get('DIRECT_PINS', '').replace(' ', '')[1:-1] | 339 | direct_pins = config_c.get('DIRECT_PINS', '').replace(' ', '')[1:-1] |
340 | info_snippet = {} | ||
197 | 341 | ||
198 | if 'MATRIX_ROWS' in config_c and 'MATRIX_COLS' in config_c: | 342 | if 'MATRIX_ROWS' in config_c and 'MATRIX_COLS' in config_c: |
199 | if 'matrix_size' in info_data: | 343 | if 'matrix_size' in info_data: |
@@ -205,19 +349,35 @@ def _extract_matrix_info(info_data, config_c): | |||
205 | } | 349 | } |
206 | 350 | ||
207 | if row_pins and col_pins: | 351 | if row_pins and col_pins: |
208 | if 'matrix_pins' in info_data: | 352 | if 'matrix_pins' in info_data and 'cols' in info_data['matrix_pins'] and 'rows' in info_data['matrix_pins']: |
209 | _log_warning(info_data, 'Matrix pins are specified in both info.json and config.h, the config.h values win.') | 353 | _log_warning(info_data, 'Matrix pins are specified in both info.json and config.h, the config.h values win.') |
210 | 354 | ||
211 | info_data['matrix_pins'] = { | 355 | info_snippet['cols'] = _extract_pins(col_pins) |
212 | 'cols': _extract_pins(col_pins), | 356 | info_snippet['rows'] = _extract_pins(row_pins) |
213 | 'rows': _extract_pins(row_pins), | ||
214 | } | ||
215 | 357 | ||
216 | if direct_pins: | 358 | if direct_pins: |
217 | if 'matrix_pins' in info_data: | 359 | if 'matrix_pins' in info_data and 'direct' in info_data['matrix_pins']: |
218 | _log_warning(info_data, 'Direct pins are specified in both info.json and config.h, the config.h values win.') | 360 | _log_warning(info_data, 'Direct pins are specified in both info.json and config.h, the config.h values win.') |
219 | 361 | ||
220 | info_data['matrix_pins']['direct'] = _extract_direct_matrix(info_data, direct_pins) | 362 | info_snippet['direct'] = _extract_direct_matrix(direct_pins) |
363 | |||
364 | if unused_pins: | ||
365 | if 'matrix_pins' not in info_data: | ||
366 | info_data['matrix_pins'] = {} | ||
367 | |||
368 | info_snippet['unused'] = _extract_pins(unused_pins) | ||
369 | |||
370 | if config_c.get('CUSTOM_MATRIX', 'no') != 'no': | ||
371 | if 'matrix_pins' in info_data and 'custom' in info_data['matrix_pins']: | ||
372 | _log_warning(info_data, 'Custom Matrix is specified in both info.json and config.h, the config.h values win.') | ||
373 | |||
374 | info_snippet['custom'] = True | ||
375 | |||
376 | if config_c['CUSTOM_MATRIX'] == 'lite': | ||
377 | info_snippet['custom_lite'] = True | ||
378 | |||
379 | if info_snippet: | ||
380 | info_data['matrix_pins'] = info_snippet | ||
221 | 381 | ||
222 | return info_data | 382 | return info_data |
223 | 383 | ||
@@ -275,6 +435,10 @@ def _extract_config_h(info_data): | |||
275 | 435 | ||
276 | # Pull data that easily can't be mapped in json | 436 | # Pull data that easily can't be mapped in json |
277 | _extract_matrix_info(info_data, config_c) | 437 | _extract_matrix_info(info_data, config_c) |
438 | _extract_audio(info_data, config_c) | ||
439 | _extract_split_main(info_data, config_c) | ||
440 | _extract_split_transport(info_data, config_c) | ||
441 | _extract_split_right_pins(info_data, config_c) | ||
278 | 442 | ||
279 | return info_data | 443 | return info_data |
280 | 444 | ||
diff --git a/lib/python/qmk/json_schema.py b/lib/python/qmk/json_schema.py index cbc5bff51..ffc7c6bcd 100644 --- a/lib/python/qmk/json_schema.py +++ b/lib/python/qmk/json_schema.py | |||
@@ -2,6 +2,7 @@ | |||
2 | """ | 2 | """ |
3 | import json | 3 | import json |
4 | from collections.abc import Mapping | 4 | from collections.abc import Mapping |
5 | from functools import lru_cache | ||
5 | from pathlib import Path | 6 | from pathlib import Path |
6 | 7 | ||
7 | import hjson | 8 | import hjson |
@@ -25,6 +26,7 @@ def json_load(json_file): | |||
25 | exit(1) | 26 | exit(1) |
26 | 27 | ||
27 | 28 | ||
29 | @lru_cache(maxsize=0) | ||
28 | def load_jsonschema(schema_name): | 30 | def load_jsonschema(schema_name): |
29 | """Read a jsonschema file from disk. | 31 | """Read a jsonschema file from disk. |
30 | """ | 32 | """ |
@@ -39,8 +41,9 @@ def load_jsonschema(schema_name): | |||
39 | return json_load(schema_path) | 41 | return json_load(schema_path) |
40 | 42 | ||
41 | 43 | ||
42 | def create_validator(schema): | 44 | @lru_cache(maxsize=0) |
43 | """Creates a validator for the given schema id. | 45 | def compile_schema_store(): |
46 | """Compile all our schemas into a schema store. | ||
44 | """ | 47 | """ |
45 | schema_store = {} | 48 | schema_store = {} |
46 | 49 | ||
@@ -51,6 +54,14 @@ def create_validator(schema): | |||
51 | continue | 54 | continue |
52 | schema_store[schema_data['$id']] = schema_data | 55 | schema_store[schema_data['$id']] = schema_data |
53 | 56 | ||
57 | return schema_store | ||
58 | |||
59 | |||
60 | @lru_cache(maxsize=0) | ||
61 | def create_validator(schema): | ||
62 | """Creates a validator for the given schema id. | ||
63 | """ | ||
64 | schema_store = compile_schema_store() | ||
54 | resolver = jsonschema.RefResolver.from_schema(schema_store['qmk.keyboard.v1'], store=schema_store) | 65 | resolver = jsonschema.RefResolver.from_schema(schema_store['qmk.keyboard.v1'], store=schema_store) |
55 | 66 | ||
56 | return jsonschema.Draft7Validator(schema_store[schema], resolver=resolver).validate | 67 | return jsonschema.Draft7Validator(schema_store[schema], resolver=resolver).validate |