aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
m---------lib/chibios-contrib0
-rw-r--r--lib/python/qmk/cli/generate/autocorrect_data.py6
-rwxr-xr-xlib/python/qmk/cli/generate/config_h.py9
-rwxr-xr-xlib/python/qmk/cli/generate/rules_mk.py9
-rw-r--r--lib/python/qmk/cli/generate/version_h.py4
-rw-r--r--lib/python/qmk/cli/lint.py4
-rw-r--r--lib/python/qmk/cli/userspace/doctor.py4
-rw-r--r--lib/python/qmk/info.py71
-rw-r--r--lib/python/qmk/keymap.py20
-rw-r--r--lib/python/qmk/tests/test_cli_commands.py2
-rw-r--r--lib/python/qmk/tests/test_qmk_keymap.py1
-rw-r--r--lib/python/qmk/util.py10
12 files changed, 112 insertions, 28 deletions
diff --git a/lib/chibios-contrib b/lib/chibios-contrib
-Subproject 3ac181e4ca5cafddaf8b472baa1d09c2b24c77b
+Subproject 8d863d9ee4eecea68ad8d15f7e7c2b451aea79d
diff --git a/lib/python/qmk/cli/generate/autocorrect_data.py b/lib/python/qmk/cli/generate/autocorrect_data.py
index 01a29b46fe..4f322adce2 100644
--- a/lib/python/qmk/cli/generate/autocorrect_data.py
+++ b/lib/python/qmk/cli/generate/autocorrect_data.py
@@ -250,8 +250,8 @@ def to_hex(b: int) -> str:
@cli.argument('filename', type=normpath, help='The autocorrection database file')
-@cli.argument('-kb', '--keyboard', type=keyboard_folder, completer=keyboard_completer, help='The keyboard to build a firmware for. Ignored when a configurator export is supplied.')
-@cli.argument('-km', '--keymap', completer=keymap_completer, help='The keymap to build a firmware for. Ignored when a configurator export is supplied.')
+@cli.argument('-kb', '--keyboard', type=keyboard_folder, completer=keyboard_completer, help='The keyboard to build a firmware for. Ignored when a output file is supplied.')
+@cli.argument('-km', '--keymap', completer=keymap_completer, help='The keymap to build a firmware for. Ignored when a output file is supplied.')
@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.subcommand('Generate the autocorrection data file from a dictionary file.')
@@ -263,7 +263,7 @@ def generate_autocorrect_data(cli):
current_keyboard = cli.args.keyboard or cli.config.user.keyboard or cli.config.generate_autocorrect_data.keyboard
current_keymap = cli.args.keymap or cli.config.user.keymap or cli.config.generate_autocorrect_data.keymap
- if current_keyboard and current_keymap:
+ if not cli.args.output and current_keyboard and current_keymap:
cli.args.output = locate_keymap(current_keyboard, current_keymap).parent / 'autocorrect_data.h'
assert all(0 <= b <= 255 for b in data)
diff --git a/lib/python/qmk/cli/generate/config_h.py b/lib/python/qmk/cli/generate/config_h.py
index d6d0299291..1ade452f95 100755
--- a/lib/python/qmk/cli/generate/config_h.py
+++ b/lib/python/qmk/cli/generate/config_h.py
@@ -125,11 +125,12 @@ def generate_encoder_config(encoder_json, config_h_lines, postfix=''):
config_h_lines.append(generate_define(f'ENCODER_A_PINS{postfix}', f'{{ {", ".join(a_pads)} }}'))
config_h_lines.append(generate_define(f'ENCODER_B_PINS{postfix}', f'{{ {", ".join(b_pads)} }}'))
- if None in resolutions:
- cli.log.debug(f"Unable to generate ENCODER_RESOLUTION{postfix} configuration")
- elif len(resolutions) == 0:
+ if len(resolutions) == 0 or all(r is None for r in resolutions):
cli.log.debug(f"Skipping ENCODER_RESOLUTION{postfix} configuration")
- elif len(set(resolutions)) == 1:
+ return
+
+ resolutions = [4 if r is None else r for r in resolutions]
+ if len(set(resolutions)) == 1:
config_h_lines.append(generate_define(f'ENCODER_RESOLUTION{postfix}', resolutions[0]))
else:
config_h_lines.append(generate_define(f'ENCODER_RESOLUTIONS{postfix}', f'{{ {", ".join(map(str,resolutions))} }}'))
diff --git a/lib/python/qmk/cli/generate/rules_mk.py b/lib/python/qmk/cli/generate/rules_mk.py
index 358a22fd1d..16084bded1 100755
--- a/lib/python/qmk/cli/generate/rules_mk.py
+++ b/lib/python/qmk/cli/generate/rules_mk.py
@@ -96,11 +96,10 @@ def generate_rules_mk(cli):
rules_mk_lines.append(generate_rule('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(generate_rule('CUSTOM_MATRIX', 'lite'))
- else:
- rules_mk_lines.append(generate_rule('CUSTOM_MATRIX', 'yes'))
+ if kb_info_json.get('matrix_pins', {}).get('custom_lite'):
+ rules_mk_lines.append(generate_rule('CUSTOM_MATRIX', 'lite'))
+ elif kb_info_json.get('matrix_pins', {}).get('custom'):
+ rules_mk_lines.append(generate_rule('CUSTOM_MATRIX', 'yes'))
if converter:
rules_mk_lines.append(generate_rule('CONVERT_TO', converter))
diff --git a/lib/python/qmk/cli/generate/version_h.py b/lib/python/qmk/cli/generate/version_h.py
index fd87df3617..8156e85559 100644
--- a/lib/python/qmk/cli/generate/version_h.py
+++ b/lib/python/qmk/cli/generate/version_h.py
@@ -8,6 +8,7 @@ from qmk.path import normpath
from qmk.commands import dump_lines
from qmk.git import git_get_qmk_hash, git_get_version, git_is_dirty
from qmk.constants import GPL2_HEADER_C_LIKE, GENERATED_HEADER_C_LIKE
+from qmk.util import triplet_to_bcd
TIME_FMT = '%Y-%m-%d-%H:%M:%S'
@@ -32,12 +33,14 @@ def generate_version_h(cli):
git_dirty = False
git_version = "NA"
git_qmk_hash = "NA"
+ git_bcd_version = "0x00000000"
chibios_version = "NA"
chibios_contrib_version = "NA"
else:
git_dirty = git_is_dirty()
git_version = git_get_version() or current_time
git_qmk_hash = git_get_qmk_hash() or "Unknown"
+ git_bcd_version = triplet_to_bcd(git_version)
chibios_version = git_get_version("chibios", "os") or current_time
chibios_contrib_version = git_get_version("chibios-contrib", "os") or current_time
@@ -48,6 +51,7 @@ def generate_version_h(cli):
f"""
#define QMK_VERSION "{git_version}"
#define QMK_BUILDDATE "{current_time}"
+#define QMK_VERSION_BCD {git_bcd_version}
#define QMK_GIT_HASH "{git_qmk_hash}{'*' if git_dirty else ''}"
#define CHIBIOS_VERSION "{chibios_version}"
#define CHIBIOS_CONTRIB_VERSION "{chibios_contrib_version}"
diff --git a/lib/python/qmk/cli/lint.py b/lib/python/qmk/cli/lint.py
index 484ddb5bd9..8a128ce6d2 100644
--- a/lib/python/qmk/cli/lint.py
+++ b/lib/python/qmk/cli/lint.py
@@ -304,6 +304,10 @@ def keyboard_check(kb): # noqa C901
cli.log.error(f'{kb}: The file "{file}" should not exist!')
ok = False
+ if not _get_readme_files(kb):
+ cli.log.error(f'{kb}: Is missing a readme.md file!')
+ ok = False
+
for file in _get_readme_files(kb):
if _is_invalid_readme(file):
cli.log.error(f'{kb}: The file "{file}" still contains template tokens!')
diff --git a/lib/python/qmk/cli/userspace/doctor.py b/lib/python/qmk/cli/userspace/doctor.py
index 2b7e29aa7e..7c016e5a2f 100644
--- a/lib/python/qmk/cli/userspace/doctor.py
+++ b/lib/python/qmk/cli/userspace/doctor.py
@@ -2,10 +2,12 @@
# SPDX-License-Identifier: GPL-2.0-or-later
from milc import cli
-from qmk.constants import QMK_FIRMWARE
+from qmk.constants import QMK_FIRMWARE, HAS_QMK_USERSPACE
from qmk.cli.doctor.main import userspace_tests
@cli.subcommand('Checks userspace configuration.')
def userspace_doctor(cli):
userspace_tests(QMK_FIRMWARE)
+
+ return 0 if HAS_QMK_USERSPACE else 1
diff --git a/lib/python/qmk/info.py b/lib/python/qmk/info.py
index e8aad760de..e07fa0ccae 100644
--- a/lib/python/qmk/info.py
+++ b/lib/python/qmk/info.py
@@ -5,6 +5,7 @@ import os
from pathlib import Path
import jsonschema
from dotty_dict import dotty
+from enum import IntFlag
from milc import cli
@@ -21,6 +22,15 @@ true_values = ['1', 'on', 'yes']
false_values = ['0', 'off', 'no']
+class LedFlags(IntFlag):
+ ALL = 0xFF
+ NONE = 0x00
+ MODIFIER = 0x01
+ UNDERGLOW = 0x02
+ KEYLIGHT = 0x04
+ INDICATOR = 0x08
+
+
def _keyboard_in_layout_name(keyboard, layout):
"""Validate that a layout macro does not contain name of keyboard
"""
@@ -302,6 +312,24 @@ def _extract_features(info_data, rules):
return info_data
+def _extract_matrix_rules(info_data, rules):
+ """Find all the features enabled in rules.mk.
+ """
+ if rules.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 rules.mk, the rules.mk values win.')
+
+ if 'matrix_pins' not in info_data:
+ info_data['matrix_pins'] = {}
+
+ if rules['CUSTOM_MATRIX'] == 'lite':
+ info_data['matrix_pins']['custom_lite'] = True
+ else:
+ info_data['matrix_pins']['custom'] = True
+
+ return info_data
+
+
def _pin_name(pin):
"""Returns the proper representation for a pin.
"""
@@ -552,7 +580,6 @@ def _extract_matrix_info(info_data, config_c):
row_pins = config_c.get('MATRIX_ROW_PINS', '').replace('{', '').replace('}', '').strip()
col_pins = config_c.get('MATRIX_COL_PINS', '').replace('{', '').replace('}', '').strip()
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:
@@ -567,26 +594,20 @@ def _extract_matrix_info(info_data, config_c):
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_snippet['cols'] = _extract_pins(col_pins)
- info_snippet['rows'] = _extract_pins(row_pins)
+ if 'matrix_pins' not in info_data:
+ info_data['matrix_pins'] = {}
+
+ info_data['matrix_pins']['cols'] = _extract_pins(col_pins)
+ info_data['matrix_pins']['rows'] = _extract_pins(row_pins)
if direct_pins:
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_snippet['direct'] = _extract_direct_matrix(direct_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 'matrix_pins' not in info_data:
+ info_data['matrix_pins'] = {}
- if config_c['CUSTOM_MATRIX'] == 'lite':
- info_snippet['custom_lite'] = True
-
- if info_snippet:
- info_data['matrix_pins'] = info_snippet
+ info_data['matrix_pins']['direct'] = _extract_direct_matrix(direct_pins)
return info_data
@@ -755,6 +776,7 @@ def _extract_rules_mk(info_data, rules):
# Merge in config values that can't be easily mapped
_extract_features(info_data, rules)
+ _extract_matrix_rules(info_data, rules)
return info_data
@@ -800,6 +822,25 @@ def _extract_led_config(info_data, keyboard):
if info_data[feature].get('layout', None) and not info_data[feature].get('led_count', None):
info_data[feature]['led_count'] = len(info_data[feature]['layout'])
+ if info_data[feature].get('layout', None) and not info_data[feature].get('flag_steps', None):
+ flags = {LedFlags.ALL, LedFlags.NONE}
+ default_flags = {LedFlags.MODIFIER | LedFlags.KEYLIGHT, LedFlags.UNDERGLOW}
+
+ # if only a single flag is used, assume only all+none flags
+ kb_flags = set(x.get('flags', LedFlags.NONE) for x in info_data[feature]['layout'])
+ if len(kb_flags) > 1:
+ # check if any part of LED flag is with the defaults
+ unique_flags = set()
+ for candidate in default_flags:
+ if any(candidate & flag for flag in kb_flags):
+ unique_flags.add(candidate)
+
+ # if we still have a single flag, assume only all+none
+ if len(unique_flags) > 1:
+ flags.update(unique_flags)
+
+ info_data[feature]['flag_steps'] = sorted([int(flag) for flag in flags], reverse=True)
+
return info_data
diff --git a/lib/python/qmk/keymap.py b/lib/python/qmk/keymap.py
index 4cf07f59d6..0ac04f6f73 100644
--- a/lib/python/qmk/keymap.py
+++ b/lib/python/qmk/keymap.py
@@ -32,6 +32,7 @@ __INCLUDES__
__KEYMAP_GOES_HERE__
__ENCODER_MAP_GOES_HERE__
+__DIP_SWITCH_MAP_GOES_HERE__
__MACRO_OUTPUT_GOES_HERE__
#ifdef OTHER_KEYMAP_C
@@ -66,6 +67,19 @@ def _generate_encodermap_table(keymap_json):
return lines
+def _generate_dipswitchmap_table(keymap_json):
+ lines = [
+ '#if defined(DIP_SWITCH_ENABLE) && defined(DIP_SWITCH_MAP_ENABLE)',
+ 'const uint16_t PROGMEM dip_switch_map[NUM_DIP_SWITCHES][NUM_DIP_STATES] = {',
+ ]
+ for index, switch in enumerate(keymap_json['dip_switches']):
+ if index != 0:
+ lines[-1] = lines[-1] + ','
+ lines.append(f' DIP_SWITCH_OFF_ON({_strip_any(switch["off"])}, {_strip_any(switch["on"])})')
+ lines.extend(['};', '#endif // defined(DIP_SWITCH_ENABLE) && defined(DIP_SWITCH_MAP_ENABLE)'])
+ return lines
+
+
def _generate_macros_function(keymap_json):
macro_txt = [
'bool process_record_user(uint16_t keycode, keyrecord_t *record) {',
@@ -286,6 +300,12 @@ def generate_c(keymap_json):
encodermap = '\n'.join(encoder_txt)
new_keymap = new_keymap.replace('__ENCODER_MAP_GOES_HERE__', encodermap)
+ dipswitchmap = ''
+ if 'dip_switches' in keymap_json and keymap_json['dip_switches'] is not None:
+ dip_txt = _generate_dipswitchmap_table(keymap_json)
+ dipswitchmap = '\n'.join(dip_txt)
+ new_keymap = new_keymap.replace('__DIP_SWITCH_MAP_GOES_HERE__', dipswitchmap)
+
macros = ''
if 'macros' in keymap_json and keymap_json['macros'] is not None:
macro_txt = _generate_macros_function(keymap_json)
diff --git a/lib/python/qmk/tests/test_cli_commands.py b/lib/python/qmk/tests/test_cli_commands.py
index dd659fe0f2..2716459989 100644
--- a/lib/python/qmk/tests/test_cli_commands.py
+++ b/lib/python/qmk/tests/test_cli_commands.py
@@ -159,6 +159,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
+
#ifdef OTHER_KEYMAP_C
# include OTHER_KEYMAP_C
#endif // OTHER_KEYMAP_C
@@ -196,6 +197,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
+
#ifdef OTHER_KEYMAP_C
# include OTHER_KEYMAP_C
#endif // OTHER_KEYMAP_C
diff --git a/lib/python/qmk/tests/test_qmk_keymap.py b/lib/python/qmk/tests/test_qmk_keymap.py
index 80cc679b00..34360d3b6d 100644
--- a/lib/python/qmk/tests/test_qmk_keymap.py
+++ b/lib/python/qmk/tests/test_qmk_keymap.py
@@ -27,6 +27,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
+
#ifdef OTHER_KEYMAP_C
# include OTHER_KEYMAP_C
#endif // OTHER_KEYMAP_C
diff --git a/lib/python/qmk/util.py b/lib/python/qmk/util.py
index 8f99410e1d..6da684a577 100644
--- a/lib/python/qmk/util.py
+++ b/lib/python/qmk/util.py
@@ -3,9 +3,12 @@
import contextlib
import multiprocessing
import sys
+import re
from milc import cli
+TRIPLET_PATTERN = re.compile(r'^(\d+)\.(\d+)\.(\d+)')
+
maybe_exit_should_exit = True
maybe_exit_reraise = False
@@ -96,3 +99,10 @@ def parallel_map(*args, **kwargs):
# before the results are returned. Returning a list ensures results are
# materialised before any worker pool is shut down.
return list(map_fn(*args, **kwargs))
+
+
+def triplet_to_bcd(ver: str):
+ m = TRIPLET_PATTERN.match(ver)
+ if not m:
+ return '0x00000000'
+ return f'0x{int(m.group(1)):02d}{int(m.group(2)):02d}{int(m.group(3)):04d}'