From 8cd71917ce74dd8301e24d80f4eabb2bfa1a7c69 Mon Sep 17 00:00:00 2001 From: Joel Challis Date: Wed, 23 Apr 2025 01:27:47 +0100 Subject: Avoid duplication in generated community modules `rules.mk` (#25135) --- lib/python/qmk/cli/generate/community_modules.py | 65 +++++++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) (limited to 'lib/python/qmk/cli/generate/community_modules.py') diff --git a/lib/python/qmk/cli/generate/community_modules.py b/lib/python/qmk/cli/generate/community_modules.py index 23678a2fb5..e12daccf1c 100644 --- a/lib/python/qmk/cli/generate/community_modules.py +++ b/lib/python/qmk/cli/generate/community_modules.py @@ -8,7 +8,7 @@ import qmk.path from qmk.info import get_modules from qmk.keyboard import keyboard_completer, keyboard_folder from qmk.commands import dump_lines -from qmk.constants import GPL2_HEADER_C_LIKE, GENERATED_HEADER_C_LIKE +from qmk.constants import GPL2_HEADER_C_LIKE, GENERATED_HEADER_C_LIKE, GPL2_HEADER_SH_LIKE, GENERATED_HEADER_SH_LIKE from qmk.community_modules import module_api_list, load_module_jsons, find_module_path @@ -121,6 +121,69 @@ def _render_core_implementation(api, modules): return lines +def _generate_features_rules(features_dict): + lines = [] + for feature, enabled in features_dict.items(): + feature = feature.upper() + enabled = 'yes' if enabled else 'no' + lines.append(f'{feature}_ENABLE={enabled}') + return lines + + +def _generate_modules_rules(keyboard, filename): + lines = [] + modules = get_modules(keyboard, filename) + if len(modules) > 0: + lines.append('') + lines.append('OPT_DEFS += -DCOMMUNITY_MODULES_ENABLE=TRUE') + for module in modules: + module_path = qmk.path.unix_style_path(find_module_path(module)) + if not module_path: + raise FileNotFoundError(f"Module '{module}' not found.") + lines.append('') + lines.append(f'COMMUNITY_MODULES += {module_path.name}') # use module_path here instead of module as it may be a subdirectory + lines.append(f'OPT_DEFS += -DCOMMUNITY_MODULE_{module_path.name.upper()}_ENABLE=TRUE') + lines.append(f'COMMUNITY_MODULE_PATHS += {module_path}') + lines.append(f'VPATH += {module_path}') + lines.append(f'SRC += $(wildcard {module_path}/{module_path.name}.c)') + lines.append(f'MODULE_NAME_{module_path.name.upper()} := {module_path.name}') + lines.append(f'MODULE_PATH_{module_path.name.upper()} := {module_path}') + lines.append(f'-include {module_path}/rules.mk') + + module_jsons = load_module_jsons(modules) + for module_json in module_jsons: + if 'features' in module_json: + lines.append('') + lines.append(f'# Module: {module_json["module_name"]}') + lines.extend(_generate_features_rules(module_json['features'])) + return lines + + +@cli.argument('-o', '--output', arg_only=True, type=qmk.path.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('-e', '--escape', arg_only=True, action='store_true', help="Escape spaces in quiet mode") +@cli.argument('-kb', '--keyboard', arg_only=True, type=keyboard_folder, completer=keyboard_completer, help='Keyboard to generate rules.mk for.') +@cli.argument('filename', nargs='?', arg_only=True, type=qmk.path.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.') +@cli.subcommand('Creates a community_modules_rules_mk from a keymap.json file.') +def generate_community_modules_rules_mk(cli): + + rules_mk_lines = [GPL2_HEADER_SH_LIKE, GENERATED_HEADER_SH_LIKE] + + rules_mk_lines.extend(_generate_modules_rules(cli.args.keyboard, cli.args.filename)) + + # Show the results + dump_lines(cli.args.output, rules_mk_lines) + + if cli.args.output: + if cli.args.quiet: + if cli.args.escape: + print(cli.args.output.as_posix().replace(' ', '\\ ')) + else: + print(cli.args.output) + else: + cli.log.info('Wrote rules.mk to %s.', cli.args.output) + + @cli.argument('-o', '--output', arg_only=True, type=qmk.path.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', arg_only=True, type=keyboard_folder, completer=keyboard_completer, help='Keyboard to generate community_modules.h for.') -- cgit v1.2.3 From 12caf0be4eab171ffeb041cc153f9addb68f404e Mon Sep 17 00:00:00 2001 From: Drashna Jaelre Date: Sun, 4 May 2025 17:21:47 -0700 Subject: Add additional hooks for Community modules (#25050) --- data/constants/module_hooks/1.1.0.hjson | 55 ++++++++++++++++++++++++ docs/features/community_modules.md | 33 ++++++++------ lib/python/qmk/cli/generate/community_modules.py | 10 +++++ quantum/action_layer.c | 19 ++++++++ quantum/action_layer.h | 3 ++ quantum/led_matrix/led_matrix.c | 10 +++++ quantum/pointing_device/pointing_device.c | 9 +++- quantum/pointing_device/pointing_device.h | 1 + quantum/rgb_matrix/rgb_matrix.c | 10 +++++ 9 files changed, 137 insertions(+), 13 deletions(-) create mode 100644 data/constants/module_hooks/1.1.0.hjson (limited to 'lib/python/qmk/cli/generate/community_modules.py') diff --git a/data/constants/module_hooks/1.1.0.hjson b/data/constants/module_hooks/1.1.0.hjson new file mode 100644 index 0000000000..b50dad6a66 --- /dev/null +++ b/data/constants/module_hooks/1.1.0.hjson @@ -0,0 +1,55 @@ +{ + pointing_device_init: { + ret_type: void + args: void + guard: defined(POINTING_DEVICE_ENABLE) + } + pointing_device_task: { + ret_type: report_mouse_t + args: report_mouse_t mouse_report + call_params: mouse_report + guard: defined(POINTING_DEVICE_ENABLE) + header: report.h + } + rgb_matrix_indicators: { + ret_type: bool + args: void + guard: defined(RGB_MATRIX_ENABLE) + header: rgb_matrix.h + } + rgb_matrix_indicators_advanced: { + ret_type: bool + args: uint8_t led_min, uint8_t led_max + call_params: led_min, led_max + guard: defined(RGB_MATRIX_ENABLE) + header: rgb_matrix.h + } + led_matrix_indicators: { + ret_type: bool + args: void + guard: defined(LED_MATRIX_ENABLE) + header: led_matrix.h + } + led_matrix_indicators_advanced: { + ret_type: bool + args: uint8_t led_min, uint8_t led_max + call_params: led_min, led_max + guard: defined(LED_MATRIX_ENABLE) + header: led_matrix.h + } + default_layer_state_set: { + ret_type: layer_state_t + args: layer_state_t state + call_params: state + guard: !defined(NO_ACTION_LAYER) + header: action_layer.h + } + layer_state_set: { + ret_type: layer_state_t + args: layer_state_t state + call_params: state + guard: !defined(NO_ACTION_LAYER) + header: action_layer.h + } + +} diff --git a/docs/features/community_modules.md b/docs/features/community_modules.md index 52526c9fe8..69fc47f617 100644 --- a/docs/features/community_modules.md +++ b/docs/features/community_modules.md @@ -127,18 +127,27 @@ Introspection is a relatively advanced topic within QMK, and existing patterns s Community Modules may provide specializations for the following APIs: -| Base API | API Format | Example (`hello_world` module) | API Version | -|----------------------------|-------------------------------------|----------------------------------------|-------------| -| `keyboard_pre_init` | `keyboard_pre_init_` | `keyboard_pre_init_hello_world` | `0.1.0` | -| `keyboard_post_init` | `keyboard_post_init_` | `keyboard_post_init_hello_world` | `0.1.0` | -| `pre_process_record` | `pre_process_record_` | `pre_process_record_hello_world` | `0.1.0` | -| `process_record` | `process_record_` | `process_record_hello_world` | `0.1.0` | -| `post_process_record` | `post_process_record_` | `post_process_record_hello_world` | `0.1.0` | -| `housekeeping_task` | `housekeeping_task_` | `housekeeping_task_hello_world` | `1.0.0` | -| `suspend_power_down` | `suspend_power_down_` | `suspend_power_down_hello_world` | `1.0.0` | -| `suspend_wakeup_init` | `suspend_wakeup_init_` | `suspend_wakeup_init_hello_world` | `1.0.0` | -| `shutdown` | `shutdown_` | `shutdown_hello_world` | `1.0.0` | -| `process_detected_host_os` | `process_detected_host_os_` | `process_detected_host_os_hello_world` | `1.0.0` | +| Base API | API Format | Example (`hello_world` module) | API Version | +|----------------------------------|-------------------------------------------|---------------------------------------------|-------------| +| `keyboard_pre_init` | `keyboard_pre_init_` | `keyboard_pre_init_hello_world` | `0.1.0` | +| `keyboard_post_init` | `keyboard_post_init_` | `keyboard_post_init_hello_world` | `0.1.0` | +| `pre_process_record` | `pre_process_record_` | `pre_process_record_hello_world` | `0.1.0` | +| `process_record` | `process_record_` | `process_record_hello_world` | `0.1.0` | +| `post_process_record` | `post_process_record_` | `post_process_record_hello_world` | `0.1.0` | +| `housekeeping_task` | `housekeeping_task_` | `housekeeping_task_hello_world` | `1.0.0` | +| `suspend_power_down` | `suspend_power_down_` | `suspend_power_down_hello_world` | `1.0.0` | +| `suspend_wakeup_init` | `suspend_wakeup_init_` | `suspend_wakeup_init_hello_world` | `1.0.0` | +| `shutdown` | `shutdown_` | `shutdown_hello_world` | `1.0.0` | +| `process_detected_host_os` | `process_detected_host_os_` | `process_detected_host_os_hello_world` | `1.0.0` | +| `default_layer_state_set` | `default_layer_state_set_` | `default_layer_state_set_hello_world` | `1.1.0` | +| `layer_state_set` | `layer_state_set_` | `layer_state_set_hello_world` | `1.1.0` | +| `led_matrix_indicators` | `led_matrix_indicators_` | `led_matrix_indicators_hello_word` | `1.1.0` | +| `led_matrix_indicators_advanced` | `led_matrix_indicators_advanced_` | `led_matrix_indicators_advanced_hello_word` | `1.1.0` | +| `rgb_matrix_indicators` | `rgb_matrix_indicators_` | `rgb_matrix_indicators_hello_word` | `1.1.0` | +| `rgb_matrix_indicators_advanced` | `rgb_matrix_indicators_advanced_` | `rgb_matrix_indicators_advanced_hello_word` | `1.1.0` | +| `pointing_device_init` | `pointing_device_init_` | `pointing_device_init_hello_word` | `1.1.0` | +| `pointing_device_task` | `pointing_device_task_` | `pointing_device_task_hello_word` | `1.1.0` | + ::: info An unspecified API is disregarded if a Community Module does not provide a specialization for it. diff --git a/lib/python/qmk/cli/generate/community_modules.py b/lib/python/qmk/cli/generate/community_modules.py index e12daccf1c..61e24077d3 100644 --- a/lib/python/qmk/cli/generate/community_modules.py +++ b/lib/python/qmk/cli/generate/community_modules.py @@ -76,6 +76,8 @@ def _render_api_implementations(api, module): lines.append(f'__attribute__((weak)) {api.ret_type} {api.name}_{module_name}_user({api.args}) {{') if api.ret_type == 'bool': lines.append(' return true;') + elif api.ret_type in ['layer_state_t', 'report_mouse_t']: + lines.append(f' return {api.call_params};') else: pass lines.append('}') @@ -86,6 +88,8 @@ def _render_api_implementations(api, module): if api.ret_type == 'bool': lines.append(f' if(!{api.name}_{module_name}_user({api.call_params})) {{ return false; }}') lines.append(' return true;') + elif api.ret_type in ['layer_state_t', 'report_mouse_t']: + lines.append(f' return {api.name}_{module_name}_user({api.call_params});') else: lines.append(f' {api.name}_{module_name}_user({api.call_params});') lines.append('}') @@ -96,6 +100,8 @@ def _render_api_implementations(api, module): if api.ret_type == 'bool': lines.append(f' if(!{api.name}_{module_name}_kb({api.call_params})) {{ return false; }}') lines.append(' return true;') + elif api.ret_type in ['layer_state_t', 'report_mouse_t']: + lines.append(f' return {api.name}_{module_name}_kb({api.call_params});') else: lines.append(f' {api.name}_{module_name}_kb({api.call_params});') lines.append('}') @@ -113,10 +119,14 @@ def _render_core_implementation(api, modules): module_name = Path(module).name if api.ret_type == 'bool': lines.append(f' && {api.name}_{module_name}({api.call_params})') + elif api.ret_type in ['layer_state_t', 'report_mouse_t']: + lines.append(f' {api.call_params} = {api.name}_{module_name}({api.call_params});') else: lines.append(f' {api.name}_{module_name}({api.call_params});') if api.ret_type == 'bool': lines.append(' ;') + elif api.ret_type in ['layer_state_t', 'report_mouse_t']: + lines.append(f' return {api.call_params};') lines.append('}') return lines diff --git a/quantum/action_layer.c b/quantum/action_layer.c index 7c09a5bd1e..5828dcb824 100644 --- a/quantum/action_layer.c +++ b/quantum/action_layer.c @@ -27,11 +27,20 @@ __attribute__((weak)) layer_state_t default_layer_state_set_kb(layer_state_t sta return default_layer_state_set_user(state); } +/** \brief Default Layer State Set At Module Level + * + * Run module code on default layer state change + */ +__attribute__((weak)) layer_state_t default_layer_state_set_modules(layer_state_t state) { + return state; +} + /** \brief Default Layer State Set * * Static function to set the default layer state, prints debug info and clears keys */ static void default_layer_state_set(layer_state_t state) { + state = default_layer_state_set_modules(state); state = default_layer_state_set_kb(state); ac_dprintf("default_layer_state: "); default_layer_debug(); @@ -107,11 +116,21 @@ __attribute__((weak)) layer_state_t layer_state_set_kb(layer_state_t state) { return layer_state_set_user(state); } +/** \brief Layer state set modules + * + * Runs module code on layer state change + */ + +__attribute__((weak)) layer_state_t layer_state_set_modules(layer_state_t state) { + return state; +} + /** \brief Layer state set * * Sets the layer to match the specified state (a bitmask) */ void layer_state_set(layer_state_t state) { + state = layer_state_set_modules(state); state = layer_state_set_kb(state); ac_dprintf("layer_state: "); layer_debug(); diff --git a/quantum/action_layer.h b/quantum/action_layer.h index a2410d49a5..067e33cdb5 100644 --- a/quantum/action_layer.h +++ b/quantum/action_layer.h @@ -78,6 +78,7 @@ extern layer_state_t default_layer_state; void default_layer_debug(void); void default_layer_set(layer_state_t state); +__attribute__((weak)) layer_state_t default_layer_state_set_modules(layer_state_t state); __attribute__((weak)) layer_state_t default_layer_state_set_kb(layer_state_t state); __attribute__((weak)) layer_state_t default_layer_state_set_user(layer_state_t state); @@ -114,6 +115,7 @@ void layer_and(layer_state_t state); void layer_xor(layer_state_t state); layer_state_t layer_state_set_user(layer_state_t state); layer_state_t layer_state_set_kb(layer_state_t state); +layer_state_t layer_state_set_modules(layer_state_t state); /** * @brief Applies the tri layer to global layer state. Not be used in layer_state_set_(kb|user) functions. @@ -149,6 +151,7 @@ layer_state_t update_tri_layer_state(layer_state_t state, uint8_t layer1, uint8_ # define layer_or(state) (void)state # define layer_and(state) (void)state # define layer_xor(state) (void)state +# define layer_state_set_modules(state) (void)state # define layer_state_set_kb(state) (void)state # define layer_state_set_user(state) (void)state # define update_tri_layer(layer1, layer2, layer3) diff --git a/quantum/led_matrix/led_matrix.c b/quantum/led_matrix/led_matrix.c index f9d76e2776..00bc199ecf 100644 --- a/quantum/led_matrix/led_matrix.c +++ b/quantum/led_matrix/led_matrix.c @@ -358,7 +358,12 @@ void led_matrix_task(void) { } } +__attribute__((weak)) bool led_matrix_indicators_modules(void) { + return true; +} + void led_matrix_indicators(void) { + led_matrix_indicators_modules(); led_matrix_indicators_kb(); } @@ -370,6 +375,10 @@ __attribute__((weak)) bool led_matrix_indicators_user(void) { return true; } +__attribute__((weak)) bool led_matrix_indicators_advanced_modules(uint8_t led_min, uint8_t led_max) { + return true; +} + void led_matrix_indicators_advanced(effect_params_t *params) { /* special handling is needed for "params->iter", since it's already been incremented. * Could move the invocations to led_task_render, but then it's missing a few checks @@ -377,6 +386,7 @@ void led_matrix_indicators_advanced(effect_params_t *params) { * led_task_render, right before the iter++ line. */ LED_MATRIX_USE_LIMITS_ITER(min, max, params->iter - 1); + led_matrix_indicators_advanced_modules(min, max); led_matrix_indicators_advanced_kb(min, max); } diff --git a/quantum/pointing_device/pointing_device.c b/quantum/pointing_device/pointing_device.c index 5ee65c9c61..564c2d294c 100644 --- a/quantum/pointing_device/pointing_device.c +++ b/quantum/pointing_device/pointing_device.c @@ -109,6 +109,11 @@ const pointing_device_driver_t custom_pointing_device_driver = { const pointing_device_driver_t *pointing_device_driver = &POINTING_DEVICE_DRIVER(POINTING_DEVICE_DRIVER_NAME); +__attribute__((weak)) void pointing_device_init_modules(void) {} +__attribute__((weak)) report_mouse_t pointing_device_task_modules(report_mouse_t mouse_report) { + return mouse_report; +} + /** * @brief Keyboard level code pointing device initialisation * @@ -190,6 +195,7 @@ __attribute__((weak)) void pointing_device_init(void) { } #endif + pointing_device_init_modules(); pointing_device_init_kb(); pointing_device_init_user(); } @@ -319,8 +325,9 @@ __attribute__((weak)) bool pointing_device_task(void) { local_mouse_report = is_keyboard_left() ? pointing_device_task_combined_kb(local_mouse_report, shared_mouse_report) : pointing_device_task_combined_kb(shared_mouse_report, local_mouse_report); #else local_mouse_report = pointing_device_adjust_by_defines(local_mouse_report); - local_mouse_report = pointing_device_task_kb(local_mouse_report); #endif + local_mouse_report = pointing_device_task_modules(local_mouse_report); + local_mouse_report = pointing_device_task_kb(local_mouse_report); // automatic mouse layer function #ifdef POINTING_DEVICE_AUTO_MOUSE_ENABLE pointing_device_task_auto_mouse(local_mouse_report); diff --git a/quantum/pointing_device/pointing_device.h b/quantum/pointing_device/pointing_device.h index d8b583c87e..e7a0819ed9 100644 --- a/quantum/pointing_device/pointing_device.h +++ b/quantum/pointing_device/pointing_device.h @@ -17,6 +17,7 @@ along with this program. If not, see . #pragma once +#include #include #include "host.h" #include "report.h" diff --git a/quantum/rgb_matrix/rgb_matrix.c b/quantum/rgb_matrix/rgb_matrix.c index 3fc9085f06..94852e3520 100644 --- a/quantum/rgb_matrix/rgb_matrix.c +++ b/quantum/rgb_matrix/rgb_matrix.c @@ -393,7 +393,12 @@ void rgb_matrix_task(void) { } } +__attribute__((weak)) bool rgb_matrix_indicators_modules(void) { + return true; +} + void rgb_matrix_indicators(void) { + rgb_matrix_indicators_modules(); rgb_matrix_indicators_kb(); } @@ -433,6 +438,10 @@ struct rgb_matrix_limits_t rgb_matrix_get_limits(uint8_t iter) { return limits; } +__attribute__((weak)) bool rgb_matrix_indicators_advanced_modules(uint8_t led_min, uint8_t led_max) { + return true; +} + void rgb_matrix_indicators_advanced(effect_params_t *params) { /* special handling is needed for "params->iter", since it's already been incremented. * Could move the invocations to rgb_task_render, but then it's missing a few checks @@ -440,6 +449,7 @@ void rgb_matrix_indicators_advanced(effect_params_t *params) { * rgb_task_render, right before the iter++ line. */ RGB_MATRIX_USE_LIMITS_ITER(min, max, params->iter - 1); + rgb_matrix_indicators_advanced_modules(min, max); rgb_matrix_indicators_advanced_kb(min, max); } -- cgit v1.2.3 From f4171412a676ae3cbd1cd50e859a7deb1a554e15 Mon Sep 17 00:00:00 2001 From: Pascal Getreuer Date: Sun, 11 May 2025 16:30:19 -0700 Subject: Enable community modules to define LED matrix and RGB matrix effects. (#25187) Co-authored-by: Joel Challis --- builddefs/build_keyboard.mk | 13 +++- data/constants/module_hooks/1.1.1.hjson | 3 + docs/features/community_modules.md | 8 +++ keyboards/handwired/onekey/info.json | 12 ++++ .../keymaps/cm_flow_led_matrix_effect/config.h | 16 +++++ .../keymaps/cm_flow_led_matrix_effect/keymap.c | 27 ++++++++ .../keymaps/cm_flow_led_matrix_effect/keymap.json | 3 + .../keymaps/cm_flow_rgb_matrix_effect/config.h | 16 +++++ .../keymaps/cm_flow_rgb_matrix_effect/keymap.c | 27 ++++++++ .../keymaps/cm_flow_rgb_matrix_effect/keymap.json | 3 + lib/python/qmk/cli/generate/community_modules.py | 75 +++++++++++----------- .../flow_led_matrix_effect/led_matrix_module.inc | 58 +++++++++++++++++ modules/qmk/flow_led_matrix_effect/qmk_module.json | 8 +++ modules/qmk/flow_rgb_matrix_effect/qmk_module.json | 8 +++ .../flow_rgb_matrix_effect/rgb_matrix_module.inc | 64 ++++++++++++++++++ quantum/led_matrix/led_matrix.c | 12 ++++ quantum/led_matrix/led_matrix.h | 6 ++ quantum/rgb_matrix/rgb_matrix.c | 12 ++++ quantum/rgb_matrix/rgb_matrix.h | 6 ++ 19 files changed, 339 insertions(+), 38 deletions(-) create mode 100644 data/constants/module_hooks/1.1.1.hjson create mode 100644 keyboards/handwired/onekey/keymaps/cm_flow_led_matrix_effect/config.h create mode 100644 keyboards/handwired/onekey/keymaps/cm_flow_led_matrix_effect/keymap.c create mode 100644 keyboards/handwired/onekey/keymaps/cm_flow_led_matrix_effect/keymap.json create mode 100644 keyboards/handwired/onekey/keymaps/cm_flow_rgb_matrix_effect/config.h create mode 100644 keyboards/handwired/onekey/keymaps/cm_flow_rgb_matrix_effect/keymap.c create mode 100644 keyboards/handwired/onekey/keymaps/cm_flow_rgb_matrix_effect/keymap.json create mode 100644 modules/qmk/flow_led_matrix_effect/led_matrix_module.inc create mode 100644 modules/qmk/flow_led_matrix_effect/qmk_module.json create mode 100644 modules/qmk/flow_rgb_matrix_effect/qmk_module.json create mode 100644 modules/qmk/flow_rgb_matrix_effect/rgb_matrix_module.inc (limited to 'lib/python/qmk/cli/generate/community_modules.py') diff --git a/builddefs/build_keyboard.mk b/builddefs/build_keyboard.mk index 514191b17d..c2c47c00fb 100644 --- a/builddefs/build_keyboard.mk +++ b/builddefs/build_keyboard.mk @@ -274,10 +274,19 @@ $(INTERMEDIATE_OUTPUT)/src/community_modules_introspection.h: $(KEYMAP_JSON) $(D $(eval CMD=$(QMK_BIN) generate-community-modules-introspection-h -kb $(KEYBOARD) --quiet --output $(INTERMEDIATE_OUTPUT)/src/community_modules_introspection.h $(KEYMAP_JSON)) @$(BUILD_CMD) -SRC += $(INTERMEDIATE_OUTPUT)/src/community_modules.c +$(INTERMEDIATE_OUTPUT)/src/led_matrix_community_modules.inc: $(KEYMAP_JSON) $(DD_CONFIG_FILES) + @$(SILENT) || printf "$(MSG_GENERATING) $@" | $(AWK_CMD) + $(eval CMD=$(QMK_BIN) generate-led-matrix-community-modules-inc -kb $(KEYBOARD) --quiet --output $(INTERMEDIATE_OUTPUT)/src/led_matrix_community_modules.inc $(KEYMAP_JSON)) + @$(BUILD_CMD) -generated-files: $(INTERMEDIATE_OUTPUT)/src/community_modules.h $(INTERMEDIATE_OUTPUT)/src/community_modules.c $(INTERMEDIATE_OUTPUT)/src/community_modules_introspection.c $(INTERMEDIATE_OUTPUT)/src/community_modules_introspection.h +$(INTERMEDIATE_OUTPUT)/src/rgb_matrix_community_modules.inc: $(KEYMAP_JSON) $(DD_CONFIG_FILES) + @$(SILENT) || printf "$(MSG_GENERATING) $@" | $(AWK_CMD) + $(eval CMD=$(QMK_BIN) generate-rgb-matrix-community-modules-inc -kb $(KEYBOARD) --quiet --output $(INTERMEDIATE_OUTPUT)/src/rgb_matrix_community_modules.inc $(KEYMAP_JSON)) + @$(BUILD_CMD) + +SRC += $(INTERMEDIATE_OUTPUT)/src/community_modules.c +generated-files: $(INTERMEDIATE_OUTPUT)/src/community_modules.h $(INTERMEDIATE_OUTPUT)/src/community_modules.c $(INTERMEDIATE_OUTPUT)/src/community_modules_introspection.c $(INTERMEDIATE_OUTPUT)/src/community_modules_introspection.h $(INTERMEDIATE_OUTPUT)/src/led_matrix_community_modules.inc $(INTERMEDIATE_OUTPUT)/src/rgb_matrix_community_modules.inc include $(BUILDDEFS_PATH)/converters.mk diff --git a/data/constants/module_hooks/1.1.1.hjson b/data/constants/module_hooks/1.1.1.hjson new file mode 100644 index 0000000000..49f5d0d5d0 --- /dev/null +++ b/data/constants/module_hooks/1.1.1.hjson @@ -0,0 +1,3 @@ +{ + // This version exists to signify addition of LED/RGB effect support. +} diff --git a/docs/features/community_modules.md b/docs/features/community_modules.md index 8dede47bd4..eff07c939a 100644 --- a/docs/features/community_modules.md +++ b/docs/features/community_modules.md @@ -123,6 +123,14 @@ The source file may provide functions which allow access to information specifie Introspection is a relatively advanced topic within QMK, and existing patterns should be followed. If you need help please [open an issue](https://github.com/qmk/qmk_firmware/issues/new) or [chat with us on Discord](https://discord.gg/qmk). ::: +### `led_matrix_module.inc` + +This file defines LED matrix effects in the same form as used with `led_matrix_kb.inc` and `led_matrix_user.inc` (see [Custom LED Matrix Effects](led_matrix#custom-led-matrix-effects)). Effect mode names are prepended with `LED_MATRIX_COMMUNITY_MODULE_`. + +### `rgb_matrix_module.inc` + +This file defines RGB matrix effects in the same form as used with `rgb_matrix_kb.inc` and `rgb_matrix_user.inc` (see [Custom RGB Matrix Effects](rgb_matrix#custom-rgb-matrix-effects)). Effect mode names are prepended with `RGB_MATRIX_COMMUNITY_MODULE_`. + ### Compatible APIs Community Modules may provide specializations for the following APIs: diff --git a/keyboards/handwired/onekey/info.json b/keyboards/handwired/onekey/info.json index 7b6b7ddab8..d5f650f1bd 100644 --- a/keyboards/handwired/onekey/info.json +++ b/keyboards/handwired/onekey/info.json @@ -26,5 +26,17 @@ {"x": 0, "y": 0, "matrix": [0, 0]} ] } + }, + "led_matrix": { + "driver": "snled27351", + "layout": [ + {"matrix": [0, 0], "x": 0, "y": 0, "flags": 1} + ] + }, + "rgb_matrix": { + "driver": "snled27351", + "layout": [ + {"matrix": [0, 0], "x": 0, "y": 0, "flags": 1} + ] } } diff --git a/keyboards/handwired/onekey/keymaps/cm_flow_led_matrix_effect/config.h b/keyboards/handwired/onekey/keymaps/cm_flow_led_matrix_effect/config.h new file mode 100644 index 0000000000..aed1e4ac6f --- /dev/null +++ b/keyboards/handwired/onekey/keymaps/cm_flow_led_matrix_effect/config.h @@ -0,0 +1,16 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once + +#define SNLED27351_I2C_ADDRESS_1 SNLED27351_I2C_ADDRESS_GND diff --git a/keyboards/handwired/onekey/keymaps/cm_flow_led_matrix_effect/keymap.c b/keyboards/handwired/onekey/keymaps/cm_flow_led_matrix_effect/keymap.c new file mode 100644 index 0000000000..0bd835ff25 --- /dev/null +++ b/keyboards/handwired/onekey/keymaps/cm_flow_led_matrix_effect/keymap.c @@ -0,0 +1,27 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// This keymap serves as a test for modules/qmk/flow_led_matrix_effect. + +#include QMK_KEYBOARD_H + +const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {LAYOUT_ortho_1x1(LM_TOGG)}; + +const snled27351_led_t PROGMEM g_snled27351_leds[LED_MATRIX_LED_COUNT] = { + {0, CB6_CA1}, +}; + +void keyboard_post_init_user(void) { + led_matrix_mode_noeeprom(LED_MATRIX_COMMUNITY_MODULE_FLOW); +} diff --git a/keyboards/handwired/onekey/keymaps/cm_flow_led_matrix_effect/keymap.json b/keyboards/handwired/onekey/keymaps/cm_flow_led_matrix_effect/keymap.json new file mode 100644 index 0000000000..0ff6bf5a4d --- /dev/null +++ b/keyboards/handwired/onekey/keymaps/cm_flow_led_matrix_effect/keymap.json @@ -0,0 +1,3 @@ +{ + "modules": ["qmk/flow_led_matrix_effect"] +} diff --git a/keyboards/handwired/onekey/keymaps/cm_flow_rgb_matrix_effect/config.h b/keyboards/handwired/onekey/keymaps/cm_flow_rgb_matrix_effect/config.h new file mode 100644 index 0000000000..aed1e4ac6f --- /dev/null +++ b/keyboards/handwired/onekey/keymaps/cm_flow_rgb_matrix_effect/config.h @@ -0,0 +1,16 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once + +#define SNLED27351_I2C_ADDRESS_1 SNLED27351_I2C_ADDRESS_GND diff --git a/keyboards/handwired/onekey/keymaps/cm_flow_rgb_matrix_effect/keymap.c b/keyboards/handwired/onekey/keymaps/cm_flow_rgb_matrix_effect/keymap.c new file mode 100644 index 0000000000..72ef2d3f80 --- /dev/null +++ b/keyboards/handwired/onekey/keymaps/cm_flow_rgb_matrix_effect/keymap.c @@ -0,0 +1,27 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// This keymap serves as a test for modules/qmk/flow_rgb_matrix_effect. + +#include QMK_KEYBOARD_H + +const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {LAYOUT_ortho_1x1(RM_TOGG)}; + +const snled27351_led_t PROGMEM g_snled27351_leds[LED_MATRIX_LED_COUNT] = { + {0, CB6_CA1}, +}; + +void keyboard_post_init_user(void) { + rgb_matrix_mode_noeeprom(RGB_MATRIX_COMMUNITY_MODULE_FLOW); +} diff --git a/keyboards/handwired/onekey/keymaps/cm_flow_rgb_matrix_effect/keymap.json b/keyboards/handwired/onekey/keymaps/cm_flow_rgb_matrix_effect/keymap.json new file mode 100644 index 0000000000..56d2342867 --- /dev/null +++ b/keyboards/handwired/onekey/keymaps/cm_flow_rgb_matrix_effect/keymap.json @@ -0,0 +1,3 @@ +{ + "modules": ["qmk/flow_rgb_matrix_effect"] +} diff --git a/lib/python/qmk/cli/generate/community_modules.py b/lib/python/qmk/cli/generate/community_modules.py index 61e24077d3..1f37b760ca 100644 --- a/lib/python/qmk/cli/generate/community_modules.py +++ b/lib/python/qmk/cli/generate/community_modules.py @@ -278,33 +278,32 @@ def generate_community_modules_c(cli): dump_lines(cli.args.output, lines, cli.args.quiet, remove_repeated_newlines=True) +def _generate_include_per_module(cli, include_file_name): + """Generates C code to include "/include_file_name" for each module.""" + if cli.args.output and cli.args.output.name == '-': + cli.args.output = None + + lines = [GPL2_HEADER_C_LIKE, GENERATED_HEADER_C_LIKE] + + for module in get_modules(cli.args.keyboard, cli.args.filename): + full_path = f'{find_module_path(module)}/{include_file_name}' + lines.append('') + lines.append(f'#if __has_include("{full_path}")') + lines.append(f'#include "{full_path}"') + lines.append(f'#endif // __has_include("{full_path}")') + + dump_lines(cli.args.output, lines, cli.args.quiet, remove_repeated_newlines=True) + + @cli.argument('-o', '--output', arg_only=True, type=qmk.path.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', arg_only=True, type=keyboard_folder, completer=keyboard_completer, help='Keyboard to generate community_modules.c for.') +@cli.argument('-kb', '--keyboard', arg_only=True, type=keyboard_folder, completer=keyboard_completer, help='Keyboard to generate community_modules_introspection.h for.') @cli.argument('filename', nargs='?', type=qmk.path.FileType('r'), arg_only=True, completer=FilesCompleter('.json'), help='Configurator JSON file') @cli.subcommand('Creates a community_modules_introspection.h from a keymap.json file.') def generate_community_modules_introspection_h(cli): """Creates a community_modules_introspection.h from a keymap.json file """ - if cli.args.output and cli.args.output.name == '-': - cli.args.output = None - - lines = [ - GPL2_HEADER_C_LIKE, - GENERATED_HEADER_C_LIKE, - '', - ] - - modules = get_modules(cli.args.keyboard, cli.args.filename) - if len(modules) > 0: - for module in modules: - module_path = find_module_path(module) - lines.append(f'#if __has_include("{module_path}/introspection.h")') - lines.append(f'#include "{module_path}/introspection.h"') - lines.append(f'#endif // __has_include("{module_path}/introspection.h")') - lines.append('') - - dump_lines(cli.args.output, lines, cli.args.quiet, remove_repeated_newlines=True) + _generate_include_per_module(cli, 'introspection.h') @cli.argument('-o', '--output', arg_only=True, type=qmk.path.normpath, help='File to write to') @@ -315,22 +314,26 @@ def generate_community_modules_introspection_h(cli): def generate_community_modules_introspection_c(cli): """Creates a community_modules_introspection.c from a keymap.json file """ - if cli.args.output and cli.args.output.name == '-': - cli.args.output = None + _generate_include_per_module(cli, 'introspection.c') - lines = [ - GPL2_HEADER_C_LIKE, - GENERATED_HEADER_C_LIKE, - '', - ] - modules = get_modules(cli.args.keyboard, cli.args.filename) - if len(modules) > 0: - for module in modules: - module_path = find_module_path(module) - lines.append(f'#if __has_include("{module_path}/introspection.c")') - lines.append(f'#include "{module_path}/introspection.c"') - lines.append(f'#endif // __has_include("{module_path}/introspection.c")') - lines.append('') +@cli.argument('-o', '--output', arg_only=True, type=qmk.path.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', arg_only=True, type=keyboard_folder, completer=keyboard_completer, help='Keyboard to generate led_matrix_community_modules.inc for.') +@cli.argument('filename', nargs='?', type=qmk.path.FileType('r'), arg_only=True, completer=FilesCompleter('.json'), help='Configurator JSON file') +@cli.subcommand('Creates an led_matrix_community_modules.inc from a keymap.json file.') +def generate_led_matrix_community_modules_inc(cli): + """Creates an led_matrix_community_modules.inc from a keymap.json file + """ + _generate_include_per_module(cli, 'led_matrix_module.inc') - dump_lines(cli.args.output, lines, cli.args.quiet, remove_repeated_newlines=True) + +@cli.argument('-o', '--output', arg_only=True, type=qmk.path.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', arg_only=True, type=keyboard_folder, completer=keyboard_completer, help='Keyboard to generate rgb_matrix_community_modules.inc for.') +@cli.argument('filename', nargs='?', type=qmk.path.FileType('r'), arg_only=True, completer=FilesCompleter('.json'), help='Configurator JSON file') +@cli.subcommand('Creates an rgb_matrix_community_modules.inc from a keymap.json file.') +def generate_rgb_matrix_community_modules_inc(cli): + """Creates an rgb_matrix_community_modules.inc from a keymap.json file + """ + _generate_include_per_module(cli, 'rgb_matrix_module.inc') diff --git a/modules/qmk/flow_led_matrix_effect/led_matrix_module.inc b/modules/qmk/flow_led_matrix_effect/led_matrix_module.inc new file mode 100644 index 0000000000..734e0f3494 --- /dev/null +++ b/modules/qmk/flow_led_matrix_effect/led_matrix_module.inc @@ -0,0 +1,58 @@ +// Copyright 2024-2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +LED_MATRIX_EFFECT(FLOW) + +#ifdef LED_MATRIX_CUSTOM_EFFECT_IMPLS + +// "Flow" animated effect. Draws moving wave patterns mimicking the appearance +// of flowing liquid. For interesting variety of patterns, space coordinates are +// slowly rotated and a function of several sine waves is evaluated. +static bool FLOW(effect_params_t* params) { + LED_MATRIX_USE_LIMITS(led_min, led_max); + + static uint16_t wrap_correction = 0; + static uint8_t last_high_byte = 0; + const uint8_t time_scale = 1 + led_matrix_eeconfig.speed / 8; + const uint8_t high_byte = (uint8_t)(g_led_timer >> 16); + if (last_high_byte != high_byte) { + last_high_byte = high_byte; + wrap_correction += ((uint16_t)time_scale) << 8; + } + const uint16_t time = scale16by8(g_led_timer, time_scale) + wrap_correction; + + // Compute rotation coefficients with 7 fractional bits. + const int8_t rot_c = cos8(time / 4) - 128; + const int8_t rot_s = sin8(time / 4) - 128; + const uint8_t omega = 32 + sin8(time) / 4; + + for (uint8_t i = led_min; i < led_max; ++i) { + LED_MATRIX_TEST_LED_FLAGS(); + const uint8_t x = g_led_config.point[i].x; + const uint8_t y = g_led_config.point[i].y; + + // Rotate (x, y) by the 2x2 rotation matrix described by rot_c, rot_s. + const uint8_t x1 = (uint8_t)((((int16_t)rot_c) * ((int16_t)x)) / 128) - (uint8_t)((((int16_t)rot_s) * ((int16_t)y)) / 128); + const uint8_t y1 = (uint8_t)((((int16_t)rot_s) * ((int16_t)x)) / 128) + (uint8_t)((((int16_t)rot_c) * ((int16_t)y)) / 128); + + uint8_t value = scale8(sin8(x1 - 2 * time), omega) + y1 + time / 4; + value = (value <= 127) ? value : (255 - value); + + led_matrix_set_value(i, scale8(led_matrix_eeconfig.val, value)); + } + + return led_matrix_check_finished_leds(led_max); +} + +#endif // LED_MATRIX_CUSTOM_EFFECT_IMPLS diff --git a/modules/qmk/flow_led_matrix_effect/qmk_module.json b/modules/qmk/flow_led_matrix_effect/qmk_module.json new file mode 100644 index 0000000000..2d047cd0d0 --- /dev/null +++ b/modules/qmk/flow_led_matrix_effect/qmk_module.json @@ -0,0 +1,8 @@ +{ + "module_name": "Flow LED matrix effect", + "maintainer": "QMK Maintainers", + "license": "Apache-2.0", + "features": { + "led_matrix": true + } +} diff --git a/modules/qmk/flow_rgb_matrix_effect/qmk_module.json b/modules/qmk/flow_rgb_matrix_effect/qmk_module.json new file mode 100644 index 0000000000..3e42fe1ef4 --- /dev/null +++ b/modules/qmk/flow_rgb_matrix_effect/qmk_module.json @@ -0,0 +1,8 @@ +{ + "module_name": "Flow RGB matrix effect", + "maintainer": "QMK Maintainers", + "license": "Apache-2.0", + "features": { + "rgb_matrix": true + } +} diff --git a/modules/qmk/flow_rgb_matrix_effect/rgb_matrix_module.inc b/modules/qmk/flow_rgb_matrix_effect/rgb_matrix_module.inc new file mode 100644 index 0000000000..410838f7ec --- /dev/null +++ b/modules/qmk/flow_rgb_matrix_effect/rgb_matrix_module.inc @@ -0,0 +1,64 @@ +// Copyright 2024-2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +RGB_MATRIX_EFFECT(FLOW) + +#ifdef RGB_MATRIX_CUSTOM_EFFECT_IMPLS + +// "Flow" animated effect. Draws moving wave patterns mimicking the appearance +// of flowing liquid. For interesting variety of patterns, space coordinates are +// slowly rotated and a function of several sine waves is evaluated. +static bool FLOW(effect_params_t* params) { + RGB_MATRIX_USE_LIMITS(led_min, led_max); + + static uint16_t wrap_correction = 0; + static uint8_t last_high_byte = 0; + const uint8_t time_scale = 1 + rgb_matrix_config.speed / 8; + const uint8_t high_byte = (uint8_t)(g_rgb_timer >> 16); + if (last_high_byte != high_byte) { + last_high_byte = high_byte; + wrap_correction += ((uint16_t)time_scale) << 8; + } + const uint16_t time = scale16by8(g_rgb_timer, time_scale) + wrap_correction; + + // Compute rotation coefficients with 7 fractional bits. + const int8_t rot_c = cos8(time / 4) - 128; + const int8_t rot_s = sin8(time / 4) - 128; + const uint8_t omega = 32 + sin8(time) / 4; + + for (uint8_t i = led_min; i < led_max; ++i) { + RGB_MATRIX_TEST_LED_FLAGS(); + const uint8_t x = g_led_config.point[i].x; + const uint8_t y = g_led_config.point[i].y; + + // Rotate (x, y) by the 2x2 rotation matrix described by rot_c, rot_s. + const uint8_t x1 = (uint8_t)((((int16_t)rot_c) * ((int16_t)x)) / 128) - (uint8_t)((((int16_t)rot_s) * ((int16_t)y)) / 128); + const uint8_t y1 = (uint8_t)((((int16_t)rot_s) * ((int16_t)x)) / 128) + (uint8_t)((((int16_t)rot_c) * ((int16_t)y)) / 128); + + uint8_t value = scale8(sin8(x1 - 2 * time), omega) + y1 + time / 4; + value = (value <= 127) ? value : (255 - value); + + hsv_t hsv = rgb_matrix_config.hsv; + hsv.h -= value / 4; + hsv.s = scale8(hsv.s, (value < 74) ? 255 : (549 - 4 * value)); + hsv.v = scale8(hsv.v, (value < 95) ? (64 + 2 * value) : 255); + + rgb_t rgb = rgb_matrix_hsv_to_rgb(hsv); + rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b); + } + + return rgb_matrix_check_finished_leds(led_max); +} + +#endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS diff --git a/quantum/led_matrix/led_matrix.c b/quantum/led_matrix/led_matrix.c index 00bc199ecf..7a0e8a5ebb 100644 --- a/quantum/led_matrix/led_matrix.c +++ b/quantum/led_matrix/led_matrix.c @@ -45,6 +45,9 @@ const led_point_t k_led_matrix_center = LED_MATRIX_CENTER; #define LED_MATRIX_CUSTOM_EFFECT_IMPLS #include "led_matrix_effects.inc" +#ifdef COMMUNITY_MODULES_ENABLE +# include "led_matrix_community_modules.inc" +#endif #ifdef LED_MATRIX_CUSTOM_KB # include "led_matrix_kb.inc" #endif @@ -282,6 +285,15 @@ static void led_task_render(uint8_t effect) { #include "led_matrix_effects.inc" #undef LED_MATRIX_EFFECT +#ifdef COMMUNITY_MODULES_ENABLE +# define LED_MATRIX_EFFECT(name, ...) \ + case LED_MATRIX_COMMUNITY_MODULE_##name: \ + rendering = name(&led_effect_params); \ + break; +# include "led_matrix_community_modules.inc" +# undef LED_MATRIX_EFFECT +#endif + #if defined(LED_MATRIX_CUSTOM_KB) || defined(LED_MATRIX_CUSTOM_USER) # define LED_MATRIX_EFFECT(name, ...) \ case LED_MATRIX_CUSTOM_##name: \ diff --git a/quantum/led_matrix/led_matrix.h b/quantum/led_matrix/led_matrix.h index 0006d487e9..0dfe33ffab 100644 --- a/quantum/led_matrix/led_matrix.h +++ b/quantum/led_matrix/led_matrix.h @@ -98,6 +98,12 @@ enum led_matrix_effects { #include "led_matrix_effects.inc" #undef LED_MATRIX_EFFECT +#ifdef COMMUNITY_MODULES_ENABLE +# define LED_MATRIX_EFFECT(name, ...) LED_MATRIX_COMMUNITY_MODULE_##name, +# include "led_matrix_community_modules.inc" +# undef LED_MATRIX_EFFECT +#endif + #if defined(LED_MATRIX_CUSTOM_KB) || defined(LED_MATRIX_CUSTOM_USER) # define LED_MATRIX_EFFECT(name, ...) LED_MATRIX_CUSTOM_##name, # ifdef LED_MATRIX_CUSTOM_KB diff --git a/quantum/rgb_matrix/rgb_matrix.c b/quantum/rgb_matrix/rgb_matrix.c index 94852e3520..2679c48342 100644 --- a/quantum/rgb_matrix/rgb_matrix.c +++ b/quantum/rgb_matrix/rgb_matrix.c @@ -47,6 +47,9 @@ __attribute__((weak)) rgb_t rgb_matrix_hsv_to_rgb(hsv_t hsv) { #define RGB_MATRIX_CUSTOM_EFFECT_IMPLS #include "rgb_matrix_effects.inc" +#ifdef COMMUNITY_MODULES_ENABLE +# include "rgb_matrix_community_modules.inc" +#endif #ifdef RGB_MATRIX_CUSTOM_KB # include "rgb_matrix_kb.inc" #endif @@ -310,6 +313,15 @@ static void rgb_task_render(uint8_t effect) { #include "rgb_matrix_effects.inc" #undef RGB_MATRIX_EFFECT +#ifdef COMMUNITY_MODULES_ENABLE +# define RGB_MATRIX_EFFECT(name, ...) \ + case RGB_MATRIX_COMMUNITY_MODULE_##name: \ + rendering = name(&rgb_effect_params); \ + break; +# include "rgb_matrix_community_modules.inc" +# undef RGB_MATRIX_EFFECT +#endif + #if defined(RGB_MATRIX_CUSTOM_KB) || defined(RGB_MATRIX_CUSTOM_USER) # define RGB_MATRIX_EFFECT(name, ...) \ case RGB_MATRIX_CUSTOM_##name: \ diff --git a/quantum/rgb_matrix/rgb_matrix.h b/quantum/rgb_matrix/rgb_matrix.h index e00e3927c7..c6b302631e 100644 --- a/quantum/rgb_matrix/rgb_matrix.h +++ b/quantum/rgb_matrix/rgb_matrix.h @@ -123,6 +123,12 @@ enum rgb_matrix_effects { #include "rgb_matrix_effects.inc" #undef RGB_MATRIX_EFFECT +#ifdef COMMUNITY_MODULES_ENABLE +# define RGB_MATRIX_EFFECT(name, ...) RGB_MATRIX_COMMUNITY_MODULE_##name, +# include "rgb_matrix_community_modules.inc" +# undef RGB_MATRIX_EFFECT +#endif + #if defined(RGB_MATRIX_CUSTOM_KB) || defined(RGB_MATRIX_CUSTOM_USER) # define RGB_MATRIX_EFFECT(name, ...) RGB_MATRIX_CUSTOM_##name, # ifdef RGB_MATRIX_CUSTOM_KB -- cgit v1.2.3 From 955809bd5aee8b1444595b450eeeef1f42799995 Mon Sep 17 00:00:00 2001 From: Pablo Martínez Date: Thu, 22 May 2025 15:31:15 +0200 Subject: Add `compiler_support.h` (#25274) --- docs/quantum_painter_qff.md | 4 ++-- docs/quantum_painter_qgf.md | 8 ++++---- drivers/lcd/st7565.c | 3 ++- drivers/oled/oled_driver.c | 4 +++- drivers/sensors/azoteq_iqs5xx.h | 7 ++++--- drivers/sensors/pmw33xx_common.h | 5 +++-- lib/fnv/qmk_fnv_type_validation.c | 9 +++++---- lib/python/qmk/cli/generate/community_modules.py | 6 ++++-- platforms/atomic_util.h | 12 +++++++----- platforms/avr/drivers/i2c_slave.h | 4 +++- platforms/avr/gpio.h | 6 ++++-- platforms/chibios/chibios_config.h | 4 +++- .../drivers/wear_leveling/wear_leveling_rp2040_flash.c | 6 ++++-- quantum/audio/audio.h | 4 +++- quantum/backlight/backlight.h | 4 +++- quantum/compiler_support.h | 15 +++++++++++++++ quantum/connection/connection.h | 4 +++- quantum/haptic.h | 4 +++- quantum/keycode_config.h | 6 ++---- quantum/keymap_introspection.c | 13 +++++++------ quantum/led_matrix/led_matrix_types.h | 4 +++- quantum/nvm/eeprom/nvm_dynamic_keymap.c | 7 ++++--- quantum/nvm/eeprom/nvm_eeprom_eeconfig_internal.h | 4 +++- quantum/painter/qff.h | 9 +++++---- quantum/painter/qgf.h | 17 +++++++++-------- quantum/painter/qp_draw_core.c | 3 ++- quantum/painter/qp_internal.c | 4 +++- quantum/painter/qp_internal_formats.h | 3 ++- quantum/rgb_matrix/rgb_matrix_types.h | 4 +++- quantum/rgblight/rgblight.h | 4 +++- quantum/split_common/split_util.c | 8 +++++--- quantum/split_common/transaction_id_define.h | 4 +++- quantum/split_common/transport.c | 3 ++- quantum/unicode/unicode.h | 4 +++- quantum/wear_leveling/wear_leveling_internal.h | 14 ++++++-------- tmk_core/protocol/vusb/vusb.c | 3 ++- 36 files changed, 142 insertions(+), 81 deletions(-) create mode 100644 quantum/compiler_support.h (limited to 'lib/python/qmk/cli/generate/community_modules.py') diff --git a/docs/quantum_painter_qff.md b/docs/quantum_painter_qff.md index 3695be2c5b..198d87384a 100644 --- a/docs/quantum_painter_qff.md +++ b/docs/quantum_painter_qff.md @@ -44,7 +44,7 @@ typedef struct __attribute__((packed)) qff_font_descriptor_v1_t { uint8_t compression_scheme; // compression scheme, see below. uint8_t transparency_index; // palette index used for transparent pixels (not yet implemented) } qff_font_descriptor_v1_t; -// _Static_assert(sizeof(qff_font_descriptor_v1_t) == (sizeof(qgf_block_header_v1_t) + 20), "qff_font_descriptor_v1_t must be 25 bytes in v1 of QFF"); +// STATIC_ASSERT(sizeof(qff_font_descriptor_v1_t) == (sizeof(qgf_block_header_v1_t) + 20), "qff_font_descriptor_v1_t must be 25 bytes in v1 of QFF"); ``` The values for `format`, `flags`, `compression_scheme`, and `transparency_index` match [QGF's frame descriptor block](quantum_painter_qgf#qgf-frame-descriptor), with the exception that the `delta` flag is ignored by QFF. @@ -66,7 +66,7 @@ typedef struct __attribute__((packed)) qff_ascii_glyph_table_v1_t { qgf_block_header_v1_t header; // = { .type_id = 0x01, .neg_type_id = (~0x01), .length = 285 } uint24_t glyph[95]; // 95 glyphs, 0x20..0x7E, see bits/masks above for values } qff_ascii_glyph_table_v1_t; -// _Static_assert(sizeof(qff_ascii_glyph_table_v1_t) == (sizeof(qgf_block_header_v1_t) + 285), "qff_ascii_glyph_table_v1_t must be 290 bytes in v1 of QFF"); +// STATIC_ASSERT(sizeof(qff_ascii_glyph_table_v1_t) == (sizeof(qgf_block_header_v1_t) + 285), "qff_ascii_glyph_table_v1_t must be 290 bytes in v1 of QFF"); ``` ## Unicode glyph table {#qff-unicode-table} diff --git a/docs/quantum_painter_qgf.md b/docs/quantum_painter_qgf.md index 700b78d105..dd525e4b83 100644 --- a/docs/quantum_painter_qgf.md +++ b/docs/quantum_painter_qgf.md @@ -32,7 +32,7 @@ typedef struct __attribute__((packed)) qgf_block_header_v1_t { uint8_t neg_type_id; // Negated type ID, used for detecting parsing errors uint24_t length; // 24-bit blob length, allowing for block sizes of a maximum of 16MB } qgf_block_header_v1_t; -// _Static_assert(sizeof(qgf_block_header_v1_t) == 5, "qgf_block_header_v1_t must be 5 bytes in v1 of QGF"); +// STATIC_ASSERT(sizeof(qgf_block_header_v1_t) == 5, "qgf_block_header_v1_t must be 5 bytes in v1 of QGF"); ``` The _length_ describes the number of octets in the data following the block header -- a block header may specify a _length_ of `0` if no blob is specified. @@ -56,7 +56,7 @@ typedef struct __attribute__((packed)) qgf_graphics_descriptor_v1_t { uint16_t image_height; // in pixels uint16_t frame_count; // minimum of 1 } qgf_graphics_descriptor_v1_t; -// _Static_assert(sizeof(qgf_graphics_descriptor_v1_t) == (sizeof(qgf_block_header_v1_t) + 18), "qgf_graphics_descriptor_v1_t must be 23 bytes in v1 of QGF"); +// STATIC_ASSERT(sizeof(qgf_graphics_descriptor_v1_t) == (sizeof(qgf_block_header_v1_t) + 18), "qgf_graphics_descriptor_v1_t must be 23 bytes in v1 of QGF"); ``` ## Frame offset block {#qgf-frame-offset-descriptor} @@ -95,7 +95,7 @@ typedef struct __attribute__((packed)) qgf_frame_v1_t { uint8_t transparency_index; // palette index used for transparent pixels (not yet implemented) uint16_t delay; // frame delay time for animations (in units of milliseconds) } qgf_frame_v1_t; -// _Static_assert(sizeof(qgf_frame_v1_t) == (sizeof(qgf_block_header_v1_t) + 6), "qgf_frame_v1_t must be 11 bytes in v1 of QGF"); +// STATIC_ASSERT(sizeof(qgf_frame_v1_t) == (sizeof(qgf_block_header_v1_t) + 6), "qgf_frame_v1_t must be 11 bytes in v1 of QGF"); ``` If this frame is grayscale, the _frame descriptor block_ (or _frame delta block_ if flags denote a delta frame) is immediately followed by this frame's corresponding _frame data block_. @@ -160,7 +160,7 @@ typedef struct __attribute__((packed)) qgf_delta_v1_t { uint16_t right; // The right pixel location to to draw the delta image uint16_t bottom; // The bottom pixel location to to draw the delta image } qgf_delta_v1_t; -// _Static_assert(sizeof(qgf_delta_v1_t) == 13, "qgf_delta_v1_t must be 13 bytes in v1 of QGF"); +// STATIC_ASSERT(sizeof(qgf_delta_v1_t) == 13, "qgf_delta_v1_t must be 13 bytes in v1 of QGF"); ``` ## Frame data block {#qgf-frame-data-descriptor} diff --git a/drivers/lcd/st7565.c b/drivers/lcd/st7565.c index cf71c5e5a3..f24bb78048 100644 --- a/drivers/lcd/st7565.c +++ b/drivers/lcd/st7565.c @@ -19,6 +19,7 @@ along with this program. If not, see . #include +#include "compiler_support.h" #include "keyboard.h" #include "progmem.h" #include "timer.h" @@ -265,7 +266,7 @@ void st7565_write_char(const char data, bool invert) { static uint8_t st7565_temp_buffer[ST7565_FONT_WIDTH]; memcpy(&st7565_temp_buffer, st7565_cursor, ST7565_FONT_WIDTH); - _Static_assert(sizeof(font) >= ((ST7565_FONT_END + 1 - ST7565_FONT_START) * ST7565_FONT_WIDTH), "ST7565_FONT_END references outside array"); + STATIC_ASSERT(sizeof(font) >= ((ST7565_FONT_END + 1 - ST7565_FONT_START) * ST7565_FONT_WIDTH), "ST7565_FONT_END references outside array"); // set the reder buffer data uint8_t cast_data = (uint8_t)data; // font based on unsigned type for index diff --git a/drivers/oled/oled_driver.c b/drivers/oled/oled_driver.c index 1d1c2a90c4..7e46bcb3f7 100644 --- a/drivers/oled/oled_driver.c +++ b/drivers/oled/oled_driver.c @@ -23,6 +23,8 @@ along with this program. If not, see . # include "keyboard.h" # endif #endif + +#include "compiler_support.h" #include "oled_driver.h" #include OLED_FONT_H #include "timer.h" @@ -601,7 +603,7 @@ void oled_write_char(const char data, bool invert) { static uint8_t oled_temp_buffer[OLED_FONT_WIDTH]; memcpy(&oled_temp_buffer, oled_cursor, OLED_FONT_WIDTH); - _Static_assert(sizeof(font) >= ((OLED_FONT_END + 1 - OLED_FONT_START) * OLED_FONT_WIDTH), "OLED_FONT_END references outside array"); + STATIC_ASSERT(sizeof(font) >= ((OLED_FONT_END + 1 - OLED_FONT_START) * OLED_FONT_WIDTH), "OLED_FONT_END references outside array"); // set the reder buffer data uint8_t cast_data = (uint8_t)data; // font based on unsigned type for index diff --git a/drivers/sensors/azoteq_iqs5xx.h b/drivers/sensors/azoteq_iqs5xx.h index e1e8b67b31..eb01903e33 100644 --- a/drivers/sensors/azoteq_iqs5xx.h +++ b/drivers/sensors/azoteq_iqs5xx.h @@ -4,6 +4,7 @@ #pragma once +#include "compiler_support.h" #include "i2c_master.h" #include "pointing_device.h" #include "util.h" @@ -79,7 +80,7 @@ typedef struct { azoteq_iqs5xx_relative_xy_t y; } azoteq_iqs5xx_base_data_t; -_Static_assert(sizeof(azoteq_iqs5xx_base_data_t) == 10, "azoteq_iqs5xx_basic_report_t should be 10 bytes"); +STATIC_ASSERT(sizeof(azoteq_iqs5xx_base_data_t) == 10, "azoteq_iqs5xx_basic_report_t should be 10 bytes"); typedef struct { uint8_t number_of_fingers; @@ -87,7 +88,7 @@ typedef struct { azoteq_iqs5xx_relative_xy_t y; } azoteq_iqs5xx_report_data_t; -_Static_assert(sizeof(azoteq_iqs5xx_report_data_t) == 5, "azoteq_iqs5xx_report_data_t should be 5 bytes"); +STATIC_ASSERT(sizeof(azoteq_iqs5xx_report_data_t) == 5, "azoteq_iqs5xx_report_data_t should be 5 bytes"); typedef struct PACKED { bool sw_input : 1; @@ -159,7 +160,7 @@ typedef struct PACKED { uint16_t zoom_consecutive_distance; } azoteq_iqs5xx_gesture_config_t; -_Static_assert(sizeof(azoteq_iqs5xx_gesture_config_t) == 24, "azoteq_iqs5xx_gesture_config_t should be 24 bytes"); +STATIC_ASSERT(sizeof(azoteq_iqs5xx_gesture_config_t) == 24, "azoteq_iqs5xx_gesture_config_t should be 24 bytes"); typedef struct { uint16_t x_resolution; diff --git a/drivers/sensors/pmw33xx_common.h b/drivers/sensors/pmw33xx_common.h index 22e35c3327..82303ba6d9 100644 --- a/drivers/sensors/pmw33xx_common.h +++ b/drivers/sensors/pmw33xx_common.h @@ -10,6 +10,7 @@ #pragma once +#include "compiler_support.h" #include "keyboard.h" #include #include "spi_master.h" @@ -39,8 +40,8 @@ typedef struct __attribute__((packed)) { int16_t delta_y; // displacement on y directions. } pmw33xx_report_t; -_Static_assert(sizeof(pmw33xx_report_t) == 6, "pmw33xx_report_t must be 6 bytes in size"); -_Static_assert(sizeof((pmw33xx_report_t){0}.motion) == 1, "pmw33xx_report_t.motion must be 1 byte in size"); +STATIC_ASSERT(sizeof(pmw33xx_report_t) == 6, "pmw33xx_report_t must be 6 bytes in size"); +STATIC_ASSERT(sizeof((pmw33xx_report_t){0}.motion) == 1, "pmw33xx_report_t.motion must be 1 byte in size"); #if !defined(PMW33XX_CLOCK_SPEED) # define PMW33XX_CLOCK_SPEED 2000000 diff --git a/lib/fnv/qmk_fnv_type_validation.c b/lib/fnv/qmk_fnv_type_validation.c index e8576617ba..5e8ef5c54c 100644 --- a/lib/fnv/qmk_fnv_type_validation.c +++ b/lib/fnv/qmk_fnv_type_validation.c @@ -1,14 +1,15 @@ // Copyright 2022 Nick Brassel (@tzarc) // SPDX-License-Identifier: GPL-2.0-or-later #include "fnv.h" +#include "compiler_support.h" // This library was originally sourced from: // http://www.isthe.com/chongo/tech/comp/fnv/index.html // // Version at the time of retrieval on 2022-06-26: v5.0.3 -_Static_assert(sizeof(long long) == 8, "long long should be 64 bits"); -_Static_assert(sizeof(unsigned long long) == 8, "unsigned long long should be 64 bits"); +STATIC_ASSERT(sizeof(long long) == 8, "long long should be 64 bits"); +STATIC_ASSERT(sizeof(unsigned long long) == 8, "unsigned long long should be 64 bits"); -_Static_assert(sizeof(Fnv32_t) == 4, "Fnv32_t should be 32 bits"); -_Static_assert(sizeof(Fnv64_t) == 8, "Fnv64_t should be 64 bits"); +STATIC_ASSERT(sizeof(Fnv32_t) == 4, "Fnv32_t should be 32 bits"); +STATIC_ASSERT(sizeof(Fnv64_t) == 8, "Fnv64_t should be 64 bits"); diff --git a/lib/python/qmk/cli/generate/community_modules.py b/lib/python/qmk/cli/generate/community_modules.py index 1f37b760ca..a5ab61f9bd 100644 --- a/lib/python/qmk/cli/generate/community_modules.py +++ b/lib/python/qmk/cli/generate/community_modules.py @@ -52,7 +52,7 @@ def _render_keycodes(module_jsons): lines.append('') lines.append(' LAST_COMMUNITY_MODULE_KEY') lines.append('};') - lines.append('_Static_assert((int)LAST_COMMUNITY_MODULE_KEY <= (int)(QK_COMMUNITY_MODULE_MAX+1), "Too many community module keycodes");') + lines.append('STATIC_ASSERT((int)LAST_COMMUNITY_MODULE_KEY <= (int)(QK_COMMUNITY_MODULE_MAX+1), "Too many community module keycodes");') return lines @@ -215,9 +215,11 @@ def generate_community_modules_h(cli): '#include ', '#include ', '', + '#include "compiler_support.h"', + '', '#define COMMUNITY_MODULES_API_VERSION_BUILDER(ver_major,ver_minor,ver_patch) (((((uint32_t)(ver_major))&0xFF) << 24) | ((((uint32_t)(ver_minor))&0xFF) << 16) | (((uint32_t)(ver_patch))&0xFF))', f'#define COMMUNITY_MODULES_API_VERSION COMMUNITY_MODULES_API_VERSION_BUILDER({ver_major},{ver_minor},{ver_patch})', - f'#define ASSERT_COMMUNITY_MODULES_MIN_API_VERSION(ver_major,ver_minor,ver_patch) _Static_assert(COMMUNITY_MODULES_API_VERSION_BUILDER(ver_major,ver_minor,ver_patch) <= COMMUNITY_MODULES_API_VERSION, "Community module requires a newer version of QMK modules API -- needs: " #ver_major "." #ver_minor "." #ver_patch ", current: {api_version}.")', + f'#define ASSERT_COMMUNITY_MODULES_MIN_API_VERSION(ver_major,ver_minor,ver_patch) STATIC_ASSERT(COMMUNITY_MODULES_API_VERSION_BUILDER(ver_major,ver_minor,ver_patch) <= COMMUNITY_MODULES_API_VERSION, "Community module requires a newer version of QMK modules API -- needs: " #ver_major "." #ver_minor "." #ver_patch ", current: {api_version}.")', '', 'typedef struct keyrecord_t keyrecord_t; // forward declaration so we don\'t need to include quantum.h', '', diff --git a/platforms/atomic_util.h b/platforms/atomic_util.h index 21286d72eb..8e81eacdb8 100644 --- a/platforms/atomic_util.h +++ b/platforms/atomic_util.h @@ -15,17 +15,19 @@ */ #pragma once +#include "compiler_support.h" + // Macro to help make GPIO and other controls atomic. #ifndef IGNORE_ATOMIC_BLOCK # if __has_include_next("atomic_util.h") # include_next "atomic_util.h" /* Include the platforms atomic.h */ # else -# define ATOMIC_BLOCK _Static_assert(0, "ATOMIC_BLOCK not implemented") -# define ATOMIC_BLOCK_RESTORESTATE _Static_assert(0, "ATOMIC_BLOCK_RESTORESTATE not implemented") -# define ATOMIC_BLOCK_FORCEON _Static_assert(0, "ATOMIC_BLOCK_FORCEON not implemented") -# define ATOMIC_FORCEON _Static_assert(0, "ATOMIC_FORCEON not implemented") -# define ATOMIC_RESTORESTATE _Static_assert(0, "ATOMIC_RESTORESTATE not implemented") +# define ATOMIC_BLOCK STATIC_ASSERT(0, "ATOMIC_BLOCK not implemented") +# define ATOMIC_BLOCK_RESTORESTATE STATIC_ASSERT(0, "ATOMIC_BLOCK_RESTORESTATE not implemented") +# define ATOMIC_BLOCK_FORCEON STATIC_ASSERT(0, "ATOMIC_BLOCK_FORCEON not implemented") +# define ATOMIC_FORCEON STATIC_ASSERT(0, "ATOMIC_FORCEON not implemented") +# define ATOMIC_RESTORESTATE STATIC_ASSERT(0, "ATOMIC_RESTORESTATE not implemented") # endif #else /* do nothing atomic macro */ # define ATOMIC_BLOCK(t) for (uint8_t __ToDo = 1; __ToDo; __ToDo = 0) diff --git a/platforms/avr/drivers/i2c_slave.h b/platforms/avr/drivers/i2c_slave.h index 178b6a29df..8614bd865a 100644 --- a/platforms/avr/drivers/i2c_slave.h +++ b/platforms/avr/drivers/i2c_slave.h @@ -22,6 +22,8 @@ #pragma once +#include "compiler_support.h" + #ifndef I2C_SLAVE_REG_COUNT # if defined(USE_I2C) && defined(SPLIT_COMMON_TRANSACTIONS) @@ -33,7 +35,7 @@ #endif // I2C_SLAVE_REG_COUNT -_Static_assert(I2C_SLAVE_REG_COUNT < 256, "I2C target registers must be single byte"); +STATIC_ASSERT(I2C_SLAVE_REG_COUNT < 256, "I2C target registers must be single byte"); extern volatile uint8_t i2c_slave_reg[I2C_SLAVE_REG_COUNT]; diff --git a/platforms/avr/gpio.h b/platforms/avr/gpio.h index 6f089bc663..4c09619772 100644 --- a/platforms/avr/gpio.h +++ b/platforms/avr/gpio.h @@ -16,6 +16,8 @@ #pragma once #include + +#include "compiler_support.h" #include "pin_defs.h" typedef uint8_t pin_t; @@ -24,9 +26,9 @@ typedef uint8_t pin_t; #define gpio_set_pin_input(pin) (DDRx_ADDRESS(pin) &= ~_BV((pin)&0xF), PORTx_ADDRESS(pin) &= ~_BV((pin)&0xF)) #define gpio_set_pin_input_high(pin) (DDRx_ADDRESS(pin) &= ~_BV((pin)&0xF), PORTx_ADDRESS(pin) |= _BV((pin)&0xF)) -#define gpio_set_pin_input_low(pin) _Static_assert(0, "GPIO pulldowns in input mode are not available on AVR") +#define gpio_set_pin_input_low(pin) STATIC_ASSERT(0, "GPIO pulldowns in input mode are not available on AVR") #define gpio_set_pin_output_push_pull(pin) (DDRx_ADDRESS(pin) |= _BV((pin)&0xF)) -#define gpio_set_pin_output_open_drain(pin) _Static_assert(0, "Open-drain outputs are not available on AVR") +#define gpio_set_pin_output_open_drain(pin) STATIC_ASSERT(0, "Open-drain outputs are not available on AVR") #define gpio_set_pin_output(pin) gpio_set_pin_output_push_pull(pin) #define gpio_write_pin_high(pin) (PORTx_ADDRESS(pin) |= _BV((pin)&0xF)) diff --git a/platforms/chibios/chibios_config.h b/platforms/chibios/chibios_config.h index 9ef8e9b4fe..41546e3e50 100644 --- a/platforms/chibios/chibios_config.h +++ b/platforms/chibios/chibios_config.h @@ -15,6 +15,8 @@ */ #pragma once +#include "compiler_support.h" + #ifndef USB_VBUS_PIN # define SPLIT_USB_DETECT // Force this on when dedicated pin is not used #endif @@ -26,7 +28,7 @@ # define REALTIME_COUNTER_CLOCK 1000000 # define USE_GPIOV1 -# define PAL_OUTPUT_TYPE_OPENDRAIN _Static_assert(0, "RP2040 has no Open Drain GPIO configuration, setting this is not possible"); +# define PAL_OUTPUT_TYPE_OPENDRAIN STATIC_ASSERT(0, "RP2040 has no Open Drain GPIO configuration, setting this is not possible"); /* Aliases for GPIO PWM channels - every pin has at least one PWM channel * assigned */ diff --git a/platforms/chibios/drivers/wear_leveling/wear_leveling_rp2040_flash.c b/platforms/chibios/drivers/wear_leveling/wear_leveling_rp2040_flash.c index 9bfc68f9d2..2f3c7c58ca 100644 --- a/platforms/chibios/drivers/wear_leveling/wear_leveling_rp2040_flash.c +++ b/platforms/chibios/drivers/wear_leveling/wear_leveling_rp2040_flash.c @@ -6,13 +6,15 @@ * SPDX-License-Identifier: BSD-3-Clause */ +#include + #include "pico/bootrom.h" #include "hardware/flash.h" #include "hardware/sync.h" #include "hardware/structs/ssi.h" #include "hardware/structs/ioqspi.h" -#include +#include "compiler_support.h" #include "timer.h" #include "wear_leveling.h" #include "wear_leveling_rp2040_flash_config.h" @@ -178,7 +180,7 @@ bool backing_store_erase(void) { #endif // Ensure the backing size can be cleanly subtracted from the flash size without alignment issues. - _Static_assert((WEAR_LEVELING_BACKING_SIZE) % (FLASH_SECTOR_SIZE) == 0, "Backing size must be a multiple of FLASH_SECTOR_SIZE"); + STATIC_ASSERT((WEAR_LEVELING_BACKING_SIZE) % (FLASH_SECTOR_SIZE) == 0, "Backing size must be a multiple of FLASH_SECTOR_SIZE"); interrupts = save_and_disable_interrupts(); flash_range_erase((WEAR_LEVELING_RP2040_FLASH_BASE), (WEAR_LEVELING_BACKING_SIZE)); diff --git a/quantum/audio/audio.h b/quantum/audio/audio.h index 93dc6f62b1..647744a686 100644 --- a/quantum/audio/audio.h +++ b/quantum/audio/audio.h @@ -18,6 +18,8 @@ #include #include + +#include "compiler_support.h" #include "musical_notes.h" #include "song_list.h" #include "voices.h" @@ -38,7 +40,7 @@ typedef union audio_config_t { }; } audio_config_t; -_Static_assert(sizeof(audio_config_t) == sizeof(uint8_t), "Audio EECONFIG out of spec."); +STATIC_ASSERT(sizeof(audio_config_t) == sizeof(uint8_t), "Audio EECONFIG out of spec."); /* * a 'musical note' is represented by pitch and duration; a 'musical tone' adds intensity and timbre diff --git a/quantum/backlight/backlight.h b/quantum/backlight/backlight.h index 561c7f8a94..2faa8fc4f2 100644 --- a/quantum/backlight/backlight.h +++ b/quantum/backlight/backlight.h @@ -20,6 +20,8 @@ along with this program. If not, see . #include #include +#include "compiler_support.h" + #ifndef BACKLIGHT_LEVELS # define BACKLIGHT_LEVELS 3 #elif BACKLIGHT_LEVELS > 31 @@ -44,7 +46,7 @@ typedef union backlight_config_t { }; } backlight_config_t; -_Static_assert(sizeof(backlight_config_t) == sizeof(uint8_t), "Backlight EECONFIG out of spec."); +STATIC_ASSERT(sizeof(backlight_config_t) == sizeof(uint8_t), "Backlight EECONFIG out of spec."); void backlight_init(void); void backlight_toggle(void); diff --git a/quantum/compiler_support.h b/quantum/compiler_support.h new file mode 100644 index 0000000000..5c0c4d2835 --- /dev/null +++ b/quantum/compiler_support.h @@ -0,0 +1,15 @@ +// Copyright 2025 QMK Contributors +// SPDX-License-Identifier: GPL-2.0-or-later + +/** + * @brief Perfom an assertion at compile time. + * + * `_Static_assert` is C<23, while `static_assert` is C++/C23. + */ +#if !defined(STATIC_ASSERT) +# ifdef __cplusplus +# define STATIC_ASSERT static_assert +# else +# define STATIC_ASSERT _Static_assert +# endif +#endif diff --git a/quantum/connection/connection.h b/quantum/connection/connection.h index e403141fae..b25160c759 100644 --- a/quantum/connection/connection.h +++ b/quantum/connection/connection.h @@ -3,6 +3,8 @@ #pragma once #include + +#include "compiler_support.h" #include "util.h" /** @@ -29,7 +31,7 @@ typedef union connection_config_t { connection_host_t desired_host : 8; } PACKED connection_config_t; -_Static_assert(sizeof(connection_config_t) == sizeof(uint8_t), "Connection EECONFIG out of spec."); +STATIC_ASSERT(sizeof(connection_config_t) == sizeof(uint8_t), "Connection EECONFIG out of spec."); /** * \brief Initialize the subsystem. diff --git a/quantum/haptic.h b/quantum/haptic.h index e27f546d40..f854c75ec3 100644 --- a/quantum/haptic.h +++ b/quantum/haptic.h @@ -20,6 +20,8 @@ #include #include +#include "compiler_support.h" + #ifndef HAPTIC_DEFAULT_FEEDBACK # define HAPTIC_DEFAULT_FEEDBACK 0 #endif @@ -42,7 +44,7 @@ typedef union haptic_config_t { }; } haptic_config_t; -_Static_assert(sizeof(haptic_config_t) == sizeof(uint32_t), "Haptic EECONFIG out of spec."); +STATIC_ASSERT(sizeof(haptic_config_t) == sizeof(uint32_t), "Haptic EECONFIG out of spec."); typedef enum HAPTIC_FEEDBACK { KEY_PRESS, diff --git a/quantum/keycode_config.h b/quantum/keycode_config.h index 529cd0e127..804f1381d0 100644 --- a/quantum/keycode_config.h +++ b/quantum/keycode_config.h @@ -16,9 +16,7 @@ #pragma once -#ifdef __cplusplus -# define _Static_assert static_assert -#endif +#include "compiler_support.h" #include "eeconfig.h" #include "keycode.h" @@ -47,6 +45,6 @@ typedef union keymap_config_t { }; } keymap_config_t; -_Static_assert(sizeof(keymap_config_t) == sizeof(uint16_t), "Keycode (magic) EECONFIG out of spec."); +STATIC_ASSERT(sizeof(keymap_config_t) == sizeof(uint16_t), "Keycode (magic) EECONFIG out of spec."); extern keymap_config_t keymap_config; diff --git a/quantum/keymap_introspection.c b/quantum/keymap_introspection.c index 23e842353a..99fd3f929e 100644 --- a/quantum/keymap_introspection.c +++ b/quantum/keymap_introspection.c @@ -13,6 +13,7 @@ # include INTROSPECTION_KEYMAP_C #endif // INTROSPECTION_KEYMAP_C +#include "compiler_support.h" #include "keymap_introspection.h" #include "util.h" @@ -30,9 +31,9 @@ __attribute__((weak)) uint8_t keymap_layer_count(void) { } #ifdef DYNAMIC_KEYMAP_ENABLE -_Static_assert(NUM_KEYMAP_LAYERS_RAW <= MAX_LAYER, "Number of keymap layers exceeds maximum set by DYNAMIC_KEYMAP_LAYER_COUNT"); +STATIC_ASSERT(NUM_KEYMAP_LAYERS_RAW <= MAX_LAYER, "Number of keymap layers exceeds maximum set by DYNAMIC_KEYMAP_LAYER_COUNT"); #else -_Static_assert(NUM_KEYMAP_LAYERS_RAW <= MAX_LAYER, "Number of keymap layers exceeds maximum set by LAYER_STATE_(8|16|32)BIT"); +STATIC_ASSERT(NUM_KEYMAP_LAYERS_RAW <= MAX_LAYER, "Number of keymap layers exceeds maximum set by LAYER_STATE_(8|16|32)BIT"); #endif uint16_t keycode_at_keymap_location_raw(uint8_t layer_num, uint8_t row, uint8_t column) { @@ -61,7 +62,7 @@ __attribute__((weak)) uint8_t encodermap_layer_count(void) { return encodermap_layer_count_raw(); } -_Static_assert(NUM_KEYMAP_LAYERS_RAW == NUM_ENCODERMAP_LAYERS_RAW, "Number of encoder_map layers doesn't match the number of keymap layers"); +STATIC_ASSERT(NUM_KEYMAP_LAYERS_RAW == NUM_ENCODERMAP_LAYERS_RAW, "Number of encoder_map layers doesn't match the number of keymap layers"); uint16_t keycode_at_encodermap_location_raw(uint8_t layer_num, uint8_t encoder_idx, bool clockwise) { if (layer_num < NUM_ENCODERMAP_LAYERS_RAW && encoder_idx < NUM_ENCODERS) { @@ -106,7 +107,7 @@ __attribute__((weak)) uint16_t combo_count(void) { return combo_count_raw(); } -_Static_assert(ARRAY_SIZE(key_combos) <= (QK_KB), "Number of combos is abnormally high. Are you using SAFE_RANGE in an enum for combos?"); +STATIC_ASSERT(ARRAY_SIZE(key_combos) <= (QK_KB), "Number of combos is abnormally high. Are you using SAFE_RANGE in an enum for combos?"); combo_t* combo_get_raw(uint16_t combo_idx) { if (combo_idx >= combo_count_raw()) { @@ -133,7 +134,7 @@ __attribute__((weak)) uint16_t tap_dance_count(void) { return tap_dance_count_raw(); } -_Static_assert(ARRAY_SIZE(tap_dance_actions) <= (QK_TAP_DANCE_MAX - QK_TAP_DANCE), "Number of tap dance actions exceeds maximum. Are you using SAFE_RANGE in tap dance enum?"); +STATIC_ASSERT(ARRAY_SIZE(tap_dance_actions) <= (QK_TAP_DANCE_MAX - QK_TAP_DANCE), "Number of tap dance actions exceeds maximum. Are you using SAFE_RANGE in tap dance enum?"); tap_dance_action_t* tap_dance_get_raw(uint16_t tap_dance_idx) { if (tap_dance_idx >= tap_dance_count_raw()) { @@ -161,7 +162,7 @@ __attribute__((weak)) uint16_t key_override_count(void) { return key_override_count_raw(); } -_Static_assert(ARRAY_SIZE(key_overrides) <= (QK_KB), "Number of key overrides is abnormally high. Are you using SAFE_RANGE in an enum for key overrides?"); +STATIC_ASSERT(ARRAY_SIZE(key_overrides) <= (QK_KB), "Number of key overrides is abnormally high. Are you using SAFE_RANGE in an enum for key overrides?"); const key_override_t* key_override_get_raw(uint16_t key_override_idx) { if (key_override_idx >= key_override_count_raw()) { diff --git a/quantum/led_matrix/led_matrix_types.h b/quantum/led_matrix/led_matrix_types.h index 810420f46f..26a199701e 100644 --- a/quantum/led_matrix/led_matrix_types.h +++ b/quantum/led_matrix/led_matrix_types.h @@ -18,6 +18,8 @@ #include #include + +#include "compiler_support.h" #include "util.h" #if defined(LED_MATRIX_KEYPRESSES) || defined(LED_MATRIX_KEYRELEASES) @@ -82,4 +84,4 @@ typedef union led_eeconfig_t { }; } led_eeconfig_t; -_Static_assert(sizeof(led_eeconfig_t) == sizeof(uint32_t), "LED Matrix EECONFIG out of spec."); +STATIC_ASSERT(sizeof(led_eeconfig_t) == sizeof(uint32_t), "LED Matrix EECONFIG out of spec."); diff --git a/quantum/nvm/eeprom/nvm_dynamic_keymap.c b/quantum/nvm/eeprom/nvm_dynamic_keymap.c index 5f514acc1a..3e315f2bcb 100644 --- a/quantum/nvm/eeprom/nvm_dynamic_keymap.c +++ b/quantum/nvm/eeprom/nvm_dynamic_keymap.c @@ -1,6 +1,7 @@ // Copyright 2024 Nick Brassel (@tzarc) // SPDX-License-Identifier: GPL-2.0-or-later +#include "compiler_support.h" #include "keycodes.h" #include "eeprom.h" #include "dynamic_keymap.h" @@ -25,10 +26,10 @@ # define DYNAMIC_KEYMAP_EEPROM_MAX_ADDR (TOTAL_EEPROM_BYTE_COUNT - 1) #endif -_Static_assert(DYNAMIC_KEYMAP_EEPROM_MAX_ADDR <= (TOTAL_EEPROM_BYTE_COUNT - 1), "DYNAMIC_KEYMAP_EEPROM_MAX_ADDR is configured to use more space than what is available for the selected EEPROM driver"); +STATIC_ASSERT(DYNAMIC_KEYMAP_EEPROM_MAX_ADDR <= (TOTAL_EEPROM_BYTE_COUNT - 1), "DYNAMIC_KEYMAP_EEPROM_MAX_ADDR is configured to use more space than what is available for the selected EEPROM driver"); // Due to usage of uint16_t check for max 65535 -_Static_assert(DYNAMIC_KEYMAP_EEPROM_MAX_ADDR <= 65535, "DYNAMIC_KEYMAP_EEPROM_MAX_ADDR must be less than 65536"); +STATIC_ASSERT(DYNAMIC_KEYMAP_EEPROM_MAX_ADDR <= 65535, "DYNAMIC_KEYMAP_EEPROM_MAX_ADDR must be less than 65536"); // If DYNAMIC_KEYMAP_EEPROM_ADDR not explicitly defined in config.h, #ifndef DYNAMIC_KEYMAP_EEPROM_ADDR @@ -56,7 +57,7 @@ _Static_assert(DYNAMIC_KEYMAP_EEPROM_MAX_ADDR <= 65535, "DYNAMIC_KEYMAP_EEPROM_M // The keyboard should override DYNAMIC_KEYMAP_LAYER_COUNT to reduce it, // or DYNAMIC_KEYMAP_EEPROM_MAX_ADDR to increase it, *only if* the microcontroller has // more than the default. -_Static_assert((DYNAMIC_KEYMAP_EEPROM_MAX_ADDR) - (DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR) >= 100, "Dynamic keymaps are configured to use more EEPROM than is available."); +STATIC_ASSERT((DYNAMIC_KEYMAP_EEPROM_MAX_ADDR) - (DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR) >= 100, "Dynamic keymaps are configured to use more EEPROM than is available."); #ifndef TOTAL_EEPROM_BYTE_COUNT # error Unknown total EEPROM size. Cannot derive maximum for dynamic keymaps. diff --git a/quantum/nvm/eeprom/nvm_eeprom_eeconfig_internal.h b/quantum/nvm/eeprom/nvm_eeprom_eeconfig_internal.h index 41b76f1f65..78b8190eaf 100644 --- a/quantum/nvm/eeprom/nvm_eeprom_eeconfig_internal.h +++ b/quantum/nvm/eeprom/nvm_eeprom_eeconfig_internal.h @@ -4,6 +4,8 @@ #include #include // offsetof + +#include "compiler_support.h" #include "eeconfig.h" #include "util.h" @@ -58,4 +60,4 @@ typedef struct PACKED { // Size of EEPROM being used, other code can refer to this for available EEPROM #define EECONFIG_SIZE ((EECONFIG_BASE_SIZE) + (EECONFIG_KB_DATA_SIZE) + (EECONFIG_USER_DATA_SIZE)) -_Static_assert((intptr_t)EECONFIG_HANDEDNESS == 14, "EEPROM handedness offset is incorrect"); +STATIC_ASSERT((intptr_t)EECONFIG_HANDEDNESS == 14, "EEPROM handedness offset is incorrect"); diff --git a/quantum/painter/qff.h b/quantum/painter/qff.h index c3b831da17..ed88508d73 100644 --- a/quantum/painter/qff.h +++ b/quantum/painter/qff.h @@ -9,6 +9,7 @@ #include #include +#include "compiler_support.h" #include "qp_stream.h" #include "qp_internal.h" #include "qgf.h" @@ -36,7 +37,7 @@ typedef struct QP_PACKED qff_font_descriptor_v1_t { uint8_t transparency_index; // palette index used for transparent pixels (not yet implemented) } qff_font_descriptor_v1_t; -_Static_assert(sizeof(qff_font_descriptor_v1_t) == (sizeof(qgf_block_header_v1_t) + 20), "qff_font_descriptor_v1_t must be 25 bytes in v1 of QFF"); +STATIC_ASSERT(sizeof(qff_font_descriptor_v1_t) == (sizeof(qgf_block_header_v1_t) + 20), "qff_font_descriptor_v1_t must be 25 bytes in v1 of QFF"); #define QFF_MAGIC 0x464651 @@ -54,14 +55,14 @@ typedef struct QP_PACKED qff_ascii_glyph_v1_t { uint32_t value : 24; // Uses QFF_GLYPH_*_(BITS|MASK) as bitfield ordering is compiler-defined } qff_ascii_glyph_v1_t; -_Static_assert(sizeof(qff_ascii_glyph_v1_t) == 3, "qff_ascii_glyph_v1_t must be 3 bytes in v1 of QFF"); +STATIC_ASSERT(sizeof(qff_ascii_glyph_v1_t) == 3, "qff_ascii_glyph_v1_t must be 3 bytes in v1 of QFF"); typedef struct QP_PACKED qff_ascii_glyph_table_v1_t { qgf_block_header_v1_t header; // = { .type_id = 0x01, .neg_type_id = (~0x01), .length = 285 } qff_ascii_glyph_v1_t glyph[95]; // 95 glyphs, 0x20..0x7E } qff_ascii_glyph_table_v1_t; -_Static_assert(sizeof(qff_ascii_glyph_table_v1_t) == (sizeof(qgf_block_header_v1_t) + (95 * sizeof(qff_ascii_glyph_v1_t))), "qff_ascii_glyph_table_v1_t must be 290 bytes in v1 of QFF"); +STATIC_ASSERT(sizeof(qff_ascii_glyph_table_v1_t) == (sizeof(qgf_block_header_v1_t) + (95 * sizeof(qff_ascii_glyph_v1_t))), "qff_ascii_glyph_table_v1_t must be 290 bytes in v1 of QFF"); ///////////////////////////////////////// // Unicode glyph table descriptor @@ -73,7 +74,7 @@ typedef struct QP_PACKED qff_unicode_glyph_v1_t { uint32_t value : 24; // Uses QFF_GLYPH_*_(BITS|MASK) as bitfield ordering is compiler-defined } qff_unicode_glyph_v1_t; -_Static_assert(sizeof(qff_unicode_glyph_v1_t) == 6, "qff_unicode_glyph_v1_t must be 6 bytes in v1 of QFF"); +STATIC_ASSERT(sizeof(qff_unicode_glyph_v1_t) == 6, "qff_unicode_glyph_v1_t must be 6 bytes in v1 of QFF"); typedef struct QP_PACKED qff_unicode_glyph_table_v1_t { qgf_block_header_v1_t header; // = { .type_id = 0x02, .neg_type_id = (~0x02), .length = (N * 6) } diff --git a/quantum/painter/qgf.h b/quantum/painter/qgf.h index 33a37709e6..a1e245f15d 100644 --- a/quantum/painter/qgf.h +++ b/quantum/painter/qgf.h @@ -9,6 +9,7 @@ #include #include +#include "compiler_support.h" #include "qp_stream.h" #include "qp_internal.h" @@ -24,7 +25,7 @@ typedef struct QP_PACKED qgf_block_header_v1_t { uint32_t length : 24; // 24-bit blob length, allowing for block sizes of a maximum of 16MB. } qgf_block_header_v1_t; -_Static_assert(sizeof(qgf_block_header_v1_t) == 5, "qgf_block_header_v1_t must be 5 bytes in v1 of QGF"); +STATIC_ASSERT(sizeof(qgf_block_header_v1_t) == 5, "qgf_block_header_v1_t must be 5 bytes in v1 of QGF"); ///////////////////////////////////////// // Graphics descriptor @@ -42,7 +43,7 @@ typedef struct QP_PACKED qgf_graphics_descriptor_v1_t { uint16_t frame_count; // minimum of 1 } qgf_graphics_descriptor_v1_t; -_Static_assert(sizeof(qgf_graphics_descriptor_v1_t) == (sizeof(qgf_block_header_v1_t) + 18), "qgf_graphics_descriptor_v1_t must be 23 bytes in v1 of QGF"); +STATIC_ASSERT(sizeof(qgf_graphics_descriptor_v1_t) == (sizeof(qgf_block_header_v1_t) + 18), "qgf_graphics_descriptor_v1_t must be 23 bytes in v1 of QGF"); #define QGF_MAGIC 0x464751 @@ -56,7 +57,7 @@ typedef struct QP_PACKED qgf_frame_offsets_v1_t { uint32_t offset[0]; // '0' signifies that this struct is immediately followed by the frame offsets } qgf_frame_offsets_v1_t; -_Static_assert(sizeof(qgf_frame_offsets_v1_t) == sizeof(qgf_block_header_v1_t), "qgf_frame_offsets_v1_t must only contain qgf_block_header_v1_t in v1 of QGF"); +STATIC_ASSERT(sizeof(qgf_frame_offsets_v1_t) == sizeof(qgf_block_header_v1_t), "qgf_frame_offsets_v1_t must only contain qgf_block_header_v1_t in v1 of QGF"); ///////////////////////////////////////// // Frame descriptor @@ -72,7 +73,7 @@ typedef struct QP_PACKED qgf_frame_v1_t { uint16_t delay; // frame delay time for animations (in units of milliseconds) } qgf_frame_v1_t; -_Static_assert(sizeof(qgf_frame_v1_t) == (sizeof(qgf_block_header_v1_t) + 6), "qgf_frame_v1_t must be 11 bytes in v1 of QGF"); +STATIC_ASSERT(sizeof(qgf_frame_v1_t) == (sizeof(qgf_block_header_v1_t) + 6), "qgf_frame_v1_t must be 11 bytes in v1 of QGF"); #define QGF_FRAME_FLAG_DELTA 0x02 #define QGF_FRAME_FLAG_TRANSPARENT 0x01 @@ -88,14 +89,14 @@ typedef struct QP_PACKED qgf_palette_entry_v1_t { uint8_t v; // value component: `[0,1]` is mapped to `[0,255]` uint8_t. } qgf_palette_entry_v1_t; -_Static_assert(sizeof(qgf_palette_entry_v1_t) == 3, "Palette entry is not 3 bytes in size"); +STATIC_ASSERT(sizeof(qgf_palette_entry_v1_t) == 3, "Palette entry is not 3 bytes in size"); typedef struct QP_PACKED qgf_palette_v1_t { qgf_block_header_v1_t header; // = { .type_id = 0x03, .neg_type_id = (~0x03), .length = (N * 3 * sizeof(uint8_t)) } qgf_palette_entry_v1_t hsv[0]; // N * hsv, where N is the number of palette entries depending on the frame format in the descriptor } qgf_palette_v1_t; -_Static_assert(sizeof(qgf_palette_v1_t) == sizeof(qgf_block_header_v1_t), "qgf_palette_v1_t must only contain qgf_block_header_v1_t in v1 of QGF"); +STATIC_ASSERT(sizeof(qgf_palette_v1_t) == sizeof(qgf_block_header_v1_t), "qgf_palette_v1_t must only contain qgf_block_header_v1_t in v1 of QGF"); ///////////////////////////////////////// // Frame delta descriptor @@ -110,7 +111,7 @@ typedef struct QP_PACKED qgf_delta_v1_t { uint16_t bottom; // The bottom pixel location to to draw the delta image } qgf_delta_v1_t; -_Static_assert(sizeof(qgf_delta_v1_t) == (sizeof(qgf_block_header_v1_t) + 8), "qgf_delta_v1_t must be 13 bytes in v1 of QGF"); +STATIC_ASSERT(sizeof(qgf_delta_v1_t) == (sizeof(qgf_block_header_v1_t) + 8), "qgf_delta_v1_t must be 13 bytes in v1 of QGF"); ///////////////////////////////////////// // Frame data descriptor @@ -122,7 +123,7 @@ typedef struct QP_PACKED qgf_data_v1_t { uint8_t data[0]; // 0 signifies that this struct is immediately followed by the length of data specified in the header } qgf_data_v1_t; -_Static_assert(sizeof(qgf_data_v1_t) == sizeof(qgf_block_header_v1_t), "qgf_data_v1_t must only contain qgf_block_header_v1_t in v1 of QGF"); +STATIC_ASSERT(sizeof(qgf_data_v1_t) == sizeof(qgf_block_header_v1_t), "qgf_data_v1_t must only contain qgf_block_header_v1_t in v1 of QGF"); //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // QGF API diff --git a/quantum/painter/qp_draw_core.c b/quantum/painter/qp_draw_core.c index aa5fa4aa76..852abb19e8 100644 --- a/quantum/painter/qp_draw_core.c +++ b/quantum/painter/qp_draw_core.c @@ -2,12 +2,13 @@ // Copyright 2021 Paul Cotter (@gr1mr3aver) // SPDX-License-Identifier: GPL-2.0-or-later +#include "compiler_support.h" #include "qp_internal.h" #include "qp_comms.h" #include "qp_draw.h" #include "qgf.h" -_Static_assert((QUANTUM_PAINTER_PIXDATA_BUFFER_SIZE > 0) && (QUANTUM_PAINTER_PIXDATA_BUFFER_SIZE % 16) == 0, "QUANTUM_PAINTER_PIXDATA_BUFFER_SIZE needs to be a non-zero multiple of 16"); +STATIC_ASSERT((QUANTUM_PAINTER_PIXDATA_BUFFER_SIZE > 0) && (QUANTUM_PAINTER_PIXDATA_BUFFER_SIZE % 16) == 0, "QUANTUM_PAINTER_PIXDATA_BUFFER_SIZE needs to be a non-zero multiple of 16"); //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Global variables diff --git a/quantum/painter/qp_internal.c b/quantum/painter/qp_internal.c index 24b881bd09..fe0c598d78 100644 --- a/quantum/painter/qp_internal.c +++ b/quantum/painter/qp_internal.c @@ -3,6 +3,8 @@ #include "qp_internal.h" +#include "compiler_support.h" + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Quantum Painter Core API: device registration @@ -67,7 +69,7 @@ static void qp_internal_display_timeout_task(void) { //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Quantum Painter Core API: qp_internal_task -_Static_assert((QUANTUM_PAINTER_TASK_THROTTLE) > 0 && (QUANTUM_PAINTER_TASK_THROTTLE) < 1000, "QUANTUM_PAINTER_TASK_THROTTLE must be between 1 and 999"); +STATIC_ASSERT((QUANTUM_PAINTER_TASK_THROTTLE) > 0 && (QUANTUM_PAINTER_TASK_THROTTLE) < 1000, "QUANTUM_PAINTER_TASK_THROTTLE must be between 1 and 999"); void qp_internal_task(void) { // Perform throttling of the internal processing of Quantum Painter diff --git a/quantum/painter/qp_internal_formats.h b/quantum/painter/qp_internal_formats.h index 1beb604b9e..bd7105cab2 100644 --- a/quantum/painter/qp_internal_formats.h +++ b/quantum/painter/qp_internal_formats.h @@ -3,6 +3,7 @@ #pragma once +#include "compiler_support.h" #include "qp_internal.h" //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -29,7 +30,7 @@ typedef union QP_PACKED qp_pixel_t { uint32_t dummy; } qp_pixel_t; -_Static_assert(sizeof(qp_pixel_t) == 4, "Invalid size for qp_pixel_t"); +STATIC_ASSERT(sizeof(qp_pixel_t) == 4, "Invalid size for qp_pixel_t"); //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Quantum Painter image format diff --git a/quantum/rgb_matrix/rgb_matrix_types.h b/quantum/rgb_matrix/rgb_matrix_types.h index 62005ebea9..0115edee6a 100644 --- a/quantum/rgb_matrix/rgb_matrix_types.h +++ b/quantum/rgb_matrix/rgb_matrix_types.h @@ -18,6 +18,8 @@ #include #include + +#include "compiler_support.h" #include "color.h" #include "util.h" @@ -84,4 +86,4 @@ typedef union rgb_config_t { }; } rgb_config_t; -_Static_assert(sizeof(rgb_config_t) == sizeof(uint64_t), "RGB Matrix EECONFIG out of spec."); +STATIC_ASSERT(sizeof(rgb_config_t) == sizeof(uint64_t), "RGB Matrix EECONFIG out of spec."); diff --git a/quantum/rgblight/rgblight.h b/quantum/rgblight/rgblight.h index f5fd450d4c..c061e71895 100644 --- a/quantum/rgblight/rgblight.h +++ b/quantum/rgblight/rgblight.h @@ -16,6 +16,8 @@ #pragma once +#include "compiler_support.h" + // DEPRECATED DEFINES - DO NOT USE #if defined(RGBLED_NUM) # define RGBLIGHT_LED_COUNT RGBLED_NUM @@ -260,7 +262,7 @@ typedef union rgblight_config_t { }; } rgblight_config_t; -_Static_assert(sizeof(rgblight_config_t) == sizeof(uint64_t), "RGB Light EECONFIG out of spec."); +STATIC_ASSERT(sizeof(rgblight_config_t) == sizeof(uint64_t), "RGB Light EECONFIG out of spec."); typedef struct _rgblight_status_t { uint8_t base_mode; diff --git a/quantum/split_common/split_util.c b/quantum/split_common/split_util.c index 9af3c29d75..59b6009ec4 100644 --- a/quantum/split_common/split_util.c +++ b/quantum/split_common/split_util.c @@ -13,6 +13,8 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + +#include "compiler_support.h" #include "split_util.h" #include "matrix.h" #include "keyboard.h" @@ -62,7 +64,7 @@ static struct { } split_config; #if defined(SPLIT_USB_DETECT) -_Static_assert((SPLIT_USB_TIMEOUT / SPLIT_USB_TIMEOUT_POLL) <= UINT16_MAX, "Please lower SPLIT_USB_TIMEOUT and/or increase SPLIT_USB_TIMEOUT_POLL."); +STATIC_ASSERT((SPLIT_USB_TIMEOUT / SPLIT_USB_TIMEOUT_POLL) <= UINT16_MAX, "Please lower SPLIT_USB_TIMEOUT and/or increase SPLIT_USB_TIMEOUT_POLL."); static bool usb_bus_detected(void) { for (uint16_t i = 0; i < (SPLIT_USB_TIMEOUT / SPLIT_USB_TIMEOUT_POLL); i++) { // This will return true if a USB connection has been established @@ -88,9 +90,9 @@ static inline bool usb_bus_detected(void) { # endif # endif # if defined(SPLIT_USB_DETECT) -_Static_assert(SPLIT_USB_TIMEOUT < SPLIT_WATCHDOG_TIMEOUT, "SPLIT_WATCHDOG_TIMEOUT should not be below SPLIT_USB_TIMEOUT."); +STATIC_ASSERT(SPLIT_USB_TIMEOUT < SPLIT_WATCHDOG_TIMEOUT, "SPLIT_WATCHDOG_TIMEOUT should not be below SPLIT_USB_TIMEOUT."); # endif -_Static_assert(SPLIT_MAX_CONNECTION_ERRORS > 0, "SPLIT_WATCHDOG_ENABLE requires SPLIT_MAX_CONNECTION_ERRORS be above 0 for a functioning disconnection check."); +STATIC_ASSERT(SPLIT_MAX_CONNECTION_ERRORS > 0, "SPLIT_WATCHDOG_ENABLE requires SPLIT_MAX_CONNECTION_ERRORS be above 0 for a functioning disconnection check."); static uint32_t split_watchdog_started = 0; static bool split_watchdog_done = false; diff --git a/quantum/split_common/transaction_id_define.h b/quantum/split_common/transaction_id_define.h index 5bfbe2aec7..694737868a 100644 --- a/quantum/split_common/transaction_id_define.h +++ b/quantum/split_common/transaction_id_define.h @@ -16,6 +16,8 @@ #pragma once +#include "compiler_support.h" + enum serial_transaction_id { #ifdef USE_I2C I2C_EXECUTE_CALLBACK, @@ -122,4 +124,4 @@ enum serial_transaction_id { }; // Ensure we only use 5 bits for transaction -_Static_assert(NUM_TOTAL_TRANSACTIONS <= (1 << 5), "Max number of usable transactions exceeded"); +STATIC_ASSERT(NUM_TOTAL_TRANSACTIONS <= (1 << 5), "Max number of usable transactions exceeded"); diff --git a/quantum/split_common/transport.c b/quantum/split_common/transport.c index 83edc34859..ea687af1c2 100644 --- a/quantum/split_common/transport.c +++ b/quantum/split_common/transport.c @@ -17,6 +17,7 @@ #include #include +#include "compiler_support.h" #include "transactions.h" #include "transport.h" #include "transaction_id_define.h" @@ -36,7 +37,7 @@ # include "i2c_slave.h" // Ensure the I2C buffer has enough space -_Static_assert(sizeof(split_shared_memory_t) <= I2C_SLAVE_REG_COUNT, "split_shared_memory_t too large for I2C_SLAVE_REG_COUNT"); +STATIC_ASSERT(sizeof(split_shared_memory_t) <= I2C_SLAVE_REG_COUNT, "split_shared_memory_t too large for I2C_SLAVE_REG_COUNT"); split_shared_memory_t *const split_shmem = (split_shared_memory_t *)i2c_slave_reg; diff --git a/quantum/unicode/unicode.h b/quantum/unicode/unicode.h index f19d803335..7cddc78b7a 100644 --- a/quantum/unicode/unicode.h +++ b/quantum/unicode/unicode.h @@ -17,6 +17,8 @@ #pragma once #include + +#include "compiler_support.h" #include "unicode_keycodes.h" /** @@ -33,7 +35,7 @@ typedef union unicode_config_t { }; } unicode_config_t; -_Static_assert(sizeof(unicode_config_t) == sizeof(uint8_t), "Unicode EECONFIG out of spec."); +STATIC_ASSERT(sizeof(unicode_config_t) == sizeof(uint8_t), "Unicode EECONFIG out of spec."); extern unicode_config_t unicode_config; diff --git a/quantum/wear_leveling/wear_leveling_internal.h b/quantum/wear_leveling/wear_leveling_internal.h index e83f9b22ea..c590f42235 100644 --- a/quantum/wear_leveling/wear_leveling_internal.h +++ b/quantum/wear_leveling/wear_leveling_internal.h @@ -2,9 +2,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later #pragma once -#ifdef __cplusplus -# define _Static_assert static_assert -#endif +#include "compiler_support.h" #include #include @@ -62,9 +60,9 @@ typedef uint64_t backing_store_int_t; #endif // WEAR_LEVELING_ASSERTS // Compile-time validation of configurable options -_Static_assert(WEAR_LEVELING_BACKING_SIZE >= (WEAR_LEVELING_LOGICAL_SIZE * 2), "Total backing size must be at least twice the size of the logical size"); -_Static_assert(WEAR_LEVELING_LOGICAL_SIZE % BACKING_STORE_WRITE_SIZE == 0, "Logical size must be a multiple of write size"); -_Static_assert(WEAR_LEVELING_BACKING_SIZE % WEAR_LEVELING_LOGICAL_SIZE == 0, "Backing size must be a multiple of logical size"); +STATIC_ASSERT(WEAR_LEVELING_BACKING_SIZE >= (WEAR_LEVELING_LOGICAL_SIZE * 2), "Total backing size must be at least twice the size of the logical size"); +STATIC_ASSERT(WEAR_LEVELING_LOGICAL_SIZE % BACKING_STORE_WRITE_SIZE == 0, "Logical size must be a multiple of write size"); +STATIC_ASSERT(WEAR_LEVELING_BACKING_SIZE % WEAR_LEVELING_LOGICAL_SIZE == 0, "Backing size must be a multiple of logical size"); // Backing Store API, to be implemented elsewhere by flash driver etc. bool backing_store_init(void); @@ -86,7 +84,7 @@ typedef union write_log_entry_t { uint8_t raw8[8]; } write_log_entry_t; -_Static_assert(sizeof(write_log_entry_t) == 8, "Wear leveling write log entry size was not 8"); +STATIC_ASSERT(sizeof(write_log_entry_t) == 8, "Wear leveling write log entry size was not 8"); /** * Log entry type discriminator. @@ -104,7 +102,7 @@ enum { LOG_ENTRY_TYPES }; -_Static_assert(LOG_ENTRY_TYPES <= (1 << 2), "Too many log entry types to fit into 2 bits of storage"); +STATIC_ASSERT(LOG_ENTRY_TYPES <= (1 << 2), "Too many log entry types to fit into 2 bits of storage"); #define BITMASK_FOR_BITCOUNT(n) ((1 << (n)) - 1) diff --git a/tmk_core/protocol/vusb/vusb.c b/tmk_core/protocol/vusb/vusb.c index 43cce6eb2f..1f0f82664b 100644 --- a/tmk_core/protocol/vusb/vusb.c +++ b/tmk_core/protocol/vusb/vusb.c @@ -21,6 +21,7 @@ along with this program. If not, see . #include +#include "compiler_support.h" #include "usbconfig.h" #include "host.h" #include "report.h" @@ -80,7 +81,7 @@ enum usb_interfaces { #define MAX_INTERFACES 3 -_Static_assert(TOTAL_INTERFACES <= MAX_INTERFACES, "There are not enough available interfaces to support all functions. Please disable one or more of the following: Mouse Keys, Extra Keys, Raw HID, Console."); +STATIC_ASSERT(TOTAL_INTERFACES <= MAX_INTERFACES, "There are not enough available interfaces to support all functions. Please disable one or more of the following: Mouse Keys, Extra Keys, Raw HID, Console."); #if (defined(MOUSE_ENABLE) || defined(EXTRAKEY_ENABLE)) && CONSOLE_ENABLE # error Mouse/Extra Keys share an endpoint with Console. Please disable one of the two. -- cgit v1.2.3