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>
This commit is contained in:
parent
fac717c11c
commit
8d9bfdc254
@ -3,19 +3,44 @@
|
||||
{
|
||||
# Format:
|
||||
# <config.h key>: {"info_key": <info.json key>, ["value_type": <value_type>], ["to_json": <true/false>], ["to_c": <true/false>]}
|
||||
# value_type: one of "array", "array.int", "int", "hex", "list", "mapping"
|
||||
# value_type: one of "array", "array.int", "bool", "int", "hex", "list", "mapping"
|
||||
# to_json: Default `true`. Set to `false` to exclude this mapping from info.json
|
||||
# to_c: Default `true`. Set to `false` to exclude this mapping from config.h
|
||||
# warn_duplicate: Default `true`. Set to `false` to turn off warning when a value exists in both places
|
||||
"DEBOUNCE": {"info_key": "debounce", "value_type": "int"}
|
||||
"AUDIO_VOICES": {"info_key": "audio.voices", "value_type": "bool"},
|
||||
"BACKLIGHT_BREATHING": {"info_key": "backlight.breathing", "value_type": "bool"},
|
||||
"BREATHING_PERIOD": {"info_key": "backlight.breathing_period", "value_type": "int"},
|
||||
"BACKLIGHT_PIN": {"info_key": "backlight.pin"},
|
||||
"COMBO_COUNT": {"info_key": "combo.count", "value_type": "int"},
|
||||
"COMBO_TERM": {"info_key": "combo.term", "value_type": "int"},
|
||||
"DEBOUNCE": {"info_key": "debounce", "value_type": "int"},
|
||||
"DEVICE_VER": {"info_key": "usb.device_ver", "value_type": "hex"},
|
||||
"DESCRIPTION": {"info_key": "keyboard_folder", "to_json": false},
|
||||
"DIODE_DIRECTION": {"info_key": "diode_direction"},
|
||||
"FORCE_NKRO": {"info_key": "usb.force_nkro", "value_type": "bool"},
|
||||
"IGNORE_MOD_TAP_INTERRUPT": {"info_key": "tapping.ignore_mod_tap_interrupt", "value_type": "bool"},
|
||||
"IGNORE_MOD_TAP_INTERRUPT_PER_KEY": {"info_key": "tapping.ignore_mod_tap_interrupt_per_key", "value_type": "bool"},
|
||||
"LAYOUTS": {"info_key": "layout_aliases", "value_type": "mapping"},
|
||||
"LEADER_PER_KEY_TIMING": {"info_key": "leader_key.timing", "value_type": "bool"},
|
||||
"LEADER_KEY_STRICT_KEY_PROCESSING": {"info_key": "leader_key.strict_processing", "value_type": "bool"},
|
||||
"LEADER_TIMEOUT": {"info_key": "leader_key.timeout", "value_type": "int"},
|
||||
"LED_CAPS_LOCK_PIN": {"info_key": "indicators.caps_lock"},
|
||||
"LED_NUM_LOCK_PIN": {"info_key": "indicators.num_lock"},
|
||||
"LED_SCROLL_LOCK_PIN": {"info_key": "indicators.scroll_lock"},
|
||||
"MANUFACTURER": {"info_key": "manufacturer"},
|
||||
"MATRIX_HAS_GHOST": {"info_key": "matrix_pins.ghost", "value_type": "bool"},
|
||||
"MATRIX_IO_DELAY": {"info_key": "matrix_pins.io_delay", "value_type": "int"},
|
||||
"MOUSEKEY_DELAY": {"info_key": "mousekey.delay", "value_type": "int"},
|
||||
"MOUSEKEY_INTERVAL": {"info_key": "mousekey.interval", "value_type": "int"},
|
||||
"MOUSEKEY_MAX_SPEED": {"info_key": "mousekey.max_speed", "value_type": "int"},
|
||||
"MOUSEKEY_TIME_TO_MAX": {"info_key": "mousekey.time_to_max", "value_type": "int"},
|
||||
"MOUSEKEY_WHEEL_DELAY": {"info_key": "mousekey.wheel_delay", "value_type": "int"},
|
||||
"ONESHOT_TIMEOUT": {"info_key": "oneshot.timeout", "value_type": "int"},
|
||||
"ONESHOT_TAP_TOGGLE": {"info_key": "oneshot.tap_toggle", "value_type": "int"},
|
||||
"PERMISSIVE_HOLD": {"info_key": "tapping.permissive_hold", "value_type": "bool"},
|
||||
"PERMISSIVE_HOLD_PER_KEY": {"info_key": "tapping.permissive_hold_per_key", "value_type": "bool"},
|
||||
"RETRO_TAPPING": {"info_key": "tapping.retro", "value_type": "bool"},
|
||||
"RETRO_TAPPING_PER_KEY": {"info_key": "tapping.retro_per_key", "value_type": "bool"},
|
||||
"RGB_DI_PIN": {"info_key": "rgblight.pin"},
|
||||
"RGBLED_NUM": {"info_key": "rgblight.led_count", "value_type": "int"},
|
||||
"RGBLED_SPLIT": {"info_key": "rgblight.split_count", "value_type": "array.int"},
|
||||
@ -30,17 +55,40 @@
|
||||
"RGBLIGHT_EFFECT_SNAKE": {"info_key": "rgblight.animations.snake", "value_type": "bool"},
|
||||
"RGBLIGHT_EFFECT_STATIC_GRADIENT": {"info_key": "rgblight.animations.static_gradient", "value_type": "bool"},
|
||||
"RGBLIGHT_EFFECT_TWINKLE": {"info_key": "rgblight.animations.twinkle"},
|
||||
"RGBLIGHT_LAYER_BLINK": {"info_key": "rgblight.layers.blink", "value_type": "bool"},
|
||||
"RGBLIGHT_LAYERS": {"info_key": "rgblight.layers.enabled", "value_type": "bool"},
|
||||
"RGBLIGHT_LAYERS_OVERRIDE_RGB_OFF": {"info_key": "rgblight.layers.override_rgb", "value_type": "bool"},
|
||||
"RGBLIGHT_LIMIT_VAL": {"info_key": "rgblight.max_brightness", "value_type": "int"},
|
||||
"RGBLIGHT_MAX_LAYERS": {"info_key": "rgblight.layers.max", "value_type": "int"},
|
||||
"RGBLIGHT_HUE_STEP": {"info_key": "rgblight.hue_steps", "value_type": "int"},
|
||||
"RGBLIGHT_SAT_STEP": {"info_key": "rgblight.saturation_steps", "value_type": "int"},
|
||||
"RGBLIGHT_VAL_STEP": {"info_key": "rgblight.brightness_steps", "value_type": "int"},
|
||||
"RGBLIGHT_SLEEP": {"info_key": "rgblight.sleep", "value_type": "bool"},
|
||||
"RGBLIGHT_SPLIT": {"info_key": "rgblight.split", "value_type": "bool"},
|
||||
"RGBW": {"info_key": "rgblight.rgbw", "value_type": "bool"},
|
||||
"PRODUCT": {"info_key": "keyboard_folder", "to_json": false},
|
||||
"PRODUCT_ID": {"info_key": "usb.pid", "value_type": "hex"},
|
||||
"VENDOR_ID": {"info_key": "usb.vid", "value_type": "hex"},
|
||||
"QMK_ESC_OUTPUT": {"info_key": "qmk_lufa_bootloader.esc_output"},
|
||||
"QMK_ESC_INPUT": {"info_key": "qmk_lufa_bootloader.esc_input"},
|
||||
"QMK_KEYS_PER_SCAN": {"info_key": "qmk.keys_per_scan", "value_type": "int"},
|
||||
"QMK_LED": {"info_key": "qmk_lufa_bootloader.led"},
|
||||
"QMK_SPEAKER": {"info_key": "qmk_lufa_bootloader.speaker"}
|
||||
"QMK_SPEAKER": {"info_key": "qmk_lufa_bootloader.speaker"},
|
||||
"SPLIT_MODS_ENABLE": {"info_key": "split.transport.sync_modifiers", "value_type": "bool"},
|
||||
"SPLIT_TRANSPORT_MIRROR": {"info_key": "split.transport.sync_matrix_state", "value_type": "bool"},
|
||||
"SPLIT_USB_DETECT": {"info_key": "split.usb_detect.enabled", "value_type": "bool"},
|
||||
"SPLIT_USB_TIMEOUT": {"info_key": "split.usb_detect.timeout", "value_type": "int"},
|
||||
"SPLIT_USB_TIMEOUT_POLL": {"info_key": "split.usb_detect.polling_interval", "value_type": "int"},
|
||||
"SOFT_SERIAL_PIN": {"info_key": "split.soft_serial_pin"},
|
||||
"SOFT_SERIAL_SPEED": {"info_key": "split.soft_serial_speed"},
|
||||
"TAP_CODE_DELAY": {"info_key": "qmk.tap_keycode_delay", "value_type": "int"},
|
||||
"TAP_HOLD_CAPS_DELAY": {"info_key": "qmk.tap_capslock_delay", "value_type": "int"},
|
||||
"TAPPING_FORCE_HOLD": {"info_key": "tapping.force_hold", "value_type": "bool"},
|
||||
"TAPPING_FORCE_HOLD_PER_KEY": {"info_key": "tapping.force_hold_per_key", "value_type": "bool"},
|
||||
"TAPPING_TERM": {"info_key": "tapping.term", "value_type": "int"},
|
||||
"TAPPING_TERM_PER_KEY": {"info_key": "tapping.term_per_key", "value_type": "bool"},
|
||||
"TAPPING_TOGGLE": {"info_key": "tapping.toggle", "value_type": "int"},
|
||||
"USB_MAX_POWER_CONSUMPTION": {"info_key": "usb.max_power", "value_type": "int"},
|
||||
"USB_POLLING_INTERVAL_MS": {"info_key": "usb.polling_interval", "value_type": "int"},
|
||||
"USB_SUSPEND_WAKEUP_DELAY": {"info_key": "usb.suspend_wakeup_delay", "value_type": "int"},
|
||||
}
|
||||
|
@ -3,13 +3,23 @@
|
||||
{
|
||||
# Format:
|
||||
# <rules.mk key>: {"info_key": <info.json key>, ["value_type": <value_type>], ["to_json": <true/false>], ["to_c": <true/false>]}
|
||||
# value_type: one of "array", "array.int", "int", "list", "hex", "mapping"
|
||||
# value_type: one of "array", "array.int", "bool", "int", "list", "hex", "mapping"
|
||||
# to_json: Default `true`. Set to `false` to exclude this mapping from info.json
|
||||
# to_c: Default `true`. Set to `false` to exclude this mapping from rules.mk
|
||||
# warn_duplicate: Default `true`. Set to `false` to turn off warning when a value exists in both places
|
||||
"BOARD": {"info_key": "board"},
|
||||
"BOOTLOADER": {"info_key": "bootloader", "warn_duplicate": false},
|
||||
"BLUETOOTH": {"info_key": "bluetooth.driver"},
|
||||
"FIRMWARE_FORMAT": {"info_key": "build.firmware_format"},
|
||||
"KEYBOARD_SHARED_EP": {"info_key": "usb.shared_endpoint.keyboard", "value_type": "bool"},
|
||||
"MOUSE_SHARED_EP": {"info_key": "usb.shared_endpoint.mouse", "value_type": "bool"},
|
||||
"LAYOUTS": {"info_key": "community_layouts", "value_type": "list"},
|
||||
"LED_MATRIX_DRIVER": {"info_key": "led_matrix.driver"},
|
||||
"LTO_ENABLE": {"info_key": "build.lto", "value_type": "bool"},
|
||||
"MCU": {"info_key": "processor", "warn_duplicate": false},
|
||||
"MOUSEKEY_ENABLE": {"info_key": "mouse_key.enabled", "value_type": "bool"},
|
||||
"NO_USB_STARTUP_CHECK": {"info_key": "usb.no_startup_check", "value_type": "bool"},
|
||||
"SPLIT_KEYBOARD": {"info_key": "split.enabled", "value_type": "bool"},
|
||||
"SPLIT_TRANSPORT": {"info_key": "split.transport.protocol", "value_type": "str", "to_c": false},
|
||||
"WAIT_FOR_USB": {"info_key": "usb.wait_for", "value_type": "bool"}
|
||||
}
|
||||
|
@ -15,6 +15,40 @@
|
||||
"type": "string",
|
||||
"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"]
|
||||
},
|
||||
"audio": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"pins": {"$ref": "qmk.definitions.v1#/mcu_pin_array"},
|
||||
"voices": {"type": "boolean"}
|
||||
}
|
||||
},
|
||||
"backlight": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"breathing": {"type": "boolean"},
|
||||
"breathing_period": {"$ref": "qmk.definitions.v1#/unsigned_int_8"},
|
||||
"levels": {
|
||||
"type": "number",
|
||||
"min": 1,
|
||||
"max": 31,
|
||||
"multipleOf": 1
|
||||
},
|
||||
"pin": {"$ref": "qmk.definitions.v1#/mcu_pin"}
|
||||
}
|
||||
},
|
||||
"bluetooth": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"driver": {
|
||||
"type": "string",
|
||||
"enum": ["AdafruitBLE", "RN42"]
|
||||
},
|
||||
"lto": {"type": "boolean"},
|
||||
}
|
||||
},
|
||||
"board": {
|
||||
"type": "string",
|
||||
"minLength": 2,
|
||||
@ -22,13 +56,39 @@
|
||||
},
|
||||
"bootloader": {
|
||||
"type": "string",
|
||||
"enum": ["atmel-dfu", "bootloadHID", "caterina", "halfkay", "kiibohd", "lufa-dfu", "lufa-ms", "micronucleus", "qmk-dfu", "qmk-hid", "stm32-dfu", "stm32duino", "unknown", "USBasp", "tinyuf2"]
|
||||
"enum": ["atmel-dfu", "bootloadHID", "caterina", "halfkay", "kiibohd", "lufa-dfu", "lufa-ms", "micronucleus", "qmk-dfu", "qmk-hid", "stm32-dfu", "stm32duino", "unknown", "USBasp", "tinyuf2"],
|
||||
},
|
||||
"bootloader_instructions": {
|
||||
"type": "string",
|
||||
"description": "Instructions for putting the keyboard into a mode that allows for firmware flashing."
|
||||
},
|
||||
"build": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"debounce_type": {
|
||||
"type": "string",
|
||||
"enum": ["custom", "eager_pk", "eager_pr", "sym_defer_pk", "sym_eager_pk"]
|
||||
},
|
||||
"firmware_format": {
|
||||
"type": "string",
|
||||
"enum": ["bin", "hex", "uf2"]
|
||||
},
|
||||
"lto": {"type": "boolean"},
|
||||
}
|
||||
},
|
||||
"diode_direction": {
|
||||
"type": "string",
|
||||
"enum": ["COL2ROW", "ROW2COL"]
|
||||
},
|
||||
"debounce": {"$ref": "qmk.definitions.v1#/unsigned_int"},
|
||||
"combo": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"count": {"$ref": "qmk.definitions.v1#/unsigned_int"},
|
||||
"term": {"$ref": "qmk.definitions.v1#/unsigned_int"}
|
||||
}
|
||||
},
|
||||
"community_layouts": {
|
||||
"type": "array",
|
||||
"items": {"$ref": "qmk.definitions.v1#/filename"}
|
||||
@ -90,16 +150,47 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"leader_key": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"timing": {"type": "boolean"},
|
||||
"strict_processing": {"type": "boolean"},
|
||||
"timeout": {"$ref": "qmk.definitions.v1#/unsigned_int"}
|
||||
}
|
||||
},
|
||||
"matrix_pins": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"custom": {"type": "boolean"},
|
||||
"custom_lite": {"type": "boolean"},
|
||||
"ghost": {"type": "boolean"},
|
||||
"io_delay": {"$ref": "qmk.definitions.v1#/unsigned_int"},
|
||||
"direct": {
|
||||
"type": "array",
|
||||
"items": {$ref": "qmk.definitions.v1#/mcu_pin_array"}
|
||||
"items": {"$ref": "qmk.definitions.v1#/mcu_pin_array"}
|
||||
},
|
||||
"cols": {"$ref": "qmk.definitions.v1#/mcu_pin_array"},
|
||||
"rows": {"$ref": "qmk.definitions.v1#/mcu_pin_array"}
|
||||
"rows": {"$ref": "qmk.definitions.v1#/mcu_pin_array"},
|
||||
"unused": {"$ref": "qmk.definitions.v1#/mcu_pin_array"}
|
||||
}
|
||||
},
|
||||
"mouse_key": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"enabled": {"type": "boolean"},
|
||||
"delay": {"$ref": "qmk.definitions.v1#/unsigned_int_8"}
|
||||
"interval": {"$ref": "qmk.definitions.v1#/unsigned_int_8"}
|
||||
"max_speed": {"$ref": "qmk.definitions.v1#/unsigned_int_8"}
|
||||
"time_to_max": {"$ref": "qmk.definitions.v1#/unsigned_int_8"}
|
||||
"wheel_delay": {"$ref": "qmk.definitions.v1#/unsigned_int_8"}
|
||||
}
|
||||
},
|
||||
"oneshot": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"tap_toggle": {"$ref": "qmk.definitions.v1#/unsigned_int"},
|
||||
"timeout": {"$ref": "qmk.definitions.v1#/unsigned_int"}
|
||||
}
|
||||
},
|
||||
"rgblight": {
|
||||
@ -114,9 +205,25 @@
|
||||
},
|
||||
"brightness_steps": {"$ref": "qmk.definitions.v1#/unsigned_int"},
|
||||
"hue_steps": {"$ref": "qmk.definitions.v1#/unsigned_int"},
|
||||
"layers": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"blink": {"type": "boolean"},
|
||||
"enabled": {"type": "boolean"},
|
||||
"max": {
|
||||
"type": "number",
|
||||
"min": 1,
|
||||
"max": 32,
|
||||
"multipleOf": 1
|
||||
},
|
||||
"override_rgb": {"type": "boolean"}
|
||||
}
|
||||
},
|
||||
"led_count": {"$ref": "qmk.definitions.v1#/unsigned_int"},
|
||||
"max_brightness": {"$ref": "qmk.definitions.v1#/unsigned_int_8"},
|
||||
"pin": {"$ref": "qmk.definitions.v1#/mcu_pin"},
|
||||
"rgbw": {"type": "boolean"},
|
||||
"saturation_steps": {"$ref": "qmk.definitions.v1#/unsigned_int"},
|
||||
"sleep": {"type": "boolean"},
|
||||
"split": {"type": "boolean"},
|
||||
@ -128,13 +235,118 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"split": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"enabled": {"type": "boolean"},
|
||||
"matrix_grid": {
|
||||
"type": "array",
|
||||
"items": {"$ref": "qmk.definitions.v1#/mcu_pin"}
|
||||
},
|
||||
"matrix_pins": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"right": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"direct": {
|
||||
"type": "array",
|
||||
"items": {"$ref": "qmk.definitions.v1#/mcu_pin_array"}
|
||||
},
|
||||
"cols": {"$ref": "qmk.definitions.v1#/mcu_pin_array"},
|
||||
"rows": {"$ref": "qmk.definitions.v1#/mcu_pin_array"},
|
||||
"unused": {"$ref": "qmk.definitions.v1#/mcu_pin_array"}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"main": {
|
||||
"type": "string",
|
||||
"enum": ["eeprom", "left", "matrix_grid", "pin", "right"]
|
||||
},
|
||||
"soft_serial_pin": {"$ref": "qmk.definitions.v1#/mcu_pin"},
|
||||
"soft_serial_speed": {
|
||||
"type": "number",
|
||||
"min": 0,
|
||||
"max": 5,
|
||||
"multipleOf": 1
|
||||
},
|
||||
"transport": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"protocol": {
|
||||
"type": "string",
|
||||
"enum": ["custom", "i2c", "serial", "serial_usart"]
|
||||
},
|
||||
"sync_matrix_state": {"type": "boolean"},
|
||||
"sync_modifiers": {"type": "boolean"}
|
||||
}
|
||||
},
|
||||
"usb_detect": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"enabled": {"type": "boolean"},
|
||||
"polling_interval": {"$ref": "qmk.definitions.v1#/unsigned_int"},
|
||||
"timeout": {"$ref": "qmk.definitions.v1#/unsigned_int"}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": {
|
||||
"type": "array",
|
||||
"items": {"type": "string"}
|
||||
},
|
||||
"tapping": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"force_hold": {"type": "boolean"},
|
||||
"force_hold_per_key": {"type": "boolean"},
|
||||
"ignore_mod_tap_interrupt": {"type": "boolean"},
|
||||
"ignore_mod_tap_interrupt_per_key": {"type": "boolean"},
|
||||
"permissive_hold": {"type": "boolean"},
|
||||
"permissive_hold_per_key": {"type": "boolean"},
|
||||
"retro": {"type": "boolean"},
|
||||
"retro_per_key": {"type": "boolean"},
|
||||
"term": {"$ref": "qmk.definitions.v1#/unsigned_int"},
|
||||
"term_per_key": {"type": "boolean"},
|
||||
"toggle": {"$ref": "qmk.definitions.v1#/unsigned_int"},
|
||||
}
|
||||
},
|
||||
"usb": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"device_ver": {"$ref": "qmk.definitions.v1#/hex_number_4d"},
|
||||
"force_nkro": {"type": "boolean"},
|
||||
"pid": {"$ref": "qmk.definitions.v1#/hex_number_4d"},
|
||||
"vid": {"$ref": "qmk.definitions.v1#/hex_number_4d"}
|
||||
"vid": {"$ref": "qmk.definitions.v1#/hex_number_4d"},
|
||||
"max_power": {"$ref": "qmk.definitions.v1#/unsigned_int_8"},
|
||||
"no_startup_check": {"type": "boolean"},
|
||||
"polling_interval": {"$ref": "qmk.definitions.v1#/unsigned_int_8"},
|
||||
"shared_endpoint": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"keyboard": {"type": "boolean"},
|
||||
"mouse": {"type": "boolean"}
|
||||
}
|
||||
},
|
||||
"suspend_wakeup_delay": {"$ref": "qmk.definitions.v1#/unsigned_int_8"},
|
||||
"wait_for": {"type": "boolean"},
|
||||
}
|
||||
},
|
||||
"qmk": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"keys_per_scan": {"$ref": "qmk.definitions.v1#/unsigned_int_8"},
|
||||
"tap_keycode_delay": {"$ref": "qmk.definitions.v1#/unsigned_int_8"},
|
||||
"tap_capslock_delay": {"$ref": "qmk.definitions.v1#/unsigned_int_8"},
|
||||
}
|
||||
},
|
||||
"qmk_lufa_bootloader": {
|
||||
|
@ -40,7 +40,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/*
|
||||
* Keyboard Matrix Assignments
|
||||
*
|
||||
* MATRIX_ROW_PINS and MATRIX_COL_PINS aren't actually used and are included
|
||||
* for data driven compatibility.
|
||||
*/
|
||||
#define MATRIX_COL_PINS { B0, B3, B2, B1, B6, B4, B5, C7 }
|
||||
#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 }
|
||||
#define UNUSED_PINS { C0, C1, C2, C3, C4, D2, D7 }
|
||||
|
||||
/* Debounce reduces chatter (unintended double-presses) - set 0 if debouncing is not needed */
|
||||
|
@ -40,7 +40,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/*
|
||||
* Keyboard Matrix Assignments
|
||||
*
|
||||
* MATRIX_ROW_PINS and MATRIX_COL_PINS aren't actually used and are included
|
||||
* for data driven compatibility.
|
||||
*/
|
||||
#define MATRIX_ROW_PINS { C2, B3, B4, B2, B1, C7, B6, B5 }
|
||||
#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 }
|
||||
#define UNUSED_PINS { B0, C4, D3 }
|
||||
|
||||
#define LED_NUM_LOCK_PIN C5
|
||||
|
@ -34,7 +34,7 @@
|
||||
#define MATRIX_ROW_PINS { B0, B1, B2, B3, B4, B5, B6, B7, C6, C7, D0 }
|
||||
/* column handy ruler: c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 */
|
||||
#define MATRIX_COL_PINS { D1, D2, D3, D4, D5, D6, D7, F0, F1, F4 }
|
||||
#define UNUSED_PINS { AF }
|
||||
#define UNUSED_PINS { }
|
||||
|
||||
//NOTE: if D6 pin shows any issues in exploatation the LED on the Teensy is to be removed
|
||||
|
||||
|
@ -35,7 +35,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#define MATRIX_ROW_PINS { A9, A8, A3, A5 }
|
||||
#define DIODE_DIRECTION COL2ROW
|
||||
|
||||
#define BACKLIGHT_PIN
|
||||
#define BACKLIGHT_LEVELS 6
|
||||
|
||||
#define GRAVE_ESC_CTRL_OVERRIDE
|
||||
|
@ -34,7 +34,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#define MATRIX_ROW_PINS { A9, A8, A3, A5 }
|
||||
#define DIODE_DIRECTION COL2ROW
|
||||
|
||||
#define BACKLIGHT_PIN
|
||||
#define BACKLIGHT_LEVELS 6
|
||||
|
||||
#define GRAVE_ESC_CTRL_OVERRIDE
|
||||
|
@ -42,7 +42,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#define MATRIX_ROW_PINS { C6, D4, D0}
|
||||
#define MATRIX_COL_PINS { D7, E6, B4, B5 }
|
||||
#define UNUSED_PINS { B1, B2, B3, B6, F4, F5, F6, F7 D1}
|
||||
#define UNUSED_PINS { B1, B2, B3, B6, F4, F5, F6, F7, D1}
|
||||
|
||||
/* COL2ROW, ROW2COL */
|
||||
#define DIODE_DIRECTION COL2ROW
|
||||
|
@ -42,7 +42,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#define MATRIX_ROW_PINS { D2, D1, D0, B0, C6, C7 }
|
||||
#define MATRIX_COL_PINS { D3, D5, D4, D6, D7, B4, B5, B6, F7, F6, F5, F4, F1, F0, B1, B2, B3 }
|
||||
#define UNUSED_PINS { B7 E6 }
|
||||
#define UNUSED_PINS { B7, E6 }
|
||||
|
||||
/* COL2ROW, ROW2COL*/
|
||||
#define DIODE_DIRECTION COL2ROW
|
||||
|
@ -29,7 +29,7 @@
|
||||
* ROW2COL = ROW = Anode (+), COL = Cathode (-, marked on diode)
|
||||
*
|
||||
*/
|
||||
#define DIRECT_PINS {}
|
||||
#define DIRECT_PINS {{NO_PIN}}
|
||||
|
||||
// These pins are not broken out, and cannot be used normally.
|
||||
// They are set as output and pulled high, by default
|
||||
|
@ -12,7 +12,7 @@ from qmk.keyboard import keyboard_completer, keyboard_folder
|
||||
from qmk.path import is_keyboard, normpath
|
||||
|
||||
|
||||
def direct_pins(direct_pins):
|
||||
def direct_pins(direct_pins, postfix):
|
||||
"""Return the config.h lines that set the direct pins.
|
||||
"""
|
||||
rows = []
|
||||
@ -24,81 +24,60 @@ def direct_pins(direct_pins):
|
||||
col_count = len(direct_pins[0])
|
||||
row_count = len(direct_pins)
|
||||
|
||||
return """
|
||||
#ifndef MATRIX_COLS
|
||||
# define MATRIX_COLS %s
|
||||
#endif // MATRIX_COLS
|
||||
return f"""
|
||||
#ifndef MATRIX_COLS{postfix}
|
||||
# define MATRIX_COLS{postfix} {col_count}
|
||||
#endif // MATRIX_COLS{postfix}
|
||||
|
||||
#ifndef MATRIX_ROWS
|
||||
# define MATRIX_ROWS %s
|
||||
#endif // MATRIX_ROWS
|
||||
#ifndef MATRIX_ROWS{postfix}
|
||||
# define MATRIX_ROWS{postfix} {row_count}
|
||||
#endif // MATRIX_ROWS{postfix}
|
||||
|
||||
#ifndef DIRECT_PINS
|
||||
# define DIRECT_PINS {%s}
|
||||
#endif // DIRECT_PINS
|
||||
""" % (col_count, row_count, ','.join(rows))
|
||||
#ifndef DIRECT_PINS{postfix}
|
||||
# define DIRECT_PINS{postfix} {{ {", ".join(rows)} }}
|
||||
#endif // DIRECT_PINS{postfix}
|
||||
"""
|
||||
|
||||
|
||||
def pin_array(define, pins):
|
||||
def pin_array(define, pins, postfix):
|
||||
"""Return the config.h lines that set a pin array.
|
||||
"""
|
||||
pin_num = len(pins)
|
||||
pin_array = ', '.join(map(str, [pin or 'NO_PIN' for pin in pins]))
|
||||
|
||||
return f"""
|
||||
#ifndef {define}S
|
||||
# define {define}S {pin_num}
|
||||
#endif // {define}S
|
||||
#ifndef {define}S{postfix}
|
||||
# define {define}S{postfix} {pin_num}
|
||||
#endif // {define}S{postfix}
|
||||
|
||||
#ifndef {define}_PINS
|
||||
# define {define}_PINS {{ {pin_array} }}
|
||||
#endif // {define}_PINS
|
||||
#ifndef {define}_PINS{postfix}
|
||||
# define {define}_PINS{postfix} {{ {pin_array} }}
|
||||
#endif // {define}_PINS{postfix}
|
||||
"""
|
||||
|
||||
|
||||
def matrix_pins(matrix_pins):
|
||||
def matrix_pins(matrix_pins, postfix=''):
|
||||
"""Add the matrix config to the config.h.
|
||||
"""
|
||||
pins = []
|
||||
|
||||
if 'direct' in matrix_pins:
|
||||
pins.append(direct_pins(matrix_pins['direct']))
|
||||
pins.append(direct_pins(matrix_pins['direct'], postfix))
|
||||
|
||||
if 'cols' in matrix_pins:
|
||||
pins.append(pin_array('MATRIX_COL', matrix_pins['cols']))
|
||||
pins.append(pin_array('MATRIX_COL', matrix_pins['cols'], postfix))
|
||||
|
||||
if 'rows' in matrix_pins:
|
||||
pins.append(pin_array('MATRIX_ROW', matrix_pins['rows']))
|
||||
pins.append(pin_array('MATRIX_ROW', matrix_pins['rows'], postfix))
|
||||
|
||||
return '\n'.join(pins)
|
||||
|
||||
|
||||
@cli.argument('-o', '--output', arg_only=True, type=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('-kb', '--keyboard', type=keyboard_folder, completer=keyboard_completer, help='Keyboard to generate config.h for.')
|
||||
@cli.subcommand('Used by the make system to generate info_config.h from info.json', hidden=True)
|
||||
@automagic_keyboard
|
||||
@automagic_keymap
|
||||
def generate_config_h(cli):
|
||||
"""Generates the info_config.h file.
|
||||
def generate_config_items(kb_info_json, config_h_lines):
|
||||
"""Iterate through the info_config map to generate basic config values.
|
||||
"""
|
||||
# Determine our keyboard(s)
|
||||
if not cli.config.generate_config_h.keyboard:
|
||||
cli.log.error('Missing parameter: --keyboard')
|
||||
cli.subcommands['info'].print_help()
|
||||
return False
|
||||
|
||||
if not is_keyboard(cli.config.generate_config_h.keyboard):
|
||||
cli.log.error('Invalid keyboard: "%s"', cli.config.generate_config_h.keyboard)
|
||||
return False
|
||||
|
||||
# Build the info_config.h file.
|
||||
kb_info_json = dotty(info_json(cli.config.generate_config_h.keyboard))
|
||||
info_config_map = json_load(Path('data/mappings/info_config.json'))
|
||||
|
||||
config_h_lines = ['/* This file was generated by `qmk generate-config-h`. Do not edit or copy.' ' */', '', '#pragma once']
|
||||
|
||||
# Iterate through the info_config map to generate basic things
|
||||
for config_key, info_dict in info_config_map.items():
|
||||
info_key = info_dict['info_key']
|
||||
key_type = info_dict.get('value_type', 'str')
|
||||
@ -135,9 +114,78 @@ def generate_config_h(cli):
|
||||
config_h_lines.append(f'# define {config_key} {config_value}')
|
||||
config_h_lines.append(f'#endif // {config_key}')
|
||||
|
||||
|
||||
def generate_split_config(kb_info_json, config_h_lines):
|
||||
"""Generate the config.h lines for split boards."""
|
||||
if 'primary' in kb_info_json['split']:
|
||||
if kb_info_json['split']['primary'] in ('left', 'right'):
|
||||
config_h_lines.append('')
|
||||
config_h_lines.append('#ifndef MASTER_LEFT')
|
||||
config_h_lines.append('# ifndef MASTER_RIGHT')
|
||||
if kb_info_json['split']['primary'] == 'left':
|
||||
config_h_lines.append('# define MASTER_LEFT')
|
||||
elif kb_info_json['split']['primary'] == 'right':
|
||||
config_h_lines.append('# define MASTER_RIGHT')
|
||||
config_h_lines.append('# endif // MASTER_RIGHT')
|
||||
config_h_lines.append('#endif // MASTER_LEFT')
|
||||
elif kb_info_json['split']['primary'] == 'pin':
|
||||
config_h_lines.append('')
|
||||
config_h_lines.append('#ifndef SPLIT_HAND_PIN')
|
||||
config_h_lines.append('# define SPLIT_HAND_PIN')
|
||||
config_h_lines.append('#endif // SPLIT_HAND_PIN')
|
||||
elif kb_info_json['split']['primary'] == 'matrix_grid':
|
||||
config_h_lines.append('')
|
||||
config_h_lines.append('#ifndef SPLIT_HAND_MATRIX_GRID')
|
||||
config_h_lines.append('# define SPLIT_HAND_MATRIX_GRID {%s}' % (','.join(kb_info_json["split"]["matrix_grid"],)))
|
||||
config_h_lines.append('#endif // SPLIT_HAND_MATRIX_GRID')
|
||||
elif kb_info_json['split']['primary'] == 'eeprom':
|
||||
config_h_lines.append('')
|
||||
config_h_lines.append('#ifndef EE_HANDS')
|
||||
config_h_lines.append('# define EE_HANDS')
|
||||
config_h_lines.append('#endif // EE_HANDS')
|
||||
|
||||
if 'protocol' in kb_info_json['split'].get('transport', {}):
|
||||
if kb_info_json['split']['transport']['protocol'] == 'i2c':
|
||||
config_h_lines.append('')
|
||||
config_h_lines.append('#ifndef USE_I2C')
|
||||
config_h_lines.append('# define USE_I2C')
|
||||
config_h_lines.append('#endif // USE_I2C')
|
||||
|
||||
if 'right' in kb_info_json['split'].get('matrix_pins', {}):
|
||||
config_h_lines.append(matrix_pins(kb_info_json['split']['matrix_pins']['right'], '_RIGHT'))
|
||||
|
||||
|
||||
@cli.argument('-o', '--output', arg_only=True, type=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('-kb', '--keyboard', type=keyboard_folder, completer=keyboard_completer, help='Keyboard to generate config.h for.')
|
||||
@cli.subcommand('Used by the make system to generate info_config.h from info.json', hidden=True)
|
||||
@automagic_keyboard
|
||||
@automagic_keymap
|
||||
def generate_config_h(cli):
|
||||
"""Generates the info_config.h file.
|
||||
"""
|
||||
# Determine our keyboard(s)
|
||||
if not cli.config.generate_config_h.keyboard:
|
||||
cli.log.error('Missing parameter: --keyboard')
|
||||
cli.subcommands['info'].print_help()
|
||||
return False
|
||||
|
||||
if not is_keyboard(cli.config.generate_config_h.keyboard):
|
||||
cli.log.error('Invalid keyboard: "%s"', cli.config.generate_config_h.keyboard)
|
||||
return False
|
||||
|
||||
# Build the info_config.h file.
|
||||
kb_info_json = dotty(info_json(cli.config.generate_config_h.keyboard))
|
||||
config_h_lines = ['/* This file was generated by `qmk generate-config-h`. Do not edit or copy.' ' */', '', '#pragma once']
|
||||
|
||||
generate_config_items(kb_info_json, config_h_lines)
|
||||
|
||||
if 'matrix_pins' in kb_info_json:
|
||||
config_h_lines.append(matrix_pins(kb_info_json['matrix_pins']))
|
||||
|
||||
if 'split' in kb_info_json:
|
||||
generate_split_config(kb_info_json, config_h_lines)
|
||||
|
||||
# Show the results
|
||||
config_h = '\n'.join(config_h_lines)
|
||||
|
||||
|
@ -4,15 +4,17 @@ Compile an info.json for a particular keyboard and pretty-print it.
|
||||
"""
|
||||
import json
|
||||
|
||||
from jsonschema import Draft7Validator, validators
|
||||
from argcomplete.completers import FilesCompleter
|
||||
from jsonschema import Draft7Validator, RefResolver, validators
|
||||
from milc import cli
|
||||
from pathlib import Path
|
||||
|
||||
from qmk.decorators import automagic_keyboard, automagic_keymap
|
||||
from qmk.info import info_json
|
||||
from qmk.json_encoders import InfoJSONEncoder
|
||||
from qmk.json_schema import load_jsonschema
|
||||
from qmk.json_schema import compile_schema_store
|
||||
from qmk.keyboard import keyboard_completer, keyboard_folder
|
||||
from qmk.path import is_keyboard
|
||||
from qmk.path import is_keyboard, normpath
|
||||
|
||||
|
||||
def pruning_validator(validator_class):
|
||||
@ -34,15 +36,19 @@ def pruning_validator(validator_class):
|
||||
def strip_info_json(kb_info_json):
|
||||
"""Remove the API-only properties from the info.json.
|
||||
"""
|
||||
schema_store = compile_schema_store()
|
||||
pruning_draft_7_validator = pruning_validator(Draft7Validator)
|
||||
schema = load_jsonschema('keyboard')
|
||||
validator = pruning_draft_7_validator(schema).validate
|
||||
schema = schema_store['qmk.keyboard.v1']
|
||||
resolver = RefResolver.from_schema(schema_store['qmk.keyboard.v1'], store=schema_store)
|
||||
validator = pruning_draft_7_validator(schema, resolver=resolver).validate
|
||||
|
||||
return validator(kb_info_json)
|
||||
|
||||
|
||||
@cli.argument('-kb', '--keyboard', type=keyboard_folder, completer=keyboard_completer, help='Keyboard to show info for.')
|
||||
@cli.argument('-km', '--keymap', help='Show the layers for a JSON keymap too.')
|
||||
@cli.argument('-o', '--output', arg_only=True, completer=FilesCompleter, help='Write the output the specified file, overwriting if necessary.')
|
||||
@cli.argument('-ow', '--overwrite', arg_only=True, action='store_true', help='Overwrite the existing info.json. (Overrides the location of --output)')
|
||||
@cli.subcommand('Generate an info.json file for a keyboard.', hidden=False if cli.config.user.developer else True)
|
||||
@automagic_keyboard
|
||||
@automagic_keymap
|
||||
@ -59,9 +65,29 @@ def generate_info_json(cli):
|
||||
cli.log.error('Invalid keyboard: "%s"', cli.config.generate_info_json.keyboard)
|
||||
return False
|
||||
|
||||
if cli.args.overwrite:
|
||||
output_path = (Path('keyboards') / cli.config.generate_info_json.keyboard / 'info.json').resolve()
|
||||
|
||||
if cli.args.output:
|
||||
cli.log.warning('Overwriting user supplied --output with %s', output_path)
|
||||
|
||||
cli.args.output = output_path
|
||||
|
||||
# Build the info.json file
|
||||
kb_info_json = info_json(cli.config.generate_info_json.keyboard)
|
||||
strip_info_json(kb_info_json)
|
||||
info_json_text = json.dumps(kb_info_json, indent=4, cls=InfoJSONEncoder)
|
||||
|
||||
if cli.args.output:
|
||||
# Write to a file
|
||||
output_path = normpath(cli.args.output)
|
||||
|
||||
if output_path.exists():
|
||||
cli.log.warning('Overwriting output file %s', output_path)
|
||||
|
||||
output_path.write_text(info_json_text + '\n')
|
||||
cli.log.info('Wrote info.json to %s.', output_path)
|
||||
|
||||
else:
|
||||
# Display the results
|
||||
print(json.dumps(kb_info_json, indent=2, cls=InfoJSONEncoder))
|
||||
print(info_json_text)
|
||||
|
@ -76,6 +76,17 @@ def generate_rules_mk(cli):
|
||||
enabled = 'yes' if enabled else 'no'
|
||||
rules_mk_lines.append(f'{feature}_ENABLE ?= {enabled}')
|
||||
|
||||
# Set SPLIT_TRANSPORT, if needed
|
||||
if kb_info_json.get('split', {}).get('transport', {}).get('protocol') == 'custom':
|
||||
rules_mk_lines.append('SPLIT_TRANSPORT ?= custom')
|
||||
|
||||
# Set CUSTOM_MATRIX, if needed
|
||||
if kb_info_json.get('matrix_pins', {}).get('custom'):
|
||||
if kb_info_json.get('matrix_pins', {}).get('custom_lite'):
|
||||
rules_mk_lines.append('CUSTOM_MATRIX ?= lite')
|
||||
else:
|
||||
rules_mk_lines.append('CUSTOM_MATRIX ?= yes')
|
||||
|
||||
# Show the results
|
||||
rules_mk = '\n'.join(rules_mk_lines) + '\n'
|
||||
|
||||
|
@ -24,19 +24,15 @@ def show_keymap(kb_info_json, title_caps=True):
|
||||
keymap_path = locate_keymap(cli.config.info.keyboard, cli.config.info.keymap)
|
||||
|
||||
if keymap_path and keymap_path.suffix == '.json':
|
||||
if title_caps:
|
||||
cli.echo('{fg_blue}Keymap "%s"{fg_reset}:', cli.config.info.keymap)
|
||||
else:
|
||||
cli.echo('{fg_blue}keymap_%s{fg_reset}:', cli.config.info.keymap)
|
||||
|
||||
keymap_data = json.load(keymap_path.open(encoding='utf-8'))
|
||||
layout_name = keymap_data['layout']
|
||||
layout_name = kb_info_json.get('layout_aliases', {}).get(layout_name, layout_name) # Resolve alias names
|
||||
|
||||
for layer_num, layer in enumerate(keymap_data['layers']):
|
||||
if title_caps:
|
||||
cli.echo('{fg_cyan}Layer %s{fg_reset}:', layer_num)
|
||||
cli.echo('{fg_cyan}Keymap %s Layer %s{fg_reset}:', cli.config.info.keymap, layer_num)
|
||||
else:
|
||||
cli.echo('{fg_cyan}layer_%s{fg_reset}:', layer_num)
|
||||
cli.echo('{fg_cyan}keymap.%s.layer.%s{fg_reset}:', cli.config.info.keymap, layer_num)
|
||||
|
||||
print(render_layout(kb_info_json['layouts'][layout_name]['layout'], cli.config.info.ascii, layer))
|
||||
|
||||
@ -45,7 +41,7 @@ def show_layouts(kb_info_json, title_caps=True):
|
||||
"""Render the layouts with info.json labels.
|
||||
"""
|
||||
for layout_name, layout_art in render_layouts(kb_info_json, cli.config.info.ascii).items():
|
||||
title = layout_name.title() if title_caps else layout_name
|
||||
title = f'Layout {layout_name.title()}' if title_caps else f'layouts.{layout_name}'
|
||||
cli.echo('{fg_cyan}%s{fg_reset}:', title)
|
||||
print(layout_art) # Avoid passing dirty data to cli.echo()
|
||||
|
||||
@ -93,15 +89,6 @@ def print_friendly_output(kb_info_json):
|
||||
aliases = [f'{key}={value}' for key, value in kb_info_json['layout_aliases'].items()]
|
||||
cli.echo('{fg_blue}Layout aliases:{fg_reset} %s' % (', '.join(aliases),))
|
||||
|
||||
if cli.config.info.layouts:
|
||||
show_layouts(kb_info_json, True)
|
||||
|
||||
if cli.config.info.matrix:
|
||||
show_matrix(kb_info_json, True)
|
||||
|
||||
if cli.config_source.info.keymap and cli.config_source.info.keymap != 'config_file':
|
||||
show_keymap(kb_info_json, True)
|
||||
|
||||
|
||||
def print_text_output(kb_info_json):
|
||||
"""Print the info.json in a plain text format.
|
||||
@ -122,6 +109,24 @@ def print_text_output(kb_info_json):
|
||||
show_keymap(kb_info_json, False)
|
||||
|
||||
|
||||
def print_dotted_output(kb_info_json, prefix=''):
|
||||
"""Print the info.json in a plain text format with dot-joined keys.
|
||||
"""
|
||||
for key in sorted(kb_info_json):
|
||||
new_prefix = f'{prefix}.{key}' if prefix else key
|
||||
|
||||
if key in ['parse_errors', 'parse_warnings']:
|
||||
continue
|
||||
elif key == 'layouts' and prefix == '':
|
||||
cli.echo('{fg_blue}layouts{fg_reset}: %s', ', '.join(sorted(kb_info_json['layouts'].keys())))
|
||||
elif isinstance(kb_info_json[key], dict):
|
||||
print_dotted_output(kb_info_json[key], new_prefix)
|
||||
elif isinstance(kb_info_json[key], list):
|
||||
cli.echo('{fg_blue}%s{fg_reset}: %s', new_prefix, ', '.join(map(str, sorted(kb_info_json[key]))))
|
||||
else:
|
||||
cli.echo('{fg_blue}%s{fg_reset}: %s', new_prefix, kb_info_json[key])
|
||||
|
||||
|
||||
def print_parsed_rules_mk(keyboard_name):
|
||||
rules = rules_mk(keyboard_name)
|
||||
for k in sorted(rules.keys()):
|
||||
@ -162,10 +167,22 @@ def info(cli):
|
||||
# Output in the requested format
|
||||
if cli.args.format == 'json':
|
||||
print(json.dumps(kb_info_json, cls=InfoJSONEncoder))
|
||||
return True
|
||||
elif cli.args.format == 'text':
|
||||
print_text_output(kb_info_json)
|
||||
print_dotted_output(kb_info_json)
|
||||
title_caps = False
|
||||
elif cli.args.format == 'friendly':
|
||||
print_friendly_output(kb_info_json)
|
||||
title_caps = True
|
||||
else:
|
||||
cli.log.error('Unknown format: %s', cli.args.format)
|
||||
return False
|
||||
|
||||
if cli.config.info.layouts:
|
||||
show_layouts(kb_info_json, title_caps)
|
||||
|
||||
if cli.config.info.matrix:
|
||||
show_matrix(kb_info_json, title_caps)
|
||||
|
||||
if cli.config_source.info.keymap and cli.config_source.info.keymap != 'config_file':
|
||||
show_keymap(kb_info_json, title_caps)
|
||||
|
@ -61,8 +61,8 @@ def info_json(keyboard):
|
||||
|
||||
# Merge in the data from info.json, config.h, and rules.mk
|
||||
info_data = merge_info_jsons(keyboard, info_data)
|
||||
info_data = _extract_config_h(info_data)
|
||||
info_data = _extract_rules_mk(info_data)
|
||||
info_data = _extract_config_h(info_data)
|
||||
|
||||
# Ensure that we have matrix row and column counts
|
||||
info_data = _matrix_size(info_data)
|
||||
@ -161,10 +161,9 @@ def _extract_pins(pins):
|
||||
return [_pin_name(pin) for pin in pins.split(',')]
|
||||
|
||||
|
||||
def _extract_direct_matrix(info_data, direct_pins):
|
||||
def _extract_direct_matrix(direct_pins):
|
||||
"""
|
||||
"""
|
||||
info_data['matrix_pins'] = {}
|
||||
direct_pin_array = []
|
||||
|
||||
while direct_pins[-1] != '}':
|
||||
@ -188,12 +187,157 @@ def _extract_direct_matrix(info_data, direct_pins):
|
||||
return direct_pin_array
|
||||
|
||||
|
||||
def _extract_audio(info_data, config_c):
|
||||
"""Populate data about the audio configuration
|
||||
"""
|
||||
audio_pins = []
|
||||
|
||||
for pin in 'B5', 'B6', 'B7', 'C4', 'C5', 'C6':
|
||||
if config_c.get(f'{pin}_AUDIO'):
|
||||
audio_pins.append(pin)
|
||||
|
||||
if audio_pins:
|
||||
info_data['audio'] = {'pins': audio_pins}
|
||||
|
||||
|
||||
def _extract_split_main(info_data, config_c):
|
||||
"""Populate data about the split configuration
|
||||
"""
|
||||
# Figure out how the main half is determined
|
||||
if config_c.get('SPLIT_HAND_PIN') is True:
|
||||
if 'split' not in info_data:
|
||||
info_data['split'] = {}
|
||||
|
||||
if 'main' in info_data['split']:
|
||||
_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'])
|
||||
|
||||
info_data['split']['main'] = 'pin'
|
||||
|
||||
if config_c.get('SPLIT_HAND_MATRIX_GRID'):
|
||||
if 'split' not in info_data:
|
||||
info_data['split'] = {}
|
||||
|
||||
if 'main' in info_data['split']:
|
||||
_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'])
|
||||
|
||||
info_data['split']['main'] = 'matrix_grid'
|
||||
info_data['split']['matrix_grid'] = _extract_pins(config_c['SPLIT_HAND_MATRIX_GRID'])
|
||||
|
||||
if config_c.get('EE_HANDS') is True:
|
||||
if 'split' not in info_data:
|
||||
info_data['split'] = {}
|
||||
|
||||
if 'main' in info_data['split']:
|
||||
_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'])
|
||||
|
||||
info_data['split']['main'] = 'eeprom'
|
||||
|
||||
if config_c.get('MASTER_RIGHT') is True:
|
||||
if 'split' not in info_data:
|
||||
info_data['split'] = {}
|
||||
|
||||
if 'main' in info_data['split']:
|
||||
_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'])
|
||||
|
||||
info_data['split']['main'] = 'right'
|
||||
|
||||
if config_c.get('MASTER_LEFT') is True:
|
||||
if 'split' not in info_data:
|
||||
info_data['split'] = {}
|
||||
|
||||
if 'main' in info_data['split']:
|
||||
_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'])
|
||||
|
||||
info_data['split']['main'] = 'left'
|
||||
|
||||
|
||||
def _extract_split_transport(info_data, config_c):
|
||||
# Figure out the transport method
|
||||
if config_c.get('USE_I2C') is True:
|
||||
if 'split' not in info_data:
|
||||
info_data['split'] = {}
|
||||
|
||||
if 'transport' not in info_data['split']:
|
||||
info_data['split']['transport'] = {}
|
||||
|
||||
if 'protocol' in info_data['split']['transport']:
|
||||
_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'])
|
||||
|
||||
info_data['split']['transport']['protocol'] = 'i2c'
|
||||
|
||||
elif 'protocol' not in info_data.get('split', {}).get('transport', {}):
|
||||
if 'split' not in info_data:
|
||||
info_data['split'] = {}
|
||||
|
||||
if 'transport' not in info_data['split']:
|
||||
info_data['split']['transport'] = {}
|
||||
|
||||
info_data['split']['transport']['protocol'] = 'serial'
|
||||
|
||||
|
||||
def _extract_split_right_pins(info_data, config_c):
|
||||
# Figure out the right half matrix pins
|
||||
row_pins = config_c.get('MATRIX_ROW_PINS_RIGHT', '').replace('{', '').replace('}', '').strip()
|
||||
col_pins = config_c.get('MATRIX_COL_PINS_RIGHT', '').replace('{', '').replace('}', '').strip()
|
||||
unused_pin_text = config_c.get('UNUSED_PINS_RIGHT')
|
||||
unused_pins = unused_pin_text.replace('{', '').replace('}', '').strip() if isinstance(unused_pin_text, str) else None
|
||||
direct_pins = config_c.get('DIRECT_PINS_RIGHT', '').replace(' ', '')[1:-1]
|
||||
|
||||
if row_pins and col_pins:
|
||||
if info_data.get('split', {}).get('matrix_pins', {}).get('right') in info_data:
|
||||
_log_warning(info_data, 'Right hand matrix data is specified in both info.json and config.h, the config.h values win.')
|
||||
|
||||
if 'split' not in info_data:
|
||||
info_data['split'] = {}
|
||||
|
||||
if 'matrix_pins' not in info_data['split']:
|
||||
info_data['split']['matrix_pins'] = {}
|
||||
|
||||
if 'right' not in info_data['split']['matrix_pins']:
|
||||
info_data['split']['matrix_pins']['right'] = {}
|
||||
|
||||
info_data['split']['matrix_pins']['right'] = {
|
||||
'cols': _extract_pins(col_pins),
|
||||
'rows': _extract_pins(row_pins),
|
||||
}
|
||||
|
||||
if direct_pins:
|
||||
if info_data.get('split', {}).get('matrix_pins', {}).get('right', {}):
|
||||
_log_warning(info_data, 'Right hand matrix data is specified in both info.json and config.h, the config.h values win.')
|
||||
|
||||
if 'split' not in info_data:
|
||||
info_data['split'] = {}
|
||||
|
||||
if 'matrix_pins' not in info_data['split']:
|
||||
info_data['split']['matrix_pins'] = {}
|
||||
|
||||
if 'right' not in info_data['split']['matrix_pins']:
|
||||
info_data['split']['matrix_pins']['right'] = {}
|
||||
|
||||
info_data['split']['matrix_pins']['right']['direct'] = _extract_direct_matrix(direct_pins)
|
||||
|
||||
if unused_pins:
|
||||
if 'split' not in info_data:
|
||||
info_data['split'] = {}
|
||||
|
||||
if 'matrix_pins' not in info_data['split']:
|
||||
info_data['split']['matrix_pins'] = {}
|
||||
|
||||
if 'right' not in info_data['split']['matrix_pins']:
|
||||
info_data['split']['matrix_pins']['right'] = {}
|
||||
|
||||
info_data['split']['matrix_pins']['right']['unused'] = _extract_pins(unused_pins)
|
||||
|
||||
|
||||
def _extract_matrix_info(info_data, config_c):
|
||||
"""Populate the matrix information.
|
||||
"""
|
||||
row_pins = config_c.get('MATRIX_ROW_PINS', '').replace('{', '').replace('}', '').strip()
|
||||
col_pins = config_c.get('MATRIX_COL_PINS', '').replace('{', '').replace('}', '').strip()
|
||||
unused_pin_text = config_c.get('UNUSED_PINS')
|
||||
unused_pins = unused_pin_text.replace('{', '').replace('}', '').strip() if isinstance(unused_pin_text, str) else None
|
||||
direct_pins = config_c.get('DIRECT_PINS', '').replace(' ', '')[1:-1]
|
||||
info_snippet = {}
|
||||
|
||||
if 'MATRIX_ROWS' in config_c and 'MATRIX_COLS' in config_c:
|
||||
if 'matrix_size' in info_data:
|
||||
@ -205,19 +349,35 @@ def _extract_matrix_info(info_data, config_c):
|
||||
}
|
||||
|
||||
if row_pins and col_pins:
|
||||
if 'matrix_pins' in info_data:
|
||||
if 'matrix_pins' in info_data and 'cols' in info_data['matrix_pins'] and 'rows' in info_data['matrix_pins']:
|
||||
_log_warning(info_data, 'Matrix pins are specified in both info.json and config.h, the config.h values win.')
|
||||
|
||||
info_data['matrix_pins'] = {
|
||||
'cols': _extract_pins(col_pins),
|
||||
'rows': _extract_pins(row_pins),
|
||||
}
|
||||
info_snippet['cols'] = _extract_pins(col_pins)
|
||||
info_snippet['rows'] = _extract_pins(row_pins)
|
||||
|
||||
if direct_pins:
|
||||
if 'matrix_pins' in info_data:
|
||||
if 'matrix_pins' in info_data and 'direct' in info_data['matrix_pins']:
|
||||
_log_warning(info_data, 'Direct pins are specified in both info.json and config.h, the config.h values win.')
|
||||
|
||||
info_data['matrix_pins']['direct'] = _extract_direct_matrix(info_data, direct_pins)
|
||||
info_snippet['direct'] = _extract_direct_matrix(direct_pins)
|
||||
|
||||
if unused_pins:
|
||||
if 'matrix_pins' not in info_data:
|
||||
info_data['matrix_pins'] = {}
|
||||
|
||||
info_snippet['unused'] = _extract_pins(unused_pins)
|
||||
|
||||
if config_c.get('CUSTOM_MATRIX', 'no') != 'no':
|
||||
if 'matrix_pins' in info_data and 'custom' in info_data['matrix_pins']:
|
||||
_log_warning(info_data, 'Custom Matrix is specified in both info.json and config.h, the config.h values win.')
|
||||
|
||||
info_snippet['custom'] = True
|
||||
|
||||
if config_c['CUSTOM_MATRIX'] == 'lite':
|
||||
info_snippet['custom_lite'] = True
|
||||
|
||||
if info_snippet:
|
||||
info_data['matrix_pins'] = info_snippet
|
||||
|
||||
return info_data
|
||||
|
||||
@ -275,6 +435,10 @@ def _extract_config_h(info_data):
|
||||
|
||||
# Pull data that easily can't be mapped in json
|
||||
_extract_matrix_info(info_data, config_c)
|
||||
_extract_audio(info_data, config_c)
|
||||
_extract_split_main(info_data, config_c)
|
||||
_extract_split_transport(info_data, config_c)
|
||||
_extract_split_right_pins(info_data, config_c)
|
||||
|
||||
return info_data
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
"""
|
||||
import json
|
||||
from collections.abc import Mapping
|
||||
from functools import lru_cache
|
||||
from pathlib import Path
|
||||
|
||||
import hjson
|
||||
@ -25,6 +26,7 @@ def json_load(json_file):
|
||||
exit(1)
|
||||
|
||||
|
||||
@lru_cache(maxsize=0)
|
||||
def load_jsonschema(schema_name):
|
||||
"""Read a jsonschema file from disk.
|
||||
"""
|
||||
@ -39,8 +41,9 @@ def load_jsonschema(schema_name):
|
||||
return json_load(schema_path)
|
||||
|
||||
|
||||
def create_validator(schema):
|
||||
"""Creates a validator for the given schema id.
|
||||
@lru_cache(maxsize=0)
|
||||
def compile_schema_store():
|
||||
"""Compile all our schemas into a schema store.
|
||||
"""
|
||||
schema_store = {}
|
||||
|
||||
@ -51,6 +54,14 @@ def create_validator(schema):
|
||||
continue
|
||||
schema_store[schema_data['$id']] = schema_data
|
||||
|
||||
return schema_store
|
||||
|
||||
|
||||
@lru_cache(maxsize=0)
|
||||
def create_validator(schema):
|
||||
"""Creates a validator for the given schema id.
|
||||
"""
|
||||
schema_store = compile_schema_store()
|
||||
resolver = jsonschema.RefResolver.from_schema(schema_store['qmk.keyboard.v1'], store=schema_store)
|
||||
|
||||
return jsonschema.Draft7Validator(schema_store[schema], resolver=resolver).validate
|
||||
|
Loading…
Reference in New Issue
Block a user