2020-12-30 19:27:37 +01:00
""" Used by the make system to generate info_config.h from info.json.
"""
2021-01-31 21:46:00 +01:00
from pathlib import Path
from dotty_dict import dotty
2022-10-19 18:43:25 +02:00
from argcomplete . completers import FilesCompleter
2020-12-30 19:27:37 +01:00
from milc import cli
2022-10-19 18:43:25 +02:00
from qmk . info import info_json
2022-03-21 11:57:41 +01:00
from qmk . json_schema import json_load
2021-04-15 04:00:22 +02:00
from qmk . keyboard import keyboard_completer , keyboard_folder
2022-10-19 18:43:25 +02:00
from qmk . commands import dump_lines , parse_configurator_json
from qmk . path import normpath , FileType
2022-03-18 02:09:29 +01:00
from qmk . constants import GPL2_HEADER_C_LIKE , GENERATED_HEADER_C_LIKE
2020-12-30 19:27:37 +01:00
2022-09-21 19:31:57 +02:00
def generate_define ( define , value = None ) :
value = f ' { value } ' if value is not None else ' '
return f """
#ifndef {define}
# define {define}{value}
#endif // {define}"""
2021-08-17 00:33:30 +02:00
def direct_pins ( direct_pins , postfix ) :
2020-12-30 19:27:37 +01:00
""" Return the config.h lines that set the direct pins.
"""
rows = [ ]
for row in direct_pins :
2021-01-08 09:00:15 +01:00
cols = ' , ' . join ( map ( str , [ col or ' NO_PIN ' for col in row ] ) )
2020-12-30 19:27:37 +01:00
rows . append ( ' { ' + cols + ' } ' )
2022-09-21 19:31:57 +02:00
return generate_define ( f ' DIRECT_PINS { postfix } ' , f ' {{ { " , " . join ( rows ) } }} ' )
2020-12-30 19:27:37 +01:00
2021-08-17 00:33:30 +02:00
def pin_array ( define , pins , postfix ) :
2021-01-31 21:46:00 +01:00
""" Return the config.h lines that set a pin array.
2020-12-30 19:27:37 +01:00
"""
2021-01-31 21:46:00 +01:00
pin_array = ' , ' . join ( map ( str , [ pin or ' NO_PIN ' for pin in pins ] ) )
2020-12-30 19:27:37 +01:00
2022-09-21 19:31:57 +02:00
return generate_define ( f ' { define } _PINS { postfix } ' , f ' {{ { pin_array } }} ' )
2020-12-30 19:27:37 +01:00
2021-08-17 00:33:30 +02:00
def matrix_pins ( matrix_pins , postfix = ' ' ) :
2020-12-30 19:27:37 +01:00
""" Add the matrix config to the config.h.
"""
pins = [ ]
if ' direct ' in matrix_pins :
2021-08-17 00:33:30 +02:00
pins . append ( direct_pins ( matrix_pins [ ' direct ' ] , postfix ) )
2020-12-30 19:27:37 +01:00
if ' cols ' in matrix_pins :
2021-08-17 00:33:30 +02:00
pins . append ( pin_array ( ' MATRIX_COL ' , matrix_pins [ ' cols ' ] , postfix ) )
2020-12-30 19:27:37 +01:00
if ' rows ' in matrix_pins :
2021-08-17 00:33:30 +02:00
pins . append ( pin_array ( ' MATRIX_ROW ' , matrix_pins [ ' rows ' ] , postfix ) )
2020-12-30 19:27:37 +01:00
return ' \n ' . join ( pins )
2022-02-27 13:39:24 +01:00
def generate_matrix_size ( kb_info_json , config_h_lines ) :
""" Add the matrix size to the config.h.
"""
2023-01-06 00:40:53 +01:00
if ' matrix_size ' in kb_info_json :
2022-09-21 19:31:57 +02:00
config_h_lines . append ( generate_define ( ' MATRIX_COLS ' , kb_info_json [ ' matrix_size ' ] [ ' cols ' ] ) )
config_h_lines . append ( generate_define ( ' MATRIX_ROWS ' , kb_info_json [ ' matrix_size ' ] [ ' rows ' ] ) )
2022-02-27 13:39:24 +01:00
2021-08-17 00:33:30 +02:00
def generate_config_items ( kb_info_json , config_h_lines ) :
""" Iterate through the info_config map to generate basic config values.
2020-12-30 19:27:37 +01:00
"""
2022-11-08 02:05:08 +01:00
info_config_map = json_load ( Path ( ' data/mappings/info_config.hjson ' ) )
2020-12-30 19:27:37 +01:00
2021-01-31 21:46:00 +01:00
for config_key , info_dict in info_config_map . items ( ) :
info_key = info_dict [ ' info_key ' ]
2022-03-04 14:25:24 +01:00
key_type = info_dict . get ( ' value_type ' , ' raw ' )
2021-01-31 21:46:00 +01:00
to_config = info_dict . get ( ' to_config ' , True )
if not to_config :
continue
try :
config_value = kb_info_json [ info_key ]
except KeyError :
continue
2022-04-16 20:13:05 +02:00
if key_type . startswith ( ' array.array ' ) :
2022-09-21 19:31:57 +02:00
config_h_lines . append ( generate_define ( config_key , f ' {{ { " , " . join ( [ " { " + " , " . join ( list ( map ( str , x ) ) ) + " } " for x in config_value ] ) } }} ' ) )
2022-04-16 20:13:05 +02:00
elif key_type . startswith ( ' array ' ) :
2022-09-21 19:31:57 +02:00
config_h_lines . append ( generate_define ( config_key , f ' {{ { " , " . join ( map ( str , config_value ) ) } }} ' ) )
2021-01-31 21:46:00 +01:00
elif key_type == ' bool ' :
if config_value :
2022-09-21 19:31:57 +02:00
config_h_lines . append ( generate_define ( config_key ) )
2021-01-31 21:46:00 +01:00
elif key_type == ' mapping ' :
for key , value in config_value . items ( ) :
2022-09-21 19:31:57 +02:00
config_h_lines . append ( generate_define ( key , value ) )
2022-03-04 14:25:24 +01:00
elif key_type == ' str ' :
2022-08-28 20:35:17 +02:00
escaped_str = config_value . replace ( ' \\ ' , ' \\ \\ ' ) . replace ( ' " ' , ' \\ " ' )
2022-09-21 19:31:57 +02:00
config_h_lines . append ( generate_define ( config_key , f ' " { escaped_str } " ' ) )
2022-01-16 22:44:34 +01:00
elif key_type == ' bcd_version ' :
( major , minor , revision ) = config_value . split ( ' . ' )
2022-09-21 19:31:57 +02:00
config_h_lines . append ( generate_define ( config_key , f ' 0x { major . zfill ( 2 ) } { minor } { revision } ' ) )
2021-01-31 21:46:00 +01:00
else :
2022-09-21 19:31:57 +02:00
config_h_lines . append ( generate_define ( config_key , config_value ) )
2020-12-30 19:27:37 +01:00
2021-08-17 00:33:30 +02:00
2022-06-21 05:15:06 +02:00
def generate_encoder_config ( encoder_json , config_h_lines , postfix = ' ' ) :
""" Generate the config.h lines for encoders. """
a_pads = [ ]
b_pads = [ ]
resolutions = [ ]
for encoder in encoder_json . get ( " rotary " , [ ] ) :
a_pads . append ( encoder [ " pin_a " ] )
b_pads . append ( encoder [ " pin_b " ] )
2022-07-11 11:51:39 +02:00
resolutions . append ( encoder . get ( " resolution " , None ) )
2022-06-21 05:15:06 +02:00
2022-09-21 19:31:57 +02:00
config_h_lines . append ( generate_define ( f ' ENCODERS_PAD_A { postfix } ' , f ' {{ { " , " . join ( a_pads ) } }} ' ) )
config_h_lines . append ( generate_define ( f ' ENCODERS_PAD_B { postfix } ' , f ' {{ { " , " . join ( b_pads ) } }} ' ) )
2022-06-21 05:15:06 +02:00
2022-07-11 11:51:39 +02:00
if None in resolutions :
cli . log . debug ( " Unable to generate ENCODER_RESOLUTION configuration " )
elif len ( set ( resolutions ) ) == 1 :
2022-09-21 19:31:57 +02:00
config_h_lines . append ( generate_define ( f ' ENCODER_RESOLUTION { postfix } ' , resolutions [ 0 ] ) )
2022-07-08 23:48:48 +02:00
else :
2022-09-21 19:31:57 +02:00
config_h_lines . append ( generate_define ( f ' ENCODER_RESOLUTIONS { postfix } ' , f ' {{ { " , " . join ( map ( str , resolutions ) ) } }} ' ) )
2022-06-21 05:15:06 +02:00
2021-08-17 00:33:30 +02:00
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 ' )
2022-09-21 19:31:57 +02:00
config_h_lines . append ( ' # ifndef MASTER_RIGHT ' )
2021-08-17 00:33:30 +02:00
if kb_info_json [ ' split ' ] [ ' primary ' ] == ' left ' :
2022-09-21 19:31:57 +02:00
config_h_lines . append ( ' # define MASTER_LEFT ' )
2021-08-17 00:33:30 +02:00
elif kb_info_json [ ' split ' ] [ ' primary ' ] == ' right ' :
2022-09-21 19:31:57 +02:00
config_h_lines . append ( ' # define MASTER_RIGHT ' )
config_h_lines . append ( ' # endif // MASTER_RIGHT ' )
2021-08-17 00:33:30 +02:00
config_h_lines . append ( ' #endif // MASTER_LEFT ' )
elif kb_info_json [ ' split ' ] [ ' primary ' ] == ' pin ' :
2022-09-21 19:31:57 +02:00
config_h_lines . append ( generate_define ( ' SPLIT_HAND_PIN ' ) )
2021-08-17 00:33:30 +02:00
elif kb_info_json [ ' split ' ] [ ' primary ' ] == ' matrix_grid ' :
2022-09-21 19:31:57 +02:00
config_h_lines . append ( generate_define ( ' SPLIT_HAND_MATRIX_GRID ' , f ' {{ { " , " . join ( kb_info_json [ " split " ] [ " matrix_grid " ] ) } }} ' ) )
2021-08-17 00:33:30 +02:00
elif kb_info_json [ ' split ' ] [ ' primary ' ] == ' eeprom ' :
2022-09-21 19:31:57 +02:00
config_h_lines . append ( generate_define ( ' EE_HANDS ' ) )
2021-08-17 00:33:30 +02:00
if ' protocol ' in kb_info_json [ ' split ' ] . get ( ' transport ' , { } ) :
if kb_info_json [ ' split ' ] [ ' transport ' ] [ ' protocol ' ] == ' i2c ' :
2022-09-21 19:31:57 +02:00
config_h_lines . append ( generate_define ( ' USE_I2C ' ) )
2021-08-17 00:33:30 +02:00
if ' right ' in kb_info_json [ ' split ' ] . get ( ' matrix_pins ' , { } ) :
config_h_lines . append ( matrix_pins ( kb_info_json [ ' split ' ] [ ' matrix_pins ' ] [ ' right ' ] , ' _RIGHT ' ) )
2022-06-21 05:15:06 +02:00
if ' right ' in kb_info_json [ ' split ' ] . get ( ' encoder ' , { } ) :
generate_encoder_config ( kb_info_json [ ' split ' ] [ ' encoder ' ] [ ' right ' ] , config_h_lines , ' _RIGHT ' )
2021-08-17 00:33:30 +02:00
2022-09-26 02:04:21 +02:00
def generate_led_animations_config ( led_feature_json , config_h_lines , prefix ) :
for animation in led_feature_json . get ( ' animations ' , { } ) :
if led_feature_json [ ' animations ' ] [ animation ] :
config_h_lines . append ( generate_define ( f ' { prefix } { animation . upper ( ) } ' ) )
2022-10-19 18:43:25 +02:00
@cli.argument ( ' filename ' , nargs = ' ? ' , arg_only = True , type = FileType ( ' r ' ) , completer = FilesCompleter ( ' .json ' ) , help = ' A configurator export JSON to be compiled and flashed or a pre-compiled binary firmware file (bin/hex) to be flashed. ' )
2021-08-17 00:33:30 +02:00
@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 " )
2022-10-19 18:43:25 +02:00
@cli.argument ( ' -kb ' , ' --keyboard ' , arg_only = True , type = keyboard_folder , completer = keyboard_completer , help = ' Keyboard to generate config.h for. ' )
2021-08-17 00:33:30 +02:00
@cli.subcommand ( ' Used by the make system to generate info_config.h from info.json ' , hidden = True )
def generate_config_h ( cli ) :
""" Generates the info_config.h file.
"""
2021-08-18 22:52:41 +02:00
# Determine our keyboard/keymap
2022-10-19 18:43:25 +02:00
if cli . args . filename :
user_keymap = parse_configurator_json ( cli . args . filename )
2022-10-21 03:21:17 +02:00
kb_info_json = dotty ( user_keymap . get ( ' config ' , { } ) )
2022-10-19 18:43:25 +02:00
elif cli . args . keyboard :
2021-08-18 22:52:41 +02:00
kb_info_json = dotty ( info_json ( cli . args . keyboard ) )
2022-10-19 18:43:25 +02:00
else :
cli . log . error ( ' You must supply a configurator export or `--keyboard`. ' )
cli . subcommands [ ' generate-config-h ' ] . print_help ( )
return False
2021-08-17 00:33:30 +02:00
# Build the info_config.h file.
2022-03-18 02:09:29 +01:00
config_h_lines = [ GPL2_HEADER_C_LIKE , GENERATED_HEADER_C_LIKE , ' #pragma once ' ]
2021-08-17 00:33:30 +02:00
generate_config_items ( kb_info_json , config_h_lines )
2022-02-27 13:39:24 +01:00
generate_matrix_size ( kb_info_json , config_h_lines )
2020-12-30 19:27:37 +01:00
if ' matrix_pins ' in kb_info_json :
config_h_lines . append ( matrix_pins ( kb_info_json [ ' matrix_pins ' ] ) )
2022-06-21 05:15:06 +02:00
if ' encoder ' in kb_info_json :
generate_encoder_config ( kb_info_json [ ' encoder ' ] , config_h_lines )
2021-08-17 00:33:30 +02:00
if ' split ' in kb_info_json :
generate_split_config ( kb_info_json , config_h_lines )
2022-09-26 02:04:21 +02:00
if ' led_matrix ' in kb_info_json :
generate_led_animations_config ( kb_info_json [ ' led_matrix ' ] , config_h_lines , ' ENABLE_LED_MATRIX_ ' )
if ' rgb_matrix ' in kb_info_json :
generate_led_animations_config ( kb_info_json [ ' rgb_matrix ' ] , config_h_lines , ' ENABLE_RGB_MATRIX_ ' )
if ' rgblight ' in kb_info_json :
generate_led_animations_config ( kb_info_json [ ' rgblight ' ] , config_h_lines , ' RGBLIGHT_EFFECT_ ' )
2020-12-30 19:27:37 +01:00
# Show the results
2022-03-18 02:09:29 +01:00
dump_lines ( cli . args . output , config_h_lines , cli . args . quiet )