2020-12-30 18:27:37 +00:00
""" Used by the make system to generate info_config.h from info.json.
"""
2021-01-31 20:46:00 +00:00
from pathlib import Path
from dotty_dict import dotty
2022-10-19 16:43:25 +00:00
from argcomplete . completers import FilesCompleter
2020-12-30 18:27:37 +00:00
from milc import cli
2022-10-19 16:43:25 +00:00
from qmk . info import info_json
2022-03-21 10:57:41 +00:00
from qmk . json_schema import json_load
2021-04-15 02:00:22 +00:00
from qmk . keyboard import keyboard_completer , keyboard_folder
2022-10-19 16:43:25 +00:00
from qmk . commands import dump_lines , parse_configurator_json
from qmk . path import normpath , FileType
2022-03-18 01:09:29 +00:00
from qmk . constants import GPL2_HEADER_C_LIKE , GENERATED_HEADER_C_LIKE
2020-12-30 18:27:37 +00:00
2022-09-21 17:31:57 +00:00
def generate_define ( define , value = None ) :
2023-09-13 00:12:46 +00:00
is_keymap = cli . args . filename
2022-09-21 17:31:57 +00:00
value = f ' { value } ' if value is not None else ' '
2023-09-13 00:12:46 +00:00
if is_keymap :
return f """
#undef {define}
#define {define}{value}"""
2022-09-21 17:31:57 +00:00
return f """
#ifndef {define}
# define {define}{value}
#endif // {define}"""
2021-08-16 22:33:30 +00:00
def direct_pins ( direct_pins , postfix ) :
2020-12-30 18:27:37 +00:00
""" Return the config.h lines that set the direct pins.
"""
rows = [ ]
for row in direct_pins :
2021-01-08 08:00:15 +00:00
cols = ' , ' . join ( map ( str , [ col or ' NO_PIN ' for col in row ] ) )
2020-12-30 18:27:37 +00:00
rows . append ( ' { ' + cols + ' } ' )
2022-09-21 17:31:57 +00:00
return generate_define ( f ' DIRECT_PINS { postfix } ' , f ' {{ { " , " . join ( rows ) } }} ' )
2020-12-30 18:27:37 +00:00
2021-08-16 22:33:30 +00:00
def pin_array ( define , pins , postfix ) :
2021-01-31 20:46:00 +00:00
""" Return the config.h lines that set a pin array.
2020-12-30 18:27:37 +00:00
"""
2021-01-31 20:46:00 +00:00
pin_array = ' , ' . join ( map ( str , [ pin or ' NO_PIN ' for pin in pins ] ) )
2020-12-30 18:27:37 +00:00
2022-09-21 17:31:57 +00:00
return generate_define ( f ' { define } _PINS { postfix } ' , f ' {{ { pin_array } }} ' )
2020-12-30 18:27:37 +00:00
2021-08-16 22:33:30 +00:00
def matrix_pins ( matrix_pins , postfix = ' ' ) :
2020-12-30 18:27:37 +00:00
""" Add the matrix config to the config.h.
"""
pins = [ ]
if ' direct ' in matrix_pins :
2021-08-16 22:33:30 +00:00
pins . append ( direct_pins ( matrix_pins [ ' direct ' ] , postfix ) )
2020-12-30 18:27:37 +00:00
if ' cols ' in matrix_pins :
2021-08-16 22:33:30 +00:00
pins . append ( pin_array ( ' MATRIX_COL ' , matrix_pins [ ' cols ' ] , postfix ) )
2020-12-30 18:27:37 +00:00
if ' rows ' in matrix_pins :
2021-08-16 22:33:30 +00:00
pins . append ( pin_array ( ' MATRIX_ROW ' , matrix_pins [ ' rows ' ] , postfix ) )
2020-12-30 18:27:37 +00:00
return ' \n ' . join ( pins )
2022-02-27 12:39:24 +00:00
def generate_matrix_size ( kb_info_json , config_h_lines ) :
""" Add the matrix size to the config.h.
"""
2023-01-05 23:40:53 +00:00
if ' matrix_size ' in kb_info_json :
2022-09-21 17:31:57 +00: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 12:39:24 +00:00
2023-10-29 00:09:02 +00:00
def generate_matrix_masked ( kb_info_json , config_h_lines ) :
""" " Enable matrix mask if required """
if ' matrix_grid ' in kb_info_json . get ( ' dip_switch ' , { } ) :
config_h_lines . append ( generate_define ( ' MATRIX_MASKED ' ) )
2021-08-16 22:33:30 +00: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 18:27:37 +00:00
"""
2022-11-08 01:05:08 +00:00
info_config_map = json_load ( Path ( ' data/mappings/info_config.hjson ' ) )
2020-12-30 18:27:37 +00:00
2021-01-31 20:46:00 +00:00
for config_key , info_dict in info_config_map . items ( ) :
info_key = info_dict [ ' info_key ' ]
2022-03-04 13:25:24 +00:00
key_type = info_dict . get ( ' value_type ' , ' raw ' )
2023-10-29 23:41:44 +00:00
to_c = info_dict . get ( ' to_c ' , True )
2021-01-31 20:46:00 +00:00
2023-10-29 23:41:44 +00:00
if not to_c :
2021-01-31 20:46:00 +00:00
continue
try :
config_value = kb_info_json [ info_key ]
except KeyError :
continue
2022-04-16 18:13:05 +00:00
if key_type . startswith ( ' array.array ' ) :
2022-09-21 17:31:57 +00:00
config_h_lines . append ( generate_define ( config_key , f ' {{ { " , " . join ( [ " { " + " , " . join ( list ( map ( str , x ) ) ) + " } " for x in config_value ] ) } }} ' ) )
2022-04-16 18:13:05 +00:00
elif key_type . startswith ( ' array ' ) :
2022-09-21 17:31:57 +00:00
config_h_lines . append ( generate_define ( config_key , f ' {{ { " , " . join ( map ( str , config_value ) ) } }} ' ) )
2021-01-31 20:46:00 +00:00
elif key_type == ' bool ' :
if config_value :
2022-09-21 17:31:57 +00:00
config_h_lines . append ( generate_define ( config_key ) )
2021-01-31 20:46:00 +00:00
elif key_type == ' mapping ' :
for key , value in config_value . items ( ) :
2022-09-21 17:31:57 +00:00
config_h_lines . append ( generate_define ( key , value ) )
2022-03-04 13:25:24 +00:00
elif key_type == ' str ' :
2022-08-28 18:35:17 +00:00
escaped_str = config_value . replace ( ' \\ ' , ' \\ \\ ' ) . replace ( ' " ' , ' \\ " ' )
2022-09-21 17:31:57 +00:00
config_h_lines . append ( generate_define ( config_key , f ' " { escaped_str } " ' ) )
2022-01-16 21:44:34 +00:00
elif key_type == ' bcd_version ' :
( major , minor , revision ) = config_value . split ( ' . ' )
2022-09-21 17:31:57 +00:00
config_h_lines . append ( generate_define ( config_key , f ' 0x { major . zfill ( 2 ) } { minor } { revision } ' ) )
2021-01-31 20:46:00 +00:00
else :
2022-09-21 17:31:57 +00:00
config_h_lines . append ( generate_define ( config_key , config_value ) )
2020-12-30 18:27:37 +00:00
2021-08-16 22:33:30 +00:00
2022-06-21 03:15:06 +00: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 09:51:39 +00:00
resolutions . append ( encoder . get ( " resolution " , None ) )
2022-06-21 03:15:06 +00:00
2022-09-21 17:31:57 +00: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 03:15:06 +00:00
2022-07-11 09:51:39 +00:00
if None in resolutions :
2023-04-07 13:07:59 +00:00
cli . log . debug ( f " Unable to generate ENCODER_RESOLUTION { postfix } configuration " )
elif len ( resolutions ) == 0 :
cli . log . debug ( f " Skipping ENCODER_RESOLUTION { postfix } configuration " )
2022-07-11 09:51:39 +00:00
elif len ( set ( resolutions ) ) == 1 :
2022-09-21 17:31:57 +00:00
config_h_lines . append ( generate_define ( f ' ENCODER_RESOLUTION { postfix } ' , resolutions [ 0 ] ) )
2022-07-08 21:48:48 +00:00
else :
2022-09-21 17:31:57 +00:00
config_h_lines . append ( generate_define ( f ' ENCODER_RESOLUTIONS { postfix } ' , f ' {{ { " , " . join ( map ( str , resolutions ) ) } }} ' ) )
2022-06-21 03:15:06 +00:00
2021-08-16 22:33:30 +00:00
def generate_split_config ( kb_info_json , config_h_lines ) :
""" Generate the config.h lines for split boards. """
if ' protocol ' in kb_info_json [ ' split ' ] . get ( ' transport ' , { } ) :
if kb_info_json [ ' split ' ] [ ' transport ' ] [ ' protocol ' ] == ' i2c ' :
2022-09-21 17:31:57 +00:00
config_h_lines . append ( generate_define ( ' USE_I2C ' ) )
2021-08-16 22:33:30 +00: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 03:15:06 +00: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-16 22:33:30 +00:00
2022-09-26 00:04:21 +00: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 16:43:25 +00: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-16 22:33:30 +00: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 16:43:25 +00:00
@cli.argument ( ' -kb ' , ' --keyboard ' , arg_only = True , type = keyboard_folder , completer = keyboard_completer , help = ' Keyboard to generate config.h for. ' )
2021-08-16 22:33:30 +00: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 20:52:41 +00:00
# Determine our keyboard/keymap
2022-10-19 16:43:25 +00:00
if cli . args . filename :
user_keymap = parse_configurator_json ( cli . args . filename )
2022-10-21 01:21:17 +00:00
kb_info_json = dotty ( user_keymap . get ( ' config ' , { } ) )
2022-10-19 16:43:25 +00:00
elif cli . args . keyboard :
2021-08-18 20:52:41 +00:00
kb_info_json = dotty ( info_json ( cli . args . keyboard ) )
2022-10-19 16:43:25 +00:00
else :
cli . log . error ( ' You must supply a configurator export or `--keyboard`. ' )
cli . subcommands [ ' generate-config-h ' ] . print_help ( )
return False
2021-08-16 22:33:30 +00:00
# Build the info_config.h file.
2022-03-18 01:09:29 +00:00
config_h_lines = [ GPL2_HEADER_C_LIKE , GENERATED_HEADER_C_LIKE , ' #pragma once ' ]
2021-08-16 22:33:30 +00:00
generate_config_items ( kb_info_json , config_h_lines )
2022-02-27 12:39:24 +00:00
generate_matrix_size ( kb_info_json , config_h_lines )
2023-10-29 00:09:02 +00:00
generate_matrix_masked ( kb_info_json , config_h_lines )
2020-12-30 18:27:37 +00:00
if ' matrix_pins ' in kb_info_json :
config_h_lines . append ( matrix_pins ( kb_info_json [ ' matrix_pins ' ] ) )
2022-06-21 03:15:06 +00:00
if ' encoder ' in kb_info_json :
generate_encoder_config ( kb_info_json [ ' encoder ' ] , config_h_lines )
2021-08-16 22:33:30 +00:00
if ' split ' in kb_info_json :
generate_split_config ( kb_info_json , config_h_lines )
2022-09-26 00:04:21 +00: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 18:27:37 +00:00
# Show the results
2022-03-18 01:09:29 +00:00
dump_lines ( cli . args . output , config_h_lines , cli . args . quiet )