aboutsummaryrefslogtreecommitdiff
path: root/quantum
diff options
context:
space:
mode:
Diffstat (limited to 'quantum')
-rw-r--r--quantum/action.c254
-rw-r--r--quantum/action.h2
-rw-r--r--quantum/action_tapping.c38
-rw-r--r--quantum/action_util.c3
-rw-r--r--quantum/api.c182
-rw-r--r--quantum/api.h55
-rw-r--r--quantum/api/api_sysex.c72
-rw-r--r--quantum/api/api_sysex.h25
-rw-r--r--quantum/audio/audio.h13
-rw-r--r--quantum/audio/driver_avr_pwm.h17
-rw-r--r--quantum/audio/driver_avr_pwm_hardware.c332
-rw-r--r--quantum/audio/driver_chibios_dac.h126
-rw-r--r--quantum/audio/driver_chibios_dac_additive.c335
-rw-r--r--quantum/audio/driver_chibios_dac_basic.c245
-rw-r--r--quantum/audio/driver_chibios_pwm.h40
-rw-r--r--quantum/audio/driver_chibios_pwm_hardware.c144
-rw-r--r--quantum/audio/driver_chibios_pwm_software.c164
-rw-r--r--quantum/audio/song_list.h8
-rw-r--r--quantum/backlight/backlight_chibios.c10
-rw-r--r--quantum/debounce/asym_eager_defer_pk.c22
-rw-r--r--quantum/debounce/sym_defer_g.c2
-rw-r--r--quantum/debounce/sym_defer_pk.c6
-rw-r--r--quantum/debounce/sym_eager_pk.c8
-rw-r--r--quantum/debounce/sym_eager_pr.c8
-rw-r--r--quantum/debounce/tests/asym_eager_defer_pk_tests.cpp66
-rw-r--r--quantum/debounce/tests/debounce_test_common.cpp72
-rw-r--r--quantum/debounce/tests/debounce_test_common.h24
-rw-r--r--quantum/debounce/tests/sym_defer_g_tests.cpp45
-rw-r--r--quantum/debounce/tests/sym_defer_pk_tests.cpp45
-rw-r--r--quantum/debounce/tests/sym_eager_pk_tests.cpp48
-rw-r--r--quantum/debounce/tests/sym_eager_pr_tests.cpp57
-rw-r--r--quantum/eeconfig.c11
-rw-r--r--quantum/eeconfig.h26
-rw-r--r--quantum/keyboard.c70
-rw-r--r--quantum/keymap_extras/keymap_steno.h3
-rw-r--r--quantum/keymap_extras/keymap_turkish_f.h2
-rw-r--r--quantum/led_matrix/animations/alpha_mods_anim.h2
-rw-r--r--quantum/led_matrix/animations/breathing_anim.h2
-rw-r--r--quantum/led_matrix/animations/runners/effect_runner_dx_dy.h2
-rw-r--r--quantum/led_matrix/animations/runners/effect_runner_dx_dy_dist.h2
-rw-r--r--quantum/led_matrix/animations/runners/effect_runner_i.h2
-rw-r--r--quantum/led_matrix/animations/runners/effect_runner_reactive.h2
-rw-r--r--quantum/led_matrix/animations/runners/effect_runner_reactive_splash.h2
-rw-r--r--quantum/led_matrix/animations/runners/effect_runner_sin_cos_i.h2
-rw-r--r--quantum/led_matrix/animations/solid_anim.h2
-rw-r--r--quantum/led_matrix/led_matrix.c46
-rw-r--r--quantum/led_matrix/led_matrix.h45
-rw-r--r--quantum/led_matrix/led_matrix_drivers.c133
-rw-r--r--quantum/main.c15
-rw-r--r--quantum/matrix.c51
-rw-r--r--quantum/mcu_selection.mk600
-rw-r--r--quantum/process_keycode/process_auto_shift.c8
-rw-r--r--quantum/process_keycode/process_combo.c184
-rw-r--r--quantum/process_keycode/process_combo.h4
-rw-r--r--quantum/process_keycode/process_haptic.c1
-rw-r--r--quantum/process_keycode/process_programmable_button.c31
-rw-r--r--quantum/process_keycode/process_programmable_button.h23
-rw-r--r--quantum/process_keycode/process_steno.c9
-rw-r--r--quantum/process_keycode/process_unicode_common.c47
-rw-r--r--quantum/programmable_button.c37
-rw-r--r--quantum/programmable_button.h30
-rw-r--r--quantum/quantum.c122
-rw-r--r--quantum/quantum.h6
-rw-r--r--quantum/quantum_keycodes.h82
-rw-r--r--quantum/raw_hid.h5
-rw-r--r--quantum/rgb_matrix/animations/alpha_mods_anim.h2
-rw-r--r--quantum/rgb_matrix/animations/breathing_anim.h2
-rw-r--r--quantum/rgb_matrix/animations/fractal_anim.h74
-rw-r--r--quantum/rgb_matrix/animations/gradient_left_right_anim.h2
-rw-r--r--quantum/rgb_matrix/animations/gradient_up_down_anim.h2
-rw-r--r--quantum/rgb_matrix/animations/hue_breathing_anim.h2
-rw-r--r--quantum/rgb_matrix/animations/jellybean_raindrops_anim.h2
-rw-r--r--quantum/rgb_matrix/animations/pixel_rain_anim.h44
-rw-r--r--quantum/rgb_matrix/animations/raindrops_anim.h2
-rw-r--r--quantum/rgb_matrix/animations/rgb_matrix_effects.inc2
-rw-r--r--quantum/rgb_matrix/animations/runners/effect_runner_dx_dy.h2
-rw-r--r--quantum/rgb_matrix/animations/runners/effect_runner_dx_dy_dist.h2
-rw-r--r--quantum/rgb_matrix/animations/runners/effect_runner_i.h2
-rw-r--r--quantum/rgb_matrix/animations/runners/effect_runner_reactive.h2
-rw-r--r--quantum/rgb_matrix/animations/runners/effect_runner_reactive_splash.h2
-rw-r--r--quantum/rgb_matrix/animations/runners/effect_runner_sin_cos_i.h2
-rw-r--r--quantum/rgb_matrix/animations/solid_color_anim.h2
-rw-r--r--quantum/rgb_matrix/rgb_matrix.c41
-rw-r--r--quantum/rgb_matrix/rgb_matrix.h47
-rw-r--r--quantum/rgb_matrix/rgb_matrix_drivers.c184
-rw-r--r--quantum/sequencer/tests/rules.mk2
-rw-r--r--quantum/serial_link/LICENSE19
-rw-r--r--quantum/serial_link/README.md1
-rw-r--r--quantum/serial_link/protocol/byte_stuffer.c135
-rw-r--r--quantum/serial_link/protocol/byte_stuffer.h34
-rw-r--r--quantum/serial_link/protocol/frame_router.c64
-rw-r--r--quantum/serial_link/protocol/frame_router.h35
-rw-r--r--quantum/serial_link/protocol/frame_validator.c57
-rw-r--r--quantum/serial_link/protocol/frame_validator.h31
-rw-r--r--quantum/serial_link/protocol/physical.h27
-rw-r--r--quantum/serial_link/protocol/transport.c121
-rw-r--r--quantum/serial_link/protocol/transport.h139
-rw-r--r--quantum/serial_link/protocol/triple_buffered_object.c77
-rw-r--r--quantum/serial_link/protocol/triple_buffered_object.h44
-rw-r--r--quantum/serial_link/system/serial_link.c250
-rw-r--r--quantum/serial_link/system/serial_link.h54
-rw-r--r--quantum/serial_link/tests/Makefile61
-rw-r--r--quantum/serial_link/tests/byte_stuffer_tests.cpp450
-rw-r--r--quantum/serial_link/tests/frame_router_tests.cpp204
-rw-r--r--quantum/serial_link/tests/frame_validator_tests.cpp100
-rw-r--r--quantum/serial_link/tests/rules.mk22
-rw-r--r--quantum/serial_link/tests/testlist.mk6
-rw-r--r--quantum/serial_link/tests/transport_tests.cpp184
-rw-r--r--quantum/serial_link/tests/triple_buffered_object_tests.cpp80
-rw-r--r--quantum/split_common/transactions.c48
-rw-r--r--quantum/sync_timer.c58
-rw-r--r--quantum/sync_timer.h54
-rw-r--r--quantum/virtser.h9
-rw-r--r--quantum/visualizer/LICENSE.md29
-rw-r--r--quantum/visualizer/common_gfxconf.h354
-rw-r--r--quantum/visualizer/default_animations.c177
-rw-r--r--quantum/visualizer/default_animations.h27
-rw-r--r--quantum/visualizer/lcd_backlight.c87
-rw-r--r--quantum/visualizer/lcd_backlight.h43
-rw-r--r--quantum/visualizer/lcd_backlight_keyframes.c69
-rw-r--r--quantum/visualizer/lcd_backlight_keyframes.h27
-rw-r--r--quantum/visualizer/lcd_keyframes.c184
-rw-r--r--quantum/visualizer/lcd_keyframes.h35
-rw-r--r--quantum/visualizer/led_backlight_keyframes.c143
-rw-r--r--quantum/visualizer/led_backlight_keyframes.h40
-rw-r--r--quantum/visualizer/readme.md18
-rw-r--r--quantum/visualizer/resources/lcd_logo.c45
-rw-r--r--quantum/visualizer/resources/lcd_logo.pngbin271 -> 0 bytes
-rw-r--r--quantum/visualizer/resources/resources.h23
-rw-r--r--quantum/visualizer/visualizer.c483
-rw-r--r--quantum/visualizer/visualizer.h154
-rw-r--r--quantum/visualizer/visualizer.mk123
-rw-r--r--quantum/visualizer/visualizer_keyframes.c23
-rw-r--r--quantum/visualizer/visualizer_keyframes.h23
134 files changed, 1552 insertions, 7418 deletions
diff --git a/quantum/action.c b/quantum/action.c
index be135f18f..5c33bd6d2 100644
--- a/quantum/action.c
+++ b/quantum/action.c
@@ -18,6 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
18#include "keycode.h" 18#include "keycode.h"
19#include "keyboard.h" 19#include "keyboard.h"
20#include "mousekey.h" 20#include "mousekey.h"
21#include "programmable_button.h"
21#include "command.h" 22#include "command.h"
22#include "led.h" 23#include "led.h"
23#include "action_layer.h" 24#include "action_layer.h"
@@ -26,6 +27,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
26#include "action_util.h" 27#include "action_util.h"
27#include "action.h" 28#include "action.h"
28#include "wait.h" 29#include "wait.h"
30#include "keycode_config.h"
29 31
30#ifdef BACKLIGHT_ENABLE 32#ifdef BACKLIGHT_ENABLE
31# include "backlight.h" 33# include "backlight.h"
@@ -86,19 +88,21 @@ void action_exec(keyevent_t event) {
86 keyrecord_t record = {.event = event}; 88 keyrecord_t record = {.event = event};
87 89
88#ifndef NO_ACTION_ONESHOT 90#ifndef NO_ACTION_ONESHOT
91 if (!keymap_config.oneshot_disable) {
89# if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0)) 92# if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0))
90 if (has_oneshot_layer_timed_out()) { 93 if (has_oneshot_layer_timed_out()) {
91 clear_oneshot_layer_state(ONESHOT_OTHER_KEY_PRESSED); 94 clear_oneshot_layer_state(ONESHOT_OTHER_KEY_PRESSED);
92 } 95 }
93 if (has_oneshot_mods_timed_out()) { 96 if (has_oneshot_mods_timed_out()) {
94 clear_oneshot_mods(); 97 clear_oneshot_mods();
95 } 98 }
96# ifdef SWAP_HANDS_ENABLE 99# ifdef SWAP_HANDS_ENABLE
97 if (has_oneshot_swaphands_timed_out()) { 100 if (has_oneshot_swaphands_timed_out()) {
98 clear_oneshot_swaphands(); 101 clear_oneshot_swaphands();
99 } 102 }
100# endif 103# endif
101# endif 104# endif
105 }
102#endif 106#endif
103 107
104#ifndef NO_ACTION_TAPPING 108#ifndef NO_ACTION_TAPPING
@@ -194,7 +198,7 @@ void process_record(keyrecord_t *record) {
194 198
195 if (!process_record_quantum(record)) { 199 if (!process_record_quantum(record)) {
196#ifndef NO_ACTION_ONESHOT 200#ifndef NO_ACTION_ONESHOT
197 if (is_oneshot_layer_active() && record->event.pressed) { 201 if (is_oneshot_layer_active() && record->event.pressed && !keymap_config.oneshot_disable) {
198 clear_oneshot_layer_state(ONESHOT_OTHER_KEY_PRESSED); 202 clear_oneshot_layer_state(ONESHOT_OTHER_KEY_PRESSED);
199 } 203 }
200#endif 204#endif
@@ -259,7 +263,7 @@ void process_action(keyrecord_t *record, action_t action) {
259# ifdef SWAP_HANDS_ENABLE 263# ifdef SWAP_HANDS_ENABLE
260 && !(action.kind.id == ACT_SWAP_HANDS && action.swap.code == OP_SH_ONESHOT) 264 && !(action.kind.id == ACT_SWAP_HANDS && action.swap.code == OP_SH_ONESHOT)
261# endif 265# endif
262 ) { 266 && !keymap_config.oneshot_disable) {
263 clear_oneshot_layer_state(ONESHOT_OTHER_KEY_PRESSED); 267 clear_oneshot_layer_state(ONESHOT_OTHER_KEY_PRESSED);
264 do_release_oneshot = !is_oneshot_layer_active(); 268 do_release_oneshot = !is_oneshot_layer_active();
265 } 269 }
@@ -303,41 +307,68 @@ void process_action(keyrecord_t *record, action_t action) {
303# ifndef NO_ACTION_ONESHOT 307# ifndef NO_ACTION_ONESHOT
304 case MODS_ONESHOT: 308 case MODS_ONESHOT:
305 // Oneshot modifier 309 // Oneshot modifier
306 if (event.pressed) { 310 if (keymap_config.oneshot_disable) {
307 if (tap_count == 0) { 311 if (event.pressed) {
308 dprint("MODS_TAP: Oneshot: 0\n"); 312 if (mods) {
309 register_mods(mods | get_oneshot_mods()); 313 if (IS_MOD(action.key.code) || action.key.code == KC_NO) {
310 } else if (tap_count == 1) { 314 // e.g. LSFT(KC_LGUI): we don't want the LSFT to be weak as it would make it useless.
311 dprint("MODS_TAP: Oneshot: start\n"); 315 // This also makes LSFT(KC_LGUI) behave exactly the same as LGUI(KC_LSFT).
312 set_oneshot_mods(mods | get_oneshot_mods()); 316 // Same applies for some keys like KC_MEH which are declared as MEH(KC_NO).
313# if defined(ONESHOT_TAP_TOGGLE) && ONESHOT_TAP_TOGGLE > 1 317 add_mods(mods);
314 } else if (tap_count == ONESHOT_TAP_TOGGLE) { 318 } else {
315 dprint("MODS_TAP: Toggling oneshot"); 319 add_weak_mods(mods);
316 clear_oneshot_mods(); 320 }
317 set_oneshot_locked_mods(mods); 321 send_keyboard_report();
318 register_mods(mods); 322 }
319# endif 323 register_code(action.key.code);
320 } else { 324 } else {
321 register_mods(mods | get_oneshot_mods()); 325 unregister_code(action.key.code);
326 if (mods) {
327 if (IS_MOD(action.key.code) || action.key.code == KC_NO) {
328 del_mods(mods);
329 } else {
330 del_weak_mods(mods);
331 }
332 send_keyboard_report();
333 }
322 } 334 }
323 } else { 335 } else {
324 if (tap_count == 0) { 336 if (event.pressed) {
325 clear_oneshot_mods(); 337 if (tap_count == 0) {
326 unregister_mods(mods); 338 dprint("MODS_TAP: Oneshot: 0\n");
327 } else if (tap_count == 1) { 339 register_mods(mods | get_oneshot_mods());
328 // Retain Oneshot mods 340 } else if (tap_count == 1) {
341 dprint("MODS_TAP: Oneshot: start\n");
342 set_oneshot_mods(mods | get_oneshot_mods());
329# if defined(ONESHOT_TAP_TOGGLE) && ONESHOT_TAP_TOGGLE > 1 343# if defined(ONESHOT_TAP_TOGGLE) && ONESHOT_TAP_TOGGLE > 1
330 if (mods & get_mods()) { 344 } else if (tap_count == ONESHOT_TAP_TOGGLE) {
331 clear_oneshot_locked_mods(); 345 dprint("MODS_TAP: Toggling oneshot");
332 clear_oneshot_mods(); 346 clear_oneshot_mods();
333 unregister_mods(mods); 347 set_oneshot_locked_mods(mods);
334 } 348 register_mods(mods);
335 } else if (tap_count == ONESHOT_TAP_TOGGLE) {
336 // Toggle Oneshot Layer
337# endif 349# endif
350 } else {
351 register_mods(mods | get_oneshot_mods());
352 }
338 } else { 353 } else {
339 clear_oneshot_mods(); 354 if (tap_count == 0) {
340 unregister_mods(mods); 355 clear_oneshot_mods();
356 unregister_mods(mods);
357 } else if (tap_count == 1) {
358 // Retain Oneshot mods
359# if defined(ONESHOT_TAP_TOGGLE) && ONESHOT_TAP_TOGGLE > 1
360 if (mods & get_mods()) {
361 clear_oneshot_locked_mods();
362 clear_oneshot_mods();
363 unregister_mods(mods);
364 }
365 } else if (tap_count == ONESHOT_TAP_TOGGLE) {
366 // Toggle Oneshot Layer
367# endif
368 } else {
369 clear_oneshot_mods();
370 unregister_mods(mods);
371 }
341 } 372 }
342 } 373 }
343 break; 374 break;
@@ -522,39 +553,47 @@ void process_action(keyrecord_t *record, action_t action) {
522# ifndef NO_ACTION_ONESHOT 553# ifndef NO_ACTION_ONESHOT
523 case OP_ONESHOT: 554 case OP_ONESHOT:
524 // Oneshot modifier 555 // Oneshot modifier
525# if defined(ONESHOT_TAP_TOGGLE) && ONESHOT_TAP_TOGGLE > 1 556 if (keymap_config.oneshot_disable) {
526 do_release_oneshot = false; 557 if (event.pressed) {
527 if (event.pressed) {
528 del_mods(get_oneshot_locked_mods());
529 if (get_oneshot_layer_state() == ONESHOT_TOGGLED) {
530 reset_oneshot_layer();
531 layer_off(action.layer_tap.val);
532 break;
533 } else if (tap_count < ONESHOT_TAP_TOGGLE) {
534 layer_on(action.layer_tap.val); 558 layer_on(action.layer_tap.val);
535 set_oneshot_layer(action.layer_tap.val, ONESHOT_START); 559 } else {
560 layer_off(action.layer_tap.val);
536 } 561 }
537 } else { 562 } else {
538 add_mods(get_oneshot_locked_mods()); 563# if defined(ONESHOT_TAP_TOGGLE) && ONESHOT_TAP_TOGGLE > 1
539 if (tap_count >= ONESHOT_TAP_TOGGLE) { 564 do_release_oneshot = false;
540 reset_oneshot_layer(); 565 if (event.pressed) {
541 clear_oneshot_locked_mods(); 566 del_mods(get_oneshot_locked_mods());
542 set_oneshot_layer(action.layer_tap.val, ONESHOT_TOGGLED); 567 if (get_oneshot_layer_state() == ONESHOT_TOGGLED) {
568 reset_oneshot_layer();
569 layer_off(action.layer_tap.val);
570 break;
571 } else if (tap_count < ONESHOT_TAP_TOGGLE) {
572 layer_on(action.layer_tap.val);
573 set_oneshot_layer(action.layer_tap.val, ONESHOT_START);
574 }
543 } else { 575 } else {
544 clear_oneshot_layer_state(ONESHOT_PRESSED); 576 add_mods(get_oneshot_locked_mods());
577 if (tap_count >= ONESHOT_TAP_TOGGLE) {
578 reset_oneshot_layer();
579 clear_oneshot_locked_mods();
580 set_oneshot_layer(action.layer_tap.val, ONESHOT_TOGGLED);
581 } else {
582 clear_oneshot_layer_state(ONESHOT_PRESSED);
583 }
545 } 584 }
546 }
547# else 585# else
548 if (event.pressed) { 586 if (event.pressed) {
549 layer_on(action.layer_tap.val); 587 layer_on(action.layer_tap.val);
550 set_oneshot_layer(action.layer_tap.val, ONESHOT_START); 588 set_oneshot_layer(action.layer_tap.val, ONESHOT_START);
551 } else { 589 } else {
552 clear_oneshot_layer_state(ONESHOT_PRESSED); 590 clear_oneshot_layer_state(ONESHOT_PRESSED);
553 if (tap_count > 1) { 591 if (tap_count > 1) {
554 clear_oneshot_layer_state(ONESHOT_OTHER_KEY_PRESSED); 592 clear_oneshot_layer_state(ONESHOT_OTHER_KEY_PRESSED);
593 }
555 } 594 }
556 }
557# endif 595# endif
596 }
558 break; 597 break;
559# endif 598# endif
560 default: 599 default:
@@ -782,9 +821,10 @@ void register_code(uint8_t code) {
782 } 821 }
783#endif 822#endif
784 823
785 else if IS_KEY (code) { 824 else if
786 // TODO: should push command_proc out of this block? 825 IS_KEY(code) {
787 if (command_proc(code)) return; 826 // TODO: should push command_proc out of this block?
827 if (command_proc(code)) return;
788 828
789#ifndef NO_ACTION_ONESHOT 829#ifndef NO_ACTION_ONESHOT
790/* TODO: remove 830/* TODO: remove
@@ -801,33 +841,35 @@ void register_code(uint8_t code) {
801 } else 841 } else
802*/ 842*/
803#endif 843#endif
804 { 844 {
805 // Force a new key press if the key is already pressed 845 // Force a new key press if the key is already pressed
806 // without this, keys with the same keycode, but different 846 // without this, keys with the same keycode, but different
807 // modifiers will be reported incorrectly, see issue #1708 847 // modifiers will be reported incorrectly, see issue #1708
808 if (is_key_pressed(keyboard_report, code)) { 848 if (is_key_pressed(keyboard_report, code)) {
809 del_key(code); 849 del_key(code);
850 send_keyboard_report();
851 }
852 add_key(code);
810 send_keyboard_report(); 853 send_keyboard_report();
811 } 854 }
812 add_key(code); 855 }
856 else if
857 IS_MOD(code) {
858 add_mods(MOD_BIT(code));
813 send_keyboard_report(); 859 send_keyboard_report();
814 } 860 }
815 } else if IS_MOD (code) {
816 add_mods(MOD_BIT(code));
817 send_keyboard_report();
818 }
819#ifdef EXTRAKEY_ENABLE 861#ifdef EXTRAKEY_ENABLE
820 else if IS_SYSTEM (code) { 862 else if
821 host_system_send(KEYCODE2SYSTEM(code)); 863 IS_SYSTEM(code) { host_system_send(KEYCODE2SYSTEM(code)); }
822 } else if IS_CONSUMER (code) { 864 else if
823 host_consumer_send(KEYCODE2CONSUMER(code)); 865 IS_CONSUMER(code) { host_consumer_send(KEYCODE2CONSUMER(code)); }
824 }
825#endif 866#endif
826#ifdef MOUSEKEY_ENABLE 867#ifdef MOUSEKEY_ENABLE
827 else if IS_MOUSEKEY (code) { 868 else if
828 mousekey_on(code); 869 IS_MOUSEKEY(code) {
829 mousekey_send(); 870 mousekey_on(code);
830 } 871 mousekey_send();
872 }
831#endif 873#endif
832} 874}
833 875
@@ -872,22 +914,26 @@ void unregister_code(uint8_t code) {
872 } 914 }
873#endif 915#endif
874 916
875 else if IS_KEY (code) { 917 else if
876 del_key(code); 918 IS_KEY(code) {
877 send_keyboard_report(); 919 del_key(code);
878 } else if IS_MOD (code) { 920 send_keyboard_report();
879 del_mods(MOD_BIT(code)); 921 }
880 send_keyboard_report(); 922 else if
881 } else if IS_SYSTEM (code) { 923 IS_MOD(code) {
882 host_system_send(0); 924 del_mods(MOD_BIT(code));
883 } else if IS_CONSUMER (code) { 925 send_keyboard_report();
884 host_consumer_send(0); 926 }
885 } 927 else if
928 IS_SYSTEM(code) { host_system_send(0); }
929 else if
930 IS_CONSUMER(code) { host_consumer_send(0); }
886#ifdef MOUSEKEY_ENABLE 931#ifdef MOUSEKEY_ENABLE
887 else if IS_MOUSEKEY (code) { 932 else if
888 mousekey_off(code); 933 IS_MOUSEKEY(code) {
889 mousekey_send(); 934 mousekey_off(code);
890 } 935 mousekey_send();
936 }
891#endif 937#endif
892} 938}
893 939
@@ -988,6 +1034,10 @@ void clear_keyboard_but_mods_and_keys() {
988 mousekey_clear(); 1034 mousekey_clear();
989 mousekey_send(); 1035 mousekey_send();
990#endif 1036#endif
1037#ifdef PROGRAMMABLE_BUTTON_ENABLE
1038 programmable_button_clear();
1039 programmable_button_send();
1040#endif
991} 1041}
992 1042
993/** \brief Utilities for actions. (FIXME: Needs better description) 1043/** \brief Utilities for actions. (FIXME: Needs better description)
diff --git a/quantum/action.h b/quantum/action.h
index 8a357ded8..b562f18c5 100644
--- a/quantum/action.h
+++ b/quantum/action.h
@@ -88,7 +88,7 @@ extern bool disable_action_cache;
88 88
89/* Code for handling one-handed key modifiers. */ 89/* Code for handling one-handed key modifiers. */
90#ifdef SWAP_HANDS_ENABLE 90#ifdef SWAP_HANDS_ENABLE
91extern bool swap_hands; 91extern bool swap_hands;
92extern const keypos_t PROGMEM hand_swap_config[MATRIX_ROWS][MATRIX_COLS]; 92extern const keypos_t PROGMEM hand_swap_config[MATRIX_ROWS][MATRIX_COLS];
93# if (MATRIX_COLS <= 8) 93# if (MATRIX_COLS <= 8)
94typedef uint8_t swap_state_row_t; 94typedef uint8_t swap_state_row_t;
diff --git a/quantum/action_tapping.c b/quantum/action_tapping.c
index 36839f9fa..60e56fb81 100644
--- a/quantum/action_tapping.c
+++ b/quantum/action_tapping.c
@@ -18,11 +18,11 @@
18# define IS_TAPPING_PRESSED() (IS_TAPPING() && tapping_key.event.pressed) 18# define IS_TAPPING_PRESSED() (IS_TAPPING() && tapping_key.event.pressed)
19# define IS_TAPPING_RELEASED() (IS_TAPPING() && !tapping_key.event.pressed) 19# define IS_TAPPING_RELEASED() (IS_TAPPING() && !tapping_key.event.pressed)
20# define IS_TAPPING_KEY(k) (IS_TAPPING() && KEYEQ(tapping_key.event.key, (k))) 20# define IS_TAPPING_KEY(k) (IS_TAPPING() && KEYEQ(tapping_key.event.key, (k)))
21#ifndef COMBO_ENABLE 21# ifndef COMBO_ENABLE
22# define IS_TAPPING_RECORD(r) (IS_TAPPING() && KEYEQ(tapping_key.event.key, (r->event.key))) 22# define IS_TAPPING_RECORD(r) (IS_TAPPING() && KEYEQ(tapping_key.event.key, (r->event.key)))
23#else 23# else
24# define IS_TAPPING_RECORD(r) (IS_TAPPING() && KEYEQ(tapping_key.event.key, (r->event.key)) && tapping_key.keycode == r->keycode) 24# define IS_TAPPING_RECORD(r) (IS_TAPPING() && KEYEQ(tapping_key.event.key, (r->event.key)) && tapping_key.keycode == r->keycode)
25#endif 25# endif
26 26
27__attribute__((weak)) uint16_t get_tapping_term(uint16_t keycode, keyrecord_t *record) { return TAPPING_TERM; } 27__attribute__((weak)) uint16_t get_tapping_term(uint16_t keycode, keyrecord_t *record) { return TAPPING_TERM; }
28 28
@@ -212,11 +212,15 @@ bool process_tapping(keyrecord_t *keyp) {
212 if (tapping_key.tap.count > 1) { 212 if (tapping_key.tap.count > 1) {
213 debug("Tapping: Start new tap with releasing last tap(>1).\n"); 213 debug("Tapping: Start new tap with releasing last tap(>1).\n");
214 // unregister key 214 // unregister key
215 process_record(&(keyrecord_t){.tap = tapping_key.tap, .event.key = tapping_key.event.key, .event.time = event.time, .event.pressed = false, 215 process_record(&(keyrecord_t){
216#ifdef COMBO_ENABLE 216 .tap = tapping_key.tap,
217 .keycode = tapping_key.keycode, 217 .event.key = tapping_key.event.key,
218#endif 218 .event.time = event.time,
219 }); 219 .event.pressed = false,
220# ifdef COMBO_ENABLE
221 .keycode = tapping_key.keycode,
222# endif
223 });
220 } else { 224 } else {
221 debug("Tapping: Start while last tap(1).\n"); 225 debug("Tapping: Start while last tap(1).\n");
222 } 226 }
@@ -254,11 +258,15 @@ bool process_tapping(keyrecord_t *keyp) {
254 if (tapping_key.tap.count > 1) { 258 if (tapping_key.tap.count > 1) {
255 debug("Tapping: Start new tap with releasing last timeout tap(>1).\n"); 259 debug("Tapping: Start new tap with releasing last timeout tap(>1).\n");
256 // unregister key 260 // unregister key
257 process_record(&(keyrecord_t){.tap = tapping_key.tap, .event.key = tapping_key.event.key, .event.time = event.time, .event.pressed = false, 261 process_record(&(keyrecord_t){
258#ifdef COMBO_ENABLE 262 .tap = tapping_key.tap,
259 .keycode = tapping_key.keycode, 263 .event.key = tapping_key.event.key,
260#endif 264 .event.time = event.time,
261 }); 265 .event.pressed = false,
266# ifdef COMBO_ENABLE
267 .keycode = tapping_key.keycode,
268# endif
269 });
262 } else { 270 } else {
263 debug("Tapping: Start while last timeout tap(1).\n"); 271 debug("Tapping: Start while last timeout tap(1).\n");
264 } 272 }
diff --git a/quantum/action_util.c b/quantum/action_util.c
index 9a85bd504..78e02aec1 100644
--- a/quantum/action_util.c
+++ b/quantum/action_util.c
@@ -170,7 +170,7 @@ void reset_oneshot_layer(void) {
170void clear_oneshot_layer_state(oneshot_fullfillment_t state) { 170void clear_oneshot_layer_state(oneshot_fullfillment_t state) {
171 uint8_t start_state = oneshot_layer_data; 171 uint8_t start_state = oneshot_layer_data;
172 oneshot_layer_data &= ~state; 172 oneshot_layer_data &= ~state;
173 if ((!get_oneshot_layer_state() && start_state != oneshot_layer_data) || keymap_config.oneshot_disable) { 173 if ((!get_oneshot_layer_state() && start_state != oneshot_layer_data) && !keymap_config.oneshot_disable) {
174 layer_off(get_oneshot_layer()); 174 layer_off(get_oneshot_layer());
175 reset_oneshot_layer(); 175 reset_oneshot_layer();
176 } 176 }
@@ -189,6 +189,7 @@ void oneshot_set(bool active) {
189 if (keymap_config.oneshot_disable != active) { 189 if (keymap_config.oneshot_disable != active) {
190 keymap_config.oneshot_disable = active; 190 keymap_config.oneshot_disable = active;
191 eeconfig_update_keymap(keymap_config.raw); 191 eeconfig_update_keymap(keymap_config.raw);
192 clear_oneshot_layer_state(ONESHOT_OTHER_KEY_PRESSED);
192 dprintf("Oneshot: active: %d\n", active); 193 dprintf("Oneshot: active: %d\n", active);
193 } 194 }
194} 195}
diff --git a/quantum/api.c b/quantum/api.c
deleted file mode 100644
index 168574458..000000000
--- a/quantum/api.c
+++ /dev/null
@@ -1,182 +0,0 @@
1/* Copyright 2016 Jack Humbert
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "api.h"
18#include "quantum.h"
19
20void dword_to_bytes(uint32_t dword, uint8_t* bytes) {
21 bytes[0] = (dword >> 24) & 0xFF;
22 bytes[1] = (dword >> 16) & 0xFF;
23 bytes[2] = (dword >> 8) & 0xFF;
24 bytes[3] = (dword >> 0) & 0xFF;
25}
26
27uint32_t bytes_to_dword(uint8_t* bytes, uint8_t index) { return ((uint32_t)bytes[index + 0] << 24) | ((uint32_t)bytes[index + 1] << 16) | ((uint32_t)bytes[index + 2] << 8) | (uint32_t)bytes[index + 3]; }
28
29__attribute__((weak)) bool process_api_quantum(uint8_t length, uint8_t* data) { return process_api_keyboard(length, data); }
30
31__attribute__((weak)) bool process_api_keyboard(uint8_t length, uint8_t* data) { return process_api_user(length, data); }
32
33__attribute__((weak)) bool process_api_user(uint8_t length, uint8_t* data) { return true; }
34
35void process_api(uint16_t length, uint8_t* data) {
36 // SEND_STRING("\nRX: ");
37 // for (uint8_t i = 0; i < length; i++) {
38 // send_byte(data[i]);
39 // SEND_STRING(" ");
40 // }
41 if (!process_api_quantum(length, data)) return;
42
43 switch (data[0]) {
44 case MT_SET_DATA:
45 switch (data[1]) {
46 case DT_DEFAULT_LAYER: {
47 eeconfig_update_default_layer(data[2]);
48 default_layer_set((uint32_t)(data[2]));
49 break;
50 }
51 case DT_KEYMAP_OPTIONS: {
52 eeconfig_update_keymap(data[2]);
53 break;
54 }
55 case DT_RGBLIGHT: {
56#ifdef RGBLIGHT_ENABLE
57 uint32_t rgblight = bytes_to_dword(data, 2);
58 eeconfig_update_rgblight(rgblight);
59#endif
60 break;
61 }
62 }
63 case MT_GET_DATA:
64 switch (data[1]) {
65 case DT_HANDSHAKE: {
66 MT_GET_DATA_ACK(DT_HANDSHAKE, NULL, 0);
67 break;
68 }
69 case DT_DEBUG: {
70 uint8_t debug_bytes[1] = {eeprom_read_byte(EECONFIG_DEBUG)};
71 MT_GET_DATA_ACK(DT_DEBUG, debug_bytes, 1);
72 break;
73 }
74 case DT_DEFAULT_LAYER: {
75 uint8_t default_bytes[1] = {eeprom_read_byte(EECONFIG_DEFAULT_LAYER)};
76 MT_GET_DATA_ACK(DT_DEFAULT_LAYER, default_bytes, 1);
77 break;
78 }
79 case DT_CURRENT_LAYER: {
80 uint8_t layer_state_bytes[4];
81 dword_to_bytes(layer_state, layer_state_bytes);
82 MT_GET_DATA_ACK(DT_CURRENT_LAYER, layer_state_bytes, 4);
83 break;
84 }
85 case DT_AUDIO: {
86#ifdef AUDIO_ENABLE
87 uint8_t audio_bytes[1] = {eeprom_read_byte(EECONFIG_AUDIO)};
88 MT_GET_DATA_ACK(DT_AUDIO, audio_bytes, 1);
89#else
90 MT_GET_DATA_ACK(DT_AUDIO, NULL, 0);
91#endif
92 break;
93 }
94 case DT_BACKLIGHT: {
95#ifdef BACKLIGHT_ENABLE
96 uint8_t backlight_bytes[1] = {eeprom_read_byte(EECONFIG_BACKLIGHT)};
97 MT_GET_DATA_ACK(DT_BACKLIGHT, backlight_bytes, 1);
98#else
99 MT_GET_DATA_ACK(DT_BACKLIGHT, NULL, 0);
100#endif
101 break;
102 }
103 case DT_RGBLIGHT: {
104#ifdef RGBLIGHT_ENABLE
105 uint8_t rgblight_bytes[4];
106 dword_to_bytes(eeconfig_read_rgblight(), rgblight_bytes);
107 MT_GET_DATA_ACK(DT_RGBLIGHT, rgblight_bytes, 4);
108#else
109 MT_GET_DATA_ACK(DT_RGBLIGHT, NULL, 0);
110#endif
111 break;
112 }
113 case DT_KEYMAP_OPTIONS: {
114 uint8_t keymap_bytes[1] = {eeconfig_read_keymap()};
115 MT_GET_DATA_ACK(DT_KEYMAP_OPTIONS, keymap_bytes, 1);
116 break;
117 }
118 case DT_KEYMAP_SIZE: {
119 uint8_t keymap_size[2] = {MATRIX_ROWS, MATRIX_COLS};
120 MT_GET_DATA_ACK(DT_KEYMAP_SIZE, keymap_size, 2);
121 break;
122 }
123 // This may be too much
124 // case DT_KEYMAP: {
125 // uint8_t keymap_data[MATRIX_ROWS * MATRIX_COLS * 4 + 3];
126 // keymap_data[0] = data[2];
127 // keymap_data[1] = MATRIX_ROWS;
128 // keymap_data[2] = MATRIX_COLS;
129 // for (int i = 0; i < MATRIX_ROWS; i++) {
130 // for (int j = 0; j < MATRIX_COLS; j++) {
131 // keymap_data[3 + (i*MATRIX_COLS*2) + (j*2)] = pgm_read_word(&keymaps[data[2]][i][j]) >> 8;
132 // keymap_data[3 + (i*MATRIX_COLS*2) + (j*2) + 1] = pgm_read_word(&keymaps[data[2]][i][j]) & 0xFF;
133 // }
134 // }
135 // MT_GET_DATA_ACK(DT_KEYMAP, keymap_data, MATRIX_ROWS * MATRIX_COLS * 4 + 3);
136 // // uint8_t keymap_data[5];
137 // // keymap_data[0] = data[2];
138 // // keymap_data[1] = data[3];
139 // // keymap_data[2] = data[4];
140 // // keymap_data[3] = pgm_read_word(&keymaps[data[2]][data[3]][data[4]]) >> 8;
141 // // keymap_data[4] = pgm_read_word(&keymaps[data[2]][data[3]][data[4]]) & 0xFF;
142
143 // // MT_GET_DATA_ACK(DT_KEYMAP, keymap_data, 5);
144 // break;
145 // }
146 default:
147 break;
148 }
149 break;
150 case MT_SET_DATA_ACK:
151 case MT_GET_DATA_ACK:
152 break;
153 case MT_SEND_DATA:
154 break;
155 case MT_SEND_DATA_ACK:
156 break;
157 case MT_EXE_ACTION:
158 break;
159 case MT_EXE_ACTION_ACK:
160 break;
161 case MT_TYPE_ERROR:
162 break;
163 default:; // command not recognised
164 SEND_BYTES(MT_TYPE_ERROR, DT_NONE, data, length);
165 break;
166
167 // #ifdef RGBLIGHT_ENABLE
168 // case 0x27: ; // RGB LED functions
169 // switch (*data++) {
170 // case 0x00: ; // Update HSV
171 // rgblight_sethsv((data[0] << 8 | data[1]) % 360, data[2], data[3]);
172 // break;
173 // case 0x01: ; // Update RGB
174 // break;
175 // case 0x02: ; // Update mode
176 // rgblight_mode(data[0]);
177 // break;
178 // }
179 // break;
180 // #endif
181 }
182}
diff --git a/quantum/api.h b/quantum/api.h
deleted file mode 100644
index 0a30e9d6c..000000000
--- a/quantum/api.h
+++ /dev/null
@@ -1,55 +0,0 @@
1/* Copyright 2016 Jack Humbert
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#pragma once
18
19#ifdef __AVR__
20# include "lufa.h"
21#endif
22
23enum MESSAGE_TYPE {
24 MT_GET_DATA = 0x10, // Get data from keyboard
25 MT_GET_DATA_ACK = 0x11, // returned data to process (ACK)
26 MT_SET_DATA = 0x20, // Set data on keyboard
27 MT_SET_DATA_ACK = 0x21, // returned data to confirm (ACK)
28 MT_SEND_DATA = 0x30, // Sending data/action from keyboard
29 MT_SEND_DATA_ACK = 0x31, // returned data/action confirmation (ACK)
30 MT_EXE_ACTION = 0x40, // executing actions on keyboard
31 MT_EXE_ACTION_ACK = 0x41, // return confirmation/value (ACK)
32 MT_TYPE_ERROR = 0x80 // type not recognised (ACK)
33};
34
35enum DATA_TYPE { DT_NONE = 0x00, DT_HANDSHAKE, DT_DEFAULT_LAYER, DT_CURRENT_LAYER, DT_KEYMAP_OPTIONS, DT_BACKLIGHT, DT_RGBLIGHT, DT_UNICODE, DT_DEBUG, DT_AUDIO, DT_QUANTUM_ACTION, DT_KEYBOARD_ACTION, DT_USER_ACTION, DT_KEYMAP_SIZE, DT_KEYMAP };
36
37void dword_to_bytes(uint32_t dword, uint8_t* bytes);
38uint32_t bytes_to_dword(uint8_t* bytes, uint8_t index);
39
40#define MT_GET_DATA(data_type, data, length) SEND_BYTES(MT_GET_DATA, data_type, data, length)
41#define MT_GET_DATA_ACK(data_type, data, length) SEND_BYTES(MT_GET_DATA_ACK, data_type, data, length)
42#define MT_SET_DATA(data_type, data, length) SEND_BYTES(MT_SET_DATA, data_type, data, length)
43#define MT_SET_DATA_ACK(data_type, data, length) SEND_BYTES(MT_SET_DATA_ACK, data_type, data, length)
44#define MT_SEND_DATA(data_type, data, length) SEND_BYTES(MT_SEND_DATA, data_type, data, length)
45#define MT_SEND_DATA_ACK(data_type, data, length) SEND_BYTES(MT_SEND_DATA_ACK, data_type, data, length)
46#define MT_EXE_ACTION(data_type, data, length) SEND_BYTES(MT_EXE_ACTION, data_type, data, length)
47#define MT_EXE_ACTION_ACK(data_type, data, length) SEND_BYTES(MT_EXE_ACTION_ACK, data_type, data, length)
48
49void process_api(uint16_t length, uint8_t* data);
50
51__attribute__((weak)) bool process_api_quantum(uint8_t length, uint8_t* data);
52
53__attribute__((weak)) bool process_api_keyboard(uint8_t length, uint8_t* data);
54
55__attribute__((weak)) bool process_api_user(uint8_t length, uint8_t* data);
diff --git a/quantum/api/api_sysex.c b/quantum/api/api_sysex.c
deleted file mode 100644
index 07c90cf80..000000000
--- a/quantum/api/api_sysex.c
+++ /dev/null
@@ -1,72 +0,0 @@
1/* Copyright 2016 Jack Humbert, Fred Sundvik
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16#include "api_sysex.h"
17#include "sysex_tools.h"
18#include "print.h"
19#include "qmk_midi.h"
20
21void send_bytes_sysex(uint8_t message_type, uint8_t data_type, uint8_t* bytes, uint16_t length) {
22 // SEND_STRING("\nTX: ");
23 // for (uint8_t i = 0; i < length; i++) {
24 // send_byte(bytes[i]);
25 // SEND_STRING(" ");
26 // }
27 if (length > API_SYSEX_MAX_SIZE) {
28 xprintf("Sysex msg too big %d %d %d", message_type, data_type, length);
29 return;
30 }
31
32 // The buffer size required is calculated as the following
33 // API_SYSEX_MAX_SIZE is the maximum length
34 // In addition to that we have a two byte message header consisting of the message_type and data_type
35 // This has to be encoded with an additional overhead of one byte for every starting 7 bytes
36 // We just add one extra byte in case it's not divisible by 7
37 // Then we have an unencoded header consisting of 4 bytes
38 // Plus a one byte terminator
39 const unsigned message_header = 2;
40 const unsigned unencoded_message = API_SYSEX_MAX_SIZE + message_header;
41 const unsigned encoding_overhead = unencoded_message / 7 + 1;
42 const unsigned encoded_size = unencoded_message + encoding_overhead;
43 const unsigned unencoded_header = 4;
44 const unsigned terminator = 1;
45 const unsigned buffer_size = encoded_size + unencoded_header + terminator;
46 uint8_t buffer[encoded_size + unencoded_header + terminator];
47 // The unencoded header
48 buffer[0] = 0xF0;
49 buffer[1] = 0x00;
50 buffer[2] = 0x00;
51 buffer[3] = 0x00;
52
53 // We copy the message to the end of the array, this way we can do an inplace encoding, using the same
54 // buffer for both input and output
55 const unsigned message_size = length + message_header;
56 uint8_t* unencoded_start = buffer + buffer_size - message_size;
57 uint8_t* ptr = unencoded_start;
58 *(ptr++) = message_type;
59 *(ptr++) = data_type;
60 memcpy(ptr, bytes, length);
61
62 unsigned encoded_length = sysex_encode(buffer + unencoded_header, unencoded_start, message_size);
63 unsigned final_size = unencoded_header + encoded_length + terminator;
64 buffer[final_size - 1] = 0xF7;
65 midi_send_array(&midi_device, final_size, buffer);
66
67 // SEND_STRING("\nTD: ");
68 // for (uint8_t i = 0; i < encoded_length + 5; i++) {
69 // send_byte(buffer[i]);
70 // SEND_STRING(" ");
71 // }
72}
diff --git a/quantum/api/api_sysex.h b/quantum/api/api_sysex.h
deleted file mode 100644
index eb0a18848..000000000
--- a/quantum/api/api_sysex.h
+++ /dev/null
@@ -1,25 +0,0 @@
1/* Copyright 2016 Jack Humbert
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#pragma once
18
19#include "api.h"
20
21#define API_SYSEX_MAX_SIZE 32
22
23void send_bytes_sysex(uint8_t message_type, uint8_t data_type, uint8_t* bytes, uint16_t length);
24
25#define SEND_BYTES(mt, dt, b, l) send_bytes_sysex(mt, dt, b, l)
diff --git a/quantum/audio/audio.h b/quantum/audio/audio.h
index 56b9158a1..290d461f5 100644
--- a/quantum/audio/audio.h
+++ b/quantum/audio/audio.h
@@ -26,17 +26,12 @@
26 26
27#if defined(__AVR__) 27#if defined(__AVR__)
28# include <avr/io.h> 28# include <avr/io.h>
29# if defined(AUDIO_DRIVER_PWM)
30# include "driver_avr_pwm.h"
31# endif
32#endif 29#endif
33 30
34#if defined(PROTOCOL_CHIBIOS) 31#if defined(AUDIO_DRIVER_PWM)
35# if defined(AUDIO_DRIVER_PWM) 32# include "audio_pwm.h"
36# include "driver_chibios_pwm.h" 33#elif defined(AUDIO_DRIVER_DAC)
37# elif defined(AUDIO_DRIVER_DAC) 34# include "audio_dac.h"
38# include "driver_chibios_dac.h"
39# endif
40#endif 35#endif
41 36
42typedef union { 37typedef union {
diff --git a/quantum/audio/driver_avr_pwm.h b/quantum/audio/driver_avr_pwm.h
deleted file mode 100644
index d6eb3571d..000000000
--- a/quantum/audio/driver_avr_pwm.h
+++ /dev/null
@@ -1,17 +0,0 @@
1/* Copyright 2020 Jack Humbert
2 * Copyright 2020 JohSchneider
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17#pragma once
diff --git a/quantum/audio/driver_avr_pwm_hardware.c b/quantum/audio/driver_avr_pwm_hardware.c
deleted file mode 100644
index df03a4558..000000000
--- a/quantum/audio/driver_avr_pwm_hardware.c
+++ /dev/null
@@ -1,332 +0,0 @@
1/* Copyright 2016 Jack Humbert
2 * Copyright 2020 JohSchneider
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#if defined(__AVR__)
19# include <avr/pgmspace.h>
20# include <avr/interrupt.h>
21# include <avr/io.h>
22#endif
23
24#include "audio.h"
25
26extern bool playing_note;
27extern bool playing_melody;
28extern uint8_t note_timbre;
29
30#define CPU_PRESCALER 8
31
32/*
33 Audio Driver: PWM
34
35 drive up to two speakers through the AVR PWM hardware-peripheral, using timer1 and/or timer3 on Atmega32U4.
36
37 the primary channel_1 can be connected to either pin PC4 PC5 or PC6 (the later being used by most AVR based keyboards) with a PMW signal generated by timer3
38 and an optional secondary channel_2 on either pin PB5, PB6 or PB7, with a PWM signal from timer1
39
40 alternatively, the PWM pins on PORTB can be used as only/primary speaker
41*/
42
43#if defined(AUDIO_PIN) && (AUDIO_PIN != C4) && (AUDIO_PIN != C5) && (AUDIO_PIN != C6) && (AUDIO_PIN != B5) && (AUDIO_PIN != B6) && (AUDIO_PIN != B7) && (AUDIO_PIN != D5)
44# error "Audio feature enabled, but no suitable pin selected as AUDIO_PIN - see docs/feature_audio under the AVR settings for available options."
45#endif
46
47#if (AUDIO_PIN == C4) || (AUDIO_PIN == C5) || (AUDIO_PIN == C6)
48# define AUDIO1_PIN_SET
49# define AUDIO1_TIMSKx TIMSK3
50# define AUDIO1_TCCRxA TCCR3A
51# define AUDIO1_TCCRxB TCCR3B
52# define AUDIO1_ICRx ICR3
53# define AUDIO1_WGMx0 WGM30
54# define AUDIO1_WGMx1 WGM31
55# define AUDIO1_WGMx2 WGM32
56# define AUDIO1_WGMx3 WGM33
57# define AUDIO1_CSx0 CS30
58# define AUDIO1_CSx1 CS31
59# define AUDIO1_CSx2 CS32
60
61# if (AUDIO_PIN == C6)
62# define AUDIO1_COMxy0 COM3A0
63# define AUDIO1_COMxy1 COM3A1
64# define AUDIO1_OCIExy OCIE3A
65# define AUDIO1_OCRxy OCR3A
66# define AUDIO1_PIN C6
67# define AUDIO1_TIMERx_COMPy_vect TIMER3_COMPA_vect
68# elif (AUDIO_PIN == C5)
69# define AUDIO1_COMxy0 COM3B0
70# define AUDIO1_COMxy1 COM3B1
71# define AUDIO1_OCIExy OCIE3B
72# define AUDIO1_OCRxy OCR3B
73# define AUDIO1_PIN C5
74# define AUDIO1_TIMERx_COMPy_vect TIMER3_COMPB_vect
75# elif (AUDIO_PIN == C4)
76# define AUDIO1_COMxy0 COM3C0
77# define AUDIO1_COMxy1 COM3C1
78# define AUDIO1_OCIExy OCIE3C
79# define AUDIO1_OCRxy OCR3C
80# define AUDIO1_PIN C4
81# define AUDIO1_TIMERx_COMPy_vect TIMER3_COMPC_vect
82# endif
83#endif
84
85#if defined(AUDIO_PIN) && defined(AUDIO_PIN_ALT) && (AUDIO_PIN == AUDIO_PIN_ALT)
86# error "Audio feature: AUDIO_PIN and AUDIO_PIN_ALT on the same pin makes no sense."
87#endif
88
89#if ((AUDIO_PIN == B5) && ((AUDIO_PIN_ALT == B6) || (AUDIO_PIN_ALT == B7))) || ((AUDIO_PIN == B6) && ((AUDIO_PIN_ALT == B5) || (AUDIO_PIN_ALT == B7))) || ((AUDIO_PIN == B7) && ((AUDIO_PIN_ALT == B5) || (AUDIO_PIN_ALT == B6)))
90# error "Audio feature: PORTB as AUDIO_PIN and AUDIO_PIN_ALT at the same time is not supported."
91#endif
92
93#if defined(AUDIO_PIN_ALT) && (AUDIO_PIN_ALT != B5) && (AUDIO_PIN_ALT != B6) && (AUDIO_PIN_ALT != B7)
94# error "Audio feature: the pin selected as AUDIO_PIN_ALT is not supported."
95#endif
96
97#if (AUDIO_PIN == B5) || (AUDIO_PIN == B6) || (AUDIO_PIN == B7) || (AUDIO_PIN_ALT == B5) || (AUDIO_PIN_ALT == B6) || (AUDIO_PIN_ALT == B7) || (AUDIO_PIN == D5)
98# define AUDIO2_PIN_SET
99# define AUDIO2_TIMSKx TIMSK1
100# define AUDIO2_TCCRxA TCCR1A
101# define AUDIO2_TCCRxB TCCR1B
102# define AUDIO2_ICRx ICR1
103# define AUDIO2_WGMx0 WGM10
104# define AUDIO2_WGMx1 WGM11
105# define AUDIO2_WGMx2 WGM12
106# define AUDIO2_WGMx3 WGM13
107# define AUDIO2_CSx0 CS10
108# define AUDIO2_CSx1 CS11
109# define AUDIO2_CSx2 CS12
110
111# if (AUDIO_PIN == B5) || (AUDIO_PIN_ALT == B5)
112# define AUDIO2_COMxy0 COM1A0
113# define AUDIO2_COMxy1 COM1A1
114# define AUDIO2_OCIExy OCIE1A
115# define AUDIO2_OCRxy OCR1A
116# define AUDIO2_PIN B5
117# define AUDIO2_TIMERx_COMPy_vect TIMER1_COMPA_vect
118# elif (AUDIO_PIN == B6) || (AUDIO_PIN_ALT == B6)
119# define AUDIO2_COMxy0 COM1B0
120# define AUDIO2_COMxy1 COM1B1
121# define AUDIO2_OCIExy OCIE1B
122# define AUDIO2_OCRxy OCR1B
123# define AUDIO2_PIN B6
124# define AUDIO2_TIMERx_COMPy_vect TIMER1_COMPB_vect
125# elif (AUDIO_PIN == B7) || (AUDIO_PIN_ALT == B7)
126# define AUDIO2_COMxy0 COM1C0
127# define AUDIO2_COMxy1 COM1C1
128# define AUDIO2_OCIExy OCIE1C
129# define AUDIO2_OCRxy OCR1C
130# define AUDIO2_PIN B7
131# define AUDIO2_TIMERx_COMPy_vect TIMER1_COMPC_vect
132# elif (AUDIO_PIN == D5) && defined(__AVR_ATmega32A__)
133# pragma message "Audio support for ATmega32A is experimental and can cause crashes."
134# undef AUDIO2_TIMSKx
135# define AUDIO2_TIMSKx TIMSK
136# define AUDIO2_COMxy0 COM1A0
137# define AUDIO2_COMxy1 COM1A1
138# define AUDIO2_OCIExy OCIE1A
139# define AUDIO2_OCRxy OCR1A
140# define AUDIO2_PIN D5
141# define AUDIO2_TIMERx_COMPy_vect TIMER1_COMPA_vect
142# endif
143#endif
144
145// C6 seems to be the assumed default by many existing keyboard - but sill warn the user
146#if !defined(AUDIO1_PIN_SET) && !defined(AUDIO2_PIN_SET)
147# pragma message "Audio feature enabled, but no suitable pin selected - see docs/feature_audio under the AVR settings for available options. Don't expect to hear anything... :-)"
148// TODO: make this an error - go through the breaking-change-process and change all keyboards to the new define
149#endif
150// -----------------------------------------------------------------------------
151
152#ifdef AUDIO1_PIN_SET
153static float channel_1_frequency = 0.0f;
154void channel_1_set_frequency(float freq) {
155 if (freq == 0.0f) // a pause/rest is a valid "note" with freq=0
156 {
157 // disable the output, but keep the pwm-ISR going (with the previous
158 // frequency) so the audio-state keeps getting updated
159 // Note: setting the duty-cycle 0 is not possible on non-inverting PWM mode - see the AVR data-sheet
160 AUDIO1_TCCRxA &= ~(_BV(AUDIO1_COMxy1) | _BV(AUDIO1_COMxy0));
161 return;
162 } else {
163 AUDIO1_TCCRxA |= _BV(AUDIO1_COMxy1); // enable output, PWM mode
164 }
165
166 channel_1_frequency = freq;
167
168 // set pwm period
169 AUDIO1_ICRx = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER));
170 // and duty cycle
171 AUDIO1_OCRxy = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre / 100);
172}
173
174void channel_1_start(void) {
175 // enable timer-counter ISR
176 AUDIO1_TIMSKx |= _BV(AUDIO1_OCIExy);
177 // enable timer-counter output
178 AUDIO1_TCCRxA |= _BV(AUDIO1_COMxy1);
179}
180
181void channel_1_stop(void) {
182 // disable timer-counter ISR
183 AUDIO1_TIMSKx &= ~_BV(AUDIO1_OCIExy);
184 // disable timer-counter output
185 AUDIO1_TCCRxA &= ~(_BV(AUDIO1_COMxy1) | _BV(AUDIO1_COMxy0));
186}
187#endif
188
189#ifdef AUDIO2_PIN_SET
190static float channel_2_frequency = 0.0f;
191void channel_2_set_frequency(float freq) {
192 if (freq == 0.0f) {
193 AUDIO2_TCCRxA &= ~(_BV(AUDIO2_COMxy1) | _BV(AUDIO2_COMxy0));
194 return;
195 } else {
196 AUDIO2_TCCRxA |= _BV(AUDIO2_COMxy1);
197 }
198
199 channel_2_frequency = freq;
200
201 AUDIO2_ICRx = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER));
202 AUDIO2_OCRxy = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre / 100);
203}
204
205float channel_2_get_frequency(void) { return channel_2_frequency; }
206
207void channel_2_start(void) {
208 AUDIO2_TIMSKx |= _BV(AUDIO2_OCIExy);
209 AUDIO2_TCCRxA |= _BV(AUDIO2_COMxy1);
210}
211
212void channel_2_stop(void) {
213 AUDIO2_TIMSKx &= ~_BV(AUDIO2_OCIExy);
214 AUDIO2_TCCRxA &= ~(_BV(AUDIO2_COMxy1) | _BV(AUDIO2_COMxy0));
215}
216#endif
217
218void audio_driver_initialize() {
219#ifdef AUDIO1_PIN_SET
220 channel_1_stop();
221 setPinOutput(AUDIO1_PIN);
222#endif
223
224#ifdef AUDIO2_PIN_SET
225 channel_2_stop();
226 setPinOutput(AUDIO2_PIN);
227#endif
228
229 // TCCR3A / TCCR3B: Timer/Counter #3 Control Registers TCCR3A/TCCR3B, TCCR1A/TCCR1B
230 // Compare Output Mode (COM3An and COM1An) = 0b00 = Normal port operation
231 // OC3A -- PC6
232 // OC3B -- PC5
233 // OC3C -- PC4
234 // OC1A -- PB5
235 // OC1B -- PB6
236 // OC1C -- PB7
237
238 // Waveform Generation Mode (WGM3n) = 0b1110 = Fast PWM Mode 14. Period = ICR3, Duty Cycle OCR3A)
239 // OCR3A - PC6
240 // OCR3B - PC5
241 // OCR3C - PC4
242 // OCR1A - PB5
243 // OCR1B - PB6
244 // OCR1C - PB7
245
246 // Clock Select (CS3n) = 0b010 = Clock / 8
247#ifdef AUDIO1_PIN_SET
248 // initialize timer-counter
249 AUDIO1_TCCRxA = (0 << AUDIO1_COMxy1) | (0 << AUDIO1_COMxy0) | (1 << AUDIO1_WGMx1) | (0 << AUDIO1_WGMx0);
250 AUDIO1_TCCRxB = (1 << AUDIO1_WGMx3) | (1 << AUDIO1_WGMx2) | (0 << AUDIO1_CSx2) | (1 << AUDIO1_CSx1) | (0 << AUDIO1_CSx0);
251#endif
252
253#ifdef AUDIO2_PIN_SET
254 AUDIO2_TCCRxA = (0 << AUDIO2_COMxy1) | (0 << AUDIO2_COMxy0) | (1 << AUDIO2_WGMx1) | (0 << AUDIO2_WGMx0);
255 AUDIO2_TCCRxB = (1 << AUDIO2_WGMx3) | (1 << AUDIO2_WGMx2) | (0 << AUDIO2_CSx2) | (1 << AUDIO2_CSx1) | (0 << AUDIO2_CSx0);
256#endif
257}
258
259void audio_driver_stop() {
260#ifdef AUDIO1_PIN_SET
261 channel_1_stop();
262#endif
263
264#ifdef AUDIO2_PIN_SET
265 channel_2_stop();
266#endif
267}
268
269void audio_driver_start(void) {
270#ifdef AUDIO1_PIN_SET
271 channel_1_start();
272 if (playing_note) {
273 channel_1_set_frequency(audio_get_processed_frequency(0));
274 }
275#endif
276
277#if !defined(AUDIO1_PIN_SET) && defined(AUDIO2_PIN_SET)
278 channel_2_start();
279 if (playing_note) {
280 channel_2_set_frequency(audio_get_processed_frequency(0));
281 }
282#endif
283}
284
285static volatile uint32_t isr_counter = 0;
286#ifdef AUDIO1_PIN_SET
287ISR(AUDIO1_TIMERx_COMPy_vect) {
288 isr_counter++;
289 if (isr_counter < channel_1_frequency / (CPU_PRESCALER * 8)) return;
290
291 isr_counter = 0;
292 bool state_changed = audio_update_state();
293
294 if (!playing_note && !playing_melody) {
295 channel_1_stop();
296# ifdef AUDIO2_PIN_SET
297 channel_2_stop();
298# endif
299 return;
300 }
301
302 if (state_changed) {
303 channel_1_set_frequency(audio_get_processed_frequency(0));
304# ifdef AUDIO2_PIN_SET
305 if (audio_get_number_of_active_tones() > 1) {
306 channel_2_set_frequency(audio_get_processed_frequency(1));
307 } else {
308 channel_2_stop();
309 }
310# endif
311 }
312}
313#endif
314
315#if !defined(AUDIO1_PIN_SET) && defined(AUDIO2_PIN_SET)
316ISR(AUDIO2_TIMERx_COMPy_vect) {
317 isr_counter++;
318 if (isr_counter < channel_2_frequency / (CPU_PRESCALER * 8)) return;
319
320 isr_counter = 0;
321 bool state_changed = audio_update_state();
322
323 if (!playing_note && !playing_melody) {
324 channel_2_stop();
325 return;
326 }
327
328 if (state_changed) {
329 channel_2_set_frequency(audio_get_processed_frequency(0));
330 }
331}
332#endif
diff --git a/quantum/audio/driver_chibios_dac.h b/quantum/audio/driver_chibios_dac.h
deleted file mode 100644
index 07cd622ea..000000000
--- a/quantum/audio/driver_chibios_dac.h
+++ /dev/null
@@ -1,126 +0,0 @@
1/* Copyright 2019 Jack Humbert
2 * Copyright 2020 JohSchneider
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17#pragma once
18
19#ifndef A4
20# define A4 PAL_LINE(GPIOA, 4)
21#endif
22#ifndef A5
23# define A5 PAL_LINE(GPIOA, 5)
24#endif
25
26/**
27 * Size of the dac_buffer arrays. All must be the same size.
28 */
29#define AUDIO_DAC_BUFFER_SIZE 256U
30
31/**
32 * Highest value allowed sample value.
33
34 * since the DAC is limited to 12 bit, the absolute max is 0xfff = 4095U;
35 * lower values adjust the peak-voltage aka volume down.
36 * adjusting this value has only an effect on a sample-buffer whose values are
37 * are NOT pregenerated - see square-wave
38 */
39#ifndef AUDIO_DAC_SAMPLE_MAX
40# define AUDIO_DAC_SAMPLE_MAX 4095U
41#endif
42
43#if !defined(AUDIO_DAC_SAMPLE_RATE) && !defined(AUDIO_MAX_SIMULTANEOUS_TONES) && !defined(AUDIO_DAC_QUALITY_VERY_LOW) && !defined(AUDIO_DAC_QUALITY_LOW) && !defined(AUDIO_DAC_QUALITY_HIGH) && !defined(AUDIO_DAC_QUALITY_VERY_HIGH)
44# define AUDIO_DAC_QUALITY_SANE_MINIMUM
45#endif
46
47/**
48 * These presets allow you to quickly switch between quality settings for
49 * the DAC. The sample rate and maximum number of simultaneous tones roughly
50 * has an inverse relationship - slightly higher sample rates may be possible.
51 *
52 * NOTE: a high sample-rate results in a higher cpu-load, which might lead to
53 * (audible) discontinuities and/or starve other processes of cpu-time
54 * (like RGB-led back-lighting, ...)
55 */
56#ifdef AUDIO_DAC_QUALITY_VERY_LOW
57# define AUDIO_DAC_SAMPLE_RATE 11025U
58# define AUDIO_MAX_SIMULTANEOUS_TONES 8
59#endif
60
61#ifdef AUDIO_DAC_QUALITY_LOW
62# define AUDIO_DAC_SAMPLE_RATE 22050U
63# define AUDIO_MAX_SIMULTANEOUS_TONES 4
64#endif
65
66#ifdef AUDIO_DAC_QUALITY_HIGH
67# define AUDIO_DAC_SAMPLE_RATE 44100U
68# define AUDIO_MAX_SIMULTANEOUS_TONES 2
69#endif
70
71#ifdef AUDIO_DAC_QUALITY_VERY_HIGH
72# define AUDIO_DAC_SAMPLE_RATE 88200U
73# define AUDIO_MAX_SIMULTANEOUS_TONES 1
74#endif
75
76#ifdef AUDIO_DAC_QUALITY_SANE_MINIMUM
77/* a sane-minimum config: with a trade-off between cpu-load and tone-range
78 *
79 * the (currently) highest defined note is NOTE_B8 with 7902Hz; if we now
80 * aim for an even even multiple of the buffer-size, we end up with:
81 * ( roundUptoPow2(highest note / AUDIO_DAC_BUFFER_SIZE) * nyquist-rate * AUDIO_DAC_BUFFER_SIZE)
82 * 7902/256 = 30.867 * 2 * 256 ~= 16384
83 * which works out (but the 'scope shows some sampling artifacts with lower harmonics :-P)
84 */
85# define AUDIO_DAC_SAMPLE_RATE 16384U
86# define AUDIO_MAX_SIMULTANEOUS_TONES 8
87#endif
88
89/**
90 * Effective bit-rate of the DAC. 44.1khz is the standard for most audio - any
91 * lower will sacrifice perceptible audio quality. Any higher will limit the
92 * number of simultaneous tones. In most situations, a tenth (1/10) of the
93 * sample rate is where notes become unbearable.
94 */
95#ifndef AUDIO_DAC_SAMPLE_RATE
96# define AUDIO_DAC_SAMPLE_RATE 44100U
97#endif
98
99/**
100 * The number of tones that can be played simultaneously. If too high a value
101 * is used here, the keyboard will freeze and glitch-out when that many tones
102 * are being played.
103 */
104#ifndef AUDIO_MAX_SIMULTANEOUS_TONES
105# define AUDIO_MAX_SIMULTANEOUS_TONES 2
106#endif
107
108/**
109 * The default value of the DAC when not playing anything. Certain hardware
110 * setups may require a high (AUDIO_DAC_SAMPLE_MAX) or low (0) value here.
111 * Since multiple added sine waves tend to oscillate around the midpoint,
112 * and possibly never/rarely reach either 0 of MAX, 1/2 MAX can be a
113 * reasonable default value.
114 */
115#ifndef AUDIO_DAC_OFF_VALUE
116# define AUDIO_DAC_OFF_VALUE AUDIO_DAC_SAMPLE_MAX / 2
117#endif
118
119#if AUDIO_DAC_OFF_VALUE > AUDIO_DAC_SAMPLE_MAX
120# error "AUDIO_DAC: OFF_VALUE may not be larger than SAMPLE_MAX"
121#endif
122
123/**
124 *user overridable sample generation/processing
125 */
126uint16_t dac_value_generate(void);
diff --git a/quantum/audio/driver_chibios_dac_additive.c b/quantum/audio/driver_chibios_dac_additive.c
deleted file mode 100644
index db304adb8..000000000
--- a/quantum/audio/driver_chibios_dac_additive.c
+++ /dev/null
@@ -1,335 +0,0 @@
1/* Copyright 2016-2019 Jack Humbert
2 * Copyright 2020 JohSchneider
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "audio.h"
19#include <ch.h>
20#include <hal.h>
21
22/*
23 Audio Driver: DAC
24
25 which utilizes the dac unit many STM32 are equipped with, to output a modulated waveform from samples stored in the dac_buffer_* array who are passed to the hardware through DMA
26
27 it is also possible to have a custom sample-LUT by implementing/overriding 'dac_value_generate'
28
29 this driver allows for multiple simultaneous tones to be played through one single channel by doing additive wave-synthesis
30*/
31
32#if !defined(AUDIO_PIN)
33# error "Audio feature enabled, but no suitable pin selected as AUDIO_PIN - see docs/feature_audio under 'ARM (DAC additive)' for available options."
34#endif
35#if defined(AUDIO_PIN_ALT) && !defined(AUDIO_PIN_ALT_AS_NEGATIVE)
36# pragma message "Audio feature: AUDIO_PIN_ALT set, but not AUDIO_PIN_ALT_AS_NEGATIVE - pin will be left unused; audio might still work though."
37#endif
38
39#if !defined(AUDIO_PIN_ALT)
40// no ALT pin defined is valid, but the c-ifs below need some value set
41# define AUDIO_PIN_ALT PAL_NOLINE
42#endif
43
44#if !defined(AUDIO_DAC_SAMPLE_WAVEFORM_SINE) && !defined(AUDIO_DAC_SAMPLE_WAVEFORM_TRIANGLE) && !defined(AUDIO_DAC_SAMPLE_WAVEFORM_SQUARE) && !defined(AUDIO_DAC_SAMPLE_WAVEFORM_TRAPEZOID)
45# define AUDIO_DAC_SAMPLE_WAVEFORM_SINE
46#endif
47
48#ifdef AUDIO_DAC_SAMPLE_WAVEFORM_SINE
49/* one full sine wave over [0,2*pi], but shifted up one amplitude and left pi/4; for the samples to start at 0
50 */
51static const dacsample_t dac_buffer_sine[AUDIO_DAC_BUFFER_SIZE] = {
52 // 256 values, max 4095
53 0x0, 0x1, 0x2, 0x6, 0xa, 0xf, 0x16, 0x1e, 0x27, 0x32, 0x3d, 0x4a, 0x58, 0x67, 0x78, 0x89, 0x9c, 0xb0, 0xc5, 0xdb, 0xf2, 0x10a, 0x123, 0x13e, 0x159, 0x175, 0x193, 0x1b1, 0x1d1, 0x1f1, 0x212, 0x235, 0x258, 0x27c, 0x2a0, 0x2c6, 0x2ed, 0x314, 0x33c, 0x365, 0x38e, 0x3b8, 0x3e3, 0x40e, 0x43a, 0x467, 0x494, 0x4c2, 0x4f0, 0x51f, 0x54e, 0x57d, 0x5ad, 0x5dd, 0x60e, 0x63f, 0x670, 0x6a1, 0x6d3, 0x705, 0x737, 0x769, 0x79b, 0x7cd, 0x800, 0x832, 0x864, 0x896, 0x8c8, 0x8fa, 0x92c, 0x95e, 0x98f, 0x9c0, 0x9f1, 0xa22, 0xa52, 0xa82, 0xab1, 0xae0, 0xb0f, 0xb3d, 0xb6b, 0xb98, 0xbc5, 0xbf1, 0xc1c, 0xc47, 0xc71, 0xc9a, 0xcc3, 0xceb, 0xd12, 0xd39, 0xd5f, 0xd83, 0xda7, 0xdca, 0xded, 0xe0e, 0xe2e, 0xe4e, 0xe6c, 0xe8a, 0xea6, 0xec1, 0xedc, 0xef5, 0xf0d, 0xf24, 0xf3a, 0xf4f, 0xf63, 0xf76, 0xf87, 0xf98, 0xfa7, 0xfb5, 0xfc2, 0xfcd, 0xfd8, 0xfe1, 0xfe9, 0xff0, 0xff5, 0xff9, 0xffd, 0xffe,
54 0xfff, 0xffe, 0xffd, 0xff9, 0xff5, 0xff0, 0xfe9, 0xfe1, 0xfd8, 0xfcd, 0xfc2, 0xfb5, 0xfa7, 0xf98, 0xf87, 0xf76, 0xf63, 0xf4f, 0xf3a, 0xf24, 0xf0d, 0xef5, 0xedc, 0xec1, 0xea6, 0xe8a, 0xe6c, 0xe4e, 0xe2e, 0xe0e, 0xded, 0xdca, 0xda7, 0xd83, 0xd5f, 0xd39, 0xd12, 0xceb, 0xcc3, 0xc9a, 0xc71, 0xc47, 0xc1c, 0xbf1, 0xbc5, 0xb98, 0xb6b, 0xb3d, 0xb0f, 0xae0, 0xab1, 0xa82, 0xa52, 0xa22, 0x9f1, 0x9c0, 0x98f, 0x95e, 0x92c, 0x8fa, 0x8c8, 0x896, 0x864, 0x832, 0x800, 0x7cd, 0x79b, 0x769, 0x737, 0x705, 0x6d3, 0x6a1, 0x670, 0x63f, 0x60e, 0x5dd, 0x5ad, 0x57d, 0x54e, 0x51f, 0x4f0, 0x4c2, 0x494, 0x467, 0x43a, 0x40e, 0x3e3, 0x3b8, 0x38e, 0x365, 0x33c, 0x314, 0x2ed, 0x2c6, 0x2a0, 0x27c, 0x258, 0x235, 0x212, 0x1f1, 0x1d1, 0x1b1, 0x193, 0x175, 0x159, 0x13e, 0x123, 0x10a, 0xf2, 0xdb, 0xc5, 0xb0, 0x9c, 0x89, 0x78, 0x67, 0x58, 0x4a, 0x3d, 0x32, 0x27, 0x1e, 0x16, 0xf, 0xa, 0x6, 0x2, 0x1};
55#endif // AUDIO_DAC_SAMPLE_WAVEFORM_SINE
56#ifdef AUDIO_DAC_SAMPLE_WAVEFORM_TRIANGLE
57static const dacsample_t dac_buffer_triangle[AUDIO_DAC_BUFFER_SIZE] = {
58 // 256 values, max 4095
59 0x0, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0, 0x100, 0x120, 0x140, 0x160, 0x180, 0x1a0, 0x1c0, 0x1e0, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0x300, 0x320, 0x340, 0x360, 0x380, 0x3a0, 0x3c0, 0x3e0, 0x400, 0x420, 0x440, 0x460, 0x480, 0x4a0, 0x4c0, 0x4e0, 0x500, 0x520, 0x540, 0x560, 0x580, 0x5a0, 0x5c0, 0x5e0, 0x600, 0x620, 0x640, 0x660, 0x680, 0x6a0, 0x6c0, 0x6e0, 0x700, 0x720, 0x740, 0x760, 0x780, 0x7a0, 0x7c0, 0x7e0, 0x800, 0x81f, 0x83f, 0x85f, 0x87f, 0x89f, 0x8bf, 0x8df, 0x8ff, 0x91f, 0x93f, 0x95f, 0x97f, 0x99f, 0x9bf, 0x9df, 0x9ff, 0xa1f, 0xa3f, 0xa5f, 0xa7f, 0xa9f, 0xabf, 0xadf, 0xaff, 0xb1f, 0xb3f, 0xb5f, 0xb7f, 0xb9f, 0xbbf, 0xbdf, 0xbff, 0xc1f, 0xc3f, 0xc5f, 0xc7f, 0xc9f, 0xcbf, 0xcdf, 0xcff, 0xd1f, 0xd3f, 0xd5f, 0xd7f, 0xd9f, 0xdbf, 0xddf, 0xdff, 0xe1f, 0xe3f, 0xe5f, 0xe7f, 0xe9f, 0xebf, 0xedf, 0xeff, 0xf1f, 0xf3f, 0xf5f, 0xf7f, 0xf9f, 0xfbf, 0xfdf,
60 0xfff, 0xfdf, 0xfbf, 0xf9f, 0xf7f, 0xf5f, 0xf3f, 0xf1f, 0xeff, 0xedf, 0xebf, 0xe9f, 0xe7f, 0xe5f, 0xe3f, 0xe1f, 0xdff, 0xddf, 0xdbf, 0xd9f, 0xd7f, 0xd5f, 0xd3f, 0xd1f, 0xcff, 0xcdf, 0xcbf, 0xc9f, 0xc7f, 0xc5f, 0xc3f, 0xc1f, 0xbff, 0xbdf, 0xbbf, 0xb9f, 0xb7f, 0xb5f, 0xb3f, 0xb1f, 0xaff, 0xadf, 0xabf, 0xa9f, 0xa7f, 0xa5f, 0xa3f, 0xa1f, 0x9ff, 0x9df, 0x9bf, 0x99f, 0x97f, 0x95f, 0x93f, 0x91f, 0x8ff, 0x8df, 0x8bf, 0x89f, 0x87f, 0x85f, 0x83f, 0x81f, 0x800, 0x7e0, 0x7c0, 0x7a0, 0x780, 0x760, 0x740, 0x720, 0x700, 0x6e0, 0x6c0, 0x6a0, 0x680, 0x660, 0x640, 0x620, 0x600, 0x5e0, 0x5c0, 0x5a0, 0x580, 0x560, 0x540, 0x520, 0x500, 0x4e0, 0x4c0, 0x4a0, 0x480, 0x460, 0x440, 0x420, 0x400, 0x3e0, 0x3c0, 0x3a0, 0x380, 0x360, 0x340, 0x320, 0x300, 0x2e0, 0x2c0, 0x2a0, 0x280, 0x260, 0x240, 0x220, 0x200, 0x1e0, 0x1c0, 0x1a0, 0x180, 0x160, 0x140, 0x120, 0x100, 0xe0, 0xc0, 0xa0, 0x80, 0x60, 0x40, 0x20};
61#endif // AUDIO_DAC_SAMPLE_WAVEFORM_TRIANGLE
62#ifdef AUDIO_DAC_SAMPLE_WAVEFORM_SQUARE
63static const dacsample_t dac_buffer_square[AUDIO_DAC_BUFFER_SIZE] = {
64 [0 ... AUDIO_DAC_BUFFER_SIZE / 2 - 1] = 0, // first and
65 [AUDIO_DAC_BUFFER_SIZE / 2 ... AUDIO_DAC_BUFFER_SIZE - 1] = AUDIO_DAC_SAMPLE_MAX, // second half
66};
67#endif // AUDIO_DAC_SAMPLE_WAVEFORM_SQUARE
68/*
69// four steps: 0, 1/3, 2/3 and 1
70static const dacsample_t dac_buffer_staircase[AUDIO_DAC_BUFFER_SIZE] = {
71 [0 ... AUDIO_DAC_BUFFER_SIZE/3 -1 ] = 0,
72 [AUDIO_DAC_BUFFER_SIZE / 4 ... AUDIO_DAC_BUFFER_SIZE / 2 -1 ] = AUDIO_DAC_SAMPLE_MAX / 3,
73 [AUDIO_DAC_BUFFER_SIZE / 2 ... 3 * AUDIO_DAC_BUFFER_SIZE / 4 -1 ] = 2 * AUDIO_DAC_SAMPLE_MAX / 3,
74 [3 * AUDIO_DAC_BUFFER_SIZE / 4 ... AUDIO_DAC_BUFFER_SIZE -1 ] = AUDIO_DAC_SAMPLE_MAX,
75}
76*/
77#ifdef AUDIO_DAC_SAMPLE_WAVEFORM_TRAPEZOID
78static const dacsample_t dac_buffer_trapezoid[AUDIO_DAC_BUFFER_SIZE] = {0x0, 0x1f, 0x7f, 0xdf, 0x13f, 0x19f, 0x1ff, 0x25f, 0x2bf, 0x31f, 0x37f, 0x3df, 0x43f, 0x49f, 0x4ff, 0x55f, 0x5bf, 0x61f, 0x67f, 0x6df, 0x73f, 0x79f, 0x7ff, 0x85f, 0x8bf, 0x91f, 0x97f, 0x9df, 0xa3f, 0xa9f, 0xaff, 0xb5f, 0xbbf, 0xc1f, 0xc7f, 0xcdf, 0xd3f, 0xd9f, 0xdff, 0xe5f, 0xebf, 0xf1f, 0xf7f, 0xfdf, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff, 0xfff,
79 0xfff, 0xfdf, 0xf7f, 0xf1f, 0xebf, 0xe5f, 0xdff, 0xd9f, 0xd3f, 0xcdf, 0xc7f, 0xc1f, 0xbbf, 0xb5f, 0xaff, 0xa9f, 0xa3f, 0x9df, 0x97f, 0x91f, 0x8bf, 0x85f, 0x7ff, 0x79f, 0x73f, 0x6df, 0x67f, 0x61f, 0x5bf, 0x55f, 0x4ff, 0x49f, 0x43f, 0x3df, 0x37f, 0x31f, 0x2bf, 0x25f, 0x1ff, 0x19f, 0x13f, 0xdf, 0x7f, 0x1f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
80#endif // AUDIO_DAC_SAMPLE_WAVEFORM_TRAPEZOID
81
82static dacsample_t dac_buffer_empty[AUDIO_DAC_BUFFER_SIZE] = {AUDIO_DAC_OFF_VALUE};
83
84/* keep track of the sample position for for each frequency */
85static float dac_if[AUDIO_MAX_SIMULTANEOUS_TONES] = {0.0};
86
87static float active_tones_snapshot[AUDIO_MAX_SIMULTANEOUS_TONES] = {0, 0};
88static uint8_t active_tones_snapshot_length = 0;
89
90typedef enum {
91 OUTPUT_SHOULD_START,
92 OUTPUT_RUN_NORMALLY,
93 // path 1: wait for zero, then change/update active tones
94 OUTPUT_TONES_CHANGED,
95 OUTPUT_REACHED_ZERO_BEFORE_TONE_CHANGE,
96 // path 2: hardware should stop, wait for zero then turn output off = stop the timer
97 OUTPUT_SHOULD_STOP,
98 OUTPUT_REACHED_ZERO_BEFORE_OFF,
99 OUTPUT_OFF,
100 OUTPUT_OFF_1,
101 OUTPUT_OFF_2, // trailing off: giving the DAC two more conversion cycles until the AUDIO_DAC_OFF_VALUE reaches the output, then turn the timer off, which leaves the output at that level
102 number_of_output_states
103} output_states_t;
104output_states_t state = OUTPUT_OFF_2;
105
106/**
107 * Generation of the waveform being passed to the callback. Declared weak so users
108 * can override it with their own wave-forms/noises.
109 */
110__attribute__((weak)) uint16_t dac_value_generate(void) {
111 // DAC is running/asking for values but snapshot length is zero -> must be playing a pause
112 if (active_tones_snapshot_length == 0) {
113 return AUDIO_DAC_OFF_VALUE;
114 }
115
116 /* doing additive wave synthesis over all currently playing tones = adding up
117 * sine-wave-samples for each frequency, scaled by the number of active tones
118 */
119 uint16_t value = 0;
120 float frequency = 0.0f;
121
122 for (uint8_t i = 0; i < active_tones_snapshot_length; i++) {
123 /* Note: a user implementation does not have to rely on the active_tones_snapshot, but
124 * could directly query the active frequencies through audio_get_processed_frequency */
125 frequency = active_tones_snapshot[i];
126
127 dac_if[i] = dac_if[i] + ((frequency * AUDIO_DAC_BUFFER_SIZE) / AUDIO_DAC_SAMPLE_RATE) * 2 / 3;
128 /*Note: the 2/3 are necessary to get the correct frequencies on the
129 * DAC output (as measured with an oscilloscope), since the gpt
130 * timer runs with 3*AUDIO_DAC_SAMPLE_RATE; and the DAC callback
131 * is called twice per conversion.*/
132
133 dac_if[i] = fmod(dac_if[i], AUDIO_DAC_BUFFER_SIZE);
134
135 // Wavetable generation/lookup
136 uint16_t dac_i = (uint16_t)dac_if[i];
137
138#if defined(AUDIO_DAC_SAMPLE_WAVEFORM_SINE)
139 value += dac_buffer_sine[dac_i] / active_tones_snapshot_length;
140#elif defined(AUDIO_DAC_SAMPLE_WAVEFORM_TRIANGLE)
141 value += dac_buffer_triangle[dac_i] / active_tones_snapshot_length;
142#elif defined(AUDIO_DAC_SAMPLE_WAVEFORM_TRAPEZOID)
143 value += dac_buffer_trapezoid[dac_i] / active_tones_snapshot_length;
144#elif defined(AUDIO_DAC_SAMPLE_WAVEFORM_SQUARE)
145 value += dac_buffer_square[dac_i] / active_tones_snapshot_length;
146#endif
147 /*
148 // SINE
149 value += dac_buffer_sine[dac_i] / active_tones_snapshot_length / 3;
150 // TRIANGLE
151 value += dac_buffer_triangle[dac_i] / active_tones_snapshot_length / 3;
152 // SQUARE
153 value += dac_buffer_square[dac_i] / active_tones_snapshot_length / 3;
154 //NOTE: combination of these three wave-forms is more exemplary - and doesn't sound particularly good :-P
155 */
156
157 // STAIRS (mostly usefully as test-pattern)
158 // value_avg = dac_buffer_staircase[dac_i] / active_tones_snapshot_length;
159 }
160
161 return value;
162}
163
164/**
165 * DAC streaming callback. Does all of the main computing for playing songs.
166 *
167 * Note: chibios calls this CB twice: during the 'half buffer event', and the 'full buffer event'.
168 */
169static void dac_end(DACDriver *dacp) {
170 dacsample_t *sample_p = (dacp)->samples;
171
172 // work on the other half of the buffer
173 if (dacIsBufferComplete(dacp)) {
174 sample_p += AUDIO_DAC_BUFFER_SIZE / 2; // 'half_index'
175 }
176
177 for (uint8_t s = 0; s < AUDIO_DAC_BUFFER_SIZE / 2; s++) {
178 if (OUTPUT_OFF <= state) {
179 sample_p[s] = AUDIO_DAC_OFF_VALUE;
180 continue;
181 } else {
182 sample_p[s] = dac_value_generate();
183 }
184
185 /* zero crossing (or approach, whereas zero == DAC_OFF_VALUE, which can be configured to anything from 0 to DAC_SAMPLE_MAX)
186 * ============================*=*========================== AUDIO_DAC_SAMPLE_MAX
187 * * *
188 * * *
189 * ---------------------------------------------------------
190 * * * } AUDIO_DAC_SAMPLE_MAX/100
191 * --------------------------------------------------------- AUDIO_DAC_OFF_VALUE
192 * * * } AUDIO_DAC_SAMPLE_MAX/100
193 * ---------------------------------------------------------
194 * *
195 * * *
196 * * *
197 * =====*=*================================================= 0x0
198 */
199 if (((sample_p[s] + (AUDIO_DAC_SAMPLE_MAX / 100)) > AUDIO_DAC_OFF_VALUE) && // value approaches from below
200 (sample_p[s] < (AUDIO_DAC_OFF_VALUE + (AUDIO_DAC_SAMPLE_MAX / 100))) // or above
201 ) {
202 if ((OUTPUT_SHOULD_START == state) && (active_tones_snapshot_length > 0)) {
203 state = OUTPUT_RUN_NORMALLY;
204 } else if (OUTPUT_TONES_CHANGED == state) {
205 state = OUTPUT_REACHED_ZERO_BEFORE_TONE_CHANGE;
206 } else if (OUTPUT_SHOULD_STOP == state) {
207 state = OUTPUT_REACHED_ZERO_BEFORE_OFF;
208 }
209 }
210
211 // still 'ramping up', reset the output to OFF_VALUE until the generated values reach that value, to do a smooth handover
212 if (OUTPUT_SHOULD_START == state) {
213 sample_p[s] = AUDIO_DAC_OFF_VALUE;
214 }
215
216 if ((OUTPUT_SHOULD_START == state) || (OUTPUT_REACHED_ZERO_BEFORE_OFF == state) || (OUTPUT_REACHED_ZERO_BEFORE_TONE_CHANGE == state)) {
217 uint8_t active_tones = MIN(AUDIO_MAX_SIMULTANEOUS_TONES, audio_get_number_of_active_tones());
218 active_tones_snapshot_length = 0;
219 // update the snapshot - once, and only on occasion that something changed;
220 // -> saves cpu cycles (?)
221 for (uint8_t i = 0; i < active_tones; i++) {
222 float freq = audio_get_processed_frequency(i);
223 if (freq > 0) { // disregard 'rest' notes, with valid frequency 0.0f; which would only lower the resulting waveform volume during the additive synthesis step
224 active_tones_snapshot[active_tones_snapshot_length++] = freq;
225 }
226 }
227
228 if ((0 == active_tones_snapshot_length) && (OUTPUT_REACHED_ZERO_BEFORE_OFF == state)) {
229 state = OUTPUT_OFF;
230 }
231 if (OUTPUT_REACHED_ZERO_BEFORE_TONE_CHANGE == state) {
232 state = OUTPUT_RUN_NORMALLY;
233 }
234 }
235 }
236
237 // update audio internal state (note position, current_note, ...)
238 if (audio_update_state()) {
239 if (OUTPUT_SHOULD_STOP != state) {
240 state = OUTPUT_TONES_CHANGED;
241 }
242 }
243
244 if (OUTPUT_OFF <= state) {
245 if (OUTPUT_OFF_2 == state) {
246 // stopping timer6 = stopping the DAC at whatever value it is currently pushing to the output = AUDIO_DAC_OFF_VALUE
247 gptStopTimer(&GPTD6);
248 } else {
249 state++;
250 }
251 }
252}
253
254static void dac_error(DACDriver *dacp, dacerror_t err) {
255 (void)dacp;
256 (void)err;
257
258 chSysHalt("DAC failure. halp");
259}
260
261static const GPTConfig gpt6cfg1 = {.frequency = AUDIO_DAC_SAMPLE_RATE * 3,
262 .callback = NULL,
263 .cr2 = TIM_CR2_MMS_1, /* MMS = 010 = TRGO on Update Event. */
264 .dier = 0U};
265
266static const DACConfig dac_conf = {.init = AUDIO_DAC_OFF_VALUE, .datamode = DAC_DHRM_12BIT_RIGHT};
267
268/**
269 * @note The DAC_TRG(0) here selects the Timer 6 TRGO event, which is triggered
270 * on the rising edge after 3 APB1 clock cycles, causing our gpt6cfg1.frequency
271 * to be a third of what we expect.
272 *
273 * Here are all the values for DAC_TRG (TSEL in the ref manual)
274 * TIM15_TRGO 0b011
275 * TIM2_TRGO 0b100
276 * TIM3_TRGO 0b001
277 * TIM6_TRGO 0b000
278 * TIM7_TRGO 0b010
279 * EXTI9 0b110
280 * SWTRIG 0b111
281 */
282static const DACConversionGroup dac_conv_cfg = {.num_channels = 1U, .end_cb = dac_end, .error_cb = dac_error, .trigger = DAC_TRG(0b000)};
283
284void audio_driver_initialize() {
285 if ((AUDIO_PIN == A4) || (AUDIO_PIN_ALT == A4)) {
286 palSetLineMode(A4, PAL_MODE_INPUT_ANALOG);
287 dacStart(&DACD1, &dac_conf);
288 }
289 if ((AUDIO_PIN == A5) || (AUDIO_PIN_ALT == A5)) {
290 palSetLineMode(A5, PAL_MODE_INPUT_ANALOG);
291 dacStart(&DACD2, &dac_conf);
292 }
293
294 /* enable the output buffer, to directly drive external loads with no additional circuitry
295 *
296 * see: AN4566 Application note: Extending the DAC performance of STM32 microcontrollers
297 * Note: Buffer-Off bit -> has to be set 0 to enable the output buffer
298 * Note: enabling the output buffer imparts an additional dc-offset of a couple mV
299 *
300 * this is done here, reaching directly into the stm32 registers since chibios has not implemented BOFF handling yet
301 * (see: chibios/os/hal/ports/STM32/todo.txt '- BOFF handling in DACv1.'
302 */
303 DACD1.params->dac->CR &= ~DAC_CR_BOFF1;
304 DACD2.params->dac->CR &= ~DAC_CR_BOFF2;
305
306 if (AUDIO_PIN == A4) {
307 dacStartConversion(&DACD1, &dac_conv_cfg, dac_buffer_empty, AUDIO_DAC_BUFFER_SIZE);
308 } else if (AUDIO_PIN == A5) {
309 dacStartConversion(&DACD2, &dac_conv_cfg, dac_buffer_empty, AUDIO_DAC_BUFFER_SIZE);
310 }
311
312 // no inverted/out-of-phase waveform (yet?), only pulling AUDIO_PIN_ALT to AUDIO_DAC_OFF_VALUE
313#if defined(AUDIO_PIN_ALT_AS_NEGATIVE)
314 if (AUDIO_PIN_ALT == A4) {
315 dacPutChannelX(&DACD1, 0, AUDIO_DAC_OFF_VALUE);
316 } else if (AUDIO_PIN_ALT == A5) {
317 dacPutChannelX(&DACD2, 0, AUDIO_DAC_OFF_VALUE);
318 }
319#endif
320
321 gptStart(&GPTD6, &gpt6cfg1);
322}
323
324void audio_driver_stop(void) { state = OUTPUT_SHOULD_STOP; }
325
326void audio_driver_start(void) {
327 gptStartContinuous(&GPTD6, 2U);
328
329 for (uint8_t i = 0; i < AUDIO_MAX_SIMULTANEOUS_TONES; i++) {
330 dac_if[i] = 0.0f;
331 active_tones_snapshot[i] = 0.0f;
332 }
333 active_tones_snapshot_length = 0;
334 state = OUTPUT_SHOULD_START;
335}
diff --git a/quantum/audio/driver_chibios_dac_basic.c b/quantum/audio/driver_chibios_dac_basic.c
deleted file mode 100644
index fac651350..000000000
--- a/quantum/audio/driver_chibios_dac_basic.c
+++ /dev/null
@@ -1,245 +0,0 @@
1/* Copyright 2016-2020 Jack Humbert
2 * Copyright 2020 JohSchneider
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "audio.h"
19#include "ch.h"
20#include "hal.h"
21
22/*
23 Audio Driver: DAC
24
25 which utilizes both channels of the DAC unit many STM32 are equipped with to output a modulated square-wave, from precomputed samples stored in a buffer, which is passed to the hardware through DMA
26
27 this driver can either be used to drive to separate speakers, wired to A4+Gnd and A5+Gnd, which allows two tones to be played simultaneously
28 OR
29 one speaker wired to A4+A5 with the AUDIO_PIN_ALT_AS_NEGATIVE define set - see docs/feature_audio
30
31*/
32
33#if !defined(AUDIO_PIN)
34# pragma message "Audio feature enabled, but no suitable pin selected as AUDIO_PIN - see docs/feature_audio under 'ARM (DAC basic)' for available options."
35// TODO: make this an 'error' instead; go through a breaking change, and add AUDIO_PIN A5 to all keyboards currently using AUDIO on STM32 based boards? - for now: set the define here
36# define AUDIO_PIN A5
37#endif
38// check configuration for ONE speaker, connected to both DAC pins
39#if defined(AUDIO_PIN_ALT_AS_NEGATIVE) && !defined(AUDIO_PIN_ALT)
40# error "Audio feature: AUDIO_PIN_ALT_AS_NEGATIVE set, but no pin configured as AUDIO_PIN_ALT"
41#endif
42
43#ifndef AUDIO_PIN_ALT
44// no ALT pin defined is valid, but the c-ifs below need some value set
45# define AUDIO_PIN_ALT -1
46#endif
47
48#if !defined(AUDIO_STATE_TIMER)
49# define AUDIO_STATE_TIMER GPTD8
50#endif
51
52// square-wave
53static const dacsample_t dac_buffer_1[AUDIO_DAC_BUFFER_SIZE] = {
54 // First half is max, second half is 0
55 [0 ... AUDIO_DAC_BUFFER_SIZE / 2 - 1] = AUDIO_DAC_SAMPLE_MAX,
56 [AUDIO_DAC_BUFFER_SIZE / 2 ... AUDIO_DAC_BUFFER_SIZE - 1] = 0,
57};
58
59// square-wave
60static const dacsample_t dac_buffer_2[AUDIO_DAC_BUFFER_SIZE] = {
61 // opposite of dac_buffer above
62 [0 ... AUDIO_DAC_BUFFER_SIZE / 2 - 1] = 0,
63 [AUDIO_DAC_BUFFER_SIZE / 2 ... AUDIO_DAC_BUFFER_SIZE - 1] = AUDIO_DAC_SAMPLE_MAX,
64};
65
66GPTConfig gpt6cfg1 = {.frequency = AUDIO_DAC_SAMPLE_RATE,
67 .callback = NULL,
68 .cr2 = TIM_CR2_MMS_1, /* MMS = 010 = TRGO on Update Event. */
69 .dier = 0U};
70GPTConfig gpt7cfg1 = {.frequency = AUDIO_DAC_SAMPLE_RATE,
71 .callback = NULL,
72 .cr2 = TIM_CR2_MMS_1, /* MMS = 010 = TRGO on Update Event. */
73 .dier = 0U};
74
75static void gpt_audio_state_cb(GPTDriver *gptp);
76GPTConfig gptStateUpdateCfg = {.frequency = 10,
77 .callback = gpt_audio_state_cb,
78 .cr2 = TIM_CR2_MMS_1, /* MMS = 010 = TRGO on Update Event. */
79 .dier = 0U};
80
81static const DACConfig dac_conf_ch1 = {.init = AUDIO_DAC_OFF_VALUE, .datamode = DAC_DHRM_12BIT_RIGHT};
82static const DACConfig dac_conf_ch2 = {.init = AUDIO_DAC_OFF_VALUE, .datamode = DAC_DHRM_12BIT_RIGHT};
83
84/**
85 * @note The DAC_TRG(0) here selects the Timer 6 TRGO event, which is triggered
86 * on the rising edge after 3 APB1 clock cycles, causing our gpt6cfg1.frequency
87 * to be a third of what we expect.
88 *
89 * Here are all the values for DAC_TRG (TSEL in the ref manual)
90 * TIM15_TRGO 0b011
91 * TIM2_TRGO 0b100
92 * TIM3_TRGO 0b001
93 * TIM6_TRGO 0b000
94 * TIM7_TRGO 0b010
95 * EXTI9 0b110
96 * SWTRIG 0b111
97 */
98static const DACConversionGroup dac_conv_grp_ch1 = {.num_channels = 1U, .trigger = DAC_TRG(0b000)};
99static const DACConversionGroup dac_conv_grp_ch2 = {.num_channels = 1U, .trigger = DAC_TRG(0b010)};
100
101void channel_1_start(void) {
102 gptStart(&GPTD6, &gpt6cfg1);
103 gptStartContinuous(&GPTD6, 2U);
104 palSetPadMode(GPIOA, 4, PAL_MODE_INPUT_ANALOG);
105}
106
107void channel_1_stop(void) {
108 gptStopTimer(&GPTD6);
109 palSetPadMode(GPIOA, 4, PAL_MODE_OUTPUT_PUSHPULL);
110 palSetPad(GPIOA, 4);
111}
112
113static float channel_1_frequency = 0.0f;
114void channel_1_set_frequency(float freq) {
115 channel_1_frequency = freq;
116
117 channel_1_stop();
118 if (freq <= 0.0) // a pause/rest has freq=0
119 return;
120
121 gpt6cfg1.frequency = 2 * freq * AUDIO_DAC_BUFFER_SIZE;
122 channel_1_start();
123}
124float channel_1_get_frequency(void) { return channel_1_frequency; }
125
126void channel_2_start(void) {
127 gptStart(&GPTD7, &gpt7cfg1);
128 gptStartContinuous(&GPTD7, 2U);
129 palSetPadMode(GPIOA, 5, PAL_MODE_INPUT_ANALOG);
130}
131
132void channel_2_stop(void) {
133 gptStopTimer(&GPTD7);
134 palSetPadMode(GPIOA, 5, PAL_MODE_OUTPUT_PUSHPULL);
135 palSetPad(GPIOA, 5);
136}
137
138static float channel_2_frequency = 0.0f;
139void channel_2_set_frequency(float freq) {
140 channel_2_frequency = freq;
141
142 channel_2_stop();
143 if (freq <= 0.0) // a pause/rest has freq=0
144 return;
145
146 gpt7cfg1.frequency = 2 * freq * AUDIO_DAC_BUFFER_SIZE;
147 channel_2_start();
148}
149float channel_2_get_frequency(void) { return channel_2_frequency; }
150
151static void gpt_audio_state_cb(GPTDriver *gptp) {
152 if (audio_update_state()) {
153#if defined(AUDIO_PIN_ALT_AS_NEGATIVE)
154 // one piezo/speaker connected to both audio pins, the generated square-waves are inverted
155 channel_1_set_frequency(audio_get_processed_frequency(0));
156 channel_2_set_frequency(audio_get_processed_frequency(0));
157
158#else // two separate audio outputs/speakers
159 // primary speaker on A4, optional secondary on A5
160 if (AUDIO_PIN == A4) {
161 channel_1_set_frequency(audio_get_processed_frequency(0));
162 if (AUDIO_PIN_ALT == A5) {
163 if (audio_get_number_of_active_tones() > 1) {
164 channel_2_set_frequency(audio_get_processed_frequency(1));
165 } else {
166 channel_2_stop();
167 }
168 }
169 }
170
171 // primary speaker on A5, optional secondary on A4
172 if (AUDIO_PIN == A5) {
173 channel_2_set_frequency(audio_get_processed_frequency(0));
174 if (AUDIO_PIN_ALT == A4) {
175 if (audio_get_number_of_active_tones() > 1) {
176 channel_1_set_frequency(audio_get_processed_frequency(1));
177 } else {
178 channel_1_stop();
179 }
180 }
181 }
182#endif
183 }
184}
185
186void audio_driver_initialize() {
187 if ((AUDIO_PIN == A4) || (AUDIO_PIN_ALT == A4)) {
188 palSetPadMode(GPIOA, 4, PAL_MODE_INPUT_ANALOG);
189 dacStart(&DACD1, &dac_conf_ch1);
190
191 // initial setup of the dac-triggering timer is still required, even
192 // though it gets reconfigured and restarted later on
193 gptStart(&GPTD6, &gpt6cfg1);
194 }
195
196 if ((AUDIO_PIN == A5) || (AUDIO_PIN_ALT == A5)) {
197 palSetPadMode(GPIOA, 5, PAL_MODE_INPUT_ANALOG);
198 dacStart(&DACD2, &dac_conf_ch2);
199
200 gptStart(&GPTD7, &gpt7cfg1);
201 }
202
203 /* enable the output buffer, to directly drive external loads with no additional circuitry
204 *
205 * see: AN4566 Application note: Extending the DAC performance of STM32 microcontrollers
206 * Note: Buffer-Off bit -> has to be set 0 to enable the output buffer
207 * Note: enabling the output buffer imparts an additional dc-offset of a couple mV
208 *
209 * this is done here, reaching directly into the stm32 registers since chibios has not implemented BOFF handling yet
210 * (see: chibios/os/hal/ports/STM32/todo.txt '- BOFF handling in DACv1.'
211 */
212 DACD1.params->dac->CR &= ~DAC_CR_BOFF1;
213 DACD2.params->dac->CR &= ~DAC_CR_BOFF2;
214
215 // start state-updater
216 gptStart(&AUDIO_STATE_TIMER, &gptStateUpdateCfg);
217}
218
219void audio_driver_stop(void) {
220 if ((AUDIO_PIN == A4) || (AUDIO_PIN_ALT == A4)) {
221 gptStopTimer(&GPTD6);
222
223 // stop the ongoing conversion and put the output in a known state
224 dacStopConversion(&DACD1);
225 dacPutChannelX(&DACD1, 0, AUDIO_DAC_OFF_VALUE);
226 }
227
228 if ((AUDIO_PIN == A5) || (AUDIO_PIN_ALT == A5)) {
229 gptStopTimer(&GPTD7);
230
231 dacStopConversion(&DACD2);
232 dacPutChannelX(&DACD2, 0, AUDIO_DAC_OFF_VALUE);
233 }
234 gptStopTimer(&AUDIO_STATE_TIMER);
235}
236
237void audio_driver_start(void) {
238 if ((AUDIO_PIN == A4) || (AUDIO_PIN_ALT == A4)) {
239 dacStartConversion(&DACD1, &dac_conv_grp_ch1, (dacsample_t *)dac_buffer_1, AUDIO_DAC_BUFFER_SIZE);
240 }
241 if ((AUDIO_PIN == A5) || (AUDIO_PIN_ALT == A5)) {
242 dacStartConversion(&DACD2, &dac_conv_grp_ch2, (dacsample_t *)dac_buffer_2, AUDIO_DAC_BUFFER_SIZE);
243 }
244 gptStartContinuous(&AUDIO_STATE_TIMER, 2U);
245}
diff --git a/quantum/audio/driver_chibios_pwm.h b/quantum/audio/driver_chibios_pwm.h
deleted file mode 100644
index 86cab916e..000000000
--- a/quantum/audio/driver_chibios_pwm.h
+++ /dev/null
@@ -1,40 +0,0 @@
1/* Copyright 2020 Jack Humbert
2 * Copyright 2020 JohSchneider
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17#pragma once
18
19#if !defined(AUDIO_PWM_DRIVER)
20// NOTE: Timer2 seems to be used otherwise in QMK, otherwise we could default to A5 (= TIM2_CH1, with PWMD2 and alternate-function(1))
21# define AUDIO_PWM_DRIVER PWMD1
22#endif
23
24#if !defined(AUDIO_PWM_CHANNEL)
25// NOTE: sticking to the STM data-sheet numbering: TIMxCH1 to TIMxCH4
26// default: STM32F303CC PA8+TIM1_CH1 -> 1
27# define AUDIO_PWM_CHANNEL 1
28#endif
29
30#if !defined(AUDIO_PWM_PAL_MODE)
31// pin-alternate function: see the data-sheet for which pin needs what AF to connect to TIMx_CHy
32// default: STM32F303CC PA8+TIM1_CH1 -> 6
33# define AUDIO_PWM_PAL_MODE 6
34#endif
35
36#if !defined(AUDIO_STATE_TIMER)
37// timer used to trigger updates in the audio-system, configured/enabled in chibios mcuconf.
38// Tim6 is the default for "larger" STMs, smaller ones might not have this one (enabled) and need to switch to a different one (e.g.: STM32F103 has only Tim1-Tim4)
39# define AUDIO_STATE_TIMER GPTD6
40#endif
diff --git a/quantum/audio/driver_chibios_pwm_hardware.c b/quantum/audio/driver_chibios_pwm_hardware.c
deleted file mode 100644
index 3c7d89b29..000000000
--- a/quantum/audio/driver_chibios_pwm_hardware.c
+++ /dev/null
@@ -1,144 +0,0 @@
1/* Copyright 2020 Jack Humbert
2 * Copyright 2020 JohSchneider
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18/*
19Audio Driver: PWM
20
21the duty-cycle is always kept at 50%, and the pwm-period is adjusted to match the frequency of a note to be played back.
22
23this driver uses the chibios-PWM system to produce a square-wave on specific output pins that are connected to the PWM hardware.
24The hardware directly toggles the pin via its alternate function. see your MCUs data-sheet for which pin can be driven by what timer - looking for TIMx_CHy and the corresponding alternate function.
25
26 */
27
28#include "audio.h"
29#include "ch.h"
30#include "hal.h"
31
32#if !defined(AUDIO_PIN)
33# error "Audio feature enabled, but no pin selected - see docs/feature_audio under the ARM PWM settings"
34#endif
35
36extern bool playing_note;
37extern bool playing_melody;
38extern uint8_t note_timbre;
39
40static PWMConfig pwmCFG = {
41 .frequency = 100000, /* PWM clock frequency */
42 // CHIBIOS-BUG? can't set the initial period to <2, or the pwm (hard or software) takes ~130ms with .frequency=500000 for a pwmChangePeriod to take effect; with no output=silence in the meantime
43 .period = 2, /* initial PWM period (in ticks) 1S (1/10kHz=0.1mS 0.1ms*10000 ticks=1S) */
44 .callback = NULL, /* no callback, the hardware directly toggles the pin */
45 .channels =
46 {
47#if AUDIO_PWM_CHANNEL == 4
48 {PWM_OUTPUT_DISABLED, NULL}, /* channel 0 -> TIMx_CH1 */
49 {PWM_OUTPUT_DISABLED, NULL}, /* channel 1 -> TIMx_CH2 */
50 {PWM_OUTPUT_DISABLED, NULL}, /* channel 2 -> TIMx_CH3 */
51 {PWM_OUTPUT_ACTIVE_HIGH, NULL} /* channel 3 -> TIMx_CH4 */
52#elif AUDIO_PWM_CHANNEL == 3
53 {PWM_OUTPUT_DISABLED, NULL},
54 {PWM_OUTPUT_DISABLED, NULL},
55 {PWM_OUTPUT_ACTIVE_HIGH, NULL}, /* TIMx_CH3 */
56 {PWM_OUTPUT_DISABLED, NULL}
57#elif AUDIO_PWM_CHANNEL == 2
58 {PWM_OUTPUT_DISABLED, NULL},
59 {PWM_OUTPUT_ACTIVE_HIGH, NULL}, /* TIMx_CH2 */
60 {PWM_OUTPUT_DISABLED, NULL},
61 {PWM_OUTPUT_DISABLED, NULL}
62#else /*fallback to CH1 */
63 {PWM_OUTPUT_ACTIVE_HIGH, NULL}, /* TIMx_CH1 */
64 {PWM_OUTPUT_DISABLED, NULL},
65 {PWM_OUTPUT_DISABLED, NULL},
66 {PWM_OUTPUT_DISABLED, NULL}
67#endif
68 },
69};
70
71static float channel_1_frequency = 0.0f;
72void channel_1_set_frequency(float freq) {
73 channel_1_frequency = freq;
74
75 if (freq <= 0.0) // a pause/rest has freq=0
76 return;
77
78 pwmcnt_t period = (pwmCFG.frequency / freq);
79 pwmChangePeriod(&AUDIO_PWM_DRIVER, period);
80 pwmEnableChannel(&AUDIO_PWM_DRIVER, AUDIO_PWM_CHANNEL - 1,
81 // adjust the duty-cycle so that the output is for 'note_timbre' duration HIGH
82 PWM_PERCENTAGE_TO_WIDTH(&AUDIO_PWM_DRIVER, (100 - note_timbre) * 100));
83}
84
85float channel_1_get_frequency(void) { return channel_1_frequency; }
86
87void channel_1_start(void) {
88 pwmStop(&AUDIO_PWM_DRIVER);
89 pwmStart(&AUDIO_PWM_DRIVER, &pwmCFG);
90}
91
92void channel_1_stop(void) { pwmStop(&AUDIO_PWM_DRIVER); }
93
94static void gpt_callback(GPTDriver *gptp);
95GPTConfig gptCFG = {
96 /* a whole note is one beat, which is - per definition in musical_notes.h - set to 64
97 the longest note is BREAVE_DOT=128+64=192, the shortest SIXTEENTH=4
98 the tempo (which might vary!) is in bpm (beats per minute)
99 therefore: if the timer ticks away at .frequency = (60*64)Hz,
100 and the .interval counts from 64 downwards - audio_update_state is
101 called just often enough to not miss any notes
102 */
103 .frequency = 60 * 64,
104 .callback = gpt_callback,
105};
106
107void audio_driver_initialize(void) {
108 pwmStart(&AUDIO_PWM_DRIVER, &pwmCFG);
109
110 // connect the AUDIO_PIN to the PWM hardware
111#if defined(USE_GPIOV1) // STM32F103C8
112 palSetLineMode(AUDIO_PIN, PAL_MODE_STM32_ALTERNATE_PUSHPULL);
113#else // GPIOv2 (or GPIOv3 for f4xx, which is the same/compatible at this command)
114 palSetLineMode(AUDIO_PIN, PAL_STM32_MODE_ALTERNATE | PAL_STM32_ALTERNATE(AUDIO_PWM_PAL_MODE));
115#endif
116
117 gptStart(&AUDIO_STATE_TIMER, &gptCFG);
118}
119
120void audio_driver_start(void) {
121 channel_1_stop();
122 channel_1_start();
123
124 if (playing_note || playing_melody) {
125 gptStartContinuous(&AUDIO_STATE_TIMER, 64);
126 }
127}
128
129void audio_driver_stop(void) {
130 channel_1_stop();
131 gptStopTimer(&AUDIO_STATE_TIMER);
132}
133
134/* a regular timer task, that checks the note to be currently played
135 * and updates the pwm to output that frequency
136 */
137static void gpt_callback(GPTDriver *gptp) {
138 float freq; // TODO: freq_alt
139
140 if (audio_update_state()) {
141 freq = audio_get_processed_frequency(0); // freq_alt would be index=1
142 channel_1_set_frequency(freq);
143 }
144}
diff --git a/quantum/audio/driver_chibios_pwm_software.c b/quantum/audio/driver_chibios_pwm_software.c
deleted file mode 100644
index 15c3e98b6..000000000
--- a/quantum/audio/driver_chibios_pwm_software.c
+++ /dev/null
@@ -1,164 +0,0 @@
1/* Copyright 2020 Jack Humbert
2 * Copyright 2020 JohSchneider
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18/*
19Audio Driver: PWM
20
21the duty-cycle is always kept at 50%, and the pwm-period is adjusted to match the frequency of a note to be played back.
22
23this driver uses the chibios-PWM system to produce a square-wave on any given output pin in software
24- a pwm callback is used to set/clear the configured pin.
25
26 */
27#include "audio.h"
28#include "ch.h"
29#include "hal.h"
30
31#if !defined(AUDIO_PIN)
32# error "Audio feature enabled, but no pin selected - see docs/feature_audio under the ARM PWM settings"
33#endif
34extern bool playing_note;
35extern bool playing_melody;
36extern uint8_t note_timbre;
37
38static void pwm_audio_period_callback(PWMDriver *pwmp);
39static void pwm_audio_channel_interrupt_callback(PWMDriver *pwmp);
40
41static PWMConfig pwmCFG = {
42 .frequency = 100000, /* PWM clock frequency */
43 // CHIBIOS-BUG? can't set the initial period to <2, or the pwm (hard or software) takes ~130ms with .frequency=500000 for a pwmChangePeriod to take effect; with no output=silence in the meantime
44 .period = 2, /* initial PWM period (in ticks) 1S (1/10kHz=0.1mS 0.1ms*10000 ticks=1S) */
45 .callback = pwm_audio_period_callback,
46 .channels =
47 {
48 // software-PWM just needs another callback on any channel
49 {PWM_OUTPUT_ACTIVE_HIGH, pwm_audio_channel_interrupt_callback}, /* channel 0 -> TIMx_CH1 */
50 {PWM_OUTPUT_DISABLED, NULL}, /* channel 1 -> TIMx_CH2 */
51 {PWM_OUTPUT_DISABLED, NULL}, /* channel 2 -> TIMx_CH3 */
52 {PWM_OUTPUT_DISABLED, NULL} /* channel 3 -> TIMx_CH4 */
53 },
54};
55
56static float channel_1_frequency = 0.0f;
57void channel_1_set_frequency(float freq) {
58 channel_1_frequency = freq;
59
60 if (freq <= 0.0) // a pause/rest has freq=0
61 return;
62
63 pwmcnt_t period = (pwmCFG.frequency / freq);
64 pwmChangePeriod(&AUDIO_PWM_DRIVER, period);
65
66 pwmEnableChannel(&AUDIO_PWM_DRIVER, AUDIO_PWM_CHANNEL - 1,
67 // adjust the duty-cycle so that the output is for 'note_timbre' duration HIGH
68 PWM_PERCENTAGE_TO_WIDTH(&AUDIO_PWM_DRIVER, (100 - note_timbre) * 100));
69}
70
71float channel_1_get_frequency(void) { return channel_1_frequency; }
72
73void channel_1_start(void) {
74 pwmStop(&AUDIO_PWM_DRIVER);
75 pwmStart(&AUDIO_PWM_DRIVER, &pwmCFG);
76
77 pwmEnablePeriodicNotification(&AUDIO_PWM_DRIVER);
78 pwmEnableChannelNotification(&AUDIO_PWM_DRIVER, AUDIO_PWM_CHANNEL - 1);
79}
80
81void channel_1_stop(void) {
82 pwmStop(&AUDIO_PWM_DRIVER);
83
84 palClearLine(AUDIO_PIN); // leave the line low, after last note was played
85
86#if defined(AUDIO_PIN_ALT) && defined(AUDIO_PIN_ALT_AS_NEGATIVE)
87 palClearLine(AUDIO_PIN_ALT); // leave the line low, after last note was played
88#endif
89}
90
91// generate a PWM signal on any pin, not necessarily the one connected to the timer
92static void pwm_audio_period_callback(PWMDriver *pwmp) {
93 (void)pwmp;
94 palClearLine(AUDIO_PIN);
95
96#if defined(AUDIO_PIN_ALT) && defined(AUDIO_PIN_ALT_AS_NEGATIVE)
97 palSetLine(AUDIO_PIN_ALT);
98#endif
99}
100static void pwm_audio_channel_interrupt_callback(PWMDriver *pwmp) {
101 (void)pwmp;
102 if (channel_1_frequency > 0) {
103 palSetLine(AUDIO_PIN); // generate a PWM signal on any pin, not necessarily the one connected to the timer
104#if defined(AUDIO_PIN_ALT) && defined(AUDIO_PIN_ALT_AS_NEGATIVE)
105 palClearLine(AUDIO_PIN_ALT);
106#endif
107 }
108}
109
110static void gpt_callback(GPTDriver *gptp);
111GPTConfig gptCFG = {
112 /* a whole note is one beat, which is - per definition in musical_notes.h - set to 64
113 the longest note is BREAVE_DOT=128+64=192, the shortest SIXTEENTH=4
114 the tempo (which might vary!) is in bpm (beats per minute)
115 therefore: if the timer ticks away at .frequency = (60*64)Hz,
116 and the .interval counts from 64 downwards - audio_update_state is
117 called just often enough to not miss anything
118 */
119 .frequency = 60 * 64,
120 .callback = gpt_callback,
121};
122
123void audio_driver_initialize(void) {
124 pwmStart(&AUDIO_PWM_DRIVER, &pwmCFG);
125
126 palSetLineMode(AUDIO_PIN, PAL_MODE_OUTPUT_PUSHPULL);
127 palClearLine(AUDIO_PIN);
128
129#if defined(AUDIO_PIN_ALT) && defined(AUDIO_PIN_ALT_AS_NEGATIVE)
130 palSetLineMode(AUDIO_PIN_ALT, PAL_MODE_OUTPUT_PUSHPULL);
131 palClearLine(AUDIO_PIN_ALT);
132#endif
133
134 pwmEnablePeriodicNotification(&AUDIO_PWM_DRIVER); // enable pwm callbacks
135 pwmEnableChannelNotification(&AUDIO_PWM_DRIVER, AUDIO_PWM_CHANNEL - 1);
136
137 gptStart(&AUDIO_STATE_TIMER, &gptCFG);
138}
139
140void audio_driver_start(void) {
141 channel_1_stop();
142 channel_1_start();
143
144 if (playing_note || playing_melody) {
145 gptStartContinuous(&AUDIO_STATE_TIMER, 64);
146 }
147}
148
149void audio_driver_stop(void) {
150 channel_1_stop();
151 gptStopTimer(&AUDIO_STATE_TIMER);
152}
153
154/* a regular timer task, that checks the note to be currently played
155 * and updates the pwm to output that frequency
156 */
157static void gpt_callback(GPTDriver *gptp) {
158 float freq; // TODO: freq_alt
159
160 if (audio_update_state()) {
161 freq = audio_get_processed_frequency(0); // freq_alt would be index=1
162 channel_1_set_frequency(freq);
163 }
164}
diff --git a/quantum/audio/song_list.h b/quantum/audio/song_list.h
index b54b397e1..8e80a016a 100644
--- a/quantum/audio/song_list.h
+++ b/quantum/audio/song_list.h
@@ -20,11 +20,9 @@
20 20
21#include "musical_notes.h" 21#include "musical_notes.h"
22 22
23#if __GNUC__ > 5 // don't use for older gcc compilers since check isn't supported. 23#if __has_include("user_song_list.h")
24# if __has_include("user_song_list.h") 24# include "user_song_list.h"
25# include "user_song_list.h" 25#endif // if file exists
26# endif // if file exists
27#endif // __GNUC__
28 26
29#define NO_SOUND 27#define NO_SOUND
30 28
diff --git a/quantum/backlight/backlight_chibios.c b/quantum/backlight/backlight_chibios.c
index 4d5a69e14..7c6edd10d 100644
--- a/quantum/backlight/backlight_chibios.c
+++ b/quantum/backlight/backlight_chibios.c
@@ -8,9 +8,13 @@
8# define BACKLIGHT_LIMIT_VAL 255 8# define BACKLIGHT_LIMIT_VAL 255
9#endif 9#endif
10 10
11// GPIOV2 && GPIOV3
12#ifndef BACKLIGHT_PAL_MODE 11#ifndef BACKLIGHT_PAL_MODE
13# define BACKLIGHT_PAL_MODE 2 12# if defined(USE_GPIOV1)
13# define BACKLIGHT_PAL_MODE PAL_MODE_ALTERNATE_PUSHPULL
14# else
15// GPIOV2 && GPIOV3
16# define BACKLIGHT_PAL_MODE 5
17# endif
14#endif 18#endif
15 19
16// GENERIC 20// GENERIC
@@ -70,7 +74,7 @@ static uint32_t rescale_limit_val(uint32_t val) {
70 74
71void backlight_init_ports(void) { 75void backlight_init_ports(void) {
72#ifdef USE_GPIOV1 76#ifdef USE_GPIOV1
73 palSetPadMode(PAL_PORT(BACKLIGHT_PIN), PAL_PAD(BACKLIGHT_PIN), PAL_MODE_STM32_ALTERNATE_PUSHPULL); 77 palSetPadMode(PAL_PORT(BACKLIGHT_PIN), PAL_PAD(BACKLIGHT_PIN), BACKLIGHT_PAL_MODE);
74#else 78#else
75 palSetPadMode(PAL_PORT(BACKLIGHT_PIN), PAL_PAD(BACKLIGHT_PIN), PAL_MODE_ALTERNATE(BACKLIGHT_PAL_MODE)); 79 palSetPadMode(PAL_PORT(BACKLIGHT_PIN), PAL_PAD(BACKLIGHT_PIN), PAL_MODE_ALTERNATE(BACKLIGHT_PAL_MODE));
76#endif 80#endif
diff --git a/quantum/debounce/asym_eager_defer_pk.c b/quantum/debounce/asym_eager_defer_pk.c
index 24380dc5e..81f39383c 100644
--- a/quantum/debounce/asym_eager_defer_pk.c
+++ b/quantum/debounce/asym_eager_defer_pk.c
@@ -46,17 +46,17 @@ When no state changes have occured for DEBOUNCE milliseconds, we push the state.
46#define ROW_SHIFTER ((matrix_row_t)1) 46#define ROW_SHIFTER ((matrix_row_t)1)
47 47
48typedef struct { 48typedef struct {
49 bool pressed : 1; 49 bool pressed : 1;
50 uint8_t time : 7; 50 uint8_t time : 7;
51} debounce_counter_t; 51} debounce_counter_t;
52 52
53#if DEBOUNCE > 0 53#if DEBOUNCE > 0
54static debounce_counter_t *debounce_counters; 54static debounce_counter_t *debounce_counters;
55static fast_timer_t last_time; 55static fast_timer_t last_time;
56static bool counters_need_update; 56static bool counters_need_update;
57static bool matrix_need_update; 57static bool matrix_need_update;
58 58
59#define DEBOUNCE_ELAPSED 0 59# define DEBOUNCE_ELAPSED 0
60 60
61static void update_debounce_counters_and_transfer_if_expired(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, uint8_t elapsed_time); 61static void update_debounce_counters_and_transfer_if_expired(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, uint8_t elapsed_time);
62static void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows); 62static void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows);
@@ -64,7 +64,7 @@ static void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], ui
64// we use num_rows rather than MATRIX_ROWS to support split keyboards 64// we use num_rows rather than MATRIX_ROWS to support split keyboards
65void debounce_init(uint8_t num_rows) { 65void debounce_init(uint8_t num_rows) {
66 debounce_counters = malloc(num_rows * MATRIX_COLS * sizeof(debounce_counter_t)); 66 debounce_counters = malloc(num_rows * MATRIX_COLS * sizeof(debounce_counter_t));
67 int i = 0; 67 int i = 0;
68 for (uint8_t r = 0; r < num_rows; r++) { 68 for (uint8_t r = 0; r < num_rows; r++) {
69 for (uint8_t c = 0; c < MATRIX_COLS; c++) { 69 for (uint8_t c = 0; c < MATRIX_COLS; c++) {
70 debounce_counters[i++].time = DEBOUNCE_ELAPSED; 70 debounce_counters[i++].time = DEBOUNCE_ELAPSED;
@@ -81,10 +81,10 @@ void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool
81 bool updated_last = false; 81 bool updated_last = false;
82 82
83 if (counters_need_update) { 83 if (counters_need_update) {
84 fast_timer_t now = timer_read_fast(); 84 fast_timer_t now = timer_read_fast();
85 fast_timer_t elapsed_time = TIMER_DIFF_FAST(now, last_time); 85 fast_timer_t elapsed_time = TIMER_DIFF_FAST(now, last_time);
86 86
87 last_time = now; 87 last_time = now;
88 updated_last = true; 88 updated_last = true;
89 if (elapsed_time > UINT8_MAX) { 89 if (elapsed_time > UINT8_MAX) {
90 elapsed_time = UINT8_MAX; 90 elapsed_time = UINT8_MAX;
@@ -108,7 +108,7 @@ static void update_debounce_counters_and_transfer_if_expired(matrix_row_t raw[],
108 debounce_counter_t *debounce_pointer = debounce_counters; 108 debounce_counter_t *debounce_pointer = debounce_counters;
109 109
110 counters_need_update = false; 110 counters_need_update = false;
111 matrix_need_update = false; 111 matrix_need_update = false;
112 112
113 for (uint8_t row = 0; row < num_rows; row++) { 113 for (uint8_t row = 0; row < num_rows; row++) {
114 for (uint8_t col = 0; col < MATRIX_COLS; col++) { 114 for (uint8_t col = 0; col < MATRIX_COLS; col++) {
@@ -146,8 +146,8 @@ static void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], ui
146 if (delta & col_mask) { 146 if (delta & col_mask) {
147 if (debounce_pointer->time == DEBOUNCE_ELAPSED) { 147 if (debounce_pointer->time == DEBOUNCE_ELAPSED) {
148 debounce_pointer->pressed = (raw[row] & col_mask); 148 debounce_pointer->pressed = (raw[row] & col_mask);
149 debounce_pointer->time = DEBOUNCE; 149 debounce_pointer->time = DEBOUNCE;
150 counters_need_update = true; 150 counters_need_update = true;
151 151
152 if (debounce_pointer->pressed) { 152 if (debounce_pointer->pressed) {
153 // key-down: eager 153 // key-down: eager
diff --git a/quantum/debounce/sym_defer_g.c b/quantum/debounce/sym_defer_g.c
index fbefd55ed..9155eb914 100644
--- a/quantum/debounce/sym_defer_g.c
+++ b/quantum/debounce/sym_defer_g.c
@@ -25,7 +25,7 @@ When no state changes have occured for DEBOUNCE milliseconds, we push the state.
25#endif 25#endif
26 26
27#if DEBOUNCE > 0 27#if DEBOUNCE > 0
28static bool debouncing = false; 28static bool debouncing = false;
29static fast_timer_t debouncing_time; 29static fast_timer_t debouncing_time;
30 30
31void debounce_init(uint8_t num_rows) {} 31void debounce_init(uint8_t num_rows) {}
diff --git a/quantum/debounce/sym_defer_pk.c b/quantum/debounce/sym_defer_pk.c
index 626a9be84..1b698ba34 100644
--- a/quantum/debounce/sym_defer_pk.c
+++ b/quantum/debounce/sym_defer_pk.c
@@ -49,7 +49,7 @@ static debounce_counter_t *debounce_counters;
49static fast_timer_t last_time; 49static fast_timer_t last_time;
50static bool counters_need_update; 50static bool counters_need_update;
51 51
52#define DEBOUNCE_ELAPSED 0 52# define DEBOUNCE_ELAPSED 0
53 53
54static void update_debounce_counters_and_transfer_if_expired(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, uint8_t elapsed_time); 54static void update_debounce_counters_and_transfer_if_expired(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, uint8_t elapsed_time);
55static void start_debounce_counters(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows); 55static void start_debounce_counters(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows);
@@ -74,10 +74,10 @@ void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool
74 bool updated_last = false; 74 bool updated_last = false;
75 75
76 if (counters_need_update) { 76 if (counters_need_update) {
77 fast_timer_t now = timer_read_fast(); 77 fast_timer_t now = timer_read_fast();
78 fast_timer_t elapsed_time = TIMER_DIFF_FAST(now, last_time); 78 fast_timer_t elapsed_time = TIMER_DIFF_FAST(now, last_time);
79 79
80 last_time = now; 80 last_time = now;
81 updated_last = true; 81 updated_last = true;
82 if (elapsed_time > UINT8_MAX) { 82 if (elapsed_time > UINT8_MAX) {
83 elapsed_time = UINT8_MAX; 83 elapsed_time = UINT8_MAX;
diff --git a/quantum/debounce/sym_eager_pk.c b/quantum/debounce/sym_eager_pk.c
index 15a3242e6..9da000ea9 100644
--- a/quantum/debounce/sym_eager_pk.c
+++ b/quantum/debounce/sym_eager_pk.c
@@ -50,7 +50,7 @@ static fast_timer_t last_time;
50static bool counters_need_update; 50static bool counters_need_update;
51static bool matrix_need_update; 51static bool matrix_need_update;
52 52
53#define DEBOUNCE_ELAPSED 0 53# define DEBOUNCE_ELAPSED 0
54 54
55static void update_debounce_counters(uint8_t num_rows, uint8_t elapsed_time); 55static void update_debounce_counters(uint8_t num_rows, uint8_t elapsed_time);
56static void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows); 56static void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows);
@@ -75,10 +75,10 @@ void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool
75 bool updated_last = false; 75 bool updated_last = false;
76 76
77 if (counters_need_update) { 77 if (counters_need_update) {
78 fast_timer_t now = timer_read_fast(); 78 fast_timer_t now = timer_read_fast();
79 fast_timer_t elapsed_time = TIMER_DIFF_FAST(now, last_time); 79 fast_timer_t elapsed_time = TIMER_DIFF_FAST(now, last_time);
80 80
81 last_time = now; 81 last_time = now;
82 updated_last = true; 82 updated_last = true;
83 if (elapsed_time > UINT8_MAX) { 83 if (elapsed_time > UINT8_MAX) {
84 elapsed_time = UINT8_MAX; 84 elapsed_time = UINT8_MAX;
@@ -107,7 +107,7 @@ static void update_debounce_counters(uint8_t num_rows, uint8_t elapsed_time) {
107 for (uint8_t col = 0; col < MATRIX_COLS; col++) { 107 for (uint8_t col = 0; col < MATRIX_COLS; col++) {
108 if (*debounce_pointer != DEBOUNCE_ELAPSED) { 108 if (*debounce_pointer != DEBOUNCE_ELAPSED) {
109 if (*debounce_pointer <= elapsed_time) { 109 if (*debounce_pointer <= elapsed_time) {
110 *debounce_pointer = DEBOUNCE_ELAPSED; 110 *debounce_pointer = DEBOUNCE_ELAPSED;
111 matrix_need_update = true; 111 matrix_need_update = true;
112 } else { 112 } else {
113 *debounce_pointer -= elapsed_time; 113 *debounce_pointer -= elapsed_time;
diff --git a/quantum/debounce/sym_eager_pr.c b/quantum/debounce/sym_eager_pr.c
index 2ad592c5a..eda92a263 100644
--- a/quantum/debounce/sym_eager_pr.c
+++ b/quantum/debounce/sym_eager_pr.c
@@ -49,7 +49,7 @@ static debounce_counter_t *debounce_counters;
49static fast_timer_t last_time; 49static fast_timer_t last_time;
50static bool counters_need_update; 50static bool counters_need_update;
51 51
52#define DEBOUNCE_ELAPSED 0 52# define DEBOUNCE_ELAPSED 0
53 53
54static void update_debounce_counters(uint8_t num_rows, uint8_t elapsed_time); 54static void update_debounce_counters(uint8_t num_rows, uint8_t elapsed_time);
55static void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows); 55static void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows);
@@ -71,10 +71,10 @@ void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool
71 bool updated_last = false; 71 bool updated_last = false;
72 72
73 if (counters_need_update) { 73 if (counters_need_update) {
74 fast_timer_t now = timer_read_fast(); 74 fast_timer_t now = timer_read_fast();
75 fast_timer_t elapsed_time = TIMER_DIFF_FAST(now, last_time); 75 fast_timer_t elapsed_time = TIMER_DIFF_FAST(now, last_time);
76 76
77 last_time = now; 77 last_time = now;
78 updated_last = true; 78 updated_last = true;
79 if (elapsed_time > UINT8_MAX) { 79 if (elapsed_time > UINT8_MAX) {
80 elapsed_time = UINT8_MAX; 80 elapsed_time = UINT8_MAX;
@@ -102,7 +102,7 @@ static void update_debounce_counters(uint8_t num_rows, uint8_t elapsed_time) {
102 for (uint8_t row = 0; row < num_rows; row++) { 102 for (uint8_t row = 0; row < num_rows; row++) {
103 if (*debounce_pointer != DEBOUNCE_ELAPSED) { 103 if (*debounce_pointer != DEBOUNCE_ELAPSED) {
104 if (*debounce_pointer <= elapsed_time) { 104 if (*debounce_pointer <= elapsed_time) {
105 *debounce_pointer = DEBOUNCE_ELAPSED; 105 *debounce_pointer = DEBOUNCE_ELAPSED;
106 matrix_need_update = true; 106 matrix_need_update = true;
107 } else { 107 } else {
108 *debounce_pointer -= elapsed_time; 108 *debounce_pointer -= elapsed_time;
diff --git a/quantum/debounce/tests/asym_eager_defer_pk_tests.cpp b/quantum/debounce/tests/asym_eager_defer_pk_tests.cpp
index fe374c3df..44b4fe195 100644
--- a/quantum/debounce/tests/asym_eager_defer_pk_tests.cpp
+++ b/quantum/debounce/tests/asym_eager_defer_pk_tests.cpp
@@ -19,7 +19,8 @@
19#include "debounce_test_common.h" 19#include "debounce_test_common.h"
20 20
21TEST_F(DebounceTest, OneKeyShort1) { 21TEST_F(DebounceTest, OneKeyShort1) {
22 addEvents({ /* Time, Inputs, Outputs */ 22 addEvents({
23 /* Time, Inputs, Outputs */
23 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}}, 24 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
24 /* Release key after 1ms delay */ 25 /* Release key after 1ms delay */
25 {1, {{0, 1, UP}}, {}}, 26 {1, {{0, 1, UP}}, {}},
@@ -43,7 +44,8 @@ TEST_F(DebounceTest, OneKeyShort1) {
43} 44}
44 45
45TEST_F(DebounceTest, OneKeyShort2) { 46TEST_F(DebounceTest, OneKeyShort2) {
46 addEvents({ /* Time, Inputs, Outputs */ 47 addEvents({
48 /* Time, Inputs, Outputs */
47 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}}, 49 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
48 /* Release key after 2ms delay */ 50 /* Release key after 2ms delay */
49 {2, {{0, 1, UP}}, {}}, 51 {2, {{0, 1, UP}}, {}},
@@ -58,7 +60,8 @@ TEST_F(DebounceTest, OneKeyShort2) {
58} 60}
59 61
60TEST_F(DebounceTest, OneKeyShort3) { 62TEST_F(DebounceTest, OneKeyShort3) {
61 addEvents({ /* Time, Inputs, Outputs */ 63 addEvents({
64 /* Time, Inputs, Outputs */
62 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}}, 65 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
63 /* Release key after 3ms delay */ 66 /* Release key after 3ms delay */
64 {3, {{0, 1, UP}}, {}}, 67 {3, {{0, 1, UP}}, {}},
@@ -73,7 +76,8 @@ TEST_F(DebounceTest, OneKeyShort3) {
73} 76}
74 77
75TEST_F(DebounceTest, OneKeyShort4) { 78TEST_F(DebounceTest, OneKeyShort4) {
76 addEvents({ /* Time, Inputs, Outputs */ 79 addEvents({
80 /* Time, Inputs, Outputs */
77 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}}, 81 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
78 /* Release key after 4ms delay */ 82 /* Release key after 4ms delay */
79 {4, {{0, 1, UP}}, {}}, 83 {4, {{0, 1, UP}}, {}},
@@ -88,7 +92,8 @@ TEST_F(DebounceTest, OneKeyShort4) {
88} 92}
89 93
90TEST_F(DebounceTest, OneKeyShort5) { 94TEST_F(DebounceTest, OneKeyShort5) {
91 addEvents({ /* Time, Inputs, Outputs */ 95 addEvents({
96 /* Time, Inputs, Outputs */
92 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}}, 97 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
93 98
94 /* Release key after 5ms delay */ 99 /* Release key after 5ms delay */
@@ -102,7 +107,8 @@ TEST_F(DebounceTest, OneKeyShort5) {
102} 107}
103 108
104TEST_F(DebounceTest, OneKeyShort6) { 109TEST_F(DebounceTest, OneKeyShort6) {
105 addEvents({ /* Time, Inputs, Outputs */ 110 addEvents({
111 /* Time, Inputs, Outputs */
106 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}}, 112 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
107 113
108 /* Release key after 6ms delay */ 114 /* Release key after 6ms delay */
@@ -116,7 +122,8 @@ TEST_F(DebounceTest, OneKeyShort6) {
116} 122}
117 123
118TEST_F(DebounceTest, OneKeyShort7) { 124TEST_F(DebounceTest, OneKeyShort7) {
119 addEvents({ /* Time, Inputs, Outputs */ 125 addEvents({
126 /* Time, Inputs, Outputs */
120 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}}, 127 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
121 128
122 /* Release key after 7ms delay */ 129 /* Release key after 7ms delay */
@@ -130,7 +137,8 @@ TEST_F(DebounceTest, OneKeyShort7) {
130} 137}
131 138
132TEST_F(DebounceTest, OneKeyShort8) { 139TEST_F(DebounceTest, OneKeyShort8) {
133 addEvents({ /* Time, Inputs, Outputs */ 140 addEvents({
141 /* Time, Inputs, Outputs */
134 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}}, 142 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
135 /* Release key after 1ms delay */ 143 /* Release key after 1ms delay */
136 {1, {{0, 1, UP}}, {}}, 144 {1, {{0, 1, UP}}, {}},
@@ -145,7 +153,8 @@ TEST_F(DebounceTest, OneKeyShort8) {
145} 153}
146 154
147TEST_F(DebounceTest, OneKeyShort9) { 155TEST_F(DebounceTest, OneKeyShort9) {
148 addEvents({ /* Time, Inputs, Outputs */ 156 addEvents({
157 /* Time, Inputs, Outputs */
149 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}}, 158 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
150 /* Release key after 1ms delay */ 159 /* Release key after 1ms delay */
151 {1, {{0, 1, UP}}, {}}, 160 {1, {{0, 1, UP}}, {}},
@@ -159,7 +168,8 @@ TEST_F(DebounceTest, OneKeyShort9) {
159} 168}
160 169
161TEST_F(DebounceTest, OneKeyBouncing1) { 170TEST_F(DebounceTest, OneKeyBouncing1) {
162 addEvents({ /* Time, Inputs, Outputs */ 171 addEvents({
172 /* Time, Inputs, Outputs */
163 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}}, 173 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
164 {1, {{0, 1, UP}}, {}}, 174 {1, {{0, 1, UP}}, {}},
165 {2, {{0, 1, DOWN}}, {}}, 175 {2, {{0, 1, DOWN}}, {}},
@@ -185,7 +195,8 @@ TEST_F(DebounceTest, OneKeyBouncing1) {
185} 195}
186 196
187TEST_F(DebounceTest, OneKeyBouncing2) { 197TEST_F(DebounceTest, OneKeyBouncing2) {
188 addEvents({ /* Time, Inputs, Outputs */ 198 addEvents({
199 /* Time, Inputs, Outputs */
189 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}}, 200 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
190 /* Change twice in the same time period */ 201 /* Change twice in the same time period */
191 {1, {{0, 1, UP}}, {}}, 202 {1, {{0, 1, UP}}, {}},
@@ -217,7 +228,8 @@ TEST_F(DebounceTest, OneKeyBouncing2) {
217} 228}
218 229
219TEST_F(DebounceTest, OneKeyLong) { 230TEST_F(DebounceTest, OneKeyLong) {
220 addEvents({ /* Time, Inputs, Outputs */ 231 addEvents({
232 /* Time, Inputs, Outputs */
221 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}}, 233 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
222 234
223 {25, {{0, 1, UP}}, {}}, 235 {25, {{0, 1, UP}}, {}},
@@ -236,7 +248,8 @@ TEST_F(DebounceTest, OneKeyLong) {
236} 248}
237 249
238TEST_F(DebounceTest, TwoKeysShort) { 250TEST_F(DebounceTest, TwoKeysShort) {
239 addEvents({ /* Time, Inputs, Outputs */ 251 addEvents({
252 /* Time, Inputs, Outputs */
240 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}}, 253 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
241 {1, {{0, 2, DOWN}}, {{0, 2, DOWN}}}, 254 {1, {{0, 2, DOWN}}, {{0, 2, DOWN}}},
242 /* Release key after 2ms delay */ 255 /* Release key after 2ms delay */
@@ -249,14 +262,14 @@ TEST_F(DebounceTest, TwoKeysShort) {
249 {10, {}, {{0, 1, UP}}}, /* 5ms+5ms after DOWN at time 0 */ 262 {10, {}, {{0, 1, UP}}}, /* 5ms+5ms after DOWN at time 0 */
250 /* Press key again after 1ms delay */ 263 /* Press key again after 1ms delay */
251 {11, {{0, 1, DOWN}}, {{0, 1, DOWN}, {0, 2, UP}}}, /* 5ms+5ms after DOWN at time 0 */ 264 {11, {{0, 1, DOWN}}, {{0, 1, DOWN}, {0, 2, UP}}}, /* 5ms+5ms after DOWN at time 0 */
252 {12, {{0, 2, DOWN}}, {{0, 2, DOWN}}}, /* 5ms+5ms after DOWN at time 0 */ 265 {12, {{0, 2, DOWN}}, {{0, 2, DOWN}}}, /* 5ms+5ms after DOWN at time 0 */
253 }); 266 });
254 runEvents(); 267 runEvents();
255} 268}
256 269
257
258TEST_F(DebounceTest, OneKeyDelayedScan1) { 270TEST_F(DebounceTest, OneKeyDelayedScan1) {
259 addEvents({ /* Time, Inputs, Outputs */ 271 addEvents({
272 /* Time, Inputs, Outputs */
260 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}}, 273 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
261 274
262 /* Processing is very late, immediately release key */ 275 /* Processing is very late, immediately release key */
@@ -269,7 +282,8 @@ TEST_F(DebounceTest, OneKeyDelayedScan1) {
269} 282}
270 283
271TEST_F(DebounceTest, OneKeyDelayedScan2) { 284TEST_F(DebounceTest, OneKeyDelayedScan2) {
272 addEvents({ /* Time, Inputs, Outputs */ 285 addEvents({
286 /* Time, Inputs, Outputs */
273 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}}, 287 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
274 288
275 /* Processing is very late, immediately release key */ 289 /* Processing is very late, immediately release key */
@@ -283,7 +297,8 @@ TEST_F(DebounceTest, OneKeyDelayedScan2) {
283} 297}
284 298
285TEST_F(DebounceTest, OneKeyDelayedScan3) { 299TEST_F(DebounceTest, OneKeyDelayedScan3) {
286 addEvents({ /* Time, Inputs, Outputs */ 300 addEvents({
301 /* Time, Inputs, Outputs */
287 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}}, 302 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
288 303
289 /* Processing is very late */ 304 /* Processing is very late */
@@ -298,7 +313,8 @@ TEST_F(DebounceTest, OneKeyDelayedScan3) {
298} 313}
299 314
300TEST_F(DebounceTest, OneKeyDelayedScan4) { 315TEST_F(DebounceTest, OneKeyDelayedScan4) {
301 addEvents({ /* Time, Inputs, Outputs */ 316 addEvents({
317 /* Time, Inputs, Outputs */
302 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}}, 318 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
303 319
304 /* Processing is very late */ 320 /* Processing is very late */
@@ -314,7 +330,8 @@ TEST_F(DebounceTest, OneKeyDelayedScan4) {
314} 330}
315 331
316TEST_F(DebounceTest, OneKeyDelayedScan5) { 332TEST_F(DebounceTest, OneKeyDelayedScan5) {
317 addEvents({ /* Time, Inputs, Outputs */ 333 addEvents({
334 /* Time, Inputs, Outputs */
318 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}}, 335 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
319 336
320 {5, {{0, 1, UP}}, {}}, 337 {5, {{0, 1, UP}}, {}},
@@ -329,7 +346,8 @@ TEST_F(DebounceTest, OneKeyDelayedScan5) {
329} 346}
330 347
331TEST_F(DebounceTest, OneKeyDelayedScan6) { 348TEST_F(DebounceTest, OneKeyDelayedScan6) {
332 addEvents({ /* Time, Inputs, Outputs */ 349 addEvents({
350 /* Time, Inputs, Outputs */
333 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}}, 351 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
334 352
335 {5, {{0, 1, UP}}, {}}, 353 {5, {{0, 1, UP}}, {}},
@@ -345,7 +363,8 @@ TEST_F(DebounceTest, OneKeyDelayedScan6) {
345} 363}
346 364
347TEST_F(DebounceTest, OneKeyDelayedScan7) { 365TEST_F(DebounceTest, OneKeyDelayedScan7) {
348 addEvents({ /* Time, Inputs, Outputs */ 366 addEvents({
367 /* Time, Inputs, Outputs */
349 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}}, 368 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
350 369
351 {5, {{0, 1, UP}}, {}}, 370 {5, {{0, 1, UP}}, {}},
@@ -358,7 +377,8 @@ TEST_F(DebounceTest, OneKeyDelayedScan7) {
358} 377}
359 378
360TEST_F(DebounceTest, OneKeyDelayedScan8) { 379TEST_F(DebounceTest, OneKeyDelayedScan8) {
361 addEvents({ /* Time, Inputs, Outputs */ 380 addEvents({
381 /* Time, Inputs, Outputs */
362 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}}, 382 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
363 383
364 /* Processing is a bit late */ 384 /* Processing is a bit late */
diff --git a/quantum/debounce/tests/debounce_test_common.cpp b/quantum/debounce/tests/debounce_test_common.cpp
index 1c5e7c9f4..f9414e571 100644
--- a/quantum/debounce/tests/debounce_test_common.cpp
+++ b/quantum/debounce/tests/debounce_test_common.cpp
@@ -31,9 +31,7 @@ void set_time(uint32_t t);
31void advance_time(uint32_t ms); 31void advance_time(uint32_t ms);
32} 32}
33 33
34void DebounceTest::addEvents(std::initializer_list<DebounceTestEvent> events) { 34void DebounceTest::addEvents(std::initializer_list<DebounceTestEvent> events) { events_.insert(events_.end(), events.begin(), events.end()); }
35 events_.insert(events_.end(), events.begin(), events.end());
36}
37 35
38void DebounceTest::runEvents() { 36void DebounceTest::runEvents() {
39 /* Run the test multiple times, from 1kHz to 10kHz scan rate */ 37 /* Run the test multiple times, from 1kHz to 10kHz scan rate */
@@ -54,7 +52,7 @@ void DebounceTest::runEvents() {
54 52
55void DebounceTest::runEventsInternal() { 53void DebounceTest::runEventsInternal() {
56 fast_timer_t previous = 0; 54 fast_timer_t previous = 0;
57 bool first = true; 55 bool first = true;
58 56
59 /* Initialise keyboard with start time (offset to avoid testing at 0) and all keys UP */ 57 /* Initialise keyboard with start time (offset to avoid testing at 0) and all keys UP */
60 debounce_init(MATRIX_ROWS); 58 debounce_init(MATRIX_ROWS);
@@ -80,7 +78,7 @@ void DebounceTest::runEventsInternal() {
80 } 78 }
81 } 79 }
82 80
83 first = false; 81 first = false;
84 previous = event.time_; 82 previous = event.time_;
85 83
86 /* Prepare input matrix */ 84 /* Prepare input matrix */
@@ -98,12 +96,7 @@ void DebounceTest::runEventsInternal() {
98 96
99 /* Check output matrix has expected change events */ 97 /* Check output matrix has expected change events */
100 for (auto &output : event.outputs_) { 98 for (auto &output : event.outputs_) {
101 EXPECT_EQ(!!(cooked_matrix_[output.row_] & (1U << output.col_)), directionValue(output.direction_)) 99 EXPECT_EQ(!!(cooked_matrix_[output.row_] & (1U << output.col_)), directionValue(output.direction_)) << "Missing event at " << strTime() << " expected key " << output.row_ << "," << output.col_ << " " << directionLabel(output.direction_) << "\ninput_matrix: changed=" << !event.inputs_.empty() << "\n" << strMatrix(input_matrix_) << "\nexpected_matrix:\n" << strMatrix(output_matrix_) << "\nactual_matrix:\n" << strMatrix(cooked_matrix_);
102 << "Missing event at " << strTime()
103 << " expected key " << output.row_ << "," << output.col_ << " " << directionLabel(output.direction_)
104 << "\ninput_matrix: changed=" << !event.inputs_.empty() << "\n" << strMatrix(input_matrix_)
105 << "\nexpected_matrix:\n" << strMatrix(output_matrix_)
106 << "\nactual_matrix:\n" << strMatrix(cooked_matrix_);
107 } 100 }
108 101
109 /* Check output matrix has no other changes */ 102 /* Check output matrix has no other changes */
@@ -133,27 +126,20 @@ void DebounceTest::runDebounce(bool changed) {
133 debounce(raw_matrix_, cooked_matrix_, MATRIX_ROWS, changed); 126 debounce(raw_matrix_, cooked_matrix_, MATRIX_ROWS, changed);
134 127
135 if (!std::equal(std::begin(input_matrix_), std::end(input_matrix_), std::begin(raw_matrix_))) { 128 if (!std::equal(std::begin(input_matrix_), std::end(input_matrix_), std::begin(raw_matrix_))) {
136 FAIL() << "Fatal error: debounce() modified raw matrix at " << strTime() 129 FAIL() << "Fatal error: debounce() modified raw matrix at " << strTime() << "\ninput_matrix: changed=" << changed << "\n" << strMatrix(input_matrix_) << "\nraw_matrix:\n" << strMatrix(raw_matrix_);
137 << "\ninput_matrix: changed=" << changed << "\n" << strMatrix(input_matrix_)
138 << "\nraw_matrix:\n" << strMatrix(raw_matrix_);
139 } 130 }
140} 131}
141 132
142void DebounceTest::checkCookedMatrix(bool changed, const std::string &error_message) { 133void DebounceTest::checkCookedMatrix(bool changed, const std::string &error_message) {
143 if (!std::equal(std::begin(output_matrix_), std::end(output_matrix_), std::begin(cooked_matrix_))) { 134 if (!std::equal(std::begin(output_matrix_), std::end(output_matrix_), std::begin(cooked_matrix_))) {
144 FAIL() << "Unexpected event: " << error_message << " at " << strTime() 135 FAIL() << "Unexpected event: " << error_message << " at " << strTime() << "\ninput_matrix: changed=" << changed << "\n" << strMatrix(input_matrix_) << "\nexpected_matrix:\n" << strMatrix(output_matrix_) << "\nactual_matrix:\n" << strMatrix(cooked_matrix_);
145 << "\ninput_matrix: changed=" << changed << "\n" << strMatrix(input_matrix_)
146 << "\nexpected_matrix:\n" << strMatrix(output_matrix_)
147 << "\nactual_matrix:\n" << strMatrix(cooked_matrix_);
148 } 136 }
149} 137}
150 138
151std::string DebounceTest::strTime() { 139std::string DebounceTest::strTime() {
152 std::stringstream text; 140 std::stringstream text;
153 141
154 text << "time " << (timer_read_fast() - time_offset_) 142 text << "time " << (timer_read_fast() - time_offset_) << " (extra_iterations=" << extra_iterations_ << ", auto_advance_time=" << auto_advance_time_ << ")";
155 << " (extra_iterations=" << extra_iterations_
156 << ", auto_advance_time=" << auto_advance_time_ << ")";
157 143
158 return text.str(); 144 return text.str();
159} 145}
@@ -181,49 +167,39 @@ std::string DebounceTest::strMatrix(matrix_row_t matrix[]) {
181 167
182bool DebounceTest::directionValue(Direction direction) { 168bool DebounceTest::directionValue(Direction direction) {
183 switch (direction) { 169 switch (direction) {
184 case DOWN: 170 case DOWN:
185 return true; 171 return true;
186 172
187 case UP: 173 case UP:
188 return false; 174 return false;
189 } 175 }
190} 176}
191 177
192std::string DebounceTest::directionLabel(Direction direction) { 178std::string DebounceTest::directionLabel(Direction direction) {
193 switch (direction) { 179 switch (direction) {
194 case DOWN: 180 case DOWN:
195 return "DOWN"; 181 return "DOWN";
196 182
197 case UP: 183 case UP:
198 return "UP"; 184 return "UP";
199 } 185 }
200} 186}
201 187
202/* Modify a matrix and verify that events always specify a change */ 188/* Modify a matrix and verify that events always specify a change */
203void DebounceTest::matrixUpdate(matrix_row_t matrix[], const std::string &name, const MatrixTestEvent &event) { 189void DebounceTest::matrixUpdate(matrix_row_t matrix[], const std::string &name, const MatrixTestEvent &event) {
204 ASSERT_NE(!!(matrix[event.row_] & (1U << event.col_)), directionValue(event.direction_)) 190 ASSERT_NE(!!(matrix[event.row_] & (1U << event.col_)), directionValue(event.direction_)) << "Test " << name << " at " << strTime() << " sets key " << event.row_ << "," << event.col_ << " " << directionLabel(event.direction_) << " but it is already " << directionLabel(event.direction_) << "\n" << name << "_matrix:\n" << strMatrix(matrix);
205 << "Test " << name << " at " << strTime()
206 << " sets key " << event.row_ << "," << event.col_ << " " << directionLabel(event.direction_)
207 << " but it is already " << directionLabel(event.direction_)
208 << "\n" << name << "_matrix:\n" << strMatrix(matrix);
209 191
210 switch (event.direction_) { 192 switch (event.direction_) {
211 case DOWN: 193 case DOWN:
212 matrix[event.row_] |= (1U << event.col_); 194 matrix[event.row_] |= (1U << event.col_);
213 break; 195 break;
214 196
215 case UP: 197 case UP:
216 matrix[event.row_] &= ~(1U << event.col_); 198 matrix[event.row_] &= ~(1U << event.col_);
217 break; 199 break;
218 } 200 }
219} 201}
220 202
221DebounceTestEvent::DebounceTestEvent(fast_timer_t time, 203DebounceTestEvent::DebounceTestEvent(fast_timer_t time, std::initializer_list<MatrixTestEvent> inputs, std::initializer_list<MatrixTestEvent> outputs) : time_(time), inputs_(inputs), outputs_(outputs) {}
222 std::initializer_list<MatrixTestEvent> inputs,
223 std::initializer_list<MatrixTestEvent> outputs)
224 : time_(time), inputs_(inputs), outputs_(outputs) {
225}
226 204
227MatrixTestEvent::MatrixTestEvent(int row, int col, Direction direction) 205MatrixTestEvent::MatrixTestEvent(int row, int col, Direction direction) : row_(row), col_(col), direction_(direction) {}
228 : row_(row), col_(col), direction_(direction) {
229}
diff --git a/quantum/debounce/tests/debounce_test_common.h b/quantum/debounce/tests/debounce_test_common.h
index d87e31059..b7becb378 100644
--- a/quantum/debounce/tests/debounce_test_common.h
+++ b/quantum/debounce/tests/debounce_test_common.h
@@ -31,36 +31,34 @@ enum Direction {
31}; 31};
32 32
33class MatrixTestEvent { 33class MatrixTestEvent {
34public: 34 public:
35 MatrixTestEvent(int row, int col, Direction direction); 35 MatrixTestEvent(int row, int col, Direction direction);
36 36
37 const int row_; 37 const int row_;
38 const int col_; 38 const int col_;
39 const Direction direction_; 39 const Direction direction_;
40}; 40};
41 41
42class DebounceTestEvent { 42class DebounceTestEvent {
43public: 43 public:
44 // 0, {{0, 1, DOWN}}, {{0, 1, DOWN}}) 44 // 0, {{0, 1, DOWN}}, {{0, 1, DOWN}})
45 DebounceTestEvent(fast_timer_t time, 45 DebounceTestEvent(fast_timer_t time, std::initializer_list<MatrixTestEvent> inputs, std::initializer_list<MatrixTestEvent> outputs);
46 std::initializer_list<MatrixTestEvent> inputs,
47 std::initializer_list<MatrixTestEvent> outputs);
48 46
49 const fast_timer_t time_; 47 const fast_timer_t time_;
50 const std::list<MatrixTestEvent> inputs_; 48 const std::list<MatrixTestEvent> inputs_;
51 const std::list<MatrixTestEvent> outputs_; 49 const std::list<MatrixTestEvent> outputs_;
52}; 50};
53 51
54class DebounceTest : public ::testing::Test { 52class DebounceTest : public ::testing::Test {
55protected: 53 protected:
56 void addEvents(std::initializer_list<DebounceTestEvent> events); 54 void addEvents(std::initializer_list<DebounceTestEvent> events);
57 void runEvents(); 55 void runEvents();
58 56
59 fast_timer_t time_offset_ = 7777; 57 fast_timer_t time_offset_ = 7777;
60 bool time_jumps_ = false; 58 bool time_jumps_ = false;
61 59
62private: 60 private:
63 static bool directionValue(Direction direction); 61 static bool directionValue(Direction direction);
64 static std::string directionLabel(Direction direction); 62 static std::string directionLabel(Direction direction);
65 63
66 void runEventsInternal(); 64 void runEventsInternal();
@@ -78,6 +76,6 @@ private:
78 matrix_row_t cooked_matrix_[MATRIX_ROWS]; 76 matrix_row_t cooked_matrix_[MATRIX_ROWS];
79 matrix_row_t output_matrix_[MATRIX_ROWS]; 77 matrix_row_t output_matrix_[MATRIX_ROWS];
80 78
81 int extra_iterations_; 79 int extra_iterations_;
82 bool auto_advance_time_; 80 bool auto_advance_time_;
83}; 81};
diff --git a/quantum/debounce/tests/sym_defer_g_tests.cpp b/quantum/debounce/tests/sym_defer_g_tests.cpp
index a56aecd8f..73d3d45e3 100644
--- a/quantum/debounce/tests/sym_defer_g_tests.cpp
+++ b/quantum/debounce/tests/sym_defer_g_tests.cpp
@@ -19,7 +19,8 @@
19#include "debounce_test_common.h" 19#include "debounce_test_common.h"
20 20
21TEST_F(DebounceTest, OneKeyShort1) { 21TEST_F(DebounceTest, OneKeyShort1) {
22 addEvents({ /* Time, Inputs, Outputs */ 22 addEvents({
23 /* Time, Inputs, Outputs */
23 {0, {{0, 1, DOWN}}, {}}, 24 {0, {{0, 1, DOWN}}, {}},
24 25
25 {5, {}, {{0, 1, DOWN}}}, 26 {5, {}, {{0, 1, DOWN}}},
@@ -32,7 +33,8 @@ TEST_F(DebounceTest, OneKeyShort1) {
32} 33}
33 34
34TEST_F(DebounceTest, OneKeyShort2) { 35TEST_F(DebounceTest, OneKeyShort2) {
35 addEvents({ /* Time, Inputs, Outputs */ 36 addEvents({
37 /* Time, Inputs, Outputs */
36 {0, {{0, 1, DOWN}}, {}}, 38 {0, {{0, 1, DOWN}}, {}},
37 39
38 {5, {}, {{0, 1, DOWN}}}, 40 {5, {}, {{0, 1, DOWN}}},
@@ -45,7 +47,8 @@ TEST_F(DebounceTest, OneKeyShort2) {
45} 47}
46 48
47TEST_F(DebounceTest, OneKeyShort3) { 49TEST_F(DebounceTest, OneKeyShort3) {
48 addEvents({ /* Time, Inputs, Outputs */ 50 addEvents({
51 /* Time, Inputs, Outputs */
49 {0, {{0, 1, DOWN}}, {}}, 52 {0, {{0, 1, DOWN}}, {}},
50 53
51 {5, {}, {{0, 1, DOWN}}}, 54 {5, {}, {{0, 1, DOWN}}},
@@ -58,7 +61,8 @@ TEST_F(DebounceTest, OneKeyShort3) {
58} 61}
59 62
60TEST_F(DebounceTest, OneKeyTooQuick1) { 63TEST_F(DebounceTest, OneKeyTooQuick1) {
61 addEvents({ /* Time, Inputs, Outputs */ 64 addEvents({
65 /* Time, Inputs, Outputs */
62 {0, {{0, 1, DOWN}}, {}}, 66 {0, {{0, 1, DOWN}}, {}},
63 /* Release key exactly on the debounce time */ 67 /* Release key exactly on the debounce time */
64 {5, {{0, 1, UP}}, {}}, 68 {5, {{0, 1, UP}}, {}},
@@ -67,7 +71,8 @@ TEST_F(DebounceTest, OneKeyTooQuick1) {
67} 71}
68 72
69TEST_F(DebounceTest, OneKeyTooQuick2) { 73TEST_F(DebounceTest, OneKeyTooQuick2) {
70 addEvents({ /* Time, Inputs, Outputs */ 74 addEvents({
75 /* Time, Inputs, Outputs */
71 {0, {{0, 1, DOWN}}, {}}, 76 {0, {{0, 1, DOWN}}, {}},
72 77
73 {5, {}, {{0, 1, DOWN}}}, 78 {5, {}, {{0, 1, DOWN}}},
@@ -80,7 +85,8 @@ TEST_F(DebounceTest, OneKeyTooQuick2) {
80} 85}
81 86
82TEST_F(DebounceTest, OneKeyBouncing1) { 87TEST_F(DebounceTest, OneKeyBouncing1) {
83 addEvents({ /* Time, Inputs, Outputs */ 88 addEvents({
89 /* Time, Inputs, Outputs */
84 {0, {{0, 1, DOWN}}, {}}, 90 {0, {{0, 1, DOWN}}, {}},
85 {1, {{0, 1, UP}}, {}}, 91 {1, {{0, 1, UP}}, {}},
86 {2, {{0, 1, DOWN}}, {}}, 92 {2, {{0, 1, DOWN}}, {}},
@@ -94,7 +100,8 @@ TEST_F(DebounceTest, OneKeyBouncing1) {
94} 100}
95 101
96TEST_F(DebounceTest, OneKeyBouncing2) { 102TEST_F(DebounceTest, OneKeyBouncing2) {
97 addEvents({ /* Time, Inputs, Outputs */ 103 addEvents({
104 /* Time, Inputs, Outputs */
98 {0, {{0, 1, DOWN}}, {}}, 105 {0, {{0, 1, DOWN}}, {}},
99 {5, {}, {{0, 1, DOWN}}}, 106 {5, {}, {{0, 1, DOWN}}},
100 {6, {{0, 1, UP}}, {}}, 107 {6, {{0, 1, UP}}, {}},
@@ -108,7 +115,8 @@ TEST_F(DebounceTest, OneKeyBouncing2) {
108} 115}
109 116
110TEST_F(DebounceTest, OneKeyLong) { 117TEST_F(DebounceTest, OneKeyLong) {
111 addEvents({ /* Time, Inputs, Outputs */ 118 addEvents({
119 /* Time, Inputs, Outputs */
112 {0, {{0, 1, DOWN}}, {}}, 120 {0, {{0, 1, DOWN}}, {}},
113 121
114 {5, {}, {{0, 1, DOWN}}}, 122 {5, {}, {{0, 1, DOWN}}},
@@ -125,7 +133,8 @@ TEST_F(DebounceTest, OneKeyLong) {
125} 133}
126 134
127TEST_F(DebounceTest, TwoKeysShort) { 135TEST_F(DebounceTest, TwoKeysShort) {
128 addEvents({ /* Time, Inputs, Outputs */ 136 addEvents({
137 /* Time, Inputs, Outputs */
129 {0, {{0, 1, DOWN}}, {}}, 138 {0, {{0, 1, DOWN}}, {}},
130 {1, {{0, 2, DOWN}}, {}}, 139 {1, {{0, 2, DOWN}}, {}},
131 140
@@ -140,7 +149,8 @@ TEST_F(DebounceTest, TwoKeysShort) {
140} 149}
141 150
142TEST_F(DebounceTest, TwoKeysSimultaneous1) { 151TEST_F(DebounceTest, TwoKeysSimultaneous1) {
143 addEvents({ /* Time, Inputs, Outputs */ 152 addEvents({
153 /* Time, Inputs, Outputs */
144 {0, {{0, 1, DOWN}, {0, 2, DOWN}}, {}}, 154 {0, {{0, 1, DOWN}, {0, 2, DOWN}}, {}},
145 155
146 {5, {}, {{0, 1, DOWN}, {0, 2, DOWN}}}, 156 {5, {}, {{0, 1, DOWN}, {0, 2, DOWN}}},
@@ -152,7 +162,8 @@ TEST_F(DebounceTest, TwoKeysSimultaneous1) {
152} 162}
153 163
154TEST_F(DebounceTest, TwoKeysSimultaneous2) { 164TEST_F(DebounceTest, TwoKeysSimultaneous2) {
155 addEvents({ /* Time, Inputs, Outputs */ 165 addEvents({
166 /* Time, Inputs, Outputs */
156 {0, {{0, 1, DOWN}}, {}}, 167 {0, {{0, 1, DOWN}}, {}},
157 {1, {{0, 2, DOWN}}, {}}, 168 {1, {{0, 2, DOWN}}, {}},
158 169
@@ -167,7 +178,8 @@ TEST_F(DebounceTest, TwoKeysSimultaneous2) {
167} 178}
168 179
169TEST_F(DebounceTest, OneKeyDelayedScan1) { 180TEST_F(DebounceTest, OneKeyDelayedScan1) {
170 addEvents({ /* Time, Inputs, Outputs */ 181 addEvents({
182 /* Time, Inputs, Outputs */
171 {0, {{0, 1, DOWN}}, {}}, 183 {0, {{0, 1, DOWN}}, {}},
172 184
173 /* Processing is very late */ 185 /* Processing is very late */
@@ -182,7 +194,8 @@ TEST_F(DebounceTest, OneKeyDelayedScan1) {
182} 194}
183 195
184TEST_F(DebounceTest, OneKeyDelayedScan2) { 196TEST_F(DebounceTest, OneKeyDelayedScan2) {
185 addEvents({ /* Time, Inputs, Outputs */ 197 addEvents({
198 /* Time, Inputs, Outputs */
186 {0, {{0, 1, DOWN}}, {}}, 199 {0, {{0, 1, DOWN}}, {}},
187 200
188 /* Processing is very late */ 201 /* Processing is very late */
@@ -197,7 +210,8 @@ TEST_F(DebounceTest, OneKeyDelayedScan2) {
197} 210}
198 211
199TEST_F(DebounceTest, OneKeyDelayedScan3) { 212TEST_F(DebounceTest, OneKeyDelayedScan3) {
200 addEvents({ /* Time, Inputs, Outputs */ 213 addEvents({
214 /* Time, Inputs, Outputs */
201 {0, {{0, 1, DOWN}}, {}}, 215 {0, {{0, 1, DOWN}}, {}},
202 216
203 /* Release key before debounce expires */ 217 /* Release key before debounce expires */
@@ -208,7 +222,8 @@ TEST_F(DebounceTest, OneKeyDelayedScan3) {
208} 222}
209 223
210TEST_F(DebounceTest, OneKeyDelayedScan4) { 224TEST_F(DebounceTest, OneKeyDelayedScan4) {
211 addEvents({ /* Time, Inputs, Outputs */ 225 addEvents({
226 /* Time, Inputs, Outputs */
212 {0, {{0, 1, DOWN}}, {}}, 227 {0, {{0, 1, DOWN}}, {}},
213 228
214 /* Processing is a bit late */ 229 /* Processing is a bit late */
diff --git a/quantum/debounce/tests/sym_defer_pk_tests.cpp b/quantum/debounce/tests/sym_defer_pk_tests.cpp
index 1f3061e59..7542c2dad 100644
--- a/quantum/debounce/tests/sym_defer_pk_tests.cpp
+++ b/quantum/debounce/tests/sym_defer_pk_tests.cpp
@@ -19,7 +19,8 @@
19#include "debounce_test_common.h" 19#include "debounce_test_common.h"
20 20
21TEST_F(DebounceTest, OneKeyShort1) { 21TEST_F(DebounceTest, OneKeyShort1) {
22 addEvents({ /* Time, Inputs, Outputs */ 22 addEvents({
23 /* Time, Inputs, Outputs */
23 {0, {{0, 1, DOWN}}, {}}, 24 {0, {{0, 1, DOWN}}, {}},
24 25
25 {5, {}, {{0, 1, DOWN}}}, 26 {5, {}, {{0, 1, DOWN}}},
@@ -32,7 +33,8 @@ TEST_F(DebounceTest, OneKeyShort1) {
32} 33}
33 34
34TEST_F(DebounceTest, OneKeyShort2) { 35TEST_F(DebounceTest, OneKeyShort2) {
35 addEvents({ /* Time, Inputs, Outputs */ 36 addEvents({
37 /* Time, Inputs, Outputs */
36 {0, {{0, 1, DOWN}}, {}}, 38 {0, {{0, 1, DOWN}}, {}},
37 39
38 {5, {}, {{0, 1, DOWN}}}, 40 {5, {}, {{0, 1, DOWN}}},
@@ -45,7 +47,8 @@ TEST_F(DebounceTest, OneKeyShort2) {
45} 47}
46 48
47TEST_F(DebounceTest, OneKeyShort3) { 49TEST_F(DebounceTest, OneKeyShort3) {
48 addEvents({ /* Time, Inputs, Outputs */ 50 addEvents({
51 /* Time, Inputs, Outputs */
49 {0, {{0, 1, DOWN}}, {}}, 52 {0, {{0, 1, DOWN}}, {}},
50 53
51 {5, {}, {{0, 1, DOWN}}}, 54 {5, {}, {{0, 1, DOWN}}},
@@ -58,7 +61,8 @@ TEST_F(DebounceTest, OneKeyShort3) {
58} 61}
59 62
60TEST_F(DebounceTest, OneKeyTooQuick1) { 63TEST_F(DebounceTest, OneKeyTooQuick1) {
61 addEvents({ /* Time, Inputs, Outputs */ 64 addEvents({
65 /* Time, Inputs, Outputs */
62 {0, {{0, 1, DOWN}}, {}}, 66 {0, {{0, 1, DOWN}}, {}},
63 /* Release key exactly on the debounce time */ 67 /* Release key exactly on the debounce time */
64 {5, {{0, 1, UP}}, {}}, 68 {5, {{0, 1, UP}}, {}},
@@ -67,7 +71,8 @@ TEST_F(DebounceTest, OneKeyTooQuick1) {
67} 71}
68 72
69TEST_F(DebounceTest, OneKeyTooQuick2) { 73TEST_F(DebounceTest, OneKeyTooQuick2) {
70 addEvents({ /* Time, Inputs, Outputs */ 74 addEvents({
75 /* Time, Inputs, Outputs */
71 {0, {{0, 1, DOWN}}, {}}, 76 {0, {{0, 1, DOWN}}, {}},
72 77
73 {5, {}, {{0, 1, DOWN}}}, 78 {5, {}, {{0, 1, DOWN}}},
@@ -80,7 +85,8 @@ TEST_F(DebounceTest, OneKeyTooQuick2) {
80} 85}
81 86
82TEST_F(DebounceTest, OneKeyBouncing1) { 87TEST_F(DebounceTest, OneKeyBouncing1) {
83 addEvents({ /* Time, Inputs, Outputs */ 88 addEvents({
89 /* Time, Inputs, Outputs */
84 {0, {{0, 1, DOWN}}, {}}, 90 {0, {{0, 1, DOWN}}, {}},
85 {1, {{0, 1, UP}}, {}}, 91 {1, {{0, 1, UP}}, {}},
86 {2, {{0, 1, DOWN}}, {}}, 92 {2, {{0, 1, DOWN}}, {}},
@@ -94,7 +100,8 @@ TEST_F(DebounceTest, OneKeyBouncing1) {
94} 100}
95 101
96TEST_F(DebounceTest, OneKeyBouncing2) { 102TEST_F(DebounceTest, OneKeyBouncing2) {
97 addEvents({ /* Time, Inputs, Outputs */ 103 addEvents({
104 /* Time, Inputs, Outputs */
98 {0, {{0, 1, DOWN}}, {}}, 105 {0, {{0, 1, DOWN}}, {}},
99 {5, {}, {{0, 1, DOWN}}}, 106 {5, {}, {{0, 1, DOWN}}},
100 {6, {{0, 1, UP}}, {}}, 107 {6, {{0, 1, UP}}, {}},
@@ -108,7 +115,8 @@ TEST_F(DebounceTest, OneKeyBouncing2) {
108} 115}
109 116
110TEST_F(DebounceTest, OneKeyLong) { 117TEST_F(DebounceTest, OneKeyLong) {
111 addEvents({ /* Time, Inputs, Outputs */ 118 addEvents({
119 /* Time, Inputs, Outputs */
112 {0, {{0, 1, DOWN}}, {}}, 120 {0, {{0, 1, DOWN}}, {}},
113 121
114 {5, {}, {{0, 1, DOWN}}}, 122 {5, {}, {{0, 1, DOWN}}},
@@ -125,7 +133,8 @@ TEST_F(DebounceTest, OneKeyLong) {
125} 133}
126 134
127TEST_F(DebounceTest, TwoKeysShort) { 135TEST_F(DebounceTest, TwoKeysShort) {
128 addEvents({ /* Time, Inputs, Outputs */ 136 addEvents({
137 /* Time, Inputs, Outputs */
129 {0, {{0, 1, DOWN}}, {}}, 138 {0, {{0, 1, DOWN}}, {}},
130 {1, {{0, 2, DOWN}}, {}}, 139 {1, {{0, 2, DOWN}}, {}},
131 140
@@ -142,7 +151,8 @@ TEST_F(DebounceTest, TwoKeysShort) {
142} 151}
143 152
144TEST_F(DebounceTest, TwoKeysSimultaneous1) { 153TEST_F(DebounceTest, TwoKeysSimultaneous1) {
145 addEvents({ /* Time, Inputs, Outputs */ 154 addEvents({
155 /* Time, Inputs, Outputs */
146 {0, {{0, 1, DOWN}, {0, 2, DOWN}}, {}}, 156 {0, {{0, 1, DOWN}, {0, 2, DOWN}}, {}},
147 157
148 {5, {}, {{0, 1, DOWN}, {0, 2, DOWN}}}, 158 {5, {}, {{0, 1, DOWN}, {0, 2, DOWN}}},
@@ -154,7 +164,8 @@ TEST_F(DebounceTest, TwoKeysSimultaneous1) {
154} 164}
155 165
156TEST_F(DebounceTest, TwoKeysSimultaneous2) { 166TEST_F(DebounceTest, TwoKeysSimultaneous2) {
157 addEvents({ /* Time, Inputs, Outputs */ 167 addEvents({
168 /* Time, Inputs, Outputs */
158 {0, {{0, 1, DOWN}}, {}}, 169 {0, {{0, 1, DOWN}}, {}},
159 {1, {{0, 2, DOWN}}, {}}, 170 {1, {{0, 2, DOWN}}, {}},
160 171
@@ -169,7 +180,8 @@ TEST_F(DebounceTest, TwoKeysSimultaneous2) {
169} 180}
170 181
171TEST_F(DebounceTest, OneKeyDelayedScan1) { 182TEST_F(DebounceTest, OneKeyDelayedScan1) {
172 addEvents({ /* Time, Inputs, Outputs */ 183 addEvents({
184 /* Time, Inputs, Outputs */
173 {0, {{0, 1, DOWN}}, {}}, 185 {0, {{0, 1, DOWN}}, {}},
174 186
175 /* Processing is very late */ 187 /* Processing is very late */
@@ -184,7 +196,8 @@ TEST_F(DebounceTest, OneKeyDelayedScan1) {
184} 196}
185 197
186TEST_F(DebounceTest, OneKeyDelayedScan2) { 198TEST_F(DebounceTest, OneKeyDelayedScan2) {
187 addEvents({ /* Time, Inputs, Outputs */ 199 addEvents({
200 /* Time, Inputs, Outputs */
188 {0, {{0, 1, DOWN}}, {}}, 201 {0, {{0, 1, DOWN}}, {}},
189 202
190 /* Processing is very late */ 203 /* Processing is very late */
@@ -199,7 +212,8 @@ TEST_F(DebounceTest, OneKeyDelayedScan2) {
199} 212}
200 213
201TEST_F(DebounceTest, OneKeyDelayedScan3) { 214TEST_F(DebounceTest, OneKeyDelayedScan3) {
202 addEvents({ /* Time, Inputs, Outputs */ 215 addEvents({
216 /* Time, Inputs, Outputs */
203 {0, {{0, 1, DOWN}}, {}}, 217 {0, {{0, 1, DOWN}}, {}},
204 218
205 /* Release key before debounce expires */ 219 /* Release key before debounce expires */
@@ -210,7 +224,8 @@ TEST_F(DebounceTest, OneKeyDelayedScan3) {
210} 224}
211 225
212TEST_F(DebounceTest, OneKeyDelayedScan4) { 226TEST_F(DebounceTest, OneKeyDelayedScan4) {
213 addEvents({ /* Time, Inputs, Outputs */ 227 addEvents({
228 /* Time, Inputs, Outputs */
214 {0, {{0, 1, DOWN}}, {}}, 229 {0, {{0, 1, DOWN}}, {}},
215 230
216 /* Processing is a bit late */ 231 /* Processing is a bit late */
diff --git a/quantum/debounce/tests/sym_eager_pk_tests.cpp b/quantum/debounce/tests/sym_eager_pk_tests.cpp
index e0fc205e3..d9a02fe33 100644
--- a/quantum/debounce/tests/sym_eager_pk_tests.cpp
+++ b/quantum/debounce/tests/sym_eager_pk_tests.cpp
@@ -19,7 +19,8 @@
19#include "debounce_test_common.h" 19#include "debounce_test_common.h"
20 20
21TEST_F(DebounceTest, OneKeyShort1) { 21TEST_F(DebounceTest, OneKeyShort1) {
22 addEvents({ /* Time, Inputs, Outputs */ 22 addEvents({
23 /* Time, Inputs, Outputs */
23 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}}, 24 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
24 {1, {{0, 1, UP}}, {}}, 25 {1, {{0, 1, UP}}, {}},
25 26
@@ -32,7 +33,8 @@ TEST_F(DebounceTest, OneKeyShort1) {
32} 33}
33 34
34TEST_F(DebounceTest, OneKeyShort2) { 35TEST_F(DebounceTest, OneKeyShort2) {
35 addEvents({ /* Time, Inputs, Outputs */ 36 addEvents({
37 /* Time, Inputs, Outputs */
36 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}}, 38 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
37 {1, {{0, 1, UP}}, {}}, 39 {1, {{0, 1, UP}}, {}},
38 40
@@ -45,7 +47,8 @@ TEST_F(DebounceTest, OneKeyShort2) {
45} 47}
46 48
47TEST_F(DebounceTest, OneKeyShort3) { 49TEST_F(DebounceTest, OneKeyShort3) {
48 addEvents({ /* Time, Inputs, Outputs */ 50 addEvents({
51 /* Time, Inputs, Outputs */
49 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}}, 52 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
50 {1, {{0, 1, UP}}, {}}, 53 {1, {{0, 1, UP}}, {}},
51 54
@@ -58,7 +61,8 @@ TEST_F(DebounceTest, OneKeyShort3) {
58} 61}
59 62
60TEST_F(DebounceTest, OneKeyShort4) { 63TEST_F(DebounceTest, OneKeyShort4) {
61 addEvents({ /* Time, Inputs, Outputs */ 64 addEvents({
65 /* Time, Inputs, Outputs */
62 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}}, 66 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
63 {1, {{0, 1, UP}}, {}}, 67 {1, {{0, 1, UP}}, {}},
64 68
@@ -71,7 +75,8 @@ TEST_F(DebounceTest, OneKeyShort4) {
71} 75}
72 76
73TEST_F(DebounceTest, OneKeyShort5) { 77TEST_F(DebounceTest, OneKeyShort5) {
74 addEvents({ /* Time, Inputs, Outputs */ 78 addEvents({
79 /* Time, Inputs, Outputs */
75 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}}, 80 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
76 {1, {{0, 1, UP}}, {}}, 81 {1, {{0, 1, UP}}, {}},
77 82
@@ -83,7 +88,8 @@ TEST_F(DebounceTest, OneKeyShort5) {
83} 88}
84 89
85TEST_F(DebounceTest, OneKeyShort6) { 90TEST_F(DebounceTest, OneKeyShort6) {
86 addEvents({ /* Time, Inputs, Outputs */ 91 addEvents({
92 /* Time, Inputs, Outputs */
87 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}}, 93 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
88 {1, {{0, 1, UP}}, {}}, 94 {1, {{0, 1, UP}}, {}},
89 95
@@ -95,7 +101,8 @@ TEST_F(DebounceTest, OneKeyShort6) {
95} 101}
96 102
97TEST_F(DebounceTest, OneKeyBouncing1) { 103TEST_F(DebounceTest, OneKeyBouncing1) {
98 addEvents({ /* Time, Inputs, Outputs */ 104 addEvents({
105 /* Time, Inputs, Outputs */
99 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}}, 106 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
100 {1, {{0, 1, UP}}, {}}, 107 {1, {{0, 1, UP}}, {}},
101 {2, {{0, 1, DOWN}}, {}}, 108 {2, {{0, 1, DOWN}}, {}},
@@ -110,7 +117,8 @@ TEST_F(DebounceTest, OneKeyBouncing1) {
110} 117}
111 118
112TEST_F(DebounceTest, OneKeyBouncing2) { 119TEST_F(DebounceTest, OneKeyBouncing2) {
113 addEvents({ /* Time, Inputs, Outputs */ 120 addEvents({
121 /* Time, Inputs, Outputs */
114 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}}, 122 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
115 /* Change twice in the same time period */ 123 /* Change twice in the same time period */
116 {1, {{0, 1, UP}}, {}}, 124 {1, {{0, 1, UP}}, {}},
@@ -135,7 +143,8 @@ TEST_F(DebounceTest, OneKeyBouncing2) {
135} 143}
136 144
137TEST_F(DebounceTest, OneKeyLong) { 145TEST_F(DebounceTest, OneKeyLong) {
138 addEvents({ /* Time, Inputs, Outputs */ 146 addEvents({
147 /* Time, Inputs, Outputs */
139 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}}, 148 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
140 149
141 {25, {{0, 1, UP}}, {{0, 1, UP}}}, 150 {25, {{0, 1, UP}}, {{0, 1, UP}}},
@@ -146,7 +155,8 @@ TEST_F(DebounceTest, OneKeyLong) {
146} 155}
147 156
148TEST_F(DebounceTest, TwoKeysShort) { 157TEST_F(DebounceTest, TwoKeysShort) {
149 addEvents({ /* Time, Inputs, Outputs */ 158 addEvents({
159 /* Time, Inputs, Outputs */
150 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}}, 160 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
151 {1, {{0, 1, UP}}, {}}, 161 {1, {{0, 1, UP}}, {}},
152 {2, {{0, 2, DOWN}}, {{0, 2, DOWN}}}, 162 {2, {{0, 2, DOWN}}, {{0, 2, DOWN}}},
@@ -167,7 +177,8 @@ TEST_F(DebounceTest, TwoKeysShort) {
167} 177}
168 178
169TEST_F(DebounceTest, OneKeyDelayedScan1) { 179TEST_F(DebounceTest, OneKeyDelayedScan1) {
170 addEvents({ /* Time, Inputs, Outputs */ 180 addEvents({
181 /* Time, Inputs, Outputs */
171 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}}, 182 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
172 183
173 /* Processing is very late but the change will now be accepted */ 184 /* Processing is very late but the change will now be accepted */
@@ -178,7 +189,8 @@ TEST_F(DebounceTest, OneKeyDelayedScan1) {
178} 189}
179 190
180TEST_F(DebounceTest, OneKeyDelayedScan2) { 191TEST_F(DebounceTest, OneKeyDelayedScan2) {
181 addEvents({ /* Time, Inputs, Outputs */ 192 addEvents({
193 /* Time, Inputs, Outputs */
182 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}}, 194 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
183 195
184 /* Processing is very late but the change will now be accepted even with a 1 scan delay */ 196 /* Processing is very late but the change will now be accepted even with a 1 scan delay */
@@ -190,7 +202,8 @@ TEST_F(DebounceTest, OneKeyDelayedScan2) {
190} 202}
191 203
192TEST_F(DebounceTest, OneKeyDelayedScan3) { 204TEST_F(DebounceTest, OneKeyDelayedScan3) {
193 addEvents({ /* Time, Inputs, Outputs */ 205 addEvents({
206 /* Time, Inputs, Outputs */
194 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}}, 207 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
195 208
196 /* Processing is very late but the change will now be accepted even with a 1ms delay */ 209 /* Processing is very late but the change will now be accepted even with a 1ms delay */
@@ -202,7 +215,8 @@ TEST_F(DebounceTest, OneKeyDelayedScan3) {
202} 215}
203 216
204TEST_F(DebounceTest, OneKeyDelayedScan4) { 217TEST_F(DebounceTest, OneKeyDelayedScan4) {
205 addEvents({ /* Time, Inputs, Outputs */ 218 addEvents({
219 /* Time, Inputs, Outputs */
206 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}}, 220 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
207 221
208 /* Processing is a bit late but the change will now be accepted */ 222 /* Processing is a bit late but the change will now be accepted */
@@ -213,7 +227,8 @@ TEST_F(DebounceTest, OneKeyDelayedScan4) {
213} 227}
214 228
215TEST_F(DebounceTest, OneKeyDelayedScan5) { 229TEST_F(DebounceTest, OneKeyDelayedScan5) {
216 addEvents({ /* Time, Inputs, Outputs */ 230 addEvents({
231 /* Time, Inputs, Outputs */
217 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}}, 232 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
218 233
219 /* Processing is very late but the change will now be accepted even with a 1 scan delay */ 234 /* Processing is very late but the change will now be accepted even with a 1 scan delay */
@@ -225,7 +240,8 @@ TEST_F(DebounceTest, OneKeyDelayedScan5) {
225} 240}
226 241
227TEST_F(DebounceTest, OneKeyDelayedScan6) { 242TEST_F(DebounceTest, OneKeyDelayedScan6) {
228 addEvents({ /* Time, Inputs, Outputs */ 243 addEvents({
244 /* Time, Inputs, Outputs */
229 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}}, 245 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
230 246
231 /* Processing is very late but the change will now be accepted even with a 1ms delay */ 247 /* Processing is very late but the change will now be accepted even with a 1ms delay */
diff --git a/quantum/debounce/tests/sym_eager_pr_tests.cpp b/quantum/debounce/tests/sym_eager_pr_tests.cpp
index 2c4bca127..e91dd9cb8 100644
--- a/quantum/debounce/tests/sym_eager_pr_tests.cpp
+++ b/quantum/debounce/tests/sym_eager_pr_tests.cpp
@@ -19,7 +19,8 @@
19#include "debounce_test_common.h" 19#include "debounce_test_common.h"
20 20
21TEST_F(DebounceTest, OneKeyShort1) { 21TEST_F(DebounceTest, OneKeyShort1) {
22 addEvents({ /* Time, Inputs, Outputs */ 22 addEvents({
23 /* Time, Inputs, Outputs */
23 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}}, 24 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
24 {1, {{0, 1, UP}}, {}}, 25 {1, {{0, 1, UP}}, {}},
25 26
@@ -32,7 +33,8 @@ TEST_F(DebounceTest, OneKeyShort1) {
32} 33}
33 34
34TEST_F(DebounceTest, OneKeyShort2) { 35TEST_F(DebounceTest, OneKeyShort2) {
35 addEvents({ /* Time, Inputs, Outputs */ 36 addEvents({
37 /* Time, Inputs, Outputs */
36 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}}, 38 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
37 {1, {{0, 1, UP}}, {}}, 39 {1, {{0, 1, UP}}, {}},
38 40
@@ -45,7 +47,8 @@ TEST_F(DebounceTest, OneKeyShort2) {
45} 47}
46 48
47TEST_F(DebounceTest, OneKeyShort3) { 49TEST_F(DebounceTest, OneKeyShort3) {
48 addEvents({ /* Time, Inputs, Outputs */ 50 addEvents({
51 /* Time, Inputs, Outputs */
49 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}}, 52 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
50 {1, {{0, 1, UP}}, {}}, 53 {1, {{0, 1, UP}}, {}},
51 54
@@ -58,7 +61,8 @@ TEST_F(DebounceTest, OneKeyShort3) {
58} 61}
59 62
60TEST_F(DebounceTest, OneKeyShort4) { 63TEST_F(DebounceTest, OneKeyShort4) {
61 addEvents({ /* Time, Inputs, Outputs */ 64 addEvents({
65 /* Time, Inputs, Outputs */
62 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}}, 66 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
63 {1, {{0, 1, UP}}, {}}, 67 {1, {{0, 1, UP}}, {}},
64 68
@@ -71,7 +75,8 @@ TEST_F(DebounceTest, OneKeyShort4) {
71} 75}
72 76
73TEST_F(DebounceTest, OneKeyShort5) { 77TEST_F(DebounceTest, OneKeyShort5) {
74 addEvents({ /* Time, Inputs, Outputs */ 78 addEvents({
79 /* Time, Inputs, Outputs */
75 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}}, 80 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
76 {1, {{0, 1, UP}}, {}}, 81 {1, {{0, 1, UP}}, {}},
77 82
@@ -83,7 +88,8 @@ TEST_F(DebounceTest, OneKeyShort5) {
83} 88}
84 89
85TEST_F(DebounceTest, OneKeyShort6) { 90TEST_F(DebounceTest, OneKeyShort6) {
86 addEvents({ /* Time, Inputs, Outputs */ 91 addEvents({
92 /* Time, Inputs, Outputs */
87 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}}, 93 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
88 {1, {{0, 1, UP}}, {}}, 94 {1, {{0, 1, UP}}, {}},
89 95
@@ -95,7 +101,8 @@ TEST_F(DebounceTest, OneKeyShort6) {
95} 101}
96 102
97TEST_F(DebounceTest, OneKeyBouncing1) { 103TEST_F(DebounceTest, OneKeyBouncing1) {
98 addEvents({ /* Time, Inputs, Outputs */ 104 addEvents({
105 /* Time, Inputs, Outputs */
99 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}}, 106 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
100 {1, {{0, 1, UP}}, {}}, 107 {1, {{0, 1, UP}}, {}},
101 {2, {{0, 1, DOWN}}, {}}, 108 {2, {{0, 1, DOWN}}, {}},
@@ -110,7 +117,8 @@ TEST_F(DebounceTest, OneKeyBouncing1) {
110} 117}
111 118
112TEST_F(DebounceTest, OneKeyBouncing2) { 119TEST_F(DebounceTest, OneKeyBouncing2) {
113 addEvents({ /* Time, Inputs, Outputs */ 120 addEvents({
121 /* Time, Inputs, Outputs */
114 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}}, 122 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
115 /* Change twice in the same time period */ 123 /* Change twice in the same time period */
116 {1, {{0, 1, UP}}, {}}, 124 {1, {{0, 1, UP}}, {}},
@@ -135,7 +143,8 @@ TEST_F(DebounceTest, OneKeyBouncing2) {
135} 143}
136 144
137TEST_F(DebounceTest, OneKeyLong) { 145TEST_F(DebounceTest, OneKeyLong) {
138 addEvents({ /* Time, Inputs, Outputs */ 146 addEvents({
147 /* Time, Inputs, Outputs */
139 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}}, 148 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
140 149
141 {25, {{0, 1, UP}}, {{0, 1, UP}}}, 150 {25, {{0, 1, UP}}, {{0, 1, UP}}},
@@ -146,7 +155,8 @@ TEST_F(DebounceTest, OneKeyLong) {
146} 155}
147 156
148TEST_F(DebounceTest, TwoRowsShort) { 157TEST_F(DebounceTest, TwoRowsShort) {
149 addEvents({ /* Time, Inputs, Outputs */ 158 addEvents({
159 /* Time, Inputs, Outputs */
150 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}}, 160 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
151 {1, {{0, 1, UP}}, {}}, 161 {1, {{0, 1, UP}}, {}},
152 {2, {{2, 0, DOWN}}, {{2, 0, DOWN}}}, 162 {2, {{2, 0, DOWN}}, {{2, 0, DOWN}}},
@@ -167,7 +177,8 @@ TEST_F(DebounceTest, TwoRowsShort) {
167} 177}
168 178
169TEST_F(DebounceTest, TwoKeysOverlap) { 179TEST_F(DebounceTest, TwoKeysOverlap) {
170 addEvents({ /* Time, Inputs, Outputs */ 180 addEvents({
181 /* Time, Inputs, Outputs */
171 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}}, 182 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
172 {1, {{0, 1, UP}}, {}}, 183 {1, {{0, 1, UP}}, {}},
173 /* Press a second key during the first debounce */ 184 /* Press a second key during the first debounce */
@@ -190,7 +201,8 @@ TEST_F(DebounceTest, TwoKeysOverlap) {
190} 201}
191 202
192TEST_F(DebounceTest, TwoKeysSimultaneous1) { 203TEST_F(DebounceTest, TwoKeysSimultaneous1) {
193 addEvents({ /* Time, Inputs, Outputs */ 204 addEvents({
205 /* Time, Inputs, Outputs */
194 {0, {{0, 1, DOWN}, {0, 2, DOWN}}, {{0, 1, DOWN}, {0, 2, DOWN}}}, 206 {0, {{0, 1, DOWN}, {0, 2, DOWN}}, {{0, 1, DOWN}, {0, 2, DOWN}}},
195 {20, {{0, 1, UP}}, {{0, 1, UP}}}, 207 {20, {{0, 1, UP}}, {{0, 1, UP}}},
196 {21, {{0, 2, UP}}, {}}, 208 {21, {{0, 2, UP}}, {}},
@@ -202,7 +214,8 @@ TEST_F(DebounceTest, TwoKeysSimultaneous1) {
202} 214}
203 215
204TEST_F(DebounceTest, TwoKeysSimultaneous2) { 216TEST_F(DebounceTest, TwoKeysSimultaneous2) {
205 addEvents({ /* Time, Inputs, Outputs */ 217 addEvents({
218 /* Time, Inputs, Outputs */
206 {0, {{0, 1, DOWN}, {0, 2, DOWN}}, {{0, 1, DOWN}, {0, 2, DOWN}}}, 219 {0, {{0, 1, DOWN}, {0, 2, DOWN}}, {{0, 1, DOWN}, {0, 2, DOWN}}},
207 {20, {{0, 1, UP}, {0, 2, UP}}, {{0, 1, UP}, {0, 2, UP}}}, 220 {20, {{0, 1, UP}, {0, 2, UP}}, {{0, 1, UP}, {0, 2, UP}}},
208 }); 221 });
@@ -210,7 +223,8 @@ TEST_F(DebounceTest, TwoKeysSimultaneous2) {
210} 223}
211 224
212TEST_F(DebounceTest, OneKeyDelayedScan1) { 225TEST_F(DebounceTest, OneKeyDelayedScan1) {
213 addEvents({ /* Time, Inputs, Outputs */ 226 addEvents({
227 /* Time, Inputs, Outputs */
214 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}}, 228 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
215 229
216 /* Processing is very late but the change will now be accepted */ 230 /* Processing is very late but the change will now be accepted */
@@ -221,7 +235,8 @@ TEST_F(DebounceTest, OneKeyDelayedScan1) {
221} 235}
222 236
223TEST_F(DebounceTest, OneKeyDelayedScan2) { 237TEST_F(DebounceTest, OneKeyDelayedScan2) {
224 addEvents({ /* Time, Inputs, Outputs */ 238 addEvents({
239 /* Time, Inputs, Outputs */
225 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}}, 240 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
226 241
227 /* Processing is very late but the change will now be accepted even with a 1 scan delay */ 242 /* Processing is very late but the change will now be accepted even with a 1 scan delay */
@@ -233,7 +248,8 @@ TEST_F(DebounceTest, OneKeyDelayedScan2) {
233} 248}
234 249
235TEST_F(DebounceTest, OneKeyDelayedScan3) { 250TEST_F(DebounceTest, OneKeyDelayedScan3) {
236 addEvents({ /* Time, Inputs, Outputs */ 251 addEvents({
252 /* Time, Inputs, Outputs */
237 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}}, 253 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
238 254
239 /* Processing is very late but the change will now be accepted even with a 1ms delay */ 255 /* Processing is very late but the change will now be accepted even with a 1ms delay */
@@ -245,7 +261,8 @@ TEST_F(DebounceTest, OneKeyDelayedScan3) {
245} 261}
246 262
247TEST_F(DebounceTest, OneKeyDelayedScan4) { 263TEST_F(DebounceTest, OneKeyDelayedScan4) {
248 addEvents({ /* Time, Inputs, Outputs */ 264 addEvents({
265 /* Time, Inputs, Outputs */
249 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}}, 266 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
250 267
251 /* Processing is a bit late but the change will now be accepted */ 268 /* Processing is a bit late but the change will now be accepted */
@@ -256,7 +273,8 @@ TEST_F(DebounceTest, OneKeyDelayedScan4) {
256} 273}
257 274
258TEST_F(DebounceTest, OneKeyDelayedScan5) { 275TEST_F(DebounceTest, OneKeyDelayedScan5) {
259 addEvents({ /* Time, Inputs, Outputs */ 276 addEvents({
277 /* Time, Inputs, Outputs */
260 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}}, 278 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
261 279
262 /* Processing is very late but the change will now be accepted even with a 1 scan delay */ 280 /* Processing is very late but the change will now be accepted even with a 1 scan delay */
@@ -268,7 +286,8 @@ TEST_F(DebounceTest, OneKeyDelayedScan5) {
268} 286}
269 287
270TEST_F(DebounceTest, OneKeyDelayedScan6) { 288TEST_F(DebounceTest, OneKeyDelayedScan6) {
271 addEvents({ /* Time, Inputs, Outputs */ 289 addEvents({
290 /* Time, Inputs, Outputs */
272 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}}, 291 {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
273 292
274 /* Processing is very late but the change will now be accepted even with a 1ms delay */ 293 /* Processing is very late but the change will now be accepted even with a 1ms delay */
diff --git a/quantum/eeconfig.c b/quantum/eeconfig.c
index 92f0ac443..4c2ad2490 100644
--- a/quantum/eeconfig.c
+++ b/quantum/eeconfig.c
@@ -4,11 +4,6 @@
4#include "eeconfig.h" 4#include "eeconfig.h"
5#include "action_layer.h" 5#include "action_layer.h"
6 6
7#ifdef STM32_EEPROM_ENABLE
8# include <hal.h>
9# include "eeprom_stm32.h"
10#endif
11
12#if defined(EEPROM_DRIVER) 7#if defined(EEPROM_DRIVER)
13# include "eeprom_driver.h" 8# include "eeprom_driver.h"
14#endif 9#endif
@@ -43,9 +38,6 @@ __attribute__((weak)) void eeconfig_init_kb(void) {
43 * FIXME: needs doc 38 * FIXME: needs doc
44 */ 39 */
45void eeconfig_init_quantum(void) { 40void eeconfig_init_quantum(void) {
46#ifdef STM32_EEPROM_ENABLE
47 EEPROM_Erase();
48#endif
49#if defined(EEPROM_DRIVER) 41#if defined(EEPROM_DRIVER)
50 eeprom_driver_erase(); 42 eeprom_driver_erase();
51#endif 43#endif
@@ -111,9 +103,6 @@ void eeconfig_enable(void) { eeprom_update_word(EECONFIG_MAGIC, EECONFIG_MAGIC_N
111 * FIXME: needs doc 103 * FIXME: needs doc
112 */ 104 */
113void eeconfig_disable(void) { 105void eeconfig_disable(void) {
114#ifdef STM32_EEPROM_ENABLE
115 EEPROM_Erase();
116#endif
117#if defined(EEPROM_DRIVER) 106#if defined(EEPROM_DRIVER)
118 eeprom_driver_erase(); 107 eeprom_driver_erase();
119#endif 108#endif
diff --git a/quantum/eeconfig.h b/quantum/eeconfig.h
index bd39971b2..22d874273 100644
--- a/quantum/eeconfig.h
+++ b/quantum/eeconfig.h
@@ -111,3 +111,29 @@ void eeconfig_update_haptic(uint32_t val);
111 111
112bool eeconfig_read_handedness(void); 112bool eeconfig_read_handedness(void);
113void eeconfig_update_handedness(bool val); 113void eeconfig_update_handedness(bool val);
114
115#define EECONFIG_DEBOUNCE_HELPER(name, offset, config) \
116 static uint8_t dirty_##name = false; \
117 \
118 static inline void eeconfig_init_##name(void) { \
119 eeprom_read_block(&config, offset, sizeof(config)); \
120 dirty_##name = false; \
121 } \
122 static inline void eeconfig_flush_##name(bool force) { \
123 if (force || dirty_##name) { \
124 eeprom_update_block(&config, offset, sizeof(config)); \
125 dirty_##name = false; \
126 } \
127 } \
128 static inline void eeconfig_flush_##name##_task(uint16_t timeout) { \
129 static uint16_t flush_timer = 0; \
130 if (timer_elapsed(flush_timer) > timeout) { \
131 eeconfig_flush_##name(false); \
132 flush_timer = timer_read(); \
133 } \
134 } \
135 static inline void eeconfig_flag_##name(bool v) { dirty_##name |= v; } \
136 static inline void eeconfig_write_##name(typeof(config) conf) { \
137 memcpy(&config, &conf, sizeof(config)); \
138 eeconfig_flag_##name(true); \
139 }
diff --git a/quantum/keyboard.c b/quantum/keyboard.c
index b98fc64e4..3bca05aab 100644
--- a/quantum/keyboard.c
+++ b/quantum/keyboard.c
@@ -40,12 +40,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
40#ifdef PS2_MOUSE_ENABLE 40#ifdef PS2_MOUSE_ENABLE
41# include "ps2_mouse.h" 41# include "ps2_mouse.h"
42#endif 42#endif
43#ifdef SERIAL_MOUSE_ENABLE
44# include "serial_mouse.h"
45#endif
46#ifdef ADB_MOUSE_ENABLE
47# include "adb.h"
48#endif
49#ifdef RGBLIGHT_ENABLE 43#ifdef RGBLIGHT_ENABLE
50# include "rgblight.h" 44# include "rgblight.h"
51#endif 45#endif
@@ -61,12 +55,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
61#ifdef STENO_ENABLE 55#ifdef STENO_ENABLE
62# include "process_steno.h" 56# include "process_steno.h"
63#endif 57#endif
64#ifdef SERIAL_LINK_ENABLE
65# include "serial_link/system/serial_link.h"
66#endif
67#ifdef VISUALIZER_ENABLE
68# include "visualizer/visualizer.h"
69#endif
70#ifdef POINTING_DEVICE_ENABLE 58#ifdef POINTING_DEVICE_ENABLE
71# include "pointing_device.h" 59# include "pointing_device.h"
72#endif 60#endif
@@ -76,12 +64,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
76#ifdef JOYSTICK_ENABLE 64#ifdef JOYSTICK_ENABLE
77# include "process_joystick.h" 65# include "process_joystick.h"
78#endif 66#endif
67#ifdef PROGRAMMABLE_BUTTON_ENABLE
68# include "programmable_button.h"
69#endif
79#ifdef HD44780_ENABLE 70#ifdef HD44780_ENABLE
80# include "hd44780.h" 71# include "hd44780.h"
81#endif 72#endif
82#ifdef QWIIC_ENABLE
83# include "qwiic.h"
84#endif
85#ifdef OLED_ENABLE 73#ifdef OLED_ENABLE
86# include "oled_driver.h" 74# include "oled_driver.h"
87#endif 75#endif
@@ -97,9 +85,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
97#ifdef DIP_SWITCH_ENABLE 85#ifdef DIP_SWITCH_ENABLE
98# include "dip_switch.h" 86# include "dip_switch.h"
99#endif 87#endif
100#ifdef STM32_EEPROM_ENABLE
101# include "eeprom_stm32.h"
102#endif
103#ifdef EEPROM_DRIVER 88#ifdef EEPROM_DRIVER
104# include "eeprom_driver.h" 89# include "eeprom_driver.h"
105#endif 90#endif
@@ -109,6 +94,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
109#ifdef DIGITIZER_ENABLE 94#ifdef DIGITIZER_ENABLE
110# include "digitizer.h" 95# include "digitizer.h"
111#endif 96#endif
97#ifdef VIRTSER_ENABLE
98# include "virtser.h"
99#endif
100#ifdef SLEEP_LED_ENABLE
101# include "sleep_led.h"
102#endif
112 103
113static uint32_t last_input_modification_time = 0; 104static uint32_t last_input_modification_time = 0;
114uint32_t last_input_activity_time(void) { return last_input_modification_time; } 105uint32_t last_input_activity_time(void) { return last_input_modification_time; }
@@ -246,9 +237,6 @@ void keyboard_setup(void) {
246 disable_jtag(); 237 disable_jtag();
247#endif 238#endif
248 print_set_sendchar(sendchar); 239 print_set_sendchar(sendchar);
249#ifdef STM32_EEPROM_ENABLE
250 EEPROM_Init();
251#endif
252#ifdef EEPROM_DRIVER 240#ifdef EEPROM_DRIVER
253 eeprom_driver_init(); 241 eeprom_driver_init();
254#endif 242#endif
@@ -316,9 +304,6 @@ void keyboard_init(void) {
316#if defined(CRC_ENABLE) 304#if defined(CRC_ENABLE)
317 crc_init(); 305 crc_init();
318#endif 306#endif
319#ifdef QWIIC_ENABLE
320 qwiic_init();
321#endif
322#ifdef OLED_ENABLE 307#ifdef OLED_ENABLE
323 oled_init(OLED_ROTATION_0); 308 oled_init(OLED_ROTATION_0);
324#endif 309#endif
@@ -328,12 +313,6 @@ void keyboard_init(void) {
328#ifdef PS2_MOUSE_ENABLE 313#ifdef PS2_MOUSE_ENABLE
329 ps2_mouse_init(); 314 ps2_mouse_init();
330#endif 315#endif
331#ifdef SERIAL_MOUSE_ENABLE
332 serial_mouse_init();
333#endif
334#ifdef ADB_MOUSE_ENABLE
335 adb_mouse_init();
336#endif
337#ifdef BACKLIGHT_ENABLE 316#ifdef BACKLIGHT_ENABLE
338 backlight_init(); 317 backlight_init();
339#endif 318#endif
@@ -356,6 +335,12 @@ void keyboard_init(void) {
356#ifdef DIP_SWITCH_ENABLE 335#ifdef DIP_SWITCH_ENABLE
357 dip_switch_init(); 336 dip_switch_init();
358#endif 337#endif
338#ifdef SLEEP_LED_ENABLE
339 sleep_led_init();
340#endif
341#ifdef VIRTSER_ENABLE
342 virtser_init();
343#endif
359 344
360#if defined(DEBUG_MATRIX_SCAN_RATE) && defined(CONSOLE_ENABLE) 345#if defined(DEBUG_MATRIX_SCAN_RATE) && defined(CONSOLE_ENABLE)
361 debug_enable = true; 346 debug_enable = true;
@@ -384,7 +369,6 @@ void switch_events(uint8_t row, uint8_t col, bool pressed) {
384 * 369 *
385 * * scan matrix 370 * * scan matrix
386 * * handle mouse movements 371 * * handle mouse movements
387 * * run visualizer code
388 * * handle midi commands 372 * * handle midi commands
389 * * light LEDs 373 * * light LEDs
390 * 374 *
@@ -473,10 +457,6 @@ MATRIX_LOOP_END:
473 if (encoders_changed) last_encoder_activity_trigger(); 457 if (encoders_changed) last_encoder_activity_trigger();
474#endif 458#endif
475 459
476#ifdef QWIIC_ENABLE
477 qwiic_task();
478#endif
479
480#ifdef OLED_ENABLE 460#ifdef OLED_ENABLE
481 oled_task(); 461 oled_task();
482# if OLED_TIMEOUT > 0 462# if OLED_TIMEOUT > 0
@@ -510,22 +490,6 @@ MATRIX_LOOP_END:
510 ps2_mouse_task(); 490 ps2_mouse_task();
511#endif 491#endif
512 492
513#ifdef SERIAL_MOUSE_ENABLE
514 serial_mouse_task();
515#endif
516
517#ifdef ADB_MOUSE_ENABLE
518 adb_mouse_task();
519#endif
520
521#ifdef SERIAL_LINK_ENABLE
522 serial_link_update();
523#endif
524
525#ifdef VISUALIZER_ENABLE
526 visualizer_update(default_layer_state, layer_state, visualizer_get_mods(), host_keyboard_leds());
527#endif
528
529#ifdef POINTING_DEVICE_ENABLE 493#ifdef POINTING_DEVICE_ENABLE
530 pointing_device_task(); 494 pointing_device_task();
531#endif 495#endif
@@ -548,6 +512,10 @@ MATRIX_LOOP_END:
548 digitizer_task(); 512 digitizer_task();
549#endif 513#endif
550 514
515#ifdef PROGRAMMABLE_BUTTON_ENABLE
516 programmable_button_send();
517#endif
518
551 // update LED 519 // update LED
552 if (led_status != host_keyboard_leds()) { 520 if (led_status != host_keyboard_leds()) {
553 led_status = host_keyboard_leds(); 521 led_status = host_keyboard_leds();
diff --git a/quantum/keymap_extras/keymap_steno.h b/quantum/keymap_extras/keymap_steno.h
index ab95b43fd..310aa0740 100644
--- a/quantum/keymap_extras/keymap_steno.h
+++ b/quantum/keymap_extras/keymap_steno.h
@@ -74,8 +74,7 @@ enum steno_keycodes {
74}; 74};
75 75
76#ifdef STENO_COMBINEDMAP 76#ifdef STENO_COMBINEDMAP
77enum steno_combined_keycodes 77enum steno_combined_keycodes {
78{
79 STN_S3 = QK_STENO_COMB, 78 STN_S3 = QK_STENO_COMB,
80 STN_TKL, 79 STN_TKL,
81 STN_PWL, 80 STN_PWL,
diff --git a/quantum/keymap_extras/keymap_turkish_f.h b/quantum/keymap_extras/keymap_turkish_f.h
index 226f8cbeb..f86ef2154 100644
--- a/quantum/keymap_extras/keymap_turkish_f.h
+++ b/quantum/keymap_extras/keymap_turkish_f.h
@@ -111,7 +111,7 @@
111#define TR_LPRN S(TR_8) // ( 111#define TR_LPRN S(TR_8) // (
112#define TR_RPRN S(TR_9) // ) 112#define TR_RPRN S(TR_9) // )
113#define TR_EQL S(TR_0) // = 113#define TR_EQL S(TR_0) // =
114#define TR_QUES S(TR_ASTR) // ? 114#define TR_QUES S(TR_SLSH) // ?
115#define TR_UNDS S(TR_MINS) // _ 115#define TR_UNDS S(TR_MINS) // _
116// Row 4 116// Row 4
117#define TR_RABK S(TR_LABK) // > 117#define TR_RABK S(TR_LABK) // >
diff --git a/quantum/led_matrix/animations/alpha_mods_anim.h b/quantum/led_matrix/animations/alpha_mods_anim.h
index 14038cd08..c82b2aa38 100644
--- a/quantum/led_matrix/animations/alpha_mods_anim.h
+++ b/quantum/led_matrix/animations/alpha_mods_anim.h
@@ -17,7 +17,7 @@ bool ALPHAS_MODS(effect_params_t* params) {
17 led_matrix_set_value(i, val1); 17 led_matrix_set_value(i, val1);
18 } 18 }
19 } 19 }
20 return led_max < DRIVER_LED_TOTAL; 20 return led_matrix_check_finished_leds(led_max);
21} 21}
22 22
23# endif // LED_MATRIX_CUSTOM_EFFECT_IMPLS 23# endif // LED_MATRIX_CUSTOM_EFFECT_IMPLS
diff --git a/quantum/led_matrix/animations/breathing_anim.h b/quantum/led_matrix/animations/breathing_anim.h
index e3f600c45..d9cc2de23 100644
--- a/quantum/led_matrix/animations/breathing_anim.h
+++ b/quantum/led_matrix/animations/breathing_anim.h
@@ -12,7 +12,7 @@ bool BREATHING(effect_params_t* params) {
12 LED_MATRIX_TEST_LED_FLAGS(); 12 LED_MATRIX_TEST_LED_FLAGS();
13 led_matrix_set_value(i, val); 13 led_matrix_set_value(i, val);
14 } 14 }
15 return led_max < DRIVER_LED_TOTAL; 15 return led_matrix_check_finished_leds(led_max);
16} 16}
17 17
18# endif // LED_MATRIX_CUSTOM_EFFECT_IMPLS 18# endif // LED_MATRIX_CUSTOM_EFFECT_IMPLS
diff --git a/quantum/led_matrix/animations/runners/effect_runner_dx_dy.h b/quantum/led_matrix/animations/runners/effect_runner_dx_dy.h
index ef97631b9..fa9b7dbbf 100644
--- a/quantum/led_matrix/animations/runners/effect_runner_dx_dy.h
+++ b/quantum/led_matrix/animations/runners/effect_runner_dx_dy.h
@@ -12,5 +12,5 @@ bool effect_runner_dx_dy(effect_params_t* params, dx_dy_f effect_func) {
12 int16_t dy = g_led_config.point[i].y - k_led_matrix_center.y; 12 int16_t dy = g_led_config.point[i].y - k_led_matrix_center.y;
13 led_matrix_set_value(i, effect_func(led_matrix_eeconfig.val, dx, dy, time)); 13 led_matrix_set_value(i, effect_func(led_matrix_eeconfig.val, dx, dy, time));
14 } 14 }
15 return led_max < DRIVER_LED_TOTAL; 15 return led_matrix_check_finished_leds(led_max);
16} 16}
diff --git a/quantum/led_matrix/animations/runners/effect_runner_dx_dy_dist.h b/quantum/led_matrix/animations/runners/effect_runner_dx_dy_dist.h
index 5ef5938be..061a5f07f 100644
--- a/quantum/led_matrix/animations/runners/effect_runner_dx_dy_dist.h
+++ b/quantum/led_matrix/animations/runners/effect_runner_dx_dy_dist.h
@@ -13,5 +13,5 @@ bool effect_runner_dx_dy_dist(effect_params_t* params, dx_dy_dist_f effect_func)
13 uint8_t dist = sqrt16(dx * dx + dy * dy); 13 uint8_t dist = sqrt16(dx * dx + dy * dy);
14 led_matrix_set_value(i, effect_func(led_matrix_eeconfig.val, dx, dy, dist, time)); 14 led_matrix_set_value(i, effect_func(led_matrix_eeconfig.val, dx, dy, dist, time));
15 } 15 }
16 return led_max < DRIVER_LED_TOTAL; 16 return led_matrix_check_finished_leds(led_max);
17} 17}
diff --git a/quantum/led_matrix/animations/runners/effect_runner_i.h b/quantum/led_matrix/animations/runners/effect_runner_i.h
index b3015759b..f6f8c0dee 100644
--- a/quantum/led_matrix/animations/runners/effect_runner_i.h
+++ b/quantum/led_matrix/animations/runners/effect_runner_i.h
@@ -10,5 +10,5 @@ bool effect_runner_i(effect_params_t* params, i_f effect_func) {
10 LED_MATRIX_TEST_LED_FLAGS(); 10 LED_MATRIX_TEST_LED_FLAGS();
11 led_matrix_set_value(i, effect_func(led_matrix_eeconfig.val, i, time)); 11 led_matrix_set_value(i, effect_func(led_matrix_eeconfig.val, i, time));
12 } 12 }
13 return led_max < DRIVER_LED_TOTAL; 13 return led_matrix_check_finished_leds(led_max);
14} 14}
diff --git a/quantum/led_matrix/animations/runners/effect_runner_reactive.h b/quantum/led_matrix/animations/runners/effect_runner_reactive.h
index 4369ea8c4..be3090aa5 100644
--- a/quantum/led_matrix/animations/runners/effect_runner_reactive.h
+++ b/quantum/led_matrix/animations/runners/effect_runner_reactive.h
@@ -22,7 +22,7 @@ bool effect_runner_reactive(effect_params_t* params, reactive_f effect_func) {
22 uint16_t offset = scale16by8(tick, led_matrix_eeconfig.speed); 22 uint16_t offset = scale16by8(tick, led_matrix_eeconfig.speed);
23 led_matrix_set_value(i, effect_func(led_matrix_eeconfig.val, offset)); 23 led_matrix_set_value(i, effect_func(led_matrix_eeconfig.val, offset));
24 } 24 }
25 return led_max < DRIVER_LED_TOTAL; 25 return led_matrix_check_finished_leds(led_max);
26} 26}
27 27
28#endif // LED_MATRIX_KEYREACTIVE_ENABLED 28#endif // LED_MATRIX_KEYREACTIVE_ENABLED
diff --git a/quantum/led_matrix/animations/runners/effect_runner_reactive_splash.h b/quantum/led_matrix/animations/runners/effect_runner_reactive_splash.h
index d6eb9731e..f6ffc825a 100644
--- a/quantum/led_matrix/animations/runners/effect_runner_reactive_splash.h
+++ b/quantum/led_matrix/animations/runners/effect_runner_reactive_splash.h
@@ -20,7 +20,7 @@ bool effect_runner_reactive_splash(uint8_t start, effect_params_t* params, react
20 } 20 }
21 led_matrix_set_value(i, scale8(val, led_matrix_eeconfig.val)); 21 led_matrix_set_value(i, scale8(val, led_matrix_eeconfig.val));
22 } 22 }
23 return led_max < DRIVER_LED_TOTAL; 23 return led_matrix_check_finished_leds(led_max);
24} 24}
25 25
26#endif // LED_MATRIX_KEYREACTIVE_ENABLED 26#endif // LED_MATRIX_KEYREACTIVE_ENABLED
diff --git a/quantum/led_matrix/animations/runners/effect_runner_sin_cos_i.h b/quantum/led_matrix/animations/runners/effect_runner_sin_cos_i.h
index 4a5219abd..3145e2713 100644
--- a/quantum/led_matrix/animations/runners/effect_runner_sin_cos_i.h
+++ b/quantum/led_matrix/animations/runners/effect_runner_sin_cos_i.h
@@ -12,5 +12,5 @@ bool effect_runner_sin_cos_i(effect_params_t* params, sin_cos_i_f effect_func) {
12 LED_MATRIX_TEST_LED_FLAGS(); 12 LED_MATRIX_TEST_LED_FLAGS();
13 led_matrix_set_value(i, effect_func(led_matrix_eeconfig.val, cos_value, sin_value, i, time)); 13 led_matrix_set_value(i, effect_func(led_matrix_eeconfig.val, cos_value, sin_value, i, time));
14 } 14 }
15 return led_max < DRIVER_LED_TOTAL; 15 return led_matrix_check_finished_leds(led_max);
16} 16}
diff --git a/quantum/led_matrix/animations/solid_anim.h b/quantum/led_matrix/animations/solid_anim.h
index 4c9e43c58..c728dbcc9 100644
--- a/quantum/led_matrix/animations/solid_anim.h
+++ b/quantum/led_matrix/animations/solid_anim.h
@@ -9,7 +9,7 @@ bool SOLID(effect_params_t* params) {
9 LED_MATRIX_TEST_LED_FLAGS(); 9 LED_MATRIX_TEST_LED_FLAGS();
10 led_matrix_set_value(i, val); 10 led_matrix_set_value(i, val);
11 } 11 }
12 return led_max < DRIVER_LED_TOTAL; 12 return led_matrix_check_finished_leds(led_max);
13} 13}
14 14
15#endif // LED_MATRIX_CUSTOM_EFFECT_IMPLS 15#endif // LED_MATRIX_CUSTOM_EFFECT_IMPLS
diff --git a/quantum/led_matrix/led_matrix.c b/quantum/led_matrix/led_matrix.c
index 50510e49a..8d6a56f27 100644
--- a/quantum/led_matrix/led_matrix.c
+++ b/quantum/led_matrix/led_matrix.c
@@ -33,14 +33,6 @@ const led_point_t k_led_matrix_center = {112, 32};
33const led_point_t k_led_matrix_center = LED_MATRIX_CENTER; 33const led_point_t k_led_matrix_center = LED_MATRIX_CENTER;
34#endif 34#endif
35 35
36// clang-format off
37#ifndef LED_MATRIX_IMMEDIATE_EEPROM
38# define led_eeconfig_update(v) led_update_eeprom |= v
39#else
40# define led_eeconfig_update(v) if (v) eeconfig_update_led_matrix()
41#endif
42// clang-format on
43
44// Generic effect runners 36// Generic effect runners
45#include "led_matrix_runners.inc" 37#include "led_matrix_runners.inc"
46 38
@@ -107,7 +99,6 @@ last_hit_t g_last_hit_tracker;
107 99
108// internals 100// internals
109static bool suspend_state = false; 101static bool suspend_state = false;
110static bool led_update_eeprom = false;
111static uint8_t led_last_enable = UINT8_MAX; 102static uint8_t led_last_enable = UINT8_MAX;
112static uint8_t led_last_effect = UINT8_MAX; 103static uint8_t led_last_effect = UINT8_MAX;
113static effect_params_t led_effect_params = {0, LED_FLAG_ALL, false}; 104static effect_params_t led_effect_params = {0, LED_FLAG_ALL, false};
@@ -127,9 +118,9 @@ static last_hit_t last_hit_buffer;
127const uint8_t k_led_matrix_split[2] = LED_MATRIX_SPLIT; 118const uint8_t k_led_matrix_split[2] = LED_MATRIX_SPLIT;
128#endif 119#endif
129 120
130void eeconfig_read_led_matrix(void) { eeprom_read_block(&led_matrix_eeconfig, EECONFIG_LED_MATRIX, sizeof(led_matrix_eeconfig)); } 121EECONFIG_DEBOUNCE_HELPER(led_matrix, EECONFIG_LED_MATRIX, led_matrix_eeconfig);
131 122
132void eeconfig_update_led_matrix(void) { eeprom_update_block(&led_matrix_eeconfig, EECONFIG_LED_MATRIX, sizeof(led_matrix_eeconfig)); } 123void eeconfig_update_led_matrix(void) { eeconfig_flush_led_matrix(true); }
133 124
134void eeconfig_update_led_matrix_default(void) { 125void eeconfig_update_led_matrix_default(void) {
135 dprintf("eeconfig_update_led_matrix_default\n"); 126 dprintf("eeconfig_update_led_matrix_default\n");
@@ -138,7 +129,7 @@ void eeconfig_update_led_matrix_default(void) {
138 led_matrix_eeconfig.val = LED_MATRIX_STARTUP_VAL; 129 led_matrix_eeconfig.val = LED_MATRIX_STARTUP_VAL;
139 led_matrix_eeconfig.speed = LED_MATRIX_STARTUP_SPD; 130 led_matrix_eeconfig.speed = LED_MATRIX_STARTUP_SPD;
140 led_matrix_eeconfig.flags = LED_FLAG_ALL; 131 led_matrix_eeconfig.flags = LED_FLAG_ALL;
141 eeconfig_update_led_matrix(); 132 eeconfig_flush_led_matrix(true);
142} 133}
143 134
144void eeconfig_debug_led_matrix(void) { 135void eeconfig_debug_led_matrix(void) {
@@ -165,20 +156,10 @@ uint8_t led_matrix_map_row_column_to_led(uint8_t row, uint8_t column, uint8_t *l
165void led_matrix_update_pwm_buffers(void) { led_matrix_driver.flush(); } 156void led_matrix_update_pwm_buffers(void) { led_matrix_driver.flush(); }
166 157
167void led_matrix_set_value(int index, uint8_t value) { 158void led_matrix_set_value(int index, uint8_t value) {
168#if defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)
169 if (!is_keyboard_left() && index >= k_led_matrix_split[0])
170# ifdef USE_CIE1931_CURVE
171 led_matrix_driver.set_value(index - k_led_matrix_split[0], pgm_read_byte(&CIE1931_CURVE[value]));
172# else
173 led_matrix_driver.set_value(index - k_led_matrix_split[0], value);
174# endif
175 else if (is_keyboard_left() && index < k_led_matrix_split[0])
176#endif
177#ifdef USE_CIE1931_CURVE 159#ifdef USE_CIE1931_CURVE
178 led_matrix_driver.set_value(index, pgm_read_byte(&CIE1931_CURVE[value])); 160 value = pgm_read_byte(&CIE1931_CURVE[value]);
179#else
180 led_matrix_driver.set_value(index, value);
181#endif 161#endif
162 led_matrix_driver.set_value(index, value);
182} 163}
183 164
184void led_matrix_set_value_all(uint8_t value) { 165void led_matrix_set_value_all(uint8_t value) {
@@ -279,9 +260,8 @@ static void led_task_timers(void) {
279} 260}
280 261
281static void led_task_sync(void) { 262static void led_task_sync(void) {
263 eeconfig_flush_led_matrix(false);
282 // next task 264 // next task
283 if (led_update_eeprom) eeconfig_update_led_matrix();
284 led_update_eeprom = false;
285 if (sync_timer_elapsed32(g_led_timer) >= LED_MATRIX_LED_FLUSH_LIMIT) led_task_state = STARTING; 265 if (sync_timer_elapsed32(g_led_timer) >= LED_MATRIX_LED_FLUSH_LIMIT) led_task_state = STARTING;
286} 266}
287 267
@@ -449,7 +429,7 @@ void led_matrix_init(void) {
449 eeconfig_update_led_matrix_default(); 429 eeconfig_update_led_matrix_default();
450 } 430 }
451 431
452 eeconfig_read_led_matrix(); 432 eeconfig_init_led_matrix();
453 if (!led_matrix_eeconfig.mode) { 433 if (!led_matrix_eeconfig.mode) {
454 dprintf("led_matrix_init_drivers led_matrix_eeconfig.mode = 0. Write default values to EEPROM.\n"); 434 dprintf("led_matrix_init_drivers led_matrix_eeconfig.mode = 0. Write default values to EEPROM.\n");
455 eeconfig_update_led_matrix_default(); 435 eeconfig_update_led_matrix_default();
@@ -472,7 +452,7 @@ bool led_matrix_get_suspend_state(void) { return suspend_state; }
472void led_matrix_toggle_eeprom_helper(bool write_to_eeprom) { 452void led_matrix_toggle_eeprom_helper(bool write_to_eeprom) {
473 led_matrix_eeconfig.enable ^= 1; 453 led_matrix_eeconfig.enable ^= 1;
474 led_task_state = STARTING; 454 led_task_state = STARTING;
475 led_eeconfig_update(write_to_eeprom); 455 eeconfig_flag_led_matrix(write_to_eeprom);
476 dprintf("led matrix toggle [%s]: led_matrix_eeconfig.enable = %u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", led_matrix_eeconfig.enable); 456 dprintf("led matrix toggle [%s]: led_matrix_eeconfig.enable = %u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", led_matrix_eeconfig.enable);
477} 457}
478void led_matrix_toggle_noeeprom(void) { led_matrix_toggle_eeprom_helper(false); } 458void led_matrix_toggle_noeeprom(void) { led_matrix_toggle_eeprom_helper(false); }
@@ -480,7 +460,7 @@ void led_matrix_toggle(void) { led_matrix_toggle_eeprom_helper(true); }
480 460
481void led_matrix_enable(void) { 461void led_matrix_enable(void) {
482 led_matrix_enable_noeeprom(); 462 led_matrix_enable_noeeprom();
483 led_eeconfig_update(true); 463 eeconfig_flag_led_matrix(true);
484} 464}
485 465
486void led_matrix_enable_noeeprom(void) { 466void led_matrix_enable_noeeprom(void) {
@@ -490,7 +470,7 @@ void led_matrix_enable_noeeprom(void) {
490 470
491void led_matrix_disable(void) { 471void led_matrix_disable(void) {
492 led_matrix_disable_noeeprom(); 472 led_matrix_disable_noeeprom();
493 led_eeconfig_update(true); 473 eeconfig_flag_led_matrix(true);
494} 474}
495 475
496void led_matrix_disable_noeeprom(void) { 476void led_matrix_disable_noeeprom(void) {
@@ -512,7 +492,7 @@ void led_matrix_mode_eeprom_helper(uint8_t mode, bool write_to_eeprom) {
512 led_matrix_eeconfig.mode = mode; 492 led_matrix_eeconfig.mode = mode;
513 } 493 }
514 led_task_state = STARTING; 494 led_task_state = STARTING;
515 led_eeconfig_update(write_to_eeprom); 495 eeconfig_flag_led_matrix(write_to_eeprom);
516 dprintf("led matrix mode [%s]: %u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", led_matrix_eeconfig.mode); 496 dprintf("led matrix mode [%s]: %u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", led_matrix_eeconfig.mode);
517} 497}
518void led_matrix_mode_noeeprom(uint8_t mode) { led_matrix_mode_eeprom_helper(mode, false); } 498void led_matrix_mode_noeeprom(uint8_t mode) { led_matrix_mode_eeprom_helper(mode, false); }
@@ -539,7 +519,7 @@ void led_matrix_set_val_eeprom_helper(uint8_t val, bool write_to_eeprom) {
539 return; 519 return;
540 } 520 }
541 led_matrix_eeconfig.val = (val > LED_MATRIX_MAXIMUM_BRIGHTNESS) ? LED_MATRIX_MAXIMUM_BRIGHTNESS : val; 521 led_matrix_eeconfig.val = (val > LED_MATRIX_MAXIMUM_BRIGHTNESS) ? LED_MATRIX_MAXIMUM_BRIGHTNESS : val;
542 led_eeconfig_update(write_to_eeprom); 522 eeconfig_flag_led_matrix(write_to_eeprom);
543 dprintf("led matrix set val [%s]: %u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", led_matrix_eeconfig.val); 523 dprintf("led matrix set val [%s]: %u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", led_matrix_eeconfig.val);
544} 524}
545void led_matrix_set_val_noeeprom(uint8_t val) { led_matrix_set_val_eeprom_helper(val, false); } 525void led_matrix_set_val_noeeprom(uint8_t val) { led_matrix_set_val_eeprom_helper(val, false); }
@@ -557,7 +537,7 @@ void led_matrix_decrease_val(void) { led_matrix_decrease_val_helper(true); }
557 537
558void led_matrix_set_speed_eeprom_helper(uint8_t speed, bool write_to_eeprom) { 538void led_matrix_set_speed_eeprom_helper(uint8_t speed, bool write_to_eeprom) {
559 led_matrix_eeconfig.speed = speed; 539 led_matrix_eeconfig.speed = speed;
560 led_eeconfig_update(write_to_eeprom); 540 eeconfig_flag_led_matrix(write_to_eeprom);
561 dprintf("led matrix set speed [%s]: %u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", led_matrix_eeconfig.speed); 541 dprintf("led matrix set speed [%s]: %u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", led_matrix_eeconfig.speed);
562} 542}
563void led_matrix_set_speed_noeeprom(uint8_t speed) { led_matrix_set_speed_eeprom_helper(speed, false); } 543void led_matrix_set_speed_noeeprom(uint8_t speed) { led_matrix_set_speed_eeprom_helper(speed, false); }
diff --git a/quantum/led_matrix/led_matrix.h b/quantum/led_matrix/led_matrix.h
index a7a1c983f..f540be44c 100644
--- a/quantum/led_matrix/led_matrix.h
+++ b/quantum/led_matrix/led_matrix.h
@@ -38,14 +38,33 @@
38#endif 38#endif
39 39
40#if defined(LED_MATRIX_LED_PROCESS_LIMIT) && LED_MATRIX_LED_PROCESS_LIMIT > 0 && LED_MATRIX_LED_PROCESS_LIMIT < DRIVER_LED_TOTAL 40#if defined(LED_MATRIX_LED_PROCESS_LIMIT) && LED_MATRIX_LED_PROCESS_LIMIT > 0 && LED_MATRIX_LED_PROCESS_LIMIT < DRIVER_LED_TOTAL
41# define LED_MATRIX_USE_LIMITS(min, max) \ 41# if defined(LED_MATRIX_SPLIT)
42 uint8_t min = LED_MATRIX_LED_PROCESS_LIMIT * params->iter; \ 42# define LED_MATRIX_USE_LIMITS(min, max)
43 uint8_t max = min + LED_MATRIX_LED_PROCESS_LIMIT; \ 43uint8_t min = LED_MATRIX_LED_PROCESS_LIMIT * params->iter;
44 if (max > DRIVER_LED_TOTAL) max = DRIVER_LED_TOTAL; 44uint8_t max = min + LED_MATRIX_LED_PROCESS_LIMIT;
45if (max > DRIVER_LED_TOTAL) max = DRIVER_LED_TOTAL;
46uint8_t k_led_matrix_split[2] = LED_MATRIX_SPLIT;
47if (is_keyboard_left() && (max > k_led_matrix_split[0])) max = k_led_matrix_split[0];
48if (!(is_keyboard_left()) && (min < k_led_matrix_split[0])) min = k_led_matrix_split[0];
49# else
50# define LED_MATRIX_USE_LIMITS(min, max) \
51 uint8_t min = LED_MATRIX_LED_PROCESS_LIMIT * params->iter; \
52 uint8_t max = min + LED_MATRIX_LED_PROCESS_LIMIT; \
53 if (max > DRIVER_LED_TOTAL) max = DRIVER_LED_TOTAL;
54# endif
45#else 55#else
46# define LED_MATRIX_USE_LIMITS(min, max) \ 56# if defined(LED_MATRIX_SPLIT)
47 uint8_t min = 0; \ 57# define LED_MATRIX_USE_LIMITS(min, max) \
48 uint8_t max = DRIVER_LED_TOTAL; 58 uint8_t min = 0; \
59 uint8_t max = DRIVER_LED_TOTAL; \
60 const uint8_t k_led_matrix_split[2] = LED_MATRIX_SPLIT; \
61 if (is_keyboard_left() && (max > k_led_matrix_split[0])) max = k_led_matrix_split[0]; \
62 if (!(is_keyboard_left()) && (min < k_led_matrix_split[0])) min = k_led_matrix_split[0];
63# else
64# define LED_MATRIX_USE_LIMITS(min, max) \
65 uint8_t min = 0; \
66 uint8_t max = DRIVER_LED_TOTAL;
67# endif
49#endif 68#endif
50 69
51#define LED_MATRIX_TEST_LED_FLAGS() \ 70#define LED_MATRIX_TEST_LED_FLAGS() \
@@ -147,6 +166,18 @@ typedef struct {
147 void (*flush)(void); 166 void (*flush)(void);
148} led_matrix_driver_t; 167} led_matrix_driver_t;
149 168
169static inline bool led_matrix_check_finished_leds(uint8_t led_idx) {
170#if defined(LED_MATRIX_SPLIT)
171 if (is_keyboard_left()) {
172 uint8_t k_led_matrix_split[2] = LED_MATRIX_SPLIT;
173 return led_idx < k_led_matrix_split[0];
174 } else
175 return led_idx < DRIVER_LED_TOTAL;
176#else
177 return led_idx < DRIVER_LED_TOTAL;
178#endif
179}
180
150extern const led_matrix_driver_t led_matrix_driver; 181extern const led_matrix_driver_t led_matrix_driver;
151 182
152extern led_eeconfig_t led_matrix_eeconfig; 183extern led_eeconfig_t led_matrix_eeconfig;
diff --git a/quantum/led_matrix/led_matrix_drivers.c b/quantum/led_matrix/led_matrix_drivers.c
index 1d46b2c50..2157619a0 100644
--- a/quantum/led_matrix/led_matrix_drivers.c
+++ b/quantum/led_matrix/led_matrix_drivers.c
@@ -26,128 +26,123 @@
26 */ 26 */
27 27
28#if defined(IS31FL3731) || defined(IS31FL3733) 28#if defined(IS31FL3731) || defined(IS31FL3733)
29
30# include "i2c_master.h" 29# include "i2c_master.h"
31 30
32static void init(void) { 31static void init(void) {
33 i2c_init(); 32 i2c_init();
34# ifdef IS31FL3731 33
35# ifdef LED_DRIVER_ADDR_1 34# if defined(IS31FL3731)
36 IS31FL3731_init(LED_DRIVER_ADDR_1); 35 IS31FL3731_init(LED_DRIVER_ADDR_1);
37# endif 36# if defined(LED_DRIVER_ADDR_2)
38# ifdef LED_DRIVER_ADDR_2
39 IS31FL3731_init(LED_DRIVER_ADDR_2); 37 IS31FL3731_init(LED_DRIVER_ADDR_2);
40# endif 38# if defined(LED_DRIVER_ADDR_3)
41# ifdef LED_DRIVER_ADDR_3
42 IS31FL3731_init(LED_DRIVER_ADDR_3); 39 IS31FL3731_init(LED_DRIVER_ADDR_3);
43# endif 40# if defined(LED_DRIVER_ADDR_4)
44# ifdef LED_DRIVER_ADDR_4
45 IS31FL3731_init(LED_DRIVER_ADDR_4); 41 IS31FL3731_init(LED_DRIVER_ADDR_4);
46# endif 42# endif
47# else
48# ifdef LED_DRIVER_ADDR_1
49# ifndef LED_DRIVER_SYNC_1
50# define LED_DRIVER_SYNC_1 0
51# endif 43# endif
52 IS31FL3733_init(LED_DRIVER_ADDR_1, LED_DRIVER_SYNC_1);
53# endif 44# endif
54# ifdef LED_DRIVER_ADDR_2 45
55# ifndef LED_DRIVER_SYNC_2 46# elif defined(IS31FL3733)
47# if !defined(LED_DRIVER_SYNC_1)
48# define LED_DRIVER_SYNC_1 0
49# endif
50 IS31FL3733_init(LED_DRIVER_ADDR_1, LED_DRIVER_SYNC_1);
51# if defined(LED_DRIVER_ADDR_2)
52# if !defined(LED_DRIVER_SYNC_2)
56# define LED_DRIVER_SYNC_2 0 53# define LED_DRIVER_SYNC_2 0
57# endif 54# endif
58 IS31FL3733_init(LED_DRIVER_ADDR_2, LED_DRIVER_SYNC_2); 55 IS31FL3733_init(LED_DRIVER_ADDR_2, LED_DRIVER_SYNC_2);
59# endif 56# if defined(LED_DRIVER_ADDR_3)
60# ifdef LED_DRIVER_ADDR_3 57# if !defined(LED_DRIVER_SYNC_3)
61# ifndef LED_DRIVER_SYNC_3 58# define LED_DRIVER_SYNC_3 0
62# define LED_DRIVER_SYNC_3 0 59# endif
63# endif
64 IS31FL3733_init(LED_DRIVER_ADDR_3, LED_DRIVER_SYNC_3); 60 IS31FL3733_init(LED_DRIVER_ADDR_3, LED_DRIVER_SYNC_3);
65# endif 61# if defined(LED_DRIVER_ADDR_4)
66# ifdef LED_DRIVER_ADDR_4 62# if !defined(LED_DRIVER_SYNC_4)
67# ifndef LED_DRIVER_SYNC_4 63# define LED_DRIVER_SYNC_4 0
68# define LED_DRIVER_SYNC_4 0 64# endif
69# endif
70 IS31FL3733_init(LED_DRIVER_ADDR_4, LED_DRIVER_SYNC_4); 65 IS31FL3733_init(LED_DRIVER_ADDR_4, LED_DRIVER_SYNC_4);
66# endif
67# endif
71# endif 68# endif
72# endif 69# endif
73 70
74 for (int index = 0; index < DRIVER_LED_TOTAL; index++) { 71 for (int index = 0; index < DRIVER_LED_TOTAL; index++) {
75# ifdef IS31FL3731 72# if defined(IS31FL3731)
76 IS31FL3731_set_led_control_register(index, true); 73 IS31FL3731_set_led_control_register(index, true);
77# else 74# elif defined(IS31FL3733)
78 IS31FL3733_set_led_control_register(index, true); 75 IS31FL3733_set_led_control_register(index, true);
79# endif 76# endif
80 } 77 }
78
81// This actually updates the LED drivers 79// This actually updates the LED drivers
82# ifdef IS31FL3731 80# if defined(IS31FL3731)
83# ifdef LED_DRIVER_ADDR_1
84 IS31FL3731_update_led_control_registers(LED_DRIVER_ADDR_1, 0); 81 IS31FL3731_update_led_control_registers(LED_DRIVER_ADDR_1, 0);
85# endif 82# if defined(LED_DRIVER_ADDR_2)
86# ifdef LED_DRIVER_ADDR_2
87 IS31FL3731_update_led_control_registers(LED_DRIVER_ADDR_2, 1); 83 IS31FL3731_update_led_control_registers(LED_DRIVER_ADDR_2, 1);
88# endif 84# if defined(LED_DRIVER_ADDR_3)
89# ifdef LED_DRIVER_ADDR_3
90 IS31FL3731_update_led_control_registers(LED_DRIVER_ADDR_3, 2); 85 IS31FL3731_update_led_control_registers(LED_DRIVER_ADDR_3, 2);
91# endif 86# if defined(LED_DRIVER_ADDR_4)
92# ifdef LED_DRIVER_ADDR_4
93 IS31FL3731_update_led_control_registers(LED_DRIVER_ADDR_4, 3); 87 IS31FL3731_update_led_control_registers(LED_DRIVER_ADDR_4, 3);
88# endif
89# endif
94# endif 90# endif
95# else 91
96# ifdef LED_DRIVER_ADDR_1 92# elif defined(IS31FL3733)
97 IS31FL3733_update_led_control_registers(LED_DRIVER_ADDR_1, 0); 93 IS31FL3733_update_led_control_registers(LED_DRIVER_ADDR_1, 0);
98# endif 94# if defined(LED_DRIVER_ADDR_2)
99# ifdef LED_DRIVER_ADDR_2
100 IS31FL3733_update_led_control_registers(LED_DRIVER_ADDR_2, 1); 95 IS31FL3733_update_led_control_registers(LED_DRIVER_ADDR_2, 1);
101# endif 96# if defined(LED_DRIVER_ADDR_3)
102# ifdef LED_DRIVER_ADDR_3
103 IS31FL3733_update_led_control_registers(LED_DRIVER_ADDR_3, 2); 97 IS31FL3733_update_led_control_registers(LED_DRIVER_ADDR_3, 2);
104# endif 98# if defined(LED_DRIVER_ADDR_4)
105# ifdef LED_DRIVER_ADDR_4
106 IS31FL3733_update_led_control_registers(LED_DRIVER_ADDR_4, 3); 99 IS31FL3733_update_led_control_registers(LED_DRIVER_ADDR_4, 3);
100# endif
101# endif
107# endif 102# endif
108# endif 103# endif
109} 104}
110 105
106# if defined(IS31FL3731)
111static void flush(void) { 107static void flush(void) {
112# ifdef IS31FL3731
113# ifdef LED_DRIVER_ADDR_1
114 IS31FL3731_update_pwm_buffers(LED_DRIVER_ADDR_1, 0); 108 IS31FL3731_update_pwm_buffers(LED_DRIVER_ADDR_1, 0);
115# endif 109# if defined(LED_DRIVER_ADDR_2)
116# ifdef LED_DRIVER_ADDR_2
117 IS31FL3731_update_pwm_buffers(LED_DRIVER_ADDR_2, 1); 110 IS31FL3731_update_pwm_buffers(LED_DRIVER_ADDR_2, 1);
118# endif 111# if defined(LED_DRIVER_ADDR_3)
119# ifdef LED_DRIVER_ADDR_3
120 IS31FL3731_update_pwm_buffers(LED_DRIVER_ADDR_3, 2); 112 IS31FL3731_update_pwm_buffers(LED_DRIVER_ADDR_3, 2);
121# endif 113# if defined(LED_DRIVER_ADDR_4)
122# ifdef LED_DRIVER_ADDR_4
123 IS31FL3731_update_pwm_buffers(LED_DRIVER_ADDR_4, 3); 114 IS31FL3731_update_pwm_buffers(LED_DRIVER_ADDR_4, 3);
115# endif
116# endif
124# endif 117# endif
125# else 118}
126# ifdef LED_DRIVER_ADDR_1 119
120const led_matrix_driver_t led_matrix_driver = {
121 .init = init,
122 .flush = flush,
123 .set_value = IS31FL3731_set_value,
124 .set_value_all = IS31FL3731_set_value_all,
125};
126
127# elif defined(IS31FL3733)
128static void flush(void) {
127 IS31FL3733_update_pwm_buffers(LED_DRIVER_ADDR_1, 0); 129 IS31FL3733_update_pwm_buffers(LED_DRIVER_ADDR_1, 0);
128# endif 130# if defined(LED_DRIVER_ADDR_2)
129# ifdef LED_DRIVER_ADDR_2
130 IS31FL3733_update_pwm_buffers(LED_DRIVER_ADDR_2, 1); 131 IS31FL3733_update_pwm_buffers(LED_DRIVER_ADDR_2, 1);
131# endif 132# if defined(LED_DRIVER_ADDR_3)
132# ifdef LED_DRIVER_ADDR_3
133 IS31FL3733_update_pwm_buffers(LED_DRIVER_ADDR_3, 2); 133 IS31FL3733_update_pwm_buffers(LED_DRIVER_ADDR_3, 2);
134# endif 134# if defined(LED_DRIVER_ADDR_4)
135# ifdef LED_DRIVER_ADDR_4
136 IS31FL3733_update_pwm_buffers(LED_DRIVER_ADDR_4, 3); 135 IS31FL3733_update_pwm_buffers(LED_DRIVER_ADDR_4, 3);
136# endif
137# endif
137# endif 138# endif
138# endif
139} 139}
140 140
141const led_matrix_driver_t led_matrix_driver = { 141const led_matrix_driver_t led_matrix_driver = {
142 .init = init, 142 .init = init,
143 .flush = flush, 143 .flush = flush,
144# ifdef IS31FL3731
145 .set_value = IS31FL3731_set_value,
146 .set_value_all = IS31FL3731_set_value_all,
147# else
148 .set_value = IS31FL3733_set_value, 144 .set_value = IS31FL3733_set_value,
149 .set_value_all = IS31FL3733_set_value_all, 145 .set_value_all = IS31FL3733_set_value_all,
150# endif
151}; 146};
152 147# endif
153#endif 148#endif
diff --git a/quantum/main.c b/quantum/main.c
index 2cbcd73d8..a896a67c6 100644
--- a/quantum/main.c
+++ b/quantum/main.c
@@ -20,7 +20,18 @@ void platform_setup(void);
20 20
21void protocol_setup(void); 21void protocol_setup(void);
22void protocol_init(void); 22void protocol_init(void);
23void protocol_task(void); 23void protocol_pre_task(void);
24void protocol_post_task(void);
25
26// Bodge as refactoring vusb sucks....
27void protocol_task(void) __attribute__((weak));
28void protocol_task(void) {
29 protocol_pre_task();
30
31 keyboard_task();
32
33 protocol_post_task();
34}
24 35
25/** \brief Main 36/** \brief Main
26 * 37 *
@@ -30,8 +41,10 @@ int main(void) __attribute__((weak));
30int main(void) { 41int main(void) {
31 platform_setup(); 42 platform_setup();
32 protocol_setup(); 43 protocol_setup();
44 keyboard_setup();
33 45
34 protocol_init(); 46 protocol_init();
47 keyboard_init();
35 48
36 /* Main loop */ 49 /* Main loop */
37 while (true) { 50 while (true) {
diff --git a/quantum/matrix.c b/quantum/matrix.c
index 33586c431..483d518ec 100644
--- a/quantum/matrix.c
+++ b/quantum/matrix.c
@@ -69,7 +69,7 @@ uint8_t thisHand, thatHand;
69// user-defined overridable functions 69// user-defined overridable functions
70__attribute__((weak)) void matrix_init_pins(void); 70__attribute__((weak)) void matrix_init_pins(void);
71__attribute__((weak)) void matrix_read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row); 71__attribute__((weak)) void matrix_read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row);
72__attribute__((weak)) void matrix_read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col); 72__attribute__((weak)) void matrix_read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col, matrix_row_t row_shifter);
73#ifdef SPLIT_KEYBOARD 73#ifdef SPLIT_KEYBOARD
74__attribute__((weak)) void matrix_slave_scan_kb(void) { matrix_slave_scan_user(); } 74__attribute__((weak)) void matrix_slave_scan_kb(void) { matrix_slave_scan_user(); }
75__attribute__((weak)) void matrix_slave_scan_user(void) {} 75__attribute__((weak)) void matrix_slave_scan_user(void) {}
@@ -113,10 +113,11 @@ __attribute__((weak)) void matrix_read_cols_on_row(matrix_row_t current_matrix[]
113 // Start with a clear matrix row 113 // Start with a clear matrix row
114 matrix_row_t current_row_value = 0; 114 matrix_row_t current_row_value = 0;
115 115
116 for (uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++) { 116 matrix_row_t row_shifter = MATRIX_ROW_SHIFTER;
117 for (uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++, row_shifter <<= 1) {
117 pin_t pin = direct_pins[current_row][col_index]; 118 pin_t pin = direct_pins[current_row][col_index];
118 if (pin != NO_PIN) { 119 if (pin != NO_PIN) {
119 current_row_value |= readPin(pin) ? 0 : (MATRIX_ROW_SHIFTER << col_index); 120 current_row_value |= readPin(pin) ? 0 : row_shifter;
120 } 121 }
121 } 122 }
122 123
@@ -169,11 +170,12 @@ __attribute__((weak)) void matrix_read_cols_on_row(matrix_row_t current_matrix[]
169 matrix_output_select_delay(); 170 matrix_output_select_delay();
170 171
171 // For each col... 172 // For each col...
172 for (uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++) { 173 matrix_row_t row_shifter = MATRIX_ROW_SHIFTER;
174 for (uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++, row_shifter <<= 1) {
173 uint8_t pin_state = readMatrixPin(col_pins[col_index]); 175 uint8_t pin_state = readMatrixPin(col_pins[col_index]);
174 176
175 // Populate the matrix row with the state of the col pin 177 // Populate the matrix row with the state of the col pin
176 current_row_value |= pin_state ? 0 : (MATRIX_ROW_SHIFTER << col_index); 178 current_row_value |= pin_state ? 0 : row_shifter;
177 } 179 }
178 180
179 // Unselect row 181 // Unselect row
@@ -217,7 +219,7 @@ __attribute__((weak)) void matrix_init_pins(void) {
217 } 219 }
218} 220}
219 221
220__attribute__((weak)) void matrix_read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col) { 222__attribute__((weak)) void matrix_read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col, matrix_row_t row_shifter) {
221 bool key_pressed = false; 223 bool key_pressed = false;
222 224
223 // Select col 225 // Select col
@@ -231,11 +233,11 @@ __attribute__((weak)) void matrix_read_rows_on_col(matrix_row_t current_matrix[]
231 // Check row pin state 233 // Check row pin state
232 if (readMatrixPin(row_pins[row_index]) == 0) { 234 if (readMatrixPin(row_pins[row_index]) == 0) {
233 // Pin LO, set col bit 235 // Pin LO, set col bit
234 current_matrix[row_index] |= (MATRIX_ROW_SHIFTER << current_col); 236 current_matrix[row_index] |= row_shifter;
235 key_pressed = true; 237 key_pressed = true;
236 } else { 238 } else {
237 // Pin HI, clear col bit 239 // Pin HI, clear col bit
238 current_matrix[row_index] &= ~(MATRIX_ROW_SHIFTER << current_col); 240 current_matrix[row_index] &= ~row_shifter;
239 } 241 }
240 } 242 }
241 243
@@ -288,10 +290,8 @@ void matrix_init(void) {
288 matrix_init_pins(); 290 matrix_init_pins();
289 291
290 // initialize matrix state: all keys off 292 // initialize matrix state: all keys off
291 for (uint8_t i = 0; i < MATRIX_ROWS; i++) { 293 memset(matrix, 0, sizeof(matrix));
292 raw_matrix[i] = 0; 294 memset(raw_matrix, 0, sizeof(raw_matrix));
293 matrix[i] = 0;
294 }
295 295
296 debounce_init(ROWS_PER_HAND); 296 debounce_init(ROWS_PER_HAND);
297 297
@@ -312,24 +312,22 @@ __attribute__((weak)) bool transport_master_if_connected(matrix_row_t master_mat
312bool matrix_post_scan(void) { 312bool matrix_post_scan(void) {
313 bool changed = false; 313 bool changed = false;
314 if (is_keyboard_master()) { 314 if (is_keyboard_master()) {
315 static bool last_connected = false;
315 matrix_row_t slave_matrix[ROWS_PER_HAND] = {0}; 316 matrix_row_t slave_matrix[ROWS_PER_HAND] = {0};
316 if (transport_master_if_connected(matrix + thisHand, slave_matrix)) { 317 if (transport_master_if_connected(matrix + thisHand, slave_matrix)) {
317 for (int i = 0; i < ROWS_PER_HAND; ++i) { 318 changed = memcmp(matrix + thatHand, slave_matrix, sizeof(slave_matrix)) != 0;
318 if (matrix[thatHand + i] != slave_matrix[i]) {
319 matrix[thatHand + i] = slave_matrix[i];
320 changed = true;
321 }
322 }
323 } else {
324 // reset other half if disconnected
325 for (int i = 0; i < ROWS_PER_HAND; ++i) {
326 matrix[thatHand + i] = 0;
327 slave_matrix[i] = 0;
328 }
329 319
320 last_connected = true;
321 } else if (last_connected) {
322 // reset other half when disconnected
323 memset(slave_matrix, 0, sizeof(slave_matrix));
330 changed = true; 324 changed = true;
325
326 last_connected = false;
331 } 327 }
332 328
329 if (changed) memcpy(matrix + thatHand, slave_matrix, sizeof(slave_matrix));
330
333 matrix_scan_quantum(); 331 matrix_scan_quantum();
334 } else { 332 } else {
335 transport_slave(matrix + thatHand, matrix + thisHand); 333 transport_slave(matrix + thatHand, matrix + thisHand);
@@ -351,8 +349,9 @@ uint8_t matrix_scan(void) {
351 } 349 }
352#elif (DIODE_DIRECTION == ROW2COL) 350#elif (DIODE_DIRECTION == ROW2COL)
353 // Set col, read rows 351 // Set col, read rows
354 for (uint8_t current_col = 0; current_col < MATRIX_COLS; current_col++) { 352 matrix_row_t row_shifter = MATRIX_ROW_SHIFTER;
355 matrix_read_rows_on_col(curr_matrix, current_col); 353 for (uint8_t current_col = 0; current_col < MATRIX_COLS; current_col++, row_shifter <<= 1) {
354 matrix_read_rows_on_col(curr_matrix, current_col, row_shifter);
356 } 355 }
357#endif 356#endif
358 357
diff --git a/quantum/mcu_selection.mk b/quantum/mcu_selection.mk
deleted file mode 100644
index 3b86433a8..000000000
--- a/quantum/mcu_selection.mk
+++ /dev/null
@@ -1,600 +0,0 @@
1MCU_ORIG := $(MCU)
2
3ifneq ($(findstring MKL26Z64, $(MCU)),)
4 # Cortex version
5 MCU = cortex-m0plus
6
7 # ARM version, CORTEX-M0/M1 are 6, CORTEX-M3/M4/M7 are 7
8 ARMV = 6
9
10 ## chip/board settings
11 # - the next two should match the directories in
12 # <chibios>/os/hal/ports/$(MCU_FAMILY)/$(MCU_SERIES)
13 MCU_FAMILY = KINETIS
14 MCU_SERIES = KL2x
15
16 # Linker script to use
17 # - it should exist either in <chibios>/os/common/ports/ARMCMx/compilers/GCC/ld/
18 # or <keyboard_dir>/ld/
19 MCU_LDSCRIPT ?= MKL26Z64
20
21 # Startup code to use
22 # - it should exist in <chibios>/os/common/ports/ARMCMx/compilers/GCC/mk/
23 MCU_STARTUP ?= kl2x
24
25 # Board: it should exist either in <chibios>/os/hal/boards/,
26 # <keyboard_dir>/boards/, or drivers/boards/
27 BOARD ?= PJRC_TEENSY_LC
28endif
29
30ifneq ($(findstring MK20DX128, $(MCU)),)
31 # Cortex version
32 MCU = cortex-m4
33
34 # ARM version, CORTEX-M0/M1 are 6, CORTEX-M3/M4/M7 are 7
35 ARMV = 7
36
37 ## chip/board settings
38 # - the next two should match the directories in
39 # <chibios>/os/hal/ports/$(MCU_FAMILY)/$(MCU_SERIES)
40 MCU_FAMILY = KINETIS
41 MCU_SERIES = K20x
42
43 # Linker script to use
44 # - it should exist either in <chibios>/os/common/ports/ARMCMx/compilers/GCC/ld/
45 # or <keyboard_dir>/ld/
46 MCU_LDSCRIPT ?= MK20DX128
47
48 # Startup code to use
49 # - it should exist in <chibios>/os/common/ports/ARMCMx/compilers/GCC/mk/
50 MCU_STARTUP ?= k20x5
51
52 # Board: it should exist either in <chibios>/os/hal/boards/,
53 # <keyboard_dir>/boards/, or drivers/boards/
54 BOARD ?= PJRC_TEENSY_3
55endif
56
57ifneq ($(findstring MK20DX256, $(MCU)),)
58 # Cortex version
59 MCU = cortex-m4
60
61 # ARM version, CORTEX-M0/M1 are 6, CORTEX-M3/M4/M7 are 7
62 ARMV = 7
63
64 ## chip/board settings
65 # - the next two should match the directories in
66 # <chibios>/os/hal/ports/$(MCU_FAMILY)/$(MCU_SERIES)
67 MCU_FAMILY = KINETIS
68 MCU_SERIES = K20x
69
70 # Linker script to use
71 # - it should exist either in <chibios>/os/common/ports/ARMCMx/compilers/GCC/ld/
72 # or <keyboard_dir>/ld/
73 MCU_LDSCRIPT ?= MK20DX256
74
75 # Startup code to use
76 # - it should exist in <chibios>/os/common/ports/ARMCMx/compilers/GCC/mk/
77 MCU_STARTUP ?= k20x7
78
79 # Board: it should exist either in <chibios>/os/hal/boards/,
80 # <keyboard_dir>/boards/, or drivers/boards/
81 BOARD ?= PJRC_TEENSY_3_1
82endif
83
84ifneq ($(findstring MK66F18, $(MCU)),)
85 # Cortex version
86 MCU = cortex-m4
87
88 # ARM version, CORTEX-M0/M1 are 6, CORTEX-M3/M4/M7 are 7
89 ARMV = 7
90
91 ## chip/board settings
92 # - the next two should match the directories in
93 # <chibios>/os/hal/ports/$(MCU_FAMILY)/$(MCU_SERIES)
94 MCU_FAMILY = KINETIS
95 MCU_SERIES = MK66F18
96
97 # Linker script to use
98 # - it should exist either in <chibios>/os/common/ports/ARMCMx/compilers/GCC/ld/
99 # or <keyboard_dir>/ld/
100 MCU_LDSCRIPT ?= MK66FX1M0
101
102 # Startup code to use
103 # - it should exist in <chibios>/os/common/startup/ARMCMx/compilers/GCC/mk/
104 MCU_STARTUP ?= MK66F18
105
106 # Board: it should exist either in <chibios>/os/hal/boards/,
107 # <keyboard_dir>/boards/, or drivers/boards/
108 BOARD ?= PJRC_TEENSY_3_6
109endif
110
111ifneq ($(findstring STM32F042, $(MCU)),)
112 # Cortex version
113 MCU = cortex-m0
114
115 # ARM version, CORTEX-M0/M1 are 6, CORTEX-M3/M4/M7 are 7
116 ARMV = 6
117
118 ## chip/board settings
119 # - the next two should match the directories in
120 # <chibios>/os/hal/ports/$(MCU_FAMILY)/$(MCU_SERIES)
121 MCU_FAMILY = STM32
122 MCU_SERIES = STM32F0xx
123
124 # Linker script to use
125 # - it should exist either in <chibios>/os/common/startup/ARMCMx/compilers/GCC/ld/
126 # or <keyboard_dir>/ld/
127 MCU_LDSCRIPT ?= STM32F042x6
128
129 # Startup code to use
130 # - it should exist in <chibios>/os/common/startup/ARMCMx/compilers/GCC/mk/
131 MCU_STARTUP ?= stm32f0xx
132
133 # Board: it should exist either in <chibios>/os/hal/boards/,
134 # <keyboard_dir>/boards/, or drivers/boards/
135 BOARD ?= GENERIC_STM32_F042X6
136
137 USE_FPU ?= no
138
139 # UF2 settings
140 UF2_FAMILY ?= STM32F0
141endif
142
143ifneq ($(findstring STM32F072, $(MCU)),)
144 # Cortex version
145 MCU = cortex-m0
146
147 # ARM version, CORTEX-M0/M1 are 6, CORTEX-M3/M4/M7 are 7
148 ARMV = 6
149
150 ## chip/board settings
151 # - the next two should match the directories in
152 # <chibios>/os/hal/ports/$(MCU_FAMILY)/$(MCU_SERIES)
153 MCU_FAMILY = STM32
154 MCU_SERIES = STM32F0xx
155
156 # Linker script to use
157 # - it should exist either in <chibios>/os/common/startup/ARMCMx/compilers/GCC/ld/
158 # or <keyboard_dir>/ld/
159 MCU_LDSCRIPT ?= STM32F072xB
160
161 # Startup code to use
162 # - it should exist in <chibios>/os/common/startup/ARMCMx/compilers/GCC/mk/
163 MCU_STARTUP ?= stm32f0xx
164
165 # Board: it should exist either in <chibios>/os/hal/boards/,
166 # <keyboard_dir>/boards/, or drivers/boards/
167 BOARD ?= GENERIC_STM32_F072XB
168
169 USE_FPU ?= no
170
171 # UF2 settings
172 UF2_FAMILY ?= STM32F0
173endif
174
175ifneq ($(findstring STM32F103, $(MCU)),)
176 # Cortex version
177 MCU = cortex-m3
178
179 # ARM version, CORTEX-M0/M1 are 6, CORTEX-M3/M4/M7 are 7
180 ARMV = 7
181
182 ## chip/board settings
183 # - the next two should match the directories in
184 # <chibios>/os/hal/ports/$(MCU_FAMILY)/$(MCU_SERIES)
185 MCU_FAMILY = STM32
186 MCU_SERIES = STM32F1xx
187
188 # Linker script to use
189 # - it should exist either in <chibios>/os/common/startup/ARMCMx/compilers/GCC/ld/
190 # or <keyboard_dir>/ld/
191 MCU_LDSCRIPT ?= STM32F103x8
192
193 # Startup code to use
194 # - it should exist in <chibios>/os/common/startup/ARMCMx/compilers/GCC/mk/
195 MCU_STARTUP ?= stm32f1xx
196
197 # Board: it should exist either in <chibios>/os/hal/boards/,
198 # <keyboard_dir>/boards/, or drivers/boards/
199 BOARD ?= GENERIC_STM32_F103
200
201 USE_FPU ?= no
202
203 # UF2 settings
204 UF2_FAMILY ?= STM32F1
205endif
206
207ifneq ($(findstring STM32F303, $(MCU)),)
208 # Cortex version
209 MCU = cortex-m4
210
211 # ARM version, CORTEX-M0/M1 are 6, CORTEX-M3/M4/M7 are 7
212 ARMV = 7
213
214 ## chip/board settings
215 # - the next two should match the directories in
216 # <chibios>/os/hal/ports/$(MCU_FAMILY)/$(MCU_SERIES)
217 MCU_FAMILY = STM32
218 MCU_SERIES = STM32F3xx
219
220 # Linker script to use
221 # - it should exist either in <chibios>/os/common/startup/ARMCMx/compilers/GCC/ld/
222 # or <keyboard_dir>/ld/
223 MCU_LDSCRIPT ?= STM32F303xC
224
225 # Startup code to use
226 # - it should exist in <chibios>/os/common/startup/ARMCMx/compilers/GCC/mk/
227 MCU_STARTUP ?= stm32f3xx
228
229 # Board: it should exist either in <chibios>/os/hal/boards/,
230 # <keyboard_dir>/boards/, or drivers/boards/
231 BOARD ?= GENERIC_STM32_F303XC
232
233 USE_FPU ?= yes
234
235 # UF2 settings
236 UF2_FAMILY ?= STM32F3
237endif
238
239ifneq ($(findstring STM32F401, $(MCU)),)
240 # Cortex version
241 MCU = cortex-m4
242
243 # ARM version, CORTEX-M0/M1 are 6, CORTEX-M3/M4/M7 are 7
244 ARMV = 7
245
246 ## chip/board settings
247 # - the next two should match the directories in
248 # <chibios>/os/hal/ports/$(MCU_FAMILY)/$(MCU_SERIES)
249 MCU_FAMILY = STM32
250 MCU_SERIES = STM32F4xx
251
252 # Linker script to use
253 # - it should exist either in <chibios>/os/common/startup/ARMCMx/compilers/GCC/ld/
254 # or <keyboard_dir>/ld/
255 ifeq ($(strip $(BOOTLOADER)), tinyuf2)
256 MCU_LDSCRIPT ?= STM32F401xC_tinyuf2
257 FIRMWARE_FORMAT ?= uf2
258 else
259 MCU_LDSCRIPT ?= STM32F401xC
260 endif
261
262 # Startup code to use
263 # - it should exist in <chibios>/os/common/startup/ARMCMx/compilers/GCC/mk/
264 MCU_STARTUP ?= stm32f4xx
265
266 # Board: it should exist either in <chibios>/os/hal/boards/,
267 # <keyboard_dir>/boards/, or drivers/boards/
268 BOARD ?= BLACKPILL_STM32_F401
269
270 USE_FPU ?= yes
271
272 # UF2 settings
273 UF2_FAMILY ?= STM32F4
274endif
275
276ifneq ($(findstring STM32F407, $(MCU)),)
277 # Cortex version
278 MCU = cortex-m4
279
280 # ARM version, CORTEX-M0/M1 are 6, CORTEX-M3/M4/M7 are 7
281 ARMV = 7
282
283 ## chip/board settings
284 # - the next two should match the directories in
285 # <chibios>/os/hal/ports/$(MCU_FAMILY)/$(MCU_SERIES)
286 MCU_FAMILY = STM32
287 MCU_SERIES = STM32F4xx
288
289 # Linker script to use
290 # - it should exist either in <chibios>/os/common/startup/ARMCMx/compilers/GCC/ld/
291 # or <keyboard_dir>/ld/
292 MCU_LDSCRIPT ?= STM32F407xE
293
294 # Startup code to use
295 # - it should exist in <chibios>/os/common/startup/ARMCMx/compilers/GCC/mk/
296 MCU_STARTUP ?= stm32f4xx
297
298 # Board: it should exist either in <chibios>/os/hal/boards/,
299 # <keyboard_dir>/boards/, or drivers/boards/
300 BOARD ?= GENERIC_STM32_F407XE
301
302 USE_FPU ?= yes
303
304 # UF2 settings
305 UF2_FAMILY ?= STM32F4
306endif
307
308ifneq ($(findstring STM32F411, $(MCU)),)
309 # Cortex version
310 MCU = cortex-m4
311
312 # ARM version, CORTEX-M0/M1 are 6, CORTEX-M3/M4/M7 are 7
313 ARMV = 7
314
315 ## chip/board settings
316 # - the next two should match the directories in
317 # <chibios>/os/hal/ports/$(MCU_FAMILY)/$(MCU_SERIES)
318 MCU_FAMILY = STM32
319 MCU_SERIES = STM32F4xx
320
321 # Linker script to use
322 # - it should exist either in <chibios>/os/common/startup/ARMCMx/compilers/GCC/ld/
323 # or <keyboard_dir>/ld/
324 ifeq ($(strip $(BOOTLOADER)), tinyuf2)
325 MCU_LDSCRIPT ?= STM32F411xE_tinyuf2
326 FIRMWARE_FORMAT ?= uf2
327 else
328 MCU_LDSCRIPT ?= STM32F411xE
329 endif
330
331 # Startup code to use
332 # - it should exist in <chibios>/os/common/startup/ARMCMx/compilers/GCC/mk/
333 MCU_STARTUP ?= stm32f4xx
334
335 # Board: it should exist either in <chibios>/os/hal/boards/,
336 # <keyboard_dir>/boards/, or drivers/boards/
337 BOARD ?= BLACKPILL_STM32_F411
338
339 USE_FPU ?= yes
340
341 # UF2 settings
342 UF2_FAMILY ?= STM32F4
343endif
344
345ifneq ($(findstring STM32F446, $(MCU)),)
346 # Cortex version
347 MCU = cortex-m4
348
349 # ARM version, CORTEX-M0/M1 are 6, CORTEX-M3/M4/M7 are 7
350 ARMV = 7
351
352 ## chip/board settings
353 # - the next two should match the directories in
354 # <chibios>/os/hal/ports/$(MCU_FAMILY)/$(MCU_SERIES)
355 MCU_FAMILY = STM32
356 MCU_SERIES = STM32F4xx
357
358 # Linker script to use
359 # - it should exist either in <chibios>/os/common/startup/ARMCMx/compilers/GCC/ld/
360 # or <keyboard_dir>/ld/
361 MCU_LDSCRIPT ?= STM32F446xE
362
363 # Startup code to use
364 # - it should exist in <chibios>/os/common/startup/ARMCMx/compilers/GCC/mk/
365 MCU_STARTUP ?= stm32f4xx
366
367 # Board: it should exist either in <chibios>/os/hal/boards/,
368 # <keyboard_dir>/boards/, or drivers/boards/
369 BOARD ?= GENERIC_STM32_F446XE
370
371 USE_FPU ?= yes
372endif
373
374ifneq ($(findstring STM32G431, $(MCU)),)
375 # Cortex version
376 MCU = cortex-m4
377
378 # ARM version, CORTEX-M0/M1 are 6, CORTEX-M3/M4/M7 are 7
379 ARMV = 7
380
381 ## chip/board settings
382 # - the next two should match the directories in
383 # <chibios>/os/hal/ports/$(MCU_FAMILY)/$(MCU_SERIES)
384 MCU_FAMILY = STM32
385 MCU_SERIES = STM32G4xx
386
387 # Linker script to use
388 # - it should exist either in <chibios>/os/common/startup/ARMCMx/compilers/GCC/ld/
389 # or <keyboard_dir>/ld/
390 MCU_LDSCRIPT ?= STM32G431xB
391
392 # Startup code to use
393 # - it should exist in <chibios>/os/common/startup/ARMCMx/compilers/GCC/mk/
394 MCU_STARTUP ?= stm32g4xx
395
396 # Board: it should exist either in <chibios>/os/hal/boards/,
397 # <keyboard_dir>/boards/, or drivers/boards/
398 BOARD ?= GENERIC_STM32_G431XB
399
400 USE_FPU ?= yes
401
402 # UF2 settings
403 UF2_FAMILY ?= STM32G4
404endif
405
406ifneq ($(findstring STM32G474, $(MCU)),)
407 # Cortex version
408 MCU = cortex-m4
409
410 # ARM version, CORTEX-M0/M1 are 6, CORTEX-M3/M4/M7 are 7
411 ARMV = 7
412
413 ## chip/board settings
414 # - the next two should match the directories in
415 # <chibios>/os/hal/ports/$(MCU_FAMILY)/$(MCU_SERIES)
416 MCU_FAMILY = STM32
417 MCU_SERIES = STM32G4xx
418
419 # Linker script to use
420 # - it should exist either in <chibios>/os/common/startup/ARMCMx/compilers/GCC/ld/
421 # or <keyboard_dir>/ld/
422 MCU_LDSCRIPT ?= STM32G474xE
423
424 # Startup code to use
425 # - it should exist in <chibios>/os/common/startup/ARMCMx/compilers/GCC/mk/
426 MCU_STARTUP ?= stm32g4xx
427
428 # Board: it should exist either in <chibios>/os/hal/boards/,
429 # <keyboard_dir>/boards/, or drivers/boards/
430 BOARD ?= GENERIC_STM32_G474XE
431
432 USE_FPU ?= yes
433
434 # UF2 settings
435 UF2_FAMILY ?= STM32G4
436endif
437
438ifneq (,$(filter $(MCU),STM32L433 STM32L443))
439 # Cortex version
440 MCU = cortex-m4
441
442 # ARM version, CORTEX-M0/M1 are 6, CORTEX-M3/M4/M7 are 7
443 ARMV = 7
444
445 ## chip/board settings
446 # - the next two should match the directories in
447 # <chibios>/os/hal/ports/$(MCU_FAMILY)/$(MCU_SERIES)
448 MCU_FAMILY = STM32
449 MCU_SERIES = STM32L4xx
450
451 # Linker script to use
452 # - it should exist either in <chibios>/os/common/startup/ARMCMx/compilers/GCC/ld/
453 # or <keyboard_dir>/ld/
454 MCU_LDSCRIPT ?= STM32L432xC
455
456 # Startup code to use
457 # - it should exist in <chibios>/os/common/startup/ARMCMx/compilers/GCC/mk/
458 MCU_STARTUP ?= stm32l4xx
459
460 # Board: it should exist either in <chibios>/os/hal/boards/,
461 # <keyboard_dir>/boards/, or drivers/boards/
462 BOARD ?= GENERIC_STM32_L433XC
463
464 PLATFORM_NAME ?= platform_l432
465
466 USE_FPU ?= yes
467
468 # UF2 settings
469 UF2_FAMILY ?= STM32L4
470endif
471
472ifneq (,$(filter $(MCU),STM32L412 STM32L422))
473 # Cortex version
474 MCU = cortex-m4
475
476 # ARM version, CORTEX-M0/M1 are 6, CORTEX-M3/M4/M7 are 7
477 ARMV = 7
478
479 ## chip/board settings
480 # - the next two should match the directories in
481 # <chibios>/os/hal/ports/$(MCU_FAMILY)/$(MCU_SERIES)
482 MCU_FAMILY = STM32
483 MCU_SERIES = STM32L4xx
484
485 # Linker script to use
486 # - it should exist either in <chibios>/os/common/startup/ARMCMx/compilers/GCC/ld/
487 # or <keyboard_dir>/ld/
488 MCU_LDSCRIPT ?= STM32L412xB
489
490 # Startup code to use
491 # - it should exist in <chibios>/os/common/startup/ARMCMx/compilers/GCC/mk/
492 MCU_STARTUP ?= stm32l4xx
493
494 # Board: it should exist either in <chibios>/os/hal/boards/,
495 # <keyboard_dir>/boards/, or drivers/boards/
496 BOARD ?= GENERIC_STM32_L412XB
497
498 PLATFORM_NAME ?= platform_l432
499
500 USE_FPU ?= yes
501
502 # UF2 settings
503 UF2_FAMILY ?= STM32L4
504endif
505
506ifneq (,$(filter $(MCU),at90usb162 atmega16u2 atmega32u2 atmega16u4 atmega32u4 at90usb646 at90usb647 at90usb1286 at90usb1287))
507 PROTOCOL = LUFA
508
509 # Processor frequency.
510 # This will define a symbol, F_CPU, in all source code files equal to the
511 # processor frequency in Hz. You can then use this symbol in your source code to
512 # calculate timings. Do NOT tack on a 'UL' at the end, this will be done
513 # automatically to create a 32-bit value in your source code.
514 #
515 # This will be an integer division of F_USB below, as it is sourced by
516 # F_USB after it has run through any CPU prescalers. Note that this value
517 # does not *change* the processor frequency - it should merely be updated to
518 # reflect the processor speed set externally so that the code can use accurate
519 # software delays.
520 F_CPU ?= 16000000
521
522 # LUFA specific
523 #
524 # Target architecture (see library "Board Types" documentation).
525 ARCH = AVR8
526
527 # Input clock frequency.
528 # This will define a symbol, F_USB, in all source code files equal to the
529 # input clock frequency (before any prescaling is performed) in Hz. This value may
530 # differ from F_CPU if prescaling is used on the latter, and is required as the
531 # raw input clock is fed directly to the PLL sections of the AVR for high speed
532 # clock generation for the USB and other AVR subsections. Do NOT tack on a 'UL'
533 # at the end, this will be done automatically to create a 32-bit value in your
534 # source code.
535 #
536 # If no clock division is performed on the input clock inside the AVR (via the
537 # CPU clock adjust registers or the clock division fuses), this will be equal to F_CPU.
538 F_USB ?= $(F_CPU)
539
540 # Interrupt driven control endpoint task
541 ifeq (,$(filter $(NO_INTERRUPT_CONTROL_ENDPOINT),yes))
542 OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT
543 endif
544 ifneq (,$(filter $(MCU),at90usb162 atmega16u2 atmega32u2))
545 NO_I2C = yes
546 endif
547endif
548
549ifneq (,$(filter $(MCU),atmega32a))
550 # MCU name for avrdude
551 AVRDUDE_MCU = m32
552
553 PROTOCOL = VUSB
554
555 # Processor frequency.
556 # This will define a symbol, F_CPU, in all source code files equal to the
557 # processor frequency in Hz. You can then use this symbol in your source code to
558 # calculate timings. Do NOT tack on a 'UL' at the end, this will be done
559 # automatically to create a 32-bit value in your source code.
560 F_CPU ?= 12000000
561endif
562
563ifneq (,$(filter $(MCU),atmega328p))
564 # MCU name for avrdude
565 AVRDUDE_MCU = m328p
566
567 PROTOCOL = VUSB
568
569 # Processor frequency.
570 # This will define a symbol, F_CPU, in all source code files equal to the
571 # processor frequency in Hz. You can then use this symbol in your source code to
572 # calculate timings. Do NOT tack on a 'UL' at the end, this will be done
573 # automatically to create a 32-bit value in your source code.
574 F_CPU ?= 16000000
575endif
576
577ifneq (,$(filter $(MCU),atmega328))
578 # MCU name for avrdude
579 AVRDUDE_MCU = m328
580
581 PROTOCOL = VUSB
582
583 # Processor frequency.
584 # This will define a symbol, F_CPU, in all source code files equal to the
585 # processor frequency in Hz. You can then use this symbol in your source code to
586 # calculate timings. Do NOT tack on a 'UL' at the end, this will be done
587 # automatically to create a 32-bit value in your source code.
588 F_CPU ?= 16000000
589endif
590
591ifneq (,$(filter $(MCU),attiny85))
592 PROTOCOL = VUSB
593
594 # Processor frequency.
595 # This will define a symbol, F_CPU, in all source code files equal to the
596 # processor frequency in Hz. You can then use this symbol in your source code to
597 # calculate timings. Do NOT tack on a 'UL' at the end, this will be done
598 # automatically to create a 32-bit value in your source code.
599 F_CPU ?= 16500000
600endif
diff --git a/quantum/process_keycode/process_auto_shift.c b/quantum/process_keycode/process_auto_shift.c
index 51b0efdb4..cc3a974ea 100644
--- a/quantum/process_keycode/process_auto_shift.c
+++ b/quantum/process_keycode/process_auto_shift.c
@@ -21,6 +21,12 @@
21 21
22# include "process_auto_shift.h" 22# include "process_auto_shift.h"
23 23
24#ifndef AUTO_SHIFT_DISABLED_AT_STARTUP
25# define AUTO_SHIFT_STARTUP_STATE true /* enabled */
26#else
27# define AUTO_SHIFT_STARTUP_STATE false /* disabled */
28#endif
29
24static uint16_t autoshift_time = 0; 30static uint16_t autoshift_time = 0;
25static uint16_t autoshift_timeout = AUTO_SHIFT_TIMEOUT; 31static uint16_t autoshift_timeout = AUTO_SHIFT_TIMEOUT;
26static uint16_t autoshift_lastkey = KC_NO; 32static uint16_t autoshift_lastkey = KC_NO;
@@ -34,7 +40,7 @@ static struct {
34 bool in_progress : 1; 40 bool in_progress : 1;
35 // Whether the auto-shifted keypress has been registered. 41 // Whether the auto-shifted keypress has been registered.
36 bool holding_shift : 1; 42 bool holding_shift : 1;
37} autoshift_flags = {true, false, false, false}; 43} autoshift_flags = {AUTO_SHIFT_STARTUP_STATE, false, false, false};
38 44
39/** \brief Record the press of an autoshiftable key 45/** \brief Record the press of an autoshiftable key
40 * 46 *
diff --git a/quantum/process_keycode/process_combo.c b/quantum/process_keycode/process_combo.c
index e8661839c..a050161ed 100644
--- a/quantum/process_keycode/process_combo.c
+++ b/quantum/process_keycode/process_combo.c
@@ -18,10 +18,9 @@
18#include "process_combo.h" 18#include "process_combo.h"
19#include "action_tapping.h" 19#include "action_tapping.h"
20 20
21
22#ifdef COMBO_COUNT 21#ifdef COMBO_COUNT
23__attribute__((weak)) combo_t key_combos[COMBO_COUNT]; 22__attribute__((weak)) combo_t key_combos[COMBO_COUNT];
24uint16_t COMBO_LEN = COMBO_COUNT; 23uint16_t COMBO_LEN = COMBO_COUNT;
25#else 24#else
26extern combo_t key_combos[]; 25extern combo_t key_combos[];
27extern uint16_t COMBO_LEN; 26extern uint16_t COMBO_LEN;
@@ -46,64 +45,86 @@ __attribute__((weak)) bool process_combo_key_release(uint16_t combo_index, combo
46#endif 45#endif
47 46
48#ifndef COMBO_NO_TIMER 47#ifndef COMBO_NO_TIMER
49static uint16_t timer = 0; 48static uint16_t timer = 0;
50#endif 49#endif
51static bool b_combo_enable = true; // defaults to enabled 50static bool b_combo_enable = true; // defaults to enabled
52static uint16_t longest_term = 0; 51static uint16_t longest_term = 0;
53 52
54typedef struct { 53typedef struct {
55 keyrecord_t record; 54 keyrecord_t record;
56 uint16_t combo_index; 55 uint16_t combo_index;
57 uint16_t keycode; 56 uint16_t keycode;
58} queued_record_t; 57} queued_record_t;
59static uint8_t key_buffer_size = 0; 58static uint8_t key_buffer_size = 0;
60static queued_record_t key_buffer[COMBO_KEY_BUFFER_LENGTH]; 59static queued_record_t key_buffer[COMBO_KEY_BUFFER_LENGTH];
61 60
62typedef struct { 61typedef struct {
63 uint16_t combo_index; 62 uint16_t combo_index;
64} queued_combo_t; 63} queued_combo_t;
65static uint8_t combo_buffer_write= 0; 64static uint8_t combo_buffer_write = 0;
66static uint8_t combo_buffer_read = 0; 65static uint8_t combo_buffer_read = 0;
67static queued_combo_t combo_buffer[COMBO_BUFFER_LENGTH]; 66static queued_combo_t combo_buffer[COMBO_BUFFER_LENGTH];
68 67
69#define INCREMENT_MOD(i) i = (i + 1) % COMBO_BUFFER_LENGTH 68#define INCREMENT_MOD(i) i = (i + 1) % COMBO_BUFFER_LENGTH
70 69
71#define COMBO_KEY_POS ((keypos_t){.col=254, .row=254}) 70#define COMBO_KEY_POS ((keypos_t){.col = 254, .row = 254})
72
73 71
74#ifndef EXTRA_SHORT_COMBOS 72#ifndef EXTRA_SHORT_COMBOS
75/* flags are their own elements in combo_t struct. */ 73/* flags are their own elements in combo_t struct. */
76# define COMBO_ACTIVE(combo) (combo->active) 74# define COMBO_ACTIVE(combo) (combo->active)
77# define COMBO_DISABLED(combo) (combo->disabled) 75# define COMBO_DISABLED(combo) (combo->disabled)
78# define COMBO_STATE(combo) (combo->state) 76# define COMBO_STATE(combo) (combo->state)
79 77
80# define ACTIVATE_COMBO(combo) do {combo->active = true;}while(0) 78# define ACTIVATE_COMBO(combo) \
81# define DEACTIVATE_COMBO(combo) do {combo->active = false;}while(0) 79 do { \
82# define DISABLE_COMBO(combo) do {combo->disabled = true;}while(0) 80 combo->active = true; \
83# define RESET_COMBO_STATE(combo) do { \ 81 } while (0)
84 combo->disabled = false; \ 82# define DEACTIVATE_COMBO(combo) \
85 combo->state = 0; \ 83 do { \
86}while(0) 84 combo->active = false; \
85 } while (0)
86# define DISABLE_COMBO(combo) \
87 do { \
88 combo->disabled = true; \
89 } while (0)
90# define RESET_COMBO_STATE(combo) \
91 do { \
92 combo->disabled = false; \
93 combo->state = 0; \
94 } while (0)
87#else 95#else
88/* flags are at the two high bits of state. */ 96/* flags are at the two high bits of state. */
89# define COMBO_ACTIVE(combo) (combo->state & 0x80) 97# define COMBO_ACTIVE(combo) (combo->state & 0x80)
90# define COMBO_DISABLED(combo) (combo->state & 0x40) 98# define COMBO_DISABLED(combo) (combo->state & 0x40)
91# define COMBO_STATE(combo) (combo->state & 0x3F) 99# define COMBO_STATE(combo) (combo->state & 0x3F)
92 100
93# define ACTIVATE_COMBO(combo) do {combo->state |= 0x80;}while(0) 101# define ACTIVATE_COMBO(combo) \
94# define DEACTIVATE_COMBO(combo) do {combo->state &= ~0x80;}while(0) 102 do { \
95# define DISABLE_COMBO(combo) do {combo->state |= 0x40;}while(0) 103 combo->state |= 0x80; \
96# define RESET_COMBO_STATE(combo) do {combo->state &= ~0x7F;}while(0) 104 } while (0)
105# define DEACTIVATE_COMBO(combo) \
106 do { \
107 combo->state &= ~0x80; \
108 } while (0)
109# define DISABLE_COMBO(combo) \
110 do { \
111 combo->state |= 0x40; \
112 } while (0)
113# define RESET_COMBO_STATE(combo) \
114 do { \
115 combo->state &= ~0x7F; \
116 } while (0)
97#endif 117#endif
98 118
99static inline void release_combo(uint16_t combo_index, combo_t *combo) { 119static inline void release_combo(uint16_t combo_index, combo_t *combo) {
100 if (combo->keycode) { 120 if (combo->keycode) {
101 keyrecord_t record = { 121 keyrecord_t record = {
102 .event = { 122 .event =
103 .key = COMBO_KEY_POS, 123 {
104 .time = timer_read()|1, 124 .key = COMBO_KEY_POS,
105 .pressed = false, 125 .time = timer_read() | 1,
106 }, 126 .pressed = false,
127 },
107 .keycode = combo->keycode, 128 .keycode = combo->keycode,
108 }; 129 };
109#ifndef NO_ACTION_TAPPING 130#ifndef NO_ACTION_TAPPING
@@ -123,18 +144,17 @@ static inline bool _get_combo_must_hold(uint16_t combo_index, combo_t *combo) {
123#elif defined(COMBO_MUST_HOLD_PER_COMBO) 144#elif defined(COMBO_MUST_HOLD_PER_COMBO)
124 return get_combo_must_hold(combo_index, combo); 145 return get_combo_must_hold(combo_index, combo);
125#elif defined(COMBO_MUST_HOLD_MODS) 146#elif defined(COMBO_MUST_HOLD_MODS)
126 return (KEYCODE_IS_MOD(combo->keycode) || 147 return (KEYCODE_IS_MOD(combo->keycode) || (combo->keycode >= QK_MOMENTARY && combo->keycode <= QK_MOMENTARY_MAX));
127 (combo->keycode >= QK_MOMENTARY && combo->keycode <= QK_MOMENTARY_MAX));
128#endif 148#endif
129 return false; 149 return false;
130} 150}
131 151
132static inline uint16_t _get_wait_time(uint16_t combo_index, combo_t *combo ) { 152static inline uint16_t _get_wait_time(uint16_t combo_index, combo_t *combo) {
133 if (_get_combo_must_hold(combo_index, combo) 153 if (_get_combo_must_hold(combo_index, combo)
134#ifdef COMBO_MUST_TAP_PER_COMBO 154#ifdef COMBO_MUST_TAP_PER_COMBO
135 || get_combo_must_tap(combo_index, combo) 155 || get_combo_must_tap(combo_index, combo)
136#endif 156#endif
137 ) { 157 ) {
138 if (longest_term < COMBO_HOLD_TERM) { 158 if (longest_term < COMBO_HOLD_TERM) {
139 return COMBO_HOLD_TERM; 159 return COMBO_HOLD_TERM;
140 } 160 }
@@ -144,9 +164,8 @@ static inline uint16_t _get_wait_time(uint16_t combo_index, combo_t *combo ) {
144} 164}
145 165
146static inline uint16_t _get_combo_term(uint16_t combo_index, combo_t *combo) { 166static inline uint16_t _get_combo_term(uint16_t combo_index, combo_t *combo) {
147
148#if defined(COMBO_TERM_PER_COMBO) 167#if defined(COMBO_TERM_PER_COMBO)
149 return get_combo_term(combo_index, combo); 168 return get_combo_term(combo_index, combo);
150#endif 169#endif
151 170
152 return COMBO_TERM; 171 return COMBO_TERM;
@@ -154,7 +173,7 @@ static inline uint16_t _get_combo_term(uint16_t combo_index, combo_t *combo) {
154 173
155void clear_combos(void) { 174void clear_combos(void) {
156 uint16_t index = 0; 175 uint16_t index = 0;
157 longest_term = 0; 176 longest_term = 0;
158 for (index = 0; index < COMBO_LEN; ++index) { 177 for (index = 0; index < COMBO_LEN; ++index) {
159 combo_t *combo = &key_combos[index]; 178 combo_t *combo = &key_combos[index];
160 if (!COMBO_ACTIVE(combo)) { 179 if (!COMBO_ACTIVE(combo)) {
@@ -175,7 +194,7 @@ static inline void dump_key_buffer(void) {
175 key_buffer_next = key_buffer_i + 1; 194 key_buffer_next = key_buffer_i + 1;
176 195
177 queued_record_t *qrecord = &key_buffer[key_buffer_i]; 196 queued_record_t *qrecord = &key_buffer[key_buffer_i];
178 keyrecord_t *record = &qrecord->record; 197 keyrecord_t * record = &qrecord->record;
179 198
180 if (IS_NOEVENT(record->event)) { 199 if (IS_NOEVENT(record->event)) {
181 continue; 200 continue;
@@ -185,9 +204,9 @@ static inline void dump_key_buffer(void) {
185 process_combo_event(qrecord->combo_index, true); 204 process_combo_event(qrecord->combo_index, true);
186 } else { 205 } else {
187#ifndef NO_ACTION_TAPPING 206#ifndef NO_ACTION_TAPPING
188 action_tapping_process(*record); 207 action_tapping_process(*record);
189#else 208#else
190 process_record(record); 209 process_record(record);
191#endif 210#endif
192 } 211 }
193 record->event.time = 0; 212 record->event.time = 0;
@@ -242,7 +261,9 @@ void apply_combo(uint16_t combo_index, combo_t *combo) {
242 /* Apply combo's result keycode to the last chord key of the combo and 261 /* Apply combo's result keycode to the last chord key of the combo and
243 * disable the other keys. */ 262 * disable the other keys. */
244 263
245 if (COMBO_DISABLED(combo)) { return; } 264 if (COMBO_DISABLED(combo)) {
265 return;
266 }
246 267
247 // state to check against so we find the last key of the combo from the buffer 268 // state to check against so we find the last key of the combo from the buffer
248#if defined(EXTRA_EXTRA_LONG_COMBOS) 269#if defined(EXTRA_EXTRA_LONG_COMBOS)
@@ -254,12 +275,11 @@ void apply_combo(uint16_t combo_index, combo_t *combo) {
254#endif 275#endif
255 276
256 for (uint8_t key_buffer_i = 0; key_buffer_i < key_buffer_size; key_buffer_i++) { 277 for (uint8_t key_buffer_i = 0; key_buffer_i < key_buffer_size; key_buffer_i++) {
257
258 queued_record_t *qrecord = &key_buffer[key_buffer_i]; 278 queued_record_t *qrecord = &key_buffer[key_buffer_i];
259 keyrecord_t *record = &qrecord->record; 279 keyrecord_t * record = &qrecord->record;
260 uint16_t keycode = qrecord->keycode; 280 uint16_t keycode = qrecord->keycode;
261 281
262 uint8_t key_count = 0; 282 uint8_t key_count = 0;
263 uint16_t key_index = -1; 283 uint16_t key_index = -1;
264 _find_key_index_and_count(combo->keys, keycode, &key_index, &key_count); 284 _find_key_index_and_count(combo->keys, keycode, &key_index, &key_count);
265 285
@@ -271,7 +291,7 @@ void apply_combo(uint16_t combo_index, combo_t *combo) {
271 KEY_STATE_DOWN(state, key_index); 291 KEY_STATE_DOWN(state, key_index);
272 if (ALL_COMBO_KEYS_ARE_DOWN(state, key_count)) { 292 if (ALL_COMBO_KEYS_ARE_DOWN(state, key_count)) {
273 // this in the end executes the combo when the key_buffer is dumped. 293 // this in the end executes the combo when the key_buffer is dumped.
274 record->keycode = combo->keycode; 294 record->keycode = combo->keycode;
275 record->event.key = COMBO_KEY_POS; 295 record->event.key = COMBO_KEY_POS;
276 296
277 qrecord->combo_index = combo_index; 297 qrecord->combo_index = combo_index;
@@ -283,19 +303,15 @@ void apply_combo(uint16_t combo_index, combo_t *combo) {
283 // by making it a TICK event. 303 // by making it a TICK event.
284 record->event.time = 0; 304 record->event.time = 0;
285 } 305 }
286
287 } 306 }
288 drop_combo_from_buffer(combo_index); 307 drop_combo_from_buffer(combo_index);
289} 308}
290 309
291static inline void apply_combos(void) { 310static inline void apply_combos(void) {
292 // Apply all buffered normal combos. 311 // Apply all buffered normal combos.
293 for (uint8_t i = combo_buffer_read; 312 for (uint8_t i = combo_buffer_read; i != combo_buffer_write; INCREMENT_MOD(i)) {
294 i != combo_buffer_write;
295 INCREMENT_MOD(i)) {
296
297 queued_combo_t *buffered_combo = &combo_buffer[i]; 313 queued_combo_t *buffered_combo = &combo_buffer[i];
298 combo_t *combo = &key_combos[buffered_combo->combo_index]; 314 combo_t * combo = &key_combos[buffered_combo->combo_index];
299 315
300#ifdef COMBO_MUST_TAP_PER_COMBO 316#ifdef COMBO_MUST_TAP_PER_COMBO
301 if (get_combo_must_tap(buffered_combo->combo_index, combo)) { 317 if (get_combo_must_tap(buffered_combo->combo_index, combo)) {
@@ -310,15 +326,15 @@ static inline void apply_combos(void) {
310 clear_combos(); 326 clear_combos();
311} 327}
312 328
313combo_t* overlaps(combo_t *combo1, combo_t *combo2) { 329combo_t *overlaps(combo_t *combo1, combo_t *combo2) {
314 /* Checks if the combos overlap and returns the combo that should be 330 /* Checks if the combos overlap and returns the combo that should be
315 * dropped from the combo buffer. 331 * dropped from the combo buffer.
316 * The combo that has less keys will be dropped. If they have the same 332 * The combo that has less keys will be dropped. If they have the same
317 * amount of keys, drop combo1. */ 333 * amount of keys, drop combo1. */
318 334
319 uint8_t idx1 = 0, idx2 = 0; 335 uint8_t idx1 = 0, idx2 = 0;
320 uint16_t key1, key2; 336 uint16_t key1, key2;
321 bool overlaps = false; 337 bool overlaps = false;
322 338
323 while ((key1 = pgm_read_word(&combo1->keys[idx1])) != COMBO_END) { 339 while ((key1 = pgm_read_word(&combo1->keys[idx1])) != COMBO_END) {
324 idx2 = 0; 340 idx2 = 0;
@@ -335,7 +351,7 @@ combo_t* overlaps(combo_t *combo1, combo_t *combo2) {
335} 351}
336 352
337static bool process_single_combo(combo_t *combo, uint16_t keycode, keyrecord_t *record, uint16_t combo_index) { 353static bool process_single_combo(combo_t *combo, uint16_t keycode, keyrecord_t *record, uint16_t combo_index) {
338 uint8_t key_count = 0; 354 uint8_t key_count = 0;
339 uint16_t key_index = -1; 355 uint16_t key_index = -1;
340 _find_key_index_and_count(combo->keys, keycode, &key_index, &key_count); 356 _find_key_index_and_count(combo->keys, keycode, &key_index, &key_count);
341 357
@@ -369,12 +385,9 @@ static bool process_single_combo(combo_t *combo, uint16_t keycode, keyrecord_t *
369 385
370 // disable readied combos that overlap with this combo 386 // disable readied combos that overlap with this combo
371 combo_t *drop = NULL; 387 combo_t *drop = NULL;
372 for (uint8_t combo_buffer_i = combo_buffer_read; 388 for (uint8_t combo_buffer_i = combo_buffer_read; combo_buffer_i != combo_buffer_write; INCREMENT_MOD(combo_buffer_i)) {
373 combo_buffer_i != combo_buffer_write; 389 queued_combo_t *qcombo = &combo_buffer[combo_buffer_i];
374 INCREMENT_MOD(combo_buffer_i)) { 390 combo_t * buffered_combo = &key_combos[qcombo->combo_index];
375
376 queued_combo_t *qcombo = &combo_buffer[combo_buffer_i];
377 combo_t *buffered_combo = &key_combos[qcombo->combo_index];
378 391
379 if ((drop = overlaps(buffered_combo, combo))) { 392 if ((drop = overlaps(buffered_combo, combo))) {
380 DISABLE_COMBO(drop); 393 DISABLE_COMBO(drop);
@@ -387,21 +400,19 @@ static bool process_single_combo(combo_t *combo, uint16_t keycode, keyrecord_t *
387 INCREMENT_MOD(combo_buffer_read); 400 INCREMENT_MOD(combo_buffer_read);
388 } 401 }
389 } 402 }
390
391 } 403 }
392 404
393 if (drop != combo) { 405 if (drop != combo) {
394 // save this combo to buffer 406 // save this combo to buffer
395 combo_buffer[combo_buffer_write] = (queued_combo_t){ 407 combo_buffer[combo_buffer_write] = (queued_combo_t){
396 .combo_index=combo_index, 408 .combo_index = combo_index,
397 }; 409 };
398 INCREMENT_MOD(combo_buffer_write); 410 INCREMENT_MOD(combo_buffer_write);
399 411
400 // get possible longer waiting time for tap-/hold-only combos. 412 // get possible longer waiting time for tap-/hold-only combos.
401 longest_term = _get_wait_time(combo_index, combo); 413 longest_term = _get_wait_time(combo_index, combo);
402 } 414 }
403 } // if timer elapsed end 415 } // if timer elapsed end
404
405 } 416 }
406 } else { 417 } else {
407 // chord releases 418 // chord releases
@@ -416,7 +427,7 @@ static bool process_single_combo(combo_t *combo, uint16_t keycode, keyrecord_t *
416 else if (get_combo_must_tap(combo_index, combo)) { 427 else if (get_combo_must_tap(combo_index, combo)) {
417 // immediately apply tap-only combo 428 // immediately apply tap-only combo
418 apply_combo(combo_index, combo); 429 apply_combo(combo_index, combo);
419 apply_combos(); // also apply other prepared combos and dump key buffer 430 apply_combos(); // also apply other prepared combos and dump key buffer
420# ifdef COMBO_PROCESS_KEY_RELEASE 431# ifdef COMBO_PROCESS_KEY_RELEASE
421 if (process_combo_key_release(combo_index, combo, key_index, keycode)) { 432 if (process_combo_key_release(combo_index, combo, key_index, keycode)) {
422 release_combo(combo_index, combo); 433 release_combo(combo_index, combo);
@@ -424,10 +435,7 @@ static bool process_single_combo(combo_t *combo, uint16_t keycode, keyrecord_t *
424# endif 435# endif
425 } 436 }
426#endif 437#endif
427 } else if (COMBO_ACTIVE(combo) 438 } else if (COMBO_ACTIVE(combo) && ONLY_ONE_KEY_IS_DOWN(COMBO_STATE(combo)) && KEY_NOT_YET_RELEASED(COMBO_STATE(combo), key_index)) {
428 && ONLY_ONE_KEY_IS_DOWN(COMBO_STATE(combo))
429 && KEY_NOT_YET_RELEASED(COMBO_STATE(combo), key_index)
430 ) {
431 /* last key released */ 439 /* last key released */
432 release_combo(combo_index, combo); 440 release_combo(combo_index, combo);
433 key_is_part_of_combo = true; 441 key_is_part_of_combo = true;
@@ -435,9 +443,7 @@ static bool process_single_combo(combo_t *combo, uint16_t keycode, keyrecord_t *
435#ifdef COMBO_PROCESS_KEY_RELEASE 443#ifdef COMBO_PROCESS_KEY_RELEASE
436 process_combo_key_release(combo_index, combo, key_index, keycode); 444 process_combo_key_release(combo_index, combo, key_index, keycode);
437#endif 445#endif
438 } else if (COMBO_ACTIVE(combo) 446 } else if (COMBO_ACTIVE(combo) && KEY_NOT_YET_RELEASED(COMBO_STATE(combo), key_index)) {
439 && KEY_NOT_YET_RELEASED(COMBO_STATE(combo), key_index)
440 ) {
441 /* first or middle key released */ 447 /* first or middle key released */
442 key_is_part_of_combo = true; 448 key_is_part_of_combo = true;
443 449
@@ -489,21 +495,21 @@ bool process_combo(uint16_t keycode, keyrecord_t *record) {
489 495
490 if (record->event.pressed && is_combo_key) { 496 if (record->event.pressed && is_combo_key) {
491#ifndef COMBO_NO_TIMER 497#ifndef COMBO_NO_TIMER
492# ifdef COMBO_STRICT_TIMER 498# ifdef COMBO_STRICT_TIMER
493 if (!timer) { 499 if (!timer) {
494 // timer is set only on the first key 500 // timer is set only on the first key
495 timer = timer_read(); 501 timer = timer_read();
496 } 502 }
497# else 503# else
498 timer = timer_read(); 504 timer = timer_read();
499# endif 505# endif
500#endif 506#endif
501 507
502 if (key_buffer_size < COMBO_KEY_BUFFER_LENGTH) { 508 if (key_buffer_size < COMBO_KEY_BUFFER_LENGTH) {
503 key_buffer[key_buffer_size++] = (queued_record_t){ 509 key_buffer[key_buffer_size++] = (queued_record_t){
504 .record = *record, 510 .record = *record,
505 .keycode = keycode, 511 .keycode = keycode,
506 .combo_index = -1, // this will be set when applying combos 512 .combo_index = -1, // this will be set when applying combos
507 }; 513 };
508 } 514 }
509 } else { 515 } else {
@@ -532,7 +538,7 @@ void combo_task(void) {
532 if (combo_buffer_read != combo_buffer_write) { 538 if (combo_buffer_read != combo_buffer_write) {
533 apply_combos(); 539 apply_combos();
534 longest_term = 0; 540 longest_term = 0;
535 timer = 0; 541 timer = 0;
536 } else { 542 } else {
537 dump_key_buffer(); 543 dump_key_buffer();
538 timer = 0; 544 timer = 0;
@@ -546,9 +552,9 @@ void combo_enable(void) { b_combo_enable = true; }
546 552
547void combo_disable(void) { 553void combo_disable(void) {
548#ifndef COMBO_NO_TIMER 554#ifndef COMBO_NO_TIMER
549 timer = 0; 555 timer = 0;
550#endif 556#endif
551 b_combo_enable = false; 557 b_combo_enable = false;
552 combo_buffer_read = combo_buffer_write; 558 combo_buffer_read = combo_buffer_write;
553 clear_combos(); 559 clear_combos();
554 dump_key_buffer(); 560 dump_key_buffer();
diff --git a/quantum/process_keycode/process_combo.h b/quantum/process_keycode/process_combo.h
index 43c36d79e..4c4e574e3 100644
--- a/quantum/process_keycode/process_combo.h
+++ b/quantum/process_keycode/process_combo.h
@@ -43,8 +43,8 @@ typedef struct {
43#ifdef EXTRA_SHORT_COMBOS 43#ifdef EXTRA_SHORT_COMBOS
44 uint8_t state; 44 uint8_t state;
45#else 45#else
46 bool disabled; 46 bool disabled;
47 bool active; 47 bool active;
48# if defined(EXTRA_EXTRA_LONG_COMBOS) 48# if defined(EXTRA_EXTRA_LONG_COMBOS)
49 uint32_t state; 49 uint32_t state;
50# elif defined(EXTRA_LONG_COMBOS) 50# elif defined(EXTRA_LONG_COMBOS)
diff --git a/quantum/process_keycode/process_haptic.c b/quantum/process_keycode/process_haptic.c
index 64d455d00..1b9c2f24f 100644
--- a/quantum/process_keycode/process_haptic.c
+++ b/quantum/process_keycode/process_haptic.c
@@ -32,6 +32,7 @@ __attribute__((weak)) bool get_haptic_enabled_key(uint16_t keycode, keyrecord_t
32 break; 32 break;
33 case KC_LCTRL ... KC_RGUI: 33 case KC_LCTRL ... KC_RGUI:
34 case QK_MOMENTARY ... QK_MOMENTARY_MAX: 34 case QK_MOMENTARY ... QK_MOMENTARY_MAX:
35 case QK_LAYER_MOD ... QK_LAYER_MOD_MAX:
35#endif 36#endif
36#ifdef NO_HAPTIC_FN 37#ifdef NO_HAPTIC_FN
37 case KC_FN0 ... KC_FN31: 38 case KC_FN0 ... KC_FN31:
diff --git a/quantum/process_keycode/process_programmable_button.c b/quantum/process_keycode/process_programmable_button.c
new file mode 100644
index 000000000..c6e77faac
--- /dev/null
+++ b/quantum/process_keycode/process_programmable_button.c
@@ -0,0 +1,31 @@
1/*
2Copyright 2021 Thomas Weißschuh <thomas@t-8ch.de>
3
4This program is free software: you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation, either version 2 of the License, or
7(at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program. If not, see <http://www.gnu.org/licenses/>.
16*/
17
18#include "process_programmable_button.h"
19#include "programmable_button.h"
20
21bool process_programmable_button(uint16_t keycode, keyrecord_t *record) {
22 if (keycode >= PROGRAMMABLE_BUTTON_MIN && keycode <= PROGRAMMABLE_BUTTON_MAX) {
23 uint8_t button = keycode - PROGRAMMABLE_BUTTON_MIN + 1;
24 if (record->event.pressed) {
25 programmable_button_on(button);
26 } else {
27 programmable_button_off(button);
28 }
29 }
30 return true;
31}
diff --git a/quantum/process_keycode/process_programmable_button.h b/quantum/process_keycode/process_programmable_button.h
new file mode 100644
index 000000000..47c6ce561
--- /dev/null
+++ b/quantum/process_keycode/process_programmable_button.h
@@ -0,0 +1,23 @@
1/*
2Copyright 2021 Thomas Weißschuh <thomas@t-8ch.de>
3
4This program is free software: you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation, either version 2 of the License, or
7(at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program. If not, see <http://www.gnu.org/licenses/>.
16*/
17
18#pragma once
19
20#include <stdint.h>
21#include "quantum.h"
22
23bool process_programmable_button(uint16_t keycode, keyrecord_t *record);
diff --git a/quantum/process_keycode/process_steno.c b/quantum/process_keycode/process_steno.c
index a964aead3..5d0bb313b 100644
--- a/quantum/process_keycode/process_steno.c
+++ b/quantum/process_keycode/process_steno.c
@@ -67,7 +67,7 @@ static const uint8_t boltmap[64] PROGMEM = {TXB_NUL, TXB_NUM, TXB_NUM, TXB_NUM,
67 67
68#ifdef STENO_COMBINEDMAP 68#ifdef STENO_COMBINEDMAP
69/* Used to look up when pressing the middle row key to combine two consonant or vowel keys */ 69/* Used to look up when pressing the middle row key to combine two consonant or vowel keys */
70static const uint16_t combinedmap_first[] PROGMEM = {STN_S1, STN_TL, STN_PL, STN_HL, STN_FR, STN_PR, STN_LR, STN_TR, STN_DR, STN_A, STN_E}; 70static const uint16_t combinedmap_first[] PROGMEM = {STN_S1, STN_TL, STN_PL, STN_HL, STN_FR, STN_PR, STN_LR, STN_TR, STN_DR, STN_A, STN_E};
71static const uint16_t combinedmap_second[] PROGMEM = {STN_S2, STN_KL, STN_WL, STN_RL, STN_RR, STN_BR, STN_GR, STN_SR, STN_ZR, STN_O, STN_U}; 71static const uint16_t combinedmap_second[] PROGMEM = {STN_S2, STN_KL, STN_WL, STN_RL, STN_RR, STN_BR, STN_GR, STN_SR, STN_ZR, STN_O, STN_U};
72#endif 72#endif
73 73
@@ -174,11 +174,10 @@ bool process_steno(uint16_t keycode, keyrecord_t *record) {
174 return false; 174 return false;
175 175
176#ifdef STENO_COMBINEDMAP 176#ifdef STENO_COMBINEDMAP
177 case QK_STENO_COMB ... QK_STENO_COMB_MAX: 177 case QK_STENO_COMB ... QK_STENO_COMB_MAX: {
178 {
179 uint8_t result; 178 uint8_t result;
180 result = process_steno(combinedmap_first[keycode-QK_STENO_COMB], record); 179 result = process_steno(combinedmap_first[keycode - QK_STENO_COMB], record);
181 result &= process_steno(combinedmap_second[keycode-QK_STENO_COMB], record); 180 result &= process_steno(combinedmap_second[keycode - QK_STENO_COMB], record);
182 return result; 181 return result;
183 } 182 }
184#endif 183#endif
diff --git a/quantum/process_keycode/process_unicode_common.c b/quantum/process_keycode/process_unicode_common.c
index 46fcaaa86..7853c22c5 100644
--- a/quantum/process_keycode/process_unicode_common.c
+++ b/quantum/process_keycode/process_unicode_common.c
@@ -22,6 +22,7 @@
22unicode_config_t unicode_config; 22unicode_config_t unicode_config;
23uint8_t unicode_saved_mods; 23uint8_t unicode_saved_mods;
24bool unicode_saved_caps_lock; 24bool unicode_saved_caps_lock;
25bool unicode_saved_num_lock;
25 26
26#if UNICODE_SELECTED_MODES != -1 27#if UNICODE_SELECTED_MODES != -1
27static uint8_t selected[] = {UNICODE_SELECTED_MODES}; 28static uint8_t selected[] = {UNICODE_SELECTED_MODES};
@@ -79,13 +80,14 @@ void persist_unicode_input_mode(void) { eeprom_update_byte(EECONFIG_UNICODEMODE,
79 80
80__attribute__((weak)) void unicode_input_start(void) { 81__attribute__((weak)) void unicode_input_start(void) {
81 unicode_saved_caps_lock = host_keyboard_led_state().caps_lock; 82 unicode_saved_caps_lock = host_keyboard_led_state().caps_lock;
83 unicode_saved_num_lock = host_keyboard_led_state().num_lock;
82 84
83 // Note the order matters here! 85 // Note the order matters here!
84 // Need to do this before we mess around with the mods, or else 86 // Need to do this before we mess around with the mods, or else
85 // UNICODE_KEY_LNX (which is usually Ctrl-Shift-U) might not work 87 // UNICODE_KEY_LNX (which is usually Ctrl-Shift-U) might not work
86 // correctly in the shifted case. 88 // correctly in the shifted case.
87 if (unicode_config.input_mode == UC_LNX && unicode_saved_caps_lock) { 89 if (unicode_config.input_mode == UC_LNX && unicode_saved_caps_lock) {
88 tap_code(KC_CAPS); 90 tap_code(KC_CAPSLOCK);
89 } 91 }
90 92
91 unicode_saved_mods = get_mods(); // Save current mods 93 unicode_saved_mods = get_mods(); // Save current mods
@@ -99,8 +101,12 @@ __attribute__((weak)) void unicode_input_start(void) {
99 tap_code16(UNICODE_KEY_LNX); 101 tap_code16(UNICODE_KEY_LNX);
100 break; 102 break;
101 case UC_WIN: 103 case UC_WIN:
104 // For increased reliability, use numpad keys for inputting digits
105 if (!unicode_saved_num_lock) {
106 tap_code(KC_NUMLOCK);
107 }
102 register_code(KC_LALT); 108 register_code(KC_LALT);
103 tap_code(KC_PPLS); 109 tap_code(KC_KP_PLUS);
104 break; 110 break;
105 case UC_WINC: 111 case UC_WINC:
106 tap_code(UNICODE_KEY_WINC); 112 tap_code(UNICODE_KEY_WINC);
@@ -117,13 +123,16 @@ __attribute__((weak)) void unicode_input_finish(void) {
117 unregister_code(UNICODE_KEY_MAC); 123 unregister_code(UNICODE_KEY_MAC);
118 break; 124 break;
119 case UC_LNX: 125 case UC_LNX:
120 tap_code(KC_SPC); 126 tap_code(KC_SPACE);
121 if (unicode_saved_caps_lock) { 127 if (unicode_saved_caps_lock) {
122 tap_code(KC_CAPS); 128 tap_code(KC_CAPSLOCK);
123 } 129 }
124 break; 130 break;
125 case UC_WIN: 131 case UC_WIN:
126 unregister_code(KC_LALT); 132 unregister_code(KC_LALT);
133 if (!unicode_saved_num_lock) {
134 tap_code(KC_NUMLOCK);
135 }
127 break; 136 break;
128 case UC_WINC: 137 case UC_WINC:
129 tap_code(KC_ENTER); 138 tap_code(KC_ENTER);
@@ -139,26 +148,44 @@ __attribute__((weak)) void unicode_input_cancel(void) {
139 unregister_code(UNICODE_KEY_MAC); 148 unregister_code(UNICODE_KEY_MAC);
140 break; 149 break;
141 case UC_LNX: 150 case UC_LNX:
142 tap_code(KC_ESC); 151 tap_code(KC_ESCAPE);
143 if (unicode_saved_caps_lock) { 152 if (unicode_saved_caps_lock) {
144 tap_code(KC_CAPS); 153 tap_code(KC_CAPSLOCK);
145 } 154 }
146 break; 155 break;
147 case UC_WINC: 156 case UC_WINC:
148 tap_code(KC_ESC); 157 tap_code(KC_ESCAPE);
149 break; 158 break;
150 case UC_WIN: 159 case UC_WIN:
151 unregister_code(KC_LALT); 160 unregister_code(KC_LALT);
161 if (!unicode_saved_num_lock) {
162 tap_code(KC_NUMLOCK);
163 }
152 break; 164 break;
153 } 165 }
154 166
155 set_mods(unicode_saved_mods); // Reregister previously set mods 167 set_mods(unicode_saved_mods); // Reregister previously set mods
156} 168}
157 169
170// clang-format off
171
172static void send_nibble_wrapper(uint8_t digit) {
173 if (unicode_config.input_mode == UC_WIN) {
174 uint8_t kc = digit < 10
175 ? KC_KP_1 + (10 + digit - 1) % 10
176 : KC_A + (digit - 10);
177 tap_code(kc);
178 return;
179 }
180 send_nibble(digit);
181}
182
183// clang-format on
184
158void register_hex(uint16_t hex) { 185void register_hex(uint16_t hex) {
159 for (int i = 3; i >= 0; i--) { 186 for (int i = 3; i >= 0; i--) {
160 uint8_t digit = ((hex >> (i * 4)) & 0xF); 187 uint8_t digit = ((hex >> (i * 4)) & 0xF);
161 send_nibble(digit); 188 send_nibble_wrapper(digit);
162 } 189 }
163} 190}
164 191
@@ -171,10 +198,10 @@ void register_hex32(uint32_t hex) {
171 uint8_t digit = ((hex >> (i * 4)) & 0xF); 198 uint8_t digit = ((hex >> (i * 4)) & 0xF);
172 if (digit == 0) { 199 if (digit == 0) {
173 if (!onzerostart) { 200 if (!onzerostart) {
174 send_nibble(digit); 201 send_nibble_wrapper(digit);
175 } 202 }
176 } else { 203 } else {
177 send_nibble(digit); 204 send_nibble_wrapper(digit);
178 onzerostart = false; 205 onzerostart = false;
179 } 206 }
180 } 207 }
diff --git a/quantum/programmable_button.c b/quantum/programmable_button.c
new file mode 100644
index 000000000..be828fd17
--- /dev/null
+++ b/quantum/programmable_button.c
@@ -0,0 +1,37 @@
1/*
2Copyright 2021 Thomas Weißschuh <thomas@t-8ch.de>
3
4This program is free software: you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation, either version 2 of the License, or
7(at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program. If not, see <http://www.gnu.org/licenses/>.
16*/
17
18#include "programmable_button.h"
19#include "host.h"
20
21#define REPORT_BIT(index) (((uint32_t)1) << (index - 1))
22
23static uint32_t programmable_button_report = 0;
24
25void programmable_button_clear(void) { programmable_button_report = 0; }
26
27void programmable_button_send(void) { host_programmable_button_send(programmable_button_report); }
28
29void programmable_button_on(uint8_t index) { programmable_button_report |= REPORT_BIT(index); }
30
31void programmable_button_off(uint8_t index) { programmable_button_report &= ~REPORT_BIT(index); }
32
33bool programmable_button_is_on(uint8_t index) { return !!(programmable_button_report & REPORT_BIT(index)); };
34
35uint32_t programmable_button_get_report(void) { return programmable_button_report; };
36
37void programmable_button_set_report(uint32_t report) { programmable_button_report = report; }
diff --git a/quantum/programmable_button.h b/quantum/programmable_button.h
new file mode 100644
index 000000000..e89b8b9fd
--- /dev/null
+++ b/quantum/programmable_button.h
@@ -0,0 +1,30 @@
1/*
2Copyright 2021 Thomas Weißschuh <thomas@t-8ch.de>
3
4This program is free software: you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation, either version 2 of the License, or
7(at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program. If not, see <http://www.gnu.org/licenses/>.
16*/
17
18#pragma once
19
20#include <stdint.h>
21#include <stdbool.h>
22#include "report.h"
23
24void programmable_button_clear(void);
25void programmable_button_send(void);
26void programmable_button_on(uint8_t index);
27void programmable_button_off(uint8_t index);
28bool programmable_button_is_on(uint8_t index);
29uint32_t programmable_button_get_report(void);
30void programmable_button_set_report(uint32_t report);
diff --git a/quantum/quantum.c b/quantum/quantum.c
index e60378afe..ac8857df8 100644
--- a/quantum/quantum.c
+++ b/quantum/quantum.c
@@ -25,10 +25,6 @@
25# include "backlight.h" 25# include "backlight.h"
26#endif 26#endif
27 27
28#ifdef API_ENABLE
29# include "api.h"
30#endif
31
32#ifdef MIDI_ENABLE 28#ifdef MIDI_ENABLE
33# include "process_midi.h" 29# include "process_midi.h"
34#endif 30#endif
@@ -145,12 +141,13 @@ void reset_keyboard(void) {
145/* Convert record into usable keycode via the contained event. */ 141/* Convert record into usable keycode via the contained event. */
146uint16_t get_record_keycode(keyrecord_t *record, bool update_layer_cache) { 142uint16_t get_record_keycode(keyrecord_t *record, bool update_layer_cache) {
147#ifdef COMBO_ENABLE 143#ifdef COMBO_ENABLE
148 if (record->keycode) { return record->keycode; } 144 if (record->keycode) {
145 return record->keycode;
146 }
149#endif 147#endif
150 return get_event_keycode(record->event, update_layer_cache); 148 return get_event_keycode(record->event, update_layer_cache);
151} 149}
152 150
153
154/* Convert event into usable keycode. Checks the layer cache to ensure that it 151/* Convert event into usable keycode. Checks the layer cache to ensure that it
155 * retains the correct keycode after a layer change, if the key is still pressed. 152 * retains the correct keycode after a layer change, if the key is still pressed.
156 * "update_layer_cache" is to ensure that it only updates the layer cache when 153 * "update_layer_cache" is to ensure that it only updates the layer cache when
@@ -179,12 +176,12 @@ uint16_t get_event_keycode(keyevent_t event, bool update_layer_cache) {
179bool pre_process_record_quantum(keyrecord_t *record) { 176bool pre_process_record_quantum(keyrecord_t *record) {
180 if (!( 177 if (!(
181#ifdef COMBO_ENABLE 178#ifdef COMBO_ENABLE
182 process_combo(get_record_keycode(record, true), record) && 179 process_combo(get_record_keycode(record, true), record) &&
183#endif 180#endif
184 true)) { 181 true)) {
185 return false; 182 return false;
186 } 183 }
187 return true; // continue processing 184 return true; // continue processing
188} 185}
189 186
190/* Get keycode, and then call keyboard function */ 187/* Get keycode, and then call keyboard function */
@@ -296,6 +293,9 @@ bool process_record_quantum(keyrecord_t *record) {
296#ifdef JOYSTICK_ENABLE 293#ifdef JOYSTICK_ENABLE
297 process_joystick(keycode, record) && 294 process_joystick(keycode, record) &&
298#endif 295#endif
296#ifdef PROGRAMMABLE_BUTTON_ENABLE
297 process_programmable_button(keycode, record) &&
298#endif
299 true)) { 299 true)) {
300 return false; 300 return false;
301 } 301 }
@@ -465,14 +465,6 @@ void matrix_scan_quantum() {
465# include "hd44780.h" 465# include "hd44780.h"
466#endif 466#endif
467 467
468void api_send_unicode(uint32_t unicode) {
469#ifdef API_ENABLE
470 uint8_t chunk[4];
471 dword_to_bytes(unicode, chunk);
472 MT_SEND_DATA(DT_UNICODE, chunk, 5);
473#endif
474}
475
476//------------------------------------------------------------------------------ 468//------------------------------------------------------------------------------
477// Override these functions in your keymap file to play different tunes on 469// Override these functions in your keymap file to play different tunes on
478// different events such as startup and bootloader jump 470// different events such as startup and bootloader jump
@@ -480,3 +472,99 @@ void api_send_unicode(uint32_t unicode) {
480__attribute__((weak)) void startup_user() {} 472__attribute__((weak)) void startup_user() {}
481 473
482__attribute__((weak)) void shutdown_user() {} 474__attribute__((weak)) void shutdown_user() {}
475
476/** \brief Run keyboard level Power down
477 *
478 * FIXME: needs doc
479 */
480__attribute__((weak)) void suspend_power_down_user(void) {}
481/** \brief Run keyboard level Power down
482 *
483 * FIXME: needs doc
484 */
485__attribute__((weak)) void suspend_power_down_kb(void) { suspend_power_down_user(); }
486
487void suspend_power_down_quantum(void) {
488#ifndef NO_SUSPEND_POWER_DOWN
489// Turn off backlight
490# ifdef BACKLIGHT_ENABLE
491 backlight_set(0);
492# endif
493
494# ifdef LED_MATRIX_ENABLE
495 led_matrix_task();
496# endif
497# ifdef RGB_MATRIX_ENABLE
498 rgb_matrix_task();
499# endif
500
501 // Turn off LED indicators
502 uint8_t leds_off = 0;
503# if defined(BACKLIGHT_CAPS_LOCK) && defined(BACKLIGHT_ENABLE)
504 if (is_backlight_enabled()) {
505 // Don't try to turn off Caps Lock indicator as it is backlight and backlight is already off
506 leds_off |= (1 << USB_LED_CAPS_LOCK);
507 }
508# endif
509 led_set(leds_off);
510
511// Turn off audio
512# ifdef AUDIO_ENABLE
513 stop_all_notes();
514# endif
515
516// Turn off underglow
517# if defined(RGBLIGHT_SLEEP) && defined(RGBLIGHT_ENABLE)
518 rgblight_suspend();
519# endif
520
521# if defined(LED_MATRIX_ENABLE)
522 led_matrix_set_suspend_state(true);
523# endif
524# if defined(RGB_MATRIX_ENABLE)
525 rgb_matrix_set_suspend_state(true);
526# endif
527
528# ifdef OLED_ENABLE
529 oled_off();
530# endif
531# ifdef ST7565_ENABLE
532 st7565_off();
533# endif
534#endif
535}
536
537/** \brief run user level code immediately after wakeup
538 *
539 * FIXME: needs doc
540 */
541__attribute__((weak)) void suspend_wakeup_init_user(void) {}
542
543/** \brief run keyboard level code immediately after wakeup
544 *
545 * FIXME: needs doc
546 */
547__attribute__((weak)) void suspend_wakeup_init_kb(void) { suspend_wakeup_init_user(); }
548
549__attribute__((weak)) void suspend_wakeup_init_quantum(void) {
550// Turn on backlight
551#ifdef BACKLIGHT_ENABLE
552 backlight_init();
553#endif
554
555 // Restore LED indicators
556 led_set(host_keyboard_leds());
557
558// Wake up underglow
559#if defined(RGBLIGHT_SLEEP) && defined(RGBLIGHT_ENABLE)
560 rgblight_wakeup();
561#endif
562
563#if defined(LED_MATRIX_ENABLE)
564 led_matrix_set_suspend_state(false);
565#endif
566#if defined(RGB_MATRIX_ENABLE)
567 rgb_matrix_set_suspend_state(false);
568#endif
569 suspend_wakeup_init_kb();
570}
diff --git a/quantum/quantum.h b/quantum/quantum.h
index 86b717e44..9250f5acc 100644
--- a/quantum/quantum.h
+++ b/quantum/quantum.h
@@ -147,6 +147,10 @@ extern layer_state_t layer_state;
147# include "process_joystick.h" 147# include "process_joystick.h"
148#endif 148#endif
149 149
150#ifdef PROGRAMMABLE_BUTTON_ENABLE
151# include "process_programmable_button.h"
152#endif
153
150#ifdef GRAVE_ESC_ENABLE 154#ifdef GRAVE_ESC_ENABLE
151# include "process_grave_esc.h" 155# include "process_grave_esc.h"
152#endif 156#endif
@@ -233,5 +237,3 @@ void led_set_user(uint8_t usb_led);
233void led_set_kb(uint8_t usb_led); 237void led_set_kb(uint8_t usb_led);
234bool led_update_user(led_t led_state); 238bool led_update_user(led_t led_state);
235bool led_update_kb(led_t led_state); 239bool led_update_kb(led_t led_state);
236
237void api_send_unicode(uint32_t unicode);
diff --git a/quantum/quantum_keycodes.h b/quantum/quantum_keycodes.h
index ef4b0f457..373a31a00 100644
--- a/quantum/quantum_keycodes.h
+++ b/quantum/quantum_keycodes.h
@@ -524,6 +524,40 @@ enum quantum_keycodes {
524 // Additional magic key 524 // Additional magic key
525 MAGIC_TOGGLE_GUI, 525 MAGIC_TOGGLE_GUI,
526 526
527 // Programmable Button
528 PROGRAMMABLE_BUTTON_1,
529 PROGRAMMABLE_BUTTON_2,
530 PROGRAMMABLE_BUTTON_3,
531 PROGRAMMABLE_BUTTON_4,
532 PROGRAMMABLE_BUTTON_5,
533 PROGRAMMABLE_BUTTON_6,
534 PROGRAMMABLE_BUTTON_7,
535 PROGRAMMABLE_BUTTON_8,
536 PROGRAMMABLE_BUTTON_9,
537 PROGRAMMABLE_BUTTON_10,
538 PROGRAMMABLE_BUTTON_11,
539 PROGRAMMABLE_BUTTON_12,
540 PROGRAMMABLE_BUTTON_13,
541 PROGRAMMABLE_BUTTON_14,
542 PROGRAMMABLE_BUTTON_15,
543 PROGRAMMABLE_BUTTON_16,
544 PROGRAMMABLE_BUTTON_17,
545 PROGRAMMABLE_BUTTON_18,
546 PROGRAMMABLE_BUTTON_19,
547 PROGRAMMABLE_BUTTON_20,
548 PROGRAMMABLE_BUTTON_21,
549 PROGRAMMABLE_BUTTON_22,
550 PROGRAMMABLE_BUTTON_23,
551 PROGRAMMABLE_BUTTON_24,
552 PROGRAMMABLE_BUTTON_25,
553 PROGRAMMABLE_BUTTON_26,
554 PROGRAMMABLE_BUTTON_27,
555 PROGRAMMABLE_BUTTON_28,
556 PROGRAMMABLE_BUTTON_29,
557 PROGRAMMABLE_BUTTON_30,
558 PROGRAMMABLE_BUTTON_31,
559 PROGRAMMABLE_BUTTON_32,
560
527 // Start of custom keycode range for keyboards and keymaps - always leave at the end 561 // Start of custom keycode range for keyboards and keymaps - always leave at the end
528 SAFE_RANGE 562 SAFE_RANGE
529}; 563};
@@ -775,12 +809,12 @@ enum quantum_keycodes {
775#define CMD_T(kc) LCMD_T(kc) 809#define CMD_T(kc) LCMD_T(kc)
776#define WIN_T(kc) LWIN_T(kc) 810#define WIN_T(kc) LWIN_T(kc)
777 811
778#define C_S_T(kc) MT(MOD_LCTL | MOD_LSFT, kc) // Left Control + Shift e.g. for gnome-terminal 812#define C_S_T(kc) MT(MOD_LCTL | MOD_LSFT, kc) // Left Control + Shift e.g. for gnome-terminal
779#define MEH_T(kc) MT(MOD_LCTL | MOD_LSFT | MOD_LALT, kc) // Meh is a less hyper version of the Hyper key -- doesn't include GUI, so just Left Control + Shift + Alt 813#define MEH_T(kc) MT(MOD_LCTL | MOD_LSFT | MOD_LALT, kc) // Meh is a less hyper version of the Hyper key -- doesn't include GUI, so just Left Control + Shift + Alt
780#define LCAG_T(kc) MT(MOD_LCTL | MOD_LALT | MOD_LGUI, kc) // Left Control + Alt + GUI 814#define LCAG_T(kc) MT(MOD_LCTL | MOD_LALT | MOD_LGUI, kc) // Left Control + Alt + GUI
781#define RCAG_T(kc) MT(MOD_RCTL | MOD_RALT | MOD_RGUI, kc) // Right Control + Alt + GUI 815#define RCAG_T(kc) MT(MOD_RCTL | MOD_RALT | MOD_RGUI, kc) // Right Control + Alt + GUI
782#define HYPR_T(kc) MT(MOD_LCTL | MOD_LSFT | MOD_LALT | MOD_LGUI, kc) // see http://brettterpstra.com/2012/12/08/a-useful-caps-lock-key/ 816#define HYPR_T(kc) MT(MOD_LCTL | MOD_LSFT | MOD_LALT | MOD_LGUI, kc) // see http://brettterpstra.com/2012/12/08/a-useful-caps-lock-key/
783#define LSG_T(kc) MT(MOD_LSFT | MOD_LGUI, kc) // Left Shift + GUI 817#define LSG_T(kc) MT(MOD_LSFT | MOD_LGUI, kc) // Left Shift + GUI
784#define SGUI_T(kc) LSG_T(kc) 818#define SGUI_T(kc) LSG_T(kc)
785#define SCMD_T(kc) LSG_T(kc) 819#define SCMD_T(kc) LSG_T(kc)
786#define SWIN_T(kc) LSG_T(kc) 820#define SWIN_T(kc) LSG_T(kc)
@@ -811,7 +845,7 @@ enum quantum_keycodes {
811 845
812#define UC_M_MA UNICODE_MODE_MAC 846#define UC_M_MA UNICODE_MODE_MAC
813#define UNICODE_MODE_OSX UNICODE_MODE_MAC // Deprecated alias 847#define UNICODE_MODE_OSX UNICODE_MODE_MAC // Deprecated alias
814#define UC_M_OS UNICODE_MODE_MAC // Deprecated alias 848#define UC_M_OS UNICODE_MODE_MAC // Deprecated alias
815#define UC_M_LN UNICODE_MODE_LNX 849#define UC_M_LN UNICODE_MODE_LNX
816#define UC_M_WI UNICODE_MODE_WIN 850#define UC_M_WI UNICODE_MODE_WIN
817#define UC_M_BS UNICODE_MODE_BSD 851#define UC_M_BS UNICODE_MODE_BSD
@@ -854,3 +888,39 @@ enum quantum_keycodes {
854#define OS_TOGG ONESHOT_TOGGLE 888#define OS_TOGG ONESHOT_TOGGLE
855#define OS_ON ONESHOT_ENABLE 889#define OS_ON ONESHOT_ENABLE
856#define OS_OFF ONESHOT_DISABLE 890#define OS_OFF ONESHOT_DISABLE
891
892// Programmable Button aliases
893#define PB_1 PROGRAMMABLE_BUTTON_1
894#define PB_2 PROGRAMMABLE_BUTTON_2
895#define PB_3 PROGRAMMABLE_BUTTON_3
896#define PB_4 PROGRAMMABLE_BUTTON_4
897#define PB_5 PROGRAMMABLE_BUTTON_5
898#define PB_6 PROGRAMMABLE_BUTTON_6
899#define PB_7 PROGRAMMABLE_BUTTON_7
900#define PB_8 PROGRAMMABLE_BUTTON_8
901#define PB_9 PROGRAMMABLE_BUTTON_9
902#define PB_10 PROGRAMMABLE_BUTTON_10
903#define PB_11 PROGRAMMABLE_BUTTON_11
904#define PB_12 PROGRAMMABLE_BUTTON_12
905#define PB_13 PROGRAMMABLE_BUTTON_13
906#define PB_14 PROGRAMMABLE_BUTTON_14
907#define PB_15 PROGRAMMABLE_BUTTON_15
908#define PB_16 PROGRAMMABLE_BUTTON_16
909#define PB_17 PROGRAMMABLE_BUTTON_17
910#define PB_18 PROGRAMMABLE_BUTTON_18
911#define PB_19 PROGRAMMABLE_BUTTON_19
912#define PB_20 PROGRAMMABLE_BUTTON_20
913#define PB_21 PROGRAMMABLE_BUTTON_21
914#define PB_22 PROGRAMMABLE_BUTTON_22
915#define PB_23 PROGRAMMABLE_BUTTON_23
916#define PB_24 PROGRAMMABLE_BUTTON_24
917#define PB_25 PROGRAMMABLE_BUTTON_25
918#define PB_26 PROGRAMMABLE_BUTTON_26
919#define PB_27 PROGRAMMABLE_BUTTON_27
920#define PB_28 PROGRAMMABLE_BUTTON_28
921#define PB_29 PROGRAMMABLE_BUTTON_29
922#define PB_30 PROGRAMMABLE_BUTTON_30
923#define PB_31 PROGRAMMABLE_BUTTON_31
924#define PB_32 PROGRAMMABLE_BUTTON_32
925#define PROGRAMMABLE_BUTTON_MIN PROGRAMMABLE_BUTTON_1
926#define PROGRAMMABLE_BUTTON_MAX PROGRAMMABLE_BUTTON_32
diff --git a/quantum/raw_hid.h b/quantum/raw_hid.h
new file mode 100644
index 000000000..6d60ab2bf
--- /dev/null
+++ b/quantum/raw_hid.h
@@ -0,0 +1,5 @@
1#pragma once
2
3void raw_hid_receive(uint8_t *data, uint8_t length);
4
5void raw_hid_send(uint8_t *data, uint8_t length);
diff --git a/quantum/rgb_matrix/animations/alpha_mods_anim.h b/quantum/rgb_matrix/animations/alpha_mods_anim.h
index 3f2c9b799..b8f507268 100644
--- a/quantum/rgb_matrix/animations/alpha_mods_anim.h
+++ b/quantum/rgb_matrix/animations/alpha_mods_anim.h
@@ -19,7 +19,7 @@ bool ALPHAS_MODS(effect_params_t* params) {
19 rgb_matrix_set_color(i, rgb1.r, rgb1.g, rgb1.b); 19 rgb_matrix_set_color(i, rgb1.r, rgb1.g, rgb1.b);
20 } 20 }
21 } 21 }
22 return led_max < DRIVER_LED_TOTAL; 22 return rgb_matrix_check_finished_leds(led_max);
23} 23}
24 24
25# endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS 25# endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
diff --git a/quantum/rgb_matrix/animations/breathing_anim.h b/quantum/rgb_matrix/animations/breathing_anim.h
index a00ccb83a..baac51ed1 100644
--- a/quantum/rgb_matrix/animations/breathing_anim.h
+++ b/quantum/rgb_matrix/animations/breathing_anim.h
@@ -13,7 +13,7 @@ bool BREATHING(effect_params_t* params) {
13 RGB_MATRIX_TEST_LED_FLAGS(); 13 RGB_MATRIX_TEST_LED_FLAGS();
14 rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b); 14 rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b);
15 } 15 }
16 return led_max < DRIVER_LED_TOTAL; 16 return rgb_matrix_check_finished_leds(led_max);
17} 17}
18 18
19# endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS 19# endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
diff --git a/quantum/rgb_matrix/animations/fractal_anim.h b/quantum/rgb_matrix/animations/fractal_anim.h
new file mode 100644
index 000000000..83a69daa6
--- /dev/null
+++ b/quantum/rgb_matrix/animations/fractal_anim.h
@@ -0,0 +1,74 @@
1/* Copyright (C) 2021 @filterpaper
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17// Inspired from 4x12 fractal created by @schwarzgrau
18
19#ifdef ENABLE_RGB_MATRIX_FRACTAL
20RGB_MATRIX_EFFECT(FRACTAL)
21# ifdef RGB_MATRIX_CUSTOM_EFFECT_IMPLS
22
23static bool FRACTAL(effect_params_t* params) {
24# define MID_COL MATRIX_COLS / 2
25 static bool led[MATRIX_ROWS][MATRIX_COLS];
26
27 static uint32_t wait_timer = 0;
28 if (wait_timer > g_rgb_timer) {
29 return false;
30 }
31
32 inline uint32_t interval(void) { return 3000 / scale16by8(qadd8(rgb_matrix_config.speed, 16), 16); }
33
34 RGB rgb = rgb_matrix_hsv_to_rgb(rgb_matrix_config.hsv);
35 for (uint8_t h = 0; h < MATRIX_ROWS; ++h) {
36 for (uint8_t l = 0; l < MID_COL - 1; ++l) { // Light and move left columns outwards
37 if (led[h][l]) {
38 rgb_matrix_set_color(g_led_config.matrix_co[h][l], rgb.r, rgb.g, rgb.b);
39 } else {
40 rgb_matrix_set_color(g_led_config.matrix_co[h][l], 0, 0, 0);
41 }
42 led[h][l] = led[h][l + 1];
43 }
44
45 for (uint8_t r = MATRIX_COLS - 1; r > MID_COL; --r) { // Light and move right columns outwards
46 if (led[h][r]) {
47 rgb_matrix_set_color(g_led_config.matrix_co[h][r], rgb.r, rgb.g, rgb.b);
48 } else {
49 rgb_matrix_set_color(g_led_config.matrix_co[h][r], 0, 0, 0);
50 }
51 led[h][r] = led[h][r - 1];
52 }
53
54 // Light both middle columns
55 if (led[h][MID_COL]) {
56 rgb_matrix_set_color(g_led_config.matrix_co[h][MID_COL], rgb.r, rgb.g, rgb.b);
57 } else {
58 rgb_matrix_set_color(g_led_config.matrix_co[h][MID_COL], 0, 0, 0);
59 }
60 if (led[h][MID_COL - 1]) {
61 rgb_matrix_set_color(g_led_config.matrix_co[h][MID_COL - 1], rgb.r, rgb.g, rgb.b);
62 } else {
63 rgb_matrix_set_color(g_led_config.matrix_co[h][MID_COL - 1], 0, 0, 0);
64 }
65
66 // Generate new random fractal columns
67 led[h][MID_COL] = led[h][MID_COL - 1] = (random8() & 3) ? false : true;
68 }
69
70 wait_timer = g_rgb_timer + interval();
71 return false;
72}
73# endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
74#endif // ENABLE_RGB_MATRIX_FRACTAL
diff --git a/quantum/rgb_matrix/animations/gradient_left_right_anim.h b/quantum/rgb_matrix/animations/gradient_left_right_anim.h
index b4f2752ff..8b13d4e48 100644
--- a/quantum/rgb_matrix/animations/gradient_left_right_anim.h
+++ b/quantum/rgb_matrix/animations/gradient_left_right_anim.h
@@ -15,7 +15,7 @@ bool GRADIENT_LEFT_RIGHT(effect_params_t* params) {
15 RGB rgb = rgb_matrix_hsv_to_rgb(hsv); 15 RGB rgb = rgb_matrix_hsv_to_rgb(hsv);
16 rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b); 16 rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b);
17 } 17 }
18 return led_max < DRIVER_LED_TOTAL; 18 return rgb_matrix_check_finished_leds(led_max);
19} 19}
20 20
21# endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS 21# endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
diff --git a/quantum/rgb_matrix/animations/gradient_up_down_anim.h b/quantum/rgb_matrix/animations/gradient_up_down_anim.h
index 3fd45cf99..7431ddcd9 100644
--- a/quantum/rgb_matrix/animations/gradient_up_down_anim.h
+++ b/quantum/rgb_matrix/animations/gradient_up_down_anim.h
@@ -15,7 +15,7 @@ bool GRADIENT_UP_DOWN(effect_params_t* params) {
15 RGB rgb = rgb_matrix_hsv_to_rgb(hsv); 15 RGB rgb = rgb_matrix_hsv_to_rgb(hsv);
16 rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b); 16 rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b);
17 } 17 }
18 return led_max < DRIVER_LED_TOTAL; 18 return rgb_matrix_check_finished_leds(led_max);
19} 19}
20 20
21# endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS 21# endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
diff --git a/quantum/rgb_matrix/animations/hue_breathing_anim.h b/quantum/rgb_matrix/animations/hue_breathing_anim.h
index 6d974b8c3..82be1a442 100644
--- a/quantum/rgb_matrix/animations/hue_breathing_anim.h
+++ b/quantum/rgb_matrix/animations/hue_breathing_anim.h
@@ -15,7 +15,7 @@ bool HUE_BREATHING(effect_params_t* params) {
15 RGB_MATRIX_TEST_LED_FLAGS(); 15 RGB_MATRIX_TEST_LED_FLAGS();
16 rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b); 16 rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b);
17 } 17 }
18 return led_max < DRIVER_LED_TOTAL; 18 return rgb_matrix_check_finished_leds(led_max);
19} 19}
20 20
21# endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS 21# endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
diff --git a/quantum/rgb_matrix/animations/jellybean_raindrops_anim.h b/quantum/rgb_matrix/animations/jellybean_raindrops_anim.h
index 7d8eafffb..d639ba9b6 100644
--- a/quantum/rgb_matrix/animations/jellybean_raindrops_anim.h
+++ b/quantum/rgb_matrix/animations/jellybean_raindrops_anim.h
@@ -22,7 +22,7 @@ bool JELLYBEAN_RAINDROPS(effect_params_t* params) {
22 for (int i = led_min; i < led_max; i++) { 22 for (int i = led_min; i < led_max; i++) {
23 jellybean_raindrops_set_color(i, params); 23 jellybean_raindrops_set_color(i, params);
24 } 24 }
25 return led_max < DRIVER_LED_TOTAL; 25 return rgb_matrix_check_finished_leds(led_max);
26} 26}
27 27
28# endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS 28# endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
diff --git a/quantum/rgb_matrix/animations/pixel_rain_anim.h b/quantum/rgb_matrix/animations/pixel_rain_anim.h
new file mode 100644
index 000000000..0209d3303
--- /dev/null
+++ b/quantum/rgb_matrix/animations/pixel_rain_anim.h
@@ -0,0 +1,44 @@
1/* Copyright (C) 2021 @filterpaper
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifdef ENABLE_RGB_MATRIX_PIXEL_RAIN
18RGB_MATRIX_EFFECT(PIXEL_RAIN)
19# ifdef RGB_MATRIX_CUSTOM_EFFECT_IMPLS
20
21static bool PIXEL_RAIN(effect_params_t* params) {
22 static uint32_t wait_timer = 0;
23 if (wait_timer > g_rgb_timer) { return false; }
24
25 inline uint32_t interval(void) { return 500 / scale16by8(qadd8(rgb_matrix_config.speed, 16), 16); }
26
27 bool rain_pixel(uint8_t i, effect_params_t* params, bool off) {
28 if (!HAS_ANY_FLAGS(g_led_config.flags[i], params->flags)) { return true; }
29 if (off) {
30 rgb_matrix_set_color(i, 0,0,0);
31 } else {
32 HSV hsv = {random8(), qadd8(random8() >> 1, 127), rgb_matrix_config.hsv.v};
33 RGB rgb = rgb_matrix_hsv_to_rgb(hsv);
34 rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b);
35 }
36 wait_timer = g_rgb_timer + interval();
37 return false;
38 }
39
40 return rain_pixel(mod8(random8(), DRIVER_LED_TOTAL), params, random8() & 2);
41}
42
43# endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
44#endif // ENABLE_RGB_MATRIX_PIXEL_RAIN
diff --git a/quantum/rgb_matrix/animations/raindrops_anim.h b/quantum/rgb_matrix/animations/raindrops_anim.h
index c01688e2c..fa61f9e0b 100644
--- a/quantum/rgb_matrix/animations/raindrops_anim.h
+++ b/quantum/rgb_matrix/animations/raindrops_anim.h
@@ -32,7 +32,7 @@ bool RAINDROPS(effect_params_t* params) {
32 for (int i = led_min; i < led_max; i++) { 32 for (int i = led_min; i < led_max; i++) {
33 raindrops_set_color(i, params); 33 raindrops_set_color(i, params);
34 } 34 }
35 return led_max < DRIVER_LED_TOTAL; 35 return rgb_matrix_check_finished_leds(led_max);
36} 36}
37 37
38# endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS 38# endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
diff --git a/quantum/rgb_matrix/animations/rgb_matrix_effects.inc b/quantum/rgb_matrix/animations/rgb_matrix_effects.inc
index 302ad79c0..8ecf4367f 100644
--- a/quantum/rgb_matrix/animations/rgb_matrix_effects.inc
+++ b/quantum/rgb_matrix/animations/rgb_matrix_effects.inc
@@ -26,6 +26,8 @@
26#include "hue_breathing_anim.h" 26#include "hue_breathing_anim.h"
27#include "hue_pendulum_anim.h" 27#include "hue_pendulum_anim.h"
28#include "hue_wave_anim.h" 28#include "hue_wave_anim.h"
29#include "fractal_anim.h"
30#include "pixel_rain_anim.h"
29#include "typing_heatmap_anim.h" 31#include "typing_heatmap_anim.h"
30#include "digital_rain_anim.h" 32#include "digital_rain_anim.h"
31#include "solid_reactive_simple_anim.h" 33#include "solid_reactive_simple_anim.h"
diff --git a/quantum/rgb_matrix/animations/runners/effect_runner_dx_dy.h b/quantum/rgb_matrix/animations/runners/effect_runner_dx_dy.h
index 4867609c8..2ad0f22c2 100644
--- a/quantum/rgb_matrix/animations/runners/effect_runner_dx_dy.h
+++ b/quantum/rgb_matrix/animations/runners/effect_runner_dx_dy.h
@@ -13,5 +13,5 @@ bool effect_runner_dx_dy(effect_params_t* params, dx_dy_f effect_func) {
13 RGB rgb = rgb_matrix_hsv_to_rgb(effect_func(rgb_matrix_config.hsv, dx, dy, time)); 13 RGB rgb = rgb_matrix_hsv_to_rgb(effect_func(rgb_matrix_config.hsv, dx, dy, time));
14 rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b); 14 rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b);
15 } 15 }
16 return led_max < DRIVER_LED_TOTAL; 16 return rgb_matrix_check_finished_leds(led_max);
17} 17}
diff --git a/quantum/rgb_matrix/animations/runners/effect_runner_dx_dy_dist.h b/quantum/rgb_matrix/animations/runners/effect_runner_dx_dy_dist.h
index 9545b418d..bcae7c79b 100644
--- a/quantum/rgb_matrix/animations/runners/effect_runner_dx_dy_dist.h
+++ b/quantum/rgb_matrix/animations/runners/effect_runner_dx_dy_dist.h
@@ -14,5 +14,5 @@ bool effect_runner_dx_dy_dist(effect_params_t* params, dx_dy_dist_f effect_func)
14 RGB rgb = rgb_matrix_hsv_to_rgb(effect_func(rgb_matrix_config.hsv, dx, dy, dist, time)); 14 RGB rgb = rgb_matrix_hsv_to_rgb(effect_func(rgb_matrix_config.hsv, dx, dy, dist, time));
15 rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b); 15 rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b);
16 } 16 }
17 return led_max < DRIVER_LED_TOTAL; 17 return rgb_matrix_check_finished_leds(led_max);
18} 18}
diff --git a/quantum/rgb_matrix/animations/runners/effect_runner_i.h b/quantum/rgb_matrix/animations/runners/effect_runner_i.h
index 1881cd6c6..b4de2992b 100644
--- a/quantum/rgb_matrix/animations/runners/effect_runner_i.h
+++ b/quantum/rgb_matrix/animations/runners/effect_runner_i.h
@@ -11,5 +11,5 @@ bool effect_runner_i(effect_params_t* params, i_f effect_func) {
11 RGB rgb = rgb_matrix_hsv_to_rgb(effect_func(rgb_matrix_config.hsv, i, time)); 11 RGB rgb = rgb_matrix_hsv_to_rgb(effect_func(rgb_matrix_config.hsv, i, time));
12 rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b); 12 rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b);
13 } 13 }
14 return led_max < DRIVER_LED_TOTAL; 14 return rgb_matrix_check_finished_leds(led_max);
15} 15}
diff --git a/quantum/rgb_matrix/animations/runners/effect_runner_reactive.h b/quantum/rgb_matrix/animations/runners/effect_runner_reactive.h
index 75b7c0df4..d5c1a26ce 100644
--- a/quantum/rgb_matrix/animations/runners/effect_runner_reactive.h
+++ b/quantum/rgb_matrix/animations/runners/effect_runner_reactive.h
@@ -23,7 +23,7 @@ bool effect_runner_reactive(effect_params_t* params, reactive_f effect_func) {
23 RGB rgb = rgb_matrix_hsv_to_rgb(effect_func(rgb_matrix_config.hsv, offset)); 23 RGB rgb = rgb_matrix_hsv_to_rgb(effect_func(rgb_matrix_config.hsv, offset));
24 rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b); 24 rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b);
25 } 25 }
26 return led_max < DRIVER_LED_TOTAL; 26 return rgb_matrix_check_finished_leds(led_max);
27} 27}
28 28
29#endif // RGB_MATRIX_KEYREACTIVE_ENABLED 29#endif // RGB_MATRIX_KEYREACTIVE_ENABLED
diff --git a/quantum/rgb_matrix/animations/runners/effect_runner_reactive_splash.h b/quantum/rgb_matrix/animations/runners/effect_runner_reactive_splash.h
index 2e46ffb35..d3a6e4e72 100644
--- a/quantum/rgb_matrix/animations/runners/effect_runner_reactive_splash.h
+++ b/quantum/rgb_matrix/animations/runners/effect_runner_reactive_splash.h
@@ -23,7 +23,7 @@ bool effect_runner_reactive_splash(uint8_t start, effect_params_t* params, react
23 RGB rgb = rgb_matrix_hsv_to_rgb(hsv); 23 RGB rgb = rgb_matrix_hsv_to_rgb(hsv);
24 rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b); 24 rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b);
25 } 25 }
26 return led_max < DRIVER_LED_TOTAL; 26 return rgb_matrix_check_finished_leds(led_max);
27} 27}
28 28
29#endif // RGB_MATRIX_KEYREACTIVE_ENABLED 29#endif // RGB_MATRIX_KEYREACTIVE_ENABLED
diff --git a/quantum/rgb_matrix/animations/runners/effect_runner_sin_cos_i.h b/quantum/rgb_matrix/animations/runners/effect_runner_sin_cos_i.h
index 02351de51..7776491d5 100644
--- a/quantum/rgb_matrix/animations/runners/effect_runner_sin_cos_i.h
+++ b/quantum/rgb_matrix/animations/runners/effect_runner_sin_cos_i.h
@@ -13,5 +13,5 @@ bool effect_runner_sin_cos_i(effect_params_t* params, sin_cos_i_f effect_func) {
13 RGB rgb = rgb_matrix_hsv_to_rgb(effect_func(rgb_matrix_config.hsv, cos_value, sin_value, i, time)); 13 RGB rgb = rgb_matrix_hsv_to_rgb(effect_func(rgb_matrix_config.hsv, cos_value, sin_value, i, time));
14 rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b); 14 rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b);
15 } 15 }
16 return led_max < DRIVER_LED_TOTAL; 16 return rgb_matrix_check_finished_leds(led_max);
17} 17}
diff --git a/quantum/rgb_matrix/animations/solid_color_anim.h b/quantum/rgb_matrix/animations/solid_color_anim.h
index 79d63cf13..420995946 100644
--- a/quantum/rgb_matrix/animations/solid_color_anim.h
+++ b/quantum/rgb_matrix/animations/solid_color_anim.h
@@ -9,7 +9,7 @@ bool SOLID_COLOR(effect_params_t* params) {
9 RGB_MATRIX_TEST_LED_FLAGS(); 9 RGB_MATRIX_TEST_LED_FLAGS();
10 rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b); 10 rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b);
11 } 11 }
12 return led_max < DRIVER_LED_TOTAL; 12 return rgb_matrix_check_finished_leds(led_max);
13} 13}
14 14
15#endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS 15#endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
diff --git a/quantum/rgb_matrix/rgb_matrix.c b/quantum/rgb_matrix/rgb_matrix.c
index 8f00b4087..558c7bd41 100644
--- a/quantum/rgb_matrix/rgb_matrix.c
+++ b/quantum/rgb_matrix/rgb_matrix.c
@@ -31,14 +31,6 @@ const led_point_t k_rgb_matrix_center = {112, 32};
31const led_point_t k_rgb_matrix_center = RGB_MATRIX_CENTER; 31const led_point_t k_rgb_matrix_center = RGB_MATRIX_CENTER;
32#endif 32#endif
33 33
34// clang-format off
35#ifndef RGB_MATRIX_IMMEDIATE_EEPROM
36# define rgb_eeconfig_update(v) rgb_update_eeprom |= v
37#else
38# define rgb_eeconfig_update(v) if (v) eeconfig_update_rgb_matrix()
39#endif
40// clang-format on
41
42__attribute__((weak)) RGB rgb_matrix_hsv_to_rgb(HSV hsv) { return hsv_to_rgb(hsv); } 34__attribute__((weak)) RGB rgb_matrix_hsv_to_rgb(HSV hsv) { return hsv_to_rgb(hsv); }
43 35
44// Generic effect runners 36// Generic effect runners
@@ -128,7 +120,6 @@ last_hit_t g_last_hit_tracker;
128 120
129// internals 121// internals
130static bool suspend_state = false; 122static bool suspend_state = false;
131static bool rgb_update_eeprom = false;
132static uint8_t rgb_last_enable = UINT8_MAX; 123static uint8_t rgb_last_enable = UINT8_MAX;
133static uint8_t rgb_last_effect = UINT8_MAX; 124static uint8_t rgb_last_effect = UINT8_MAX;
134static effect_params_t rgb_effect_params = {0, LED_FLAG_ALL, false}; 125static effect_params_t rgb_effect_params = {0, LED_FLAG_ALL, false};
@@ -148,9 +139,9 @@ static last_hit_t last_hit_buffer;
148const uint8_t k_rgb_matrix_split[2] = RGB_MATRIX_SPLIT; 139const uint8_t k_rgb_matrix_split[2] = RGB_MATRIX_SPLIT;
149#endif 140#endif
150 141
151void eeconfig_read_rgb_matrix(void) { eeprom_read_block(&rgb_matrix_config, EECONFIG_RGB_MATRIX, sizeof(rgb_matrix_config)); } 142EECONFIG_DEBOUNCE_HELPER(rgb_matrix, EECONFIG_RGB_MATRIX, rgb_matrix_config);
152 143
153void eeconfig_update_rgb_matrix(void) { eeprom_update_block(&rgb_matrix_config, EECONFIG_RGB_MATRIX, sizeof(rgb_matrix_config)); } 144void eeconfig_update_rgb_matrix(void) { eeconfig_flush_rgb_matrix(true); }
154 145
155void eeconfig_update_rgb_matrix_default(void) { 146void eeconfig_update_rgb_matrix_default(void) {
156 dprintf("eeconfig_update_rgb_matrix_default\n"); 147 dprintf("eeconfig_update_rgb_matrix_default\n");
@@ -159,7 +150,7 @@ void eeconfig_update_rgb_matrix_default(void) {
159 rgb_matrix_config.hsv = (HSV){RGB_MATRIX_STARTUP_HUE, RGB_MATRIX_STARTUP_SAT, RGB_MATRIX_STARTUP_VAL}; 150 rgb_matrix_config.hsv = (HSV){RGB_MATRIX_STARTUP_HUE, RGB_MATRIX_STARTUP_SAT, RGB_MATRIX_STARTUP_VAL};
160 rgb_matrix_config.speed = RGB_MATRIX_STARTUP_SPD; 151 rgb_matrix_config.speed = RGB_MATRIX_STARTUP_SPD;
161 rgb_matrix_config.flags = LED_FLAG_ALL; 152 rgb_matrix_config.flags = LED_FLAG_ALL;
162 eeconfig_update_rgb_matrix(); 153 eeconfig_flush_rgb_matrix(true);
163} 154}
164 155
165void eeconfig_debug_rgb_matrix(void) { 156void eeconfig_debug_rgb_matrix(void) {
@@ -187,14 +178,7 @@ uint8_t rgb_matrix_map_row_column_to_led(uint8_t row, uint8_t column, uint8_t *l
187 178
188void rgb_matrix_update_pwm_buffers(void) { rgb_matrix_driver.flush(); } 179void rgb_matrix_update_pwm_buffers(void) { rgb_matrix_driver.flush(); }
189 180
190void rgb_matrix_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) { 181void rgb_matrix_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) { rgb_matrix_driver.set_color(index, red, green, blue); }
191#if defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT)
192 if (!is_keyboard_left() && index >= k_rgb_matrix_split[0])
193 rgb_matrix_driver.set_color(index - k_rgb_matrix_split[0], red, green, blue);
194 else if (is_keyboard_left() && index < k_rgb_matrix_split[0])
195#endif
196 rgb_matrix_driver.set_color(index, red, green, blue);
197}
198 182
199void rgb_matrix_set_color_all(uint8_t red, uint8_t green, uint8_t blue) { 183void rgb_matrix_set_color_all(uint8_t red, uint8_t green, uint8_t blue) {
200#if defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT) 184#if defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT)
@@ -314,9 +298,8 @@ static void rgb_task_timers(void) {
314} 298}
315 299
316static void rgb_task_sync(void) { 300static void rgb_task_sync(void) {
301 eeconfig_flush_rgb_matrix(false);
317 // next task 302 // next task
318 if (rgb_update_eeprom) eeconfig_update_rgb_matrix();
319 rgb_update_eeprom = false;
320 if (sync_timer_elapsed32(g_rgb_timer) >= RGB_MATRIX_LED_FLUSH_LIMIT) rgb_task_state = STARTING; 303 if (sync_timer_elapsed32(g_rgb_timer) >= RGB_MATRIX_LED_FLUSH_LIMIT) rgb_task_state = STARTING;
321} 304}
322 305
@@ -491,7 +474,7 @@ void rgb_matrix_init(void) {
491 eeconfig_update_rgb_matrix_default(); 474 eeconfig_update_rgb_matrix_default();
492 } 475 }
493 476
494 eeconfig_read_rgb_matrix(); 477 eeconfig_init_rgb_matrix();
495 if (!rgb_matrix_config.mode) { 478 if (!rgb_matrix_config.mode) {
496 dprintf("rgb_matrix_init_drivers rgb_matrix_config.mode = 0. Write default values to EEPROM.\n"); 479 dprintf("rgb_matrix_init_drivers rgb_matrix_config.mode = 0. Write default values to EEPROM.\n");
497 eeconfig_update_rgb_matrix_default(); 480 eeconfig_update_rgb_matrix_default();
@@ -514,7 +497,7 @@ bool rgb_matrix_get_suspend_state(void) { return suspend_state; }
514void rgb_matrix_toggle_eeprom_helper(bool write_to_eeprom) { 497void rgb_matrix_toggle_eeprom_helper(bool write_to_eeprom) {
515 rgb_matrix_config.enable ^= 1; 498 rgb_matrix_config.enable ^= 1;
516 rgb_task_state = STARTING; 499 rgb_task_state = STARTING;
517 rgb_eeconfig_update(write_to_eeprom); 500 eeconfig_flag_rgb_matrix(write_to_eeprom);
518 dprintf("rgb matrix toggle [%s]: rgb_matrix_config.enable = %u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", rgb_matrix_config.enable); 501 dprintf("rgb matrix toggle [%s]: rgb_matrix_config.enable = %u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", rgb_matrix_config.enable);
519} 502}
520void rgb_matrix_toggle_noeeprom(void) { rgb_matrix_toggle_eeprom_helper(false); } 503void rgb_matrix_toggle_noeeprom(void) { rgb_matrix_toggle_eeprom_helper(false); }
@@ -522,7 +505,7 @@ void rgb_matrix_toggle(void) { rgb_matrix_toggle_eeprom_helper(true); }
522 505
523void rgb_matrix_enable(void) { 506void rgb_matrix_enable(void) {
524 rgb_matrix_enable_noeeprom(); 507 rgb_matrix_enable_noeeprom();
525 rgb_eeconfig_update(true); 508 eeconfig_flag_rgb_matrix(true);
526} 509}
527 510
528void rgb_matrix_enable_noeeprom(void) { 511void rgb_matrix_enable_noeeprom(void) {
@@ -532,7 +515,7 @@ void rgb_matrix_enable_noeeprom(void) {
532 515
533void rgb_matrix_disable(void) { 516void rgb_matrix_disable(void) {
534 rgb_matrix_disable_noeeprom(); 517 rgb_matrix_disable_noeeprom();
535 rgb_eeconfig_update(true); 518 eeconfig_flag_rgb_matrix(true);
536} 519}
537 520
538void rgb_matrix_disable_noeeprom(void) { 521void rgb_matrix_disable_noeeprom(void) {
@@ -554,7 +537,7 @@ void rgb_matrix_mode_eeprom_helper(uint8_t mode, bool write_to_eeprom) {
554 rgb_matrix_config.mode = mode; 537 rgb_matrix_config.mode = mode;
555 } 538 }
556 rgb_task_state = STARTING; 539 rgb_task_state = STARTING;
557 rgb_eeconfig_update(write_to_eeprom); 540 eeconfig_flag_rgb_matrix(write_to_eeprom);
558 dprintf("rgb matrix mode [%s]: %u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", rgb_matrix_config.mode); 541 dprintf("rgb matrix mode [%s]: %u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", rgb_matrix_config.mode);
559} 542}
560void rgb_matrix_mode_noeeprom(uint8_t mode) { rgb_matrix_mode_eeprom_helper(mode, false); } 543void rgb_matrix_mode_noeeprom(uint8_t mode) { rgb_matrix_mode_eeprom_helper(mode, false); }
@@ -583,7 +566,7 @@ void rgb_matrix_sethsv_eeprom_helper(uint16_t hue, uint8_t sat, uint8_t val, boo
583 rgb_matrix_config.hsv.h = hue; 566 rgb_matrix_config.hsv.h = hue;
584 rgb_matrix_config.hsv.s = sat; 567 rgb_matrix_config.hsv.s = sat;
585 rgb_matrix_config.hsv.v = (val > RGB_MATRIX_MAXIMUM_BRIGHTNESS) ? RGB_MATRIX_MAXIMUM_BRIGHTNESS : val; 568 rgb_matrix_config.hsv.v = (val > RGB_MATRIX_MAXIMUM_BRIGHTNESS) ? RGB_MATRIX_MAXIMUM_BRIGHTNESS : val;
586 rgb_eeconfig_update(write_to_eeprom); 569 eeconfig_flag_rgb_matrix(write_to_eeprom);
587 dprintf("rgb matrix set hsv [%s]: %u,%u,%u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", rgb_matrix_config.hsv.h, rgb_matrix_config.hsv.s, rgb_matrix_config.hsv.v); 570 dprintf("rgb matrix set hsv [%s]: %u,%u,%u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", rgb_matrix_config.hsv.h, rgb_matrix_config.hsv.s, rgb_matrix_config.hsv.v);
588} 571}
589void rgb_matrix_sethsv_noeeprom(uint16_t hue, uint8_t sat, uint8_t val) { rgb_matrix_sethsv_eeprom_helper(hue, sat, val, false); } 572void rgb_matrix_sethsv_noeeprom(uint16_t hue, uint8_t sat, uint8_t val) { rgb_matrix_sethsv_eeprom_helper(hue, sat, val, false); }
@@ -620,7 +603,7 @@ void rgb_matrix_decrease_val(void) { rgb_matrix_decrease_val_helper(true); }
620 603
621void rgb_matrix_set_speed_eeprom_helper(uint8_t speed, bool write_to_eeprom) { 604void rgb_matrix_set_speed_eeprom_helper(uint8_t speed, bool write_to_eeprom) {
622 rgb_matrix_config.speed = speed; 605 rgb_matrix_config.speed = speed;
623 rgb_eeconfig_update(write_to_eeprom); 606 eeconfig_flag_rgb_matrix(write_to_eeprom);
624 dprintf("rgb matrix set speed [%s]: %u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", rgb_matrix_config.speed); 607 dprintf("rgb matrix set speed [%s]: %u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", rgb_matrix_config.speed);
625} 608}
626void rgb_matrix_set_speed_noeeprom(uint8_t speed) { rgb_matrix_set_speed_eeprom_helper(speed, false); } 609void rgb_matrix_set_speed_noeeprom(uint8_t speed) { rgb_matrix_set_speed_eeprom_helper(speed, false); }
diff --git a/quantum/rgb_matrix/rgb_matrix.h b/quantum/rgb_matrix/rgb_matrix.h
index f53e011c1..af5ca9e79 100644
--- a/quantum/rgb_matrix/rgb_matrix.h
+++ b/quantum/rgb_matrix/rgb_matrix.h
@@ -33,6 +33,8 @@
33# include "is31fl3737.h" 33# include "is31fl3737.h"
34#elif defined(IS31FL3741) 34#elif defined(IS31FL3741)
35# include "is31fl3741.h" 35# include "is31fl3741.h"
36#elif defined(CKLED2001)
37# include "ckled2001.h"
36#elif defined(AW20216) 38#elif defined(AW20216)
37# include "aw20216.h" 39# include "aw20216.h"
38#elif defined(WS2812) 40#elif defined(WS2812)
@@ -48,14 +50,33 @@
48#endif 50#endif
49 51
50#if defined(RGB_MATRIX_LED_PROCESS_LIMIT) && RGB_MATRIX_LED_PROCESS_LIMIT > 0 && RGB_MATRIX_LED_PROCESS_LIMIT < DRIVER_LED_TOTAL 52#if defined(RGB_MATRIX_LED_PROCESS_LIMIT) && RGB_MATRIX_LED_PROCESS_LIMIT > 0 && RGB_MATRIX_LED_PROCESS_LIMIT < DRIVER_LED_TOTAL
51# define RGB_MATRIX_USE_LIMITS(min, max) \ 53# if defined(RGB_MATRIX_SPLIT)
52 uint8_t min = RGB_MATRIX_LED_PROCESS_LIMIT * params->iter; \ 54# define RGB_MATRIX_USE_LIMITS(min, max) \
53 uint8_t max = min + RGB_MATRIX_LED_PROCESS_LIMIT; \ 55 uint8_t min = RGB_MATRIX_LED_PROCESS_LIMIT * params->iter; \
54 if (max > DRIVER_LED_TOTAL) max = DRIVER_LED_TOTAL; 56 uint8_t max = min + RGB_MATRIX_LED_PROCESS_LIMIT; \
57 if (max > DRIVER_LED_TOTAL) max = DRIVER_LED_TOTAL; \
58 uint8_t k_rgb_matrix_split[2] = RGB_MATRIX_SPLIT; \
59 if (is_keyboard_left() && (max > k_rgb_matrix_split[0])) max = k_rgb_matrix_split[0]; \
60 if (!(is_keyboard_left()) && (min < k_rgb_matrix_split[0])) min = k_rgb_matrix_split[0];
61# else
62# define RGB_MATRIX_USE_LIMITS(min, max) \
63 uint8_t min = RGB_MATRIX_LED_PROCESS_LIMIT * params->iter; \
64 uint8_t max = min + RGB_MATRIX_LED_PROCESS_LIMIT; \
65 if (max > DRIVER_LED_TOTAL) max = DRIVER_LED_TOTAL;
66# endif
55#else 67#else
56# define RGB_MATRIX_USE_LIMITS(min, max) \ 68# if defined(RGB_MATRIX_SPLIT)
57 uint8_t min = 0; \ 69# define RGB_MATRIX_USE_LIMITS(min, max) \
58 uint8_t max = DRIVER_LED_TOTAL; 70 uint8_t min = 0; \
71 uint8_t max = DRIVER_LED_TOTAL; \
72 const uint8_t k_rgb_matrix_split[2] = RGB_MATRIX_SPLIT; \
73 if (is_keyboard_left() && (max > k_rgb_matrix_split[0])) max = k_rgb_matrix_split[0]; \
74 if (!(is_keyboard_left()) && (min < k_rgb_matrix_split[0])) min = k_rgb_matrix_split[0];
75# else
76# define RGB_MATRIX_USE_LIMITS(min, max) \
77 uint8_t min = 0; \
78 uint8_t max = DRIVER_LED_TOTAL;
79# endif
59#endif 80#endif
60 81
61#define RGB_MATRIX_INDICATOR_SET_COLOR(i, r, g, b) \ 82#define RGB_MATRIX_INDICATOR_SET_COLOR(i, r, g, b) \
@@ -214,6 +235,18 @@ typedef struct {
214 void (*flush)(void); 235 void (*flush)(void);
215} rgb_matrix_driver_t; 236} rgb_matrix_driver_t;
216 237
238static inline bool rgb_matrix_check_finished_leds(uint8_t led_idx) {
239#if defined(RGB_MATRIX_SPLIT)
240 if (is_keyboard_left()) {
241 uint8_t k_rgb_matrix_split[2] = RGB_MATRIX_SPLIT;
242 return led_idx < k_rgb_matrix_split[0];
243 } else
244 return led_idx < DRIVER_LED_TOTAL;
245#else
246 return led_idx < DRIVER_LED_TOTAL;
247#endif
248}
249
217extern const rgb_matrix_driver_t rgb_matrix_driver; 250extern const rgb_matrix_driver_t rgb_matrix_driver;
218 251
219extern rgb_config_t rgb_matrix_config; 252extern rgb_config_t rgb_matrix_config;
diff --git a/quantum/rgb_matrix/rgb_matrix_drivers.c b/quantum/rgb_matrix/rgb_matrix_drivers.c
index 2cec162e2..130ca47a6 100644
--- a/quantum/rgb_matrix/rgb_matrix_drivers.c
+++ b/quantum/rgb_matrix/rgb_matrix_drivers.c
@@ -23,111 +23,153 @@
23 * be here if shared between boards. 23 * be here if shared between boards.
24 */ 24 */
25 25
26#if defined(IS31FL3731) || defined(IS31FL3733) || defined(IS31FL3737) || defined(IS31FL3741) 26#if defined(IS31FL3731) || defined(IS31FL3733) || defined(IS31FL3737) || defined(IS31FL3741) || defined(CKLED2001)
27
28# include "i2c_master.h" 27# include "i2c_master.h"
29 28
29// TODO: Remove this at some later date
30# if defined(DRIVER_ADDR_1) && defined(DRIVER_ADDR_2)
31# if DRIVER_ADDR_1 == DRIVER_ADDR_2
32# error "Setting DRIVER_ADDR_2 == DRIVER_ADDR_1 is obsolete. If you are only using one ISSI driver, set DRIVER_COUNT to 1 and remove DRIVER_ADDR_2"
33# endif
34# endif
35
30static void init(void) { 36static void init(void) {
31 i2c_init(); 37 i2c_init();
32# ifdef IS31FL3731 38
39# if defined(IS31FL3731)
33 IS31FL3731_init(DRIVER_ADDR_1); 40 IS31FL3731_init(DRIVER_ADDR_1);
34# ifdef DRIVER_ADDR_2 41# if defined(DRIVER_ADDR_2)
35 IS31FL3731_init(DRIVER_ADDR_2); 42 IS31FL3731_init(DRIVER_ADDR_2);
36# endif 43# if defined(DRIVER_ADDR_3)
37# ifdef DRIVER_ADDR_3
38 IS31FL3731_init(DRIVER_ADDR_3); 44 IS31FL3731_init(DRIVER_ADDR_3);
39# endif 45# if defined(DRIVER_ADDR_4)
40# ifdef DRIVER_ADDR_4
41 IS31FL3731_init(DRIVER_ADDR_4); 46 IS31FL3731_init(DRIVER_ADDR_4);
47# endif
48# endif
42# endif 49# endif
50
43# elif defined(IS31FL3733) 51# elif defined(IS31FL3733)
44# ifndef DRIVER_SYNC_1 52# if !defined(DRIVER_SYNC_1)
45# define DRIVER_SYNC_1 0 53# define DRIVER_SYNC_1 0
46# endif 54# endif
47 IS31FL3733_init(DRIVER_ADDR_1, DRIVER_SYNC_1); 55 IS31FL3733_init(DRIVER_ADDR_1, DRIVER_SYNC_1);
48# if defined DRIVER_ADDR_2 && (DRIVER_ADDR_1 != DRIVER_ADDR_2) 56# if defined(DRIVER_ADDR_2)
49# ifndef DRIVER_SYNC_2 57# if !defined(DRIVER_SYNC_2)
50# define DRIVER_SYNC_2 0 58# define DRIVER_SYNC_2 0
51# endif 59# endif
52 IS31FL3733_init(DRIVER_ADDR_2, DRIVER_SYNC_2); 60 IS31FL3733_init(DRIVER_ADDR_2, DRIVER_SYNC_2);
53# endif 61# if defined(DRIVER_ADDR_3)
54# ifdef DRIVER_ADDR_3 62# if !defined(DRIVER_SYNC_3)
55# ifndef DRIVER_SYNC_3 63# define DRIVER_SYNC_3 0
56# define DRIVER_SYNC_3 0 64# endif
57# endif
58 IS31FL3733_init(DRIVER_ADDR_3, DRIVER_SYNC_3); 65 IS31FL3733_init(DRIVER_ADDR_3, DRIVER_SYNC_3);
59# endif 66# if defined(DRIVER_ADDR_4)
60# ifdef DRIVER_ADDR_4 67# if !defined(DRIVER_SYNC_4)
61# ifndef DRIVER_SYNC_4 68# define DRIVER_SYNC_4 0
62# define DRIVER_SYNC_4 0 69# endif
63# endif
64 IS31FL3733_init(DRIVER_ADDR_4, DRIVER_SYNC_4); 70 IS31FL3733_init(DRIVER_ADDR_4, DRIVER_SYNC_4);
71# endif
72# endif
65# endif 73# endif
74
66# elif defined(IS31FL3737) 75# elif defined(IS31FL3737)
67 IS31FL3737_init(DRIVER_ADDR_1); 76 IS31FL3737_init(DRIVER_ADDR_1);
68# if defined(DRIVER_ADDR_2) && (DRIVER_ADDR_2 != DRIVER_ADDR_1) // provides backward compatibility 77# if defined(DRIVER_ADDR_2)
69 IS31FL3737_init(DRIVER_ADDR_2); 78 IS31FL3737_init(DRIVER_ADDR_2);
70# endif 79# endif
71# else 80
81# elif defined(IS31FL3741)
72 IS31FL3741_init(DRIVER_ADDR_1); 82 IS31FL3741_init(DRIVER_ADDR_1);
83
84# elif defined(CKLED2001)
85 CKLED2001_init(DRIVER_ADDR_1);
86# if defined(DRIVER_ADDR_2)
87 CKLED2001_init(DRIVER_ADDR_2);
88# if defined(DRIVER_ADDR_3)
89 CKLED2001_init(DRIVER_ADDR_3);
90# if defined(DRIVER_ADDR_4)
91 CKLED2001_init(DRIVER_ADDR_4);
92# endif
93# endif
94# endif
73# endif 95# endif
96
74 for (int index = 0; index < DRIVER_LED_TOTAL; index++) { 97 for (int index = 0; index < DRIVER_LED_TOTAL; index++) {
75 bool enabled = true; 98 bool enabled = true;
99
76 // This only caches it for later 100 // This only caches it for later
77# ifdef IS31FL3731 101# if defined(IS31FL3731)
78 IS31FL3731_set_led_control_register(index, enabled, enabled, enabled); 102 IS31FL3731_set_led_control_register(index, enabled, enabled, enabled);
79# elif defined(IS31FL3733) 103# elif defined(IS31FL3733)
80 IS31FL3733_set_led_control_register(index, enabled, enabled, enabled); 104 IS31FL3733_set_led_control_register(index, enabled, enabled, enabled);
81# elif defined(IS31FL3737) 105# elif defined(IS31FL3737)
82 IS31FL3737_set_led_control_register(index, enabled, enabled, enabled); 106 IS31FL3737_set_led_control_register(index, enabled, enabled, enabled);
83# else 107# elif defined(IS31FL3741)
84 IS31FL3741_set_led_control_register(index, enabled, enabled, enabled); 108 IS31FL3741_set_led_control_register(index, enabled, enabled, enabled);
109# elif defined(CKLED2001)
110 CKLED2001_set_led_control_register(index, enabled, enabled, enabled);
85# endif 111# endif
86 } 112 }
113
87 // This actually updates the LED drivers 114 // This actually updates the LED drivers
88# ifdef IS31FL3731 115# if defined(IS31FL3731)
89 IS31FL3731_update_led_control_registers(DRIVER_ADDR_1, 0); 116 IS31FL3731_update_led_control_registers(DRIVER_ADDR_1, 0);
90# ifdef DRIVER_ADDR_2 117# if defined(DRIVER_ADDR_2)
91 IS31FL3731_update_led_control_registers(DRIVER_ADDR_2, 1); 118 IS31FL3731_update_led_control_registers(DRIVER_ADDR_2, 1);
92# endif 119# if defined(DRIVER_ADDR_3)
93# ifdef DRIVER_ADDR_3
94 IS31FL3731_update_led_control_registers(DRIVER_ADDR_3, 2); 120 IS31FL3731_update_led_control_registers(DRIVER_ADDR_3, 2);
95# endif 121# if defined(DRIVER_ADDR_4)
96# ifdef DRIVER_ADDR_4
97 IS31FL3731_update_led_control_registers(DRIVER_ADDR_4, 3); 122 IS31FL3731_update_led_control_registers(DRIVER_ADDR_4, 3);
123# endif
124# endif
98# endif 125# endif
126
99# elif defined(IS31FL3733) 127# elif defined(IS31FL3733)
100 IS31FL3733_update_led_control_registers(DRIVER_ADDR_1, 0); 128 IS31FL3733_update_led_control_registers(DRIVER_ADDR_1, 0);
101# ifdef DRIVER_ADDR_2 129# if defined(DRIVER_ADDR_2)
102 IS31FL3733_update_led_control_registers(DRIVER_ADDR_2, 1); 130 IS31FL3733_update_led_control_registers(DRIVER_ADDR_2, 1);
103# endif 131# if defined(DRIVER_ADDR_3)
104# ifdef DRIVER_ADDR_3
105 IS31FL3733_update_led_control_registers(DRIVER_ADDR_3, 2); 132 IS31FL3733_update_led_control_registers(DRIVER_ADDR_3, 2);
106# endif 133# if defined(DRIVER_ADDR_4)
107# ifdef DRIVER_ADDR_4
108 IS31FL3733_update_led_control_registers(DRIVER_ADDR_4, 3); 134 IS31FL3733_update_led_control_registers(DRIVER_ADDR_4, 3);
135# endif
136# endif
109# endif 137# endif
138
110# elif defined(IS31FL3737) 139# elif defined(IS31FL3737)
111 IS31FL3737_update_led_control_registers(DRIVER_ADDR_1, 0); 140 IS31FL3737_update_led_control_registers(DRIVER_ADDR_1, 0);
112# if defined(DRIVER_ADDR_2) && (DRIVER_ADDR_2 != DRIVER_ADDR_1) // provides backward compatibility 141# if defined(DRIVER_ADDR_2)
113 IS31FL3737_update_led_control_registers(DRIVER_ADDR_2, 1); 142 IS31FL3737_update_led_control_registers(DRIVER_ADDR_2, 1);
114# endif 143# endif
115# else 144
145# elif defined(IS31FL3741)
116 IS31FL3741_update_led_control_registers(DRIVER_ADDR_1, 0); 146 IS31FL3741_update_led_control_registers(DRIVER_ADDR_1, 0);
147
148# elif defined(CKLED2001)
149 CKLED2001_update_led_control_registers(DRIVER_ADDR_1, 0);
150# if defined(DRIVER_ADDR_2)
151 CKLED2001_update_led_control_registers(DRIVER_ADDR_2, 1);
152# if defined(DRIVER_ADDR_3)
153 CKLED2001_update_led_control_registers(DRIVER_ADDR_3, 2);
154# if defined(DRIVER_ADDR_4)
155 CKLED2001_update_led_control_registers(DRIVER_ADDR_4, 3);
156# endif
157# endif
158# endif
117# endif 159# endif
118} 160}
119 161
120# ifdef IS31FL3731 162# if defined(IS31FL3731)
121static void flush(void) { 163static void flush(void) {
122 IS31FL3731_update_pwm_buffers(DRIVER_ADDR_1, 0); 164 IS31FL3731_update_pwm_buffers(DRIVER_ADDR_1, 0);
123# ifdef DRIVER_ADDR_2 165# if defined(DRIVER_ADDR_2)
124 IS31FL3731_update_pwm_buffers(DRIVER_ADDR_2, 1); 166 IS31FL3731_update_pwm_buffers(DRIVER_ADDR_2, 1);
125# endif 167# if defined(DRIVER_ADDR_3)
126# ifdef DRIVER_ADDR_3
127 IS31FL3731_update_pwm_buffers(DRIVER_ADDR_3, 2); 168 IS31FL3731_update_pwm_buffers(DRIVER_ADDR_3, 2);
128# endif 169# if defined(DRIVER_ADDR_4)
129# ifdef DRIVER_ADDR_4
130 IS31FL3731_update_pwm_buffers(DRIVER_ADDR_4, 3); 170 IS31FL3731_update_pwm_buffers(DRIVER_ADDR_4, 3);
171# endif
172# endif
131# endif 173# endif
132} 174}
133 175
@@ -137,17 +179,18 @@ const rgb_matrix_driver_t rgb_matrix_driver = {
137 .set_color = IS31FL3731_set_color, 179 .set_color = IS31FL3731_set_color,
138 .set_color_all = IS31FL3731_set_color_all, 180 .set_color_all = IS31FL3731_set_color_all,
139}; 181};
182
140# elif defined(IS31FL3733) 183# elif defined(IS31FL3733)
141static void flush(void) { 184static void flush(void) {
142 IS31FL3733_update_pwm_buffers(DRIVER_ADDR_1, 0); 185 IS31FL3733_update_pwm_buffers(DRIVER_ADDR_1, 0);
143# ifdef DRIVER_ADDR_2 186# if defined(DRIVER_ADDR_2)
144 IS31FL3733_update_pwm_buffers(DRIVER_ADDR_2, 1); 187 IS31FL3733_update_pwm_buffers(DRIVER_ADDR_2, 1);
145# endif 188# if defined(DRIVER_ADDR_3)
146# ifdef DRIVER_ADDR_3
147 IS31FL3733_update_pwm_buffers(DRIVER_ADDR_3, 2); 189 IS31FL3733_update_pwm_buffers(DRIVER_ADDR_3, 2);
148# endif 190# if defined(DRIVER_ADDR_4)
149# ifdef DRIVER_ADDR_4
150 IS31FL3733_update_pwm_buffers(DRIVER_ADDR_4, 3); 191 IS31FL3733_update_pwm_buffers(DRIVER_ADDR_4, 3);
192# endif
193# endif
151# endif 194# endif
152} 195}
153 196
@@ -157,10 +200,11 @@ const rgb_matrix_driver_t rgb_matrix_driver = {
157 .set_color = IS31FL3733_set_color, 200 .set_color = IS31FL3733_set_color,
158 .set_color_all = IS31FL3733_set_color_all, 201 .set_color_all = IS31FL3733_set_color_all,
159}; 202};
203
160# elif defined(IS31FL3737) 204# elif defined(IS31FL3737)
161static void flush(void) { 205static void flush(void) {
162 IS31FL3737_update_pwm_buffers(DRIVER_ADDR_1, 0); 206 IS31FL3737_update_pwm_buffers(DRIVER_ADDR_1, 0);
163# if defined(DRIVER_ADDR_2) && (DRIVER_ADDR_2 != DRIVER_ADDR_1) // provides backward compatibility 207# if defined(DRIVER_ADDR_2)
164 IS31FL3737_update_pwm_buffers(DRIVER_ADDR_2, 1); 208 IS31FL3737_update_pwm_buffers(DRIVER_ADDR_2, 1);
165# endif 209# endif
166} 210}
@@ -171,10 +215,11 @@ const rgb_matrix_driver_t rgb_matrix_driver = {
171 .set_color = IS31FL3737_set_color, 215 .set_color = IS31FL3737_set_color,
172 .set_color_all = IS31FL3737_set_color_all, 216 .set_color_all = IS31FL3737_set_color_all,
173}; 217};
174# else 218
219# elif defined(IS31FL3741)
175static void flush(void) { 220static void flush(void) {
176 IS31FL3741_update_pwm_buffers(DRIVER_ADDR_1, 0); 221 IS31FL3741_update_pwm_buffers(DRIVER_ADDR_1, 0);
177# if defined(DRIVER_ADDR_2) && (DRIVER_ADDR_2 != DRIVER_ADDR_1) // provides backward compatibility 222# if defined(DRIVER_ADDR_2)
178 IS31FL3741_update_pwm_buffers(DRIVER_ADDR_2, 1); 223 IS31FL3741_update_pwm_buffers(DRIVER_ADDR_2, 1);
179# endif 224# endif
180} 225}
@@ -185,21 +230,44 @@ const rgb_matrix_driver_t rgb_matrix_driver = {
185 .set_color = IS31FL3741_set_color, 230 .set_color = IS31FL3741_set_color,
186 .set_color_all = IS31FL3741_set_color_all, 231 .set_color_all = IS31FL3741_set_color_all,
187}; 232};
233
234# elif defined(CKLED2001)
235static void flush(void) {
236 CKLED2001_update_pwm_buffers(DRIVER_ADDR_1, 0);
237# if defined(DRIVER_ADDR_2)
238 CKLED2001_update_pwm_buffers(DRIVER_ADDR_2, 1);
239# if defined(DRIVER_ADDR_3)
240 CKLED2001_update_pwm_buffers(DRIVER_ADDR_3, 2);
241# if defined(DRIVER_ADDR_4)
242 CKLED2001_update_pwm_buffers(DRIVER_ADDR_4, 3);
243# endif
244# endif
245# endif
246}
247
248const rgb_matrix_driver_t rgb_matrix_driver = {
249 .init = init,
250 .flush = flush,
251 .set_color = CKLED2001_set_color,
252 .set_color_all = CKLED2001_set_color_all,
253};
188# endif 254# endif
189 255
190#elif defined(AW20216) 256#elif defined(AW20216)
191# include "spi_master.h" 257# include "spi_master.h"
258
192static void init(void) { 259static void init(void) {
193 spi_init(); 260 spi_init();
261
194 AW20216_init(DRIVER_1_CS, DRIVER_1_EN); 262 AW20216_init(DRIVER_1_CS, DRIVER_1_EN);
195# ifdef DRIVER_2_CS 263# if defined(DRIVER_2_CS)
196 AW20216_init(DRIVER_2_CS, DRIVER_2_EN); 264 AW20216_init(DRIVER_2_CS, DRIVER_2_EN);
197# endif 265# endif
198} 266}
199 267
200static void flush(void) { 268static void flush(void) {
201 AW20216_update_pwm_buffers(DRIVER_1_CS, 0); 269 AW20216_update_pwm_buffers(DRIVER_1_CS, 0);
202# ifdef DRIVER_2_CS 270# if defined(DRIVER_2_CS)
203 AW20216_update_pwm_buffers(DRIVER_2_CS, 1); 271 AW20216_update_pwm_buffers(DRIVER_2_CS, 1);
204# endif 272# endif
205} 273}
@@ -229,6 +297,14 @@ static void flush(void) {
229 297
230// Set an led in the buffer to a color 298// Set an led in the buffer to a color
231static inline void setled(int i, uint8_t r, uint8_t g, uint8_t b) { 299static inline void setled(int i, uint8_t r, uint8_t g, uint8_t b) {
300# if defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT)
301 const uint8_t k_rgb_matrix_split[2] = RGB_MATRIX_SPLIT;
302 if (!is_keyboard_left() && (i >= k_rgb_matrix_split[0])) {
303 i -= k_rgb_matrix_split[0];
304 } else if (is_keyboard_left() && (i >= k_rgb_matrix_split[0]))
305 return;
306# endif
307
232 rgb_matrix_ws2812_array[i].r = r; 308 rgb_matrix_ws2812_array[i].r = r;
233 rgb_matrix_ws2812_array[i].g = g; 309 rgb_matrix_ws2812_array[i].g = g;
234 rgb_matrix_ws2812_array[i].b = b; 310 rgb_matrix_ws2812_array[i].b = b;
diff --git a/quantum/sequencer/tests/rules.mk b/quantum/sequencer/tests/rules.mk
index 76c221cf9..87a204669 100644
--- a/quantum/sequencer/tests/rules.mk
+++ b/quantum/sequencer/tests/rules.mk
@@ -1,5 +1,5 @@
1# The letter case of these variables might seem odd. However: 1# The letter case of these variables might seem odd. However:
2# - it is consistent with the serial_link example that is used as a reference in the Unit Testing article (https://docs.qmk.fm/#/unit_testing?id=adding-tests-for-new-or-existing-features) 2# - it is consistent with the example that is used as a reference in the Unit Testing article (https://docs.qmk.fm/#/unit_testing?id=adding-tests-for-new-or-existing-features)
3# - Neither `make test:sequencer` or `make test:SEQUENCER` work when using SCREAMING_SNAKE_CASE 3# - Neither `make test:sequencer` or `make test:SEQUENCER` work when using SCREAMING_SNAKE_CASE
4 4
5sequencer_DEFS := -DNO_DEBUG -DMIDI_MOCKED 5sequencer_DEFS := -DNO_DEBUG -DMIDI_MOCKED
diff --git a/quantum/serial_link/LICENSE b/quantum/serial_link/LICENSE
deleted file mode 100644
index d13cc4b26..000000000
--- a/quantum/serial_link/LICENSE
+++ /dev/null
@@ -1,19 +0,0 @@
1The MIT License (MIT)
2
3Permission is hereby granted, free of charge, to any person obtaining a copy
4of this software and associated documentation files (the "Software"), to deal
5in the Software without restriction, including without limitation the rights
6to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7copies of the Software, and to permit persons to whom the Software is
8furnished to do so, subject to the following conditions:
9
10The above copyright notice and this permission notice shall be included in all
11copies or substantial portions of the Software.
12
13THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19SOFTWARE.
diff --git a/quantum/serial_link/README.md b/quantum/serial_link/README.md
deleted file mode 100644
index 05871dbdf..000000000
--- a/quantum/serial_link/README.md
+++ /dev/null
@@ -1 +0,0 @@
1# qmk_serial_link
diff --git a/quantum/serial_link/protocol/byte_stuffer.c b/quantum/serial_link/protocol/byte_stuffer.c
deleted file mode 100644
index d3a91d828..000000000
--- a/quantum/serial_link/protocol/byte_stuffer.c
+++ /dev/null
@@ -1,135 +0,0 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2016 Fred Sundvik
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24
25#include "serial_link/protocol/byte_stuffer.h"
26#include "serial_link/protocol/frame_validator.h"
27#include "serial_link/protocol/physical.h"
28#include <stdbool.h>
29
30// This implements the "Consistent overhead byte stuffing protocol"
31// https://en.wikipedia.org/wiki/Consistent_Overhead_Byte_Stuffing
32// http://www.stuartcheshire.org/papers/COBSforToN.pdf
33
34typedef struct byte_stuffer_state {
35 uint16_t next_zero;
36 uint16_t data_pos;
37 bool long_frame;
38 uint8_t data[MAX_FRAME_SIZE];
39} byte_stuffer_state_t;
40
41static byte_stuffer_state_t states[NUM_LINKS];
42
43void init_byte_stuffer_state(byte_stuffer_state_t* state) {
44 state->next_zero = 0;
45 state->data_pos = 0;
46 state->long_frame = false;
47}
48
49void init_byte_stuffer(void) {
50 int i;
51 for (i = 0; i < NUM_LINKS; i++) {
52 init_byte_stuffer_state(&states[i]);
53 }
54}
55
56void byte_stuffer_recv_byte(uint8_t link, uint8_t data) {
57 byte_stuffer_state_t* state = &states[link];
58 // Start of a new frame
59 if (state->next_zero == 0) {
60 state->next_zero = data;
61 state->long_frame = data == 0xFF;
62 state->data_pos = 0;
63 return;
64 }
65
66 state->next_zero--;
67 if (data == 0) {
68 if (state->next_zero == 0) {
69 // The frame is completed
70 if (state->data_pos > 0) {
71 validator_recv_frame(link, state->data, state->data_pos);
72 }
73 } else {
74 // The frame is invalid, so reset
75 init_byte_stuffer_state(state);
76 }
77 } else {
78 if (state->data_pos == MAX_FRAME_SIZE) {
79 // We exceeded our maximum frame size
80 // therefore there's nothing else to do than reset to a new frame
81 state->next_zero = data;
82 state->long_frame = data == 0xFF;
83 state->data_pos = 0;
84 } else if (state->next_zero == 0) {
85 if (state->long_frame) {
86 // This is part of a long frame, so continue
87 state->next_zero = data;
88 state->long_frame = data == 0xFF;
89 } else {
90 // Special case for zeroes
91 state->next_zero = data;
92 state->data[state->data_pos++] = 0;
93 }
94 } else {
95 state->data[state->data_pos++] = data;
96 }
97 }
98}
99
100static void send_block(uint8_t link, uint8_t* start, uint8_t* end, uint8_t num_non_zero) {
101 send_data(link, &num_non_zero, 1);
102 if (end > start) {
103 send_data(link, start, end - start);
104 }
105}
106
107void byte_stuffer_send_frame(uint8_t link, uint8_t* data, uint16_t size) {
108 const uint8_t zero = 0;
109 if (size > 0) {
110 uint16_t num_non_zero = 1;
111 uint8_t* end = data + size;
112 uint8_t* start = data;
113 while (data < end) {
114 if (num_non_zero == 0xFF) {
115 // There's more data after big non-zero block
116 // So send it, and start a new block
117 send_block(link, start, data, num_non_zero);
118 start = data;
119 num_non_zero = 1;
120 } else {
121 if (*data == 0) {
122 // A zero encountered, so send the block
123 send_block(link, start, data, num_non_zero);
124 start = data + 1;
125 num_non_zero = 1;
126 } else {
127 num_non_zero++;
128 }
129 ++data;
130 }
131 }
132 send_block(link, start, data, num_non_zero);
133 send_data(link, &zero, 1);
134 }
135}
diff --git a/quantum/serial_link/protocol/byte_stuffer.h b/quantum/serial_link/protocol/byte_stuffer.h
deleted file mode 100644
index 397ed3baa..000000000
--- a/quantum/serial_link/protocol/byte_stuffer.h
+++ /dev/null
@@ -1,34 +0,0 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2016 Fred Sundvik
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24
25#pragma once
26
27#include <stdint.h>
28
29#define MAX_FRAME_SIZE 1024
30#define NUM_LINKS 2
31
32void init_byte_stuffer(void);
33void byte_stuffer_recv_byte(uint8_t link, uint8_t data);
34void byte_stuffer_send_frame(uint8_t link, uint8_t* data, uint16_t size);
diff --git a/quantum/serial_link/protocol/frame_router.c b/quantum/serial_link/protocol/frame_router.c
deleted file mode 100644
index 529267370..000000000
--- a/quantum/serial_link/protocol/frame_router.c
+++ /dev/null
@@ -1,64 +0,0 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2016 Fred Sundvik
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24
25#include "serial_link/protocol/frame_router.h"
26#include "serial_link/protocol/transport.h"
27#include "serial_link/protocol/frame_validator.h"
28
29static bool is_master;
30
31void router_set_master(bool master) { is_master = master; }
32
33void route_incoming_frame(uint8_t link, uint8_t* data, uint16_t size) {
34 if (is_master) {
35 if (link == DOWN_LINK) {
36 transport_recv_frame(data[size - 1], data, size - 1);
37 }
38 } else {
39 if (link == UP_LINK) {
40 if (data[size - 1] & 1) {
41 transport_recv_frame(0, data, size - 1);
42 }
43 data[size - 1] >>= 1;
44 validator_send_frame(DOWN_LINK, data, size);
45 } else {
46 data[size - 1]++;
47 validator_send_frame(UP_LINK, data, size);
48 }
49 }
50}
51
52void router_send_frame(uint8_t destination, uint8_t* data, uint16_t size) {
53 if (destination == 0) {
54 if (!is_master) {
55 data[size] = 1;
56 validator_send_frame(UP_LINK, data, size + 1);
57 }
58 } else {
59 if (is_master) {
60 data[size] = destination;
61 validator_send_frame(DOWN_LINK, data, size + 1);
62 }
63 }
64}
diff --git a/quantum/serial_link/protocol/frame_router.h b/quantum/serial_link/protocol/frame_router.h
deleted file mode 100644
index 9325fe4ee..000000000
--- a/quantum/serial_link/protocol/frame_router.h
+++ /dev/null
@@ -1,35 +0,0 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2016 Fred Sundvik
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24
25#pragma once
26
27#include <stdint.h>
28#include <stdbool.h>
29
30#define UP_LINK 0
31#define DOWN_LINK 1
32
33void router_set_master(bool master);
34void route_incoming_frame(uint8_t link, uint8_t* data, uint16_t size);
35void router_send_frame(uint8_t destination, uint8_t* data, uint16_t size);
diff --git a/quantum/serial_link/protocol/frame_validator.c b/quantum/serial_link/protocol/frame_validator.c
deleted file mode 100644
index bc9136f70..000000000
--- a/quantum/serial_link/protocol/frame_validator.c
+++ /dev/null
@@ -1,57 +0,0 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2016 Fred Sundvik
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24
25#include "serial_link/protocol/frame_validator.h"
26#include "serial_link/protocol/frame_router.h"
27#include "serial_link/protocol/byte_stuffer.h"
28#include <string.h>
29
30const uint32_t poly8_lookup[256] = {0, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
31 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
32 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
33 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D};
34
35static uint32_t crc32_byte(uint8_t* p, uint32_t bytelength) {
36 uint32_t crc = 0xffffffff;
37 while (bytelength-- != 0) crc = poly8_lookup[((uint8_t)crc ^ *(p++))] ^ (crc >> 8);
38 // return (~crc); also works
39 return (crc ^ 0xffffffff);
40}
41
42void validator_recv_frame(uint8_t link, uint8_t* data, uint16_t size) {
43 if (size > 4) {
44 uint32_t frame_crc;
45 memcpy(&frame_crc, data + size - 4, 4);
46 uint32_t expected_crc = crc32_byte(data, size - 4);
47 if (frame_crc == expected_crc) {
48 route_incoming_frame(link, data, size - 4);
49 }
50 }
51}
52
53void validator_send_frame(uint8_t link, uint8_t* data, uint16_t size) {
54 uint32_t crc = crc32_byte(data, size);
55 memcpy(data + size, &crc, 4);
56 byte_stuffer_send_frame(link, data, size + 4);
57}
diff --git a/quantum/serial_link/protocol/frame_validator.h b/quantum/serial_link/protocol/frame_validator.h
deleted file mode 100644
index 0f78768a0..000000000
--- a/quantum/serial_link/protocol/frame_validator.h
+++ /dev/null
@@ -1,31 +0,0 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2016 Fred Sundvik
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24
25#pragma once
26
27#include <stdint.h>
28
29void validator_recv_frame(uint8_t link, uint8_t* data, uint16_t size);
30// The buffer pointed to by the data needs 4 additional bytes
31void validator_send_frame(uint8_t link, uint8_t* data, uint16_t size);
diff --git a/quantum/serial_link/protocol/physical.h b/quantum/serial_link/protocol/physical.h
deleted file mode 100644
index 399c9d1f7..000000000
--- a/quantum/serial_link/protocol/physical.h
+++ /dev/null
@@ -1,27 +0,0 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2016 Fred Sundvik
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24
25#pragma once
26
27void send_data(uint8_t link, const uint8_t* data, uint16_t size);
diff --git a/quantum/serial_link/protocol/transport.c b/quantum/serial_link/protocol/transport.c
deleted file mode 100644
index 73b8dc62e..000000000
--- a/quantum/serial_link/protocol/transport.c
+++ /dev/null
@@ -1,121 +0,0 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2016 Fred Sundvik
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24
25#include "serial_link/protocol/transport.h"
26#include "serial_link/protocol/frame_router.h"
27#include "serial_link/protocol/triple_buffered_object.h"
28#include <string.h>
29
30#define MAX_REMOTE_OBJECTS 16
31static remote_object_t* remote_objects[MAX_REMOTE_OBJECTS];
32static uint32_t num_remote_objects = 0;
33
34void reinitialize_serial_link_transport(void) { num_remote_objects = 0; }
35
36void add_remote_objects(remote_object_t** _remote_objects, uint32_t _num_remote_objects) {
37 unsigned int i;
38 for (i = 0; i < _num_remote_objects; i++) {
39 remote_object_t* obj = _remote_objects[i];
40 remote_objects[num_remote_objects++] = obj;
41 if (obj->object_type == MASTER_TO_ALL_SLAVES) {
42 triple_buffer_object_t* tb = (triple_buffer_object_t*)obj->buffer;
43 triple_buffer_init(tb);
44 uint8_t* start = obj->buffer + LOCAL_OBJECT_SIZE(obj->object_size);
45 tb = (triple_buffer_object_t*)start;
46 triple_buffer_init(tb);
47 } else if (obj->object_type == MASTER_TO_SINGLE_SLAVE) {
48 uint8_t* start = obj->buffer;
49 unsigned int j;
50 for (j = 0; j < NUM_SLAVES; j++) {
51 triple_buffer_object_t* tb = (triple_buffer_object_t*)start;
52 triple_buffer_init(tb);
53 start += LOCAL_OBJECT_SIZE(obj->object_size);
54 }
55 triple_buffer_object_t* tb = (triple_buffer_object_t*)start;
56 triple_buffer_init(tb);
57 } else {
58 uint8_t* start = obj->buffer;
59 triple_buffer_object_t* tb = (triple_buffer_object_t*)start;
60 triple_buffer_init(tb);
61 start += LOCAL_OBJECT_SIZE(obj->object_size);
62 unsigned int j;
63 for (j = 0; j < NUM_SLAVES; j++) {
64 tb = (triple_buffer_object_t*)start;
65 triple_buffer_init(tb);
66 start += REMOTE_OBJECT_SIZE(obj->object_size);
67 }
68 }
69 }
70}
71
72void transport_recv_frame(uint8_t from, uint8_t* data, uint16_t size) {
73 uint8_t id = data[size - 1];
74 if (id < num_remote_objects) {
75 remote_object_t* obj = remote_objects[id];
76 if (obj->object_size == size - 1) {
77 uint8_t* start;
78 if (obj->object_type == MASTER_TO_ALL_SLAVES) {
79 start = obj->buffer + LOCAL_OBJECT_SIZE(obj->object_size);
80 } else if (obj->object_type == SLAVE_TO_MASTER) {
81 start = obj->buffer + LOCAL_OBJECT_SIZE(obj->object_size);
82 start += (from - 1) * REMOTE_OBJECT_SIZE(obj->object_size);
83 } else {
84 start = obj->buffer + NUM_SLAVES * LOCAL_OBJECT_SIZE(obj->object_size);
85 }
86 triple_buffer_object_t* tb = (triple_buffer_object_t*)start;
87 void* ptr = triple_buffer_begin_write_internal(obj->object_size, tb);
88 memcpy(ptr, data, size - 1);
89 triple_buffer_end_write_internal(tb);
90 }
91 }
92}
93
94void update_transport(void) {
95 unsigned int i;
96 for (i = 0; i < num_remote_objects; i++) {
97 remote_object_t* obj = remote_objects[i];
98 if (obj->object_type == MASTER_TO_ALL_SLAVES || obj->object_type == SLAVE_TO_MASTER) {
99 triple_buffer_object_t* tb = (triple_buffer_object_t*)obj->buffer;
100 uint8_t* ptr = (uint8_t*)triple_buffer_read_internal(obj->object_size + LOCAL_OBJECT_EXTRA, tb);
101 if (ptr) {
102 ptr[obj->object_size] = i;
103 uint8_t dest = obj->object_type == MASTER_TO_ALL_SLAVES ? 0xFF : 0;
104 router_send_frame(dest, ptr, obj->object_size + 1);
105 }
106 } else {
107 uint8_t* start = obj->buffer;
108 unsigned int j;
109 for (j = 0; j < NUM_SLAVES; j++) {
110 triple_buffer_object_t* tb = (triple_buffer_object_t*)start;
111 uint8_t* ptr = (uint8_t*)triple_buffer_read_internal(obj->object_size + LOCAL_OBJECT_EXTRA, tb);
112 if (ptr) {
113 ptr[obj->object_size] = i;
114 uint8_t dest = j + 1;
115 router_send_frame(dest, ptr, obj->object_size + 1);
116 }
117 start += LOCAL_OBJECT_SIZE(obj->object_size);
118 }
119 }
120 }
121}
diff --git a/quantum/serial_link/protocol/transport.h b/quantum/serial_link/protocol/transport.h
deleted file mode 100644
index 3ce0c9fe4..000000000
--- a/quantum/serial_link/protocol/transport.h
+++ /dev/null
@@ -1,139 +0,0 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2016 Fred Sundvik
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24
25#pragma once
26
27#include "serial_link/protocol/triple_buffered_object.h"
28#include "serial_link/system/serial_link.h"
29
30#define NUM_SLAVES 8
31#define LOCAL_OBJECT_EXTRA 16
32
33// master -> slave = 1 local(target all), 1 remote object
34// slave -> master = 1 local(target 0), multiple remote objects
35// master -> single slave (multiple local, target id), 1 remote object
36typedef enum {
37 MASTER_TO_ALL_SLAVES,
38 MASTER_TO_SINGLE_SLAVE,
39 SLAVE_TO_MASTER,
40} remote_object_type;
41
42typedef struct {
43 remote_object_type object_type;
44 uint16_t object_size;
45 uint8_t buffer[] __attribute__((aligned(4)));
46} remote_object_t;
47
48#define REMOTE_OBJECT_SIZE(objectsize) (sizeof(triple_buffer_object_t) + objectsize * 3)
49#define LOCAL_OBJECT_SIZE(objectsize) (sizeof(triple_buffer_object_t) + (objectsize + LOCAL_OBJECT_EXTRA) * 3)
50
51#define REMOTE_OBJECT_HELPER(name, type, num_local, num_remote) \
52 typedef struct { \
53 remote_object_t object; \
54 uint8_t buffer[num_remote * REMOTE_OBJECT_SIZE(sizeof(type)) + num_local * LOCAL_OBJECT_SIZE(sizeof(type))]; \
55 } remote_object_##name##_t;
56
57#define MASTER_TO_ALL_SLAVES_OBJECT(name, type) \
58 REMOTE_OBJECT_HELPER(name, type, 1, 1) \
59 remote_object_##name##_t remote_object_##name = {.object = { \
60 .object_type = MASTER_TO_ALL_SLAVES, \
61 .object_size = sizeof(type), \
62 }}; \
63 type* begin_write_##name(void) { \
64 remote_object_t* obj = (remote_object_t*)&remote_object_##name; \
65 triple_buffer_object_t* tb = (triple_buffer_object_t*)obj->buffer; \
66 return (type*)triple_buffer_begin_write_internal(sizeof(type) + LOCAL_OBJECT_EXTRA, tb); \
67 } \
68 void end_write_##name(void) { \
69 remote_object_t* obj = (remote_object_t*)&remote_object_##name; \
70 triple_buffer_object_t* tb = (triple_buffer_object_t*)obj->buffer; \
71 triple_buffer_end_write_internal(tb); \
72 signal_data_written(); \
73 } \
74 type* read_##name(void) { \
75 remote_object_t* obj = (remote_object_t*)&remote_object_##name; \
76 uint8_t* start = obj->buffer + LOCAL_OBJECT_SIZE(obj->object_size); \
77 triple_buffer_object_t* tb = (triple_buffer_object_t*)start; \
78 return (type*)triple_buffer_read_internal(obj->object_size, tb); \
79 }
80
81#define MASTER_TO_SINGLE_SLAVE_OBJECT(name, type) \
82 REMOTE_OBJECT_HELPER(name, type, NUM_SLAVES, 1) \
83 remote_object_##name##_t remote_object_##name = {.object = { \
84 .object_type = MASTER_TO_SINGLE_SLAVE, \
85 .object_size = sizeof(type), \
86 }}; \
87 type* begin_write_##name(uint8_t slave) { \
88 remote_object_t* obj = (remote_object_t*)&remote_object_##name; \
89 uint8_t* start = obj->buffer; \
90 start += slave * LOCAL_OBJECT_SIZE(obj->object_size); \
91 triple_buffer_object_t* tb = (triple_buffer_object_t*)start; \
92 return (type*)triple_buffer_begin_write_internal(sizeof(type) + LOCAL_OBJECT_EXTRA, tb); \
93 } \
94 void end_write_##name(uint8_t slave) { \
95 remote_object_t* obj = (remote_object_t*)&remote_object_##name; \
96 uint8_t* start = obj->buffer; \
97 start += slave * LOCAL_OBJECT_SIZE(obj->object_size); \
98 triple_buffer_object_t* tb = (triple_buffer_object_t*)start; \
99 triple_buffer_end_write_internal(tb); \
100 signal_data_written(); \
101 } \
102 type* read_##name() { \
103 remote_object_t* obj = (remote_object_t*)&remote_object_##name; \
104 uint8_t* start = obj->buffer + NUM_SLAVES * LOCAL_OBJECT_SIZE(obj->object_size); \
105 triple_buffer_object_t* tb = (triple_buffer_object_t*)start; \
106 return (type*)triple_buffer_read_internal(obj->object_size, tb); \
107 }
108
109#define SLAVE_TO_MASTER_OBJECT(name, type) \
110 REMOTE_OBJECT_HELPER(name, type, 1, NUM_SLAVES) \
111 remote_object_##name##_t remote_object_##name = {.object = { \
112 .object_type = SLAVE_TO_MASTER, \
113 .object_size = sizeof(type), \
114 }}; \
115 type* begin_write_##name(void) { \
116 remote_object_t* obj = (remote_object_t*)&remote_object_##name; \
117 triple_buffer_object_t* tb = (triple_buffer_object_t*)obj->buffer; \
118 return (type*)triple_buffer_begin_write_internal(sizeof(type) + LOCAL_OBJECT_EXTRA, tb); \
119 } \
120 void end_write_##name(void) { \
121 remote_object_t* obj = (remote_object_t*)&remote_object_##name; \
122 triple_buffer_object_t* tb = (triple_buffer_object_t*)obj->buffer; \
123 triple_buffer_end_write_internal(tb); \
124 signal_data_written(); \
125 } \
126 type* read_##name(uint8_t slave) { \
127 remote_object_t* obj = (remote_object_t*)&remote_object_##name; \
128 uint8_t* start = obj->buffer + LOCAL_OBJECT_SIZE(obj->object_size); \
129 start += slave * REMOTE_OBJECT_SIZE(obj->object_size); \
130 triple_buffer_object_t* tb = (triple_buffer_object_t*)start; \
131 return (type*)triple_buffer_read_internal(obj->object_size, tb); \
132 }
133
134#define REMOTE_OBJECT(name) (remote_object_t*)&remote_object_##name
135
136void add_remote_objects(remote_object_t** remote_objects, uint32_t num_remote_objects);
137void reinitialize_serial_link_transport(void);
138void transport_recv_frame(uint8_t from, uint8_t* data, uint16_t size);
139void update_transport(void);
diff --git a/quantum/serial_link/protocol/triple_buffered_object.c b/quantum/serial_link/protocol/triple_buffered_object.c
deleted file mode 100644
index e0c6d702a..000000000
--- a/quantum/serial_link/protocol/triple_buffered_object.c
+++ /dev/null
@@ -1,77 +0,0 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2016 Fred Sundvik
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24
25#include "serial_link/protocol/triple_buffered_object.h"
26#include "serial_link/system/serial_link.h"
27#include <stdbool.h>
28#include <stddef.h>
29
30#define GET_READ_INDEX() object->state & 3
31#define GET_WRITE_INDEX() (object->state >> 2) & 3
32#define GET_SHARED_INDEX() (object->state >> 4) & 3
33#define GET_DATA_AVAILABLE() (object->state >> 6) & 1
34
35#define SET_READ_INDEX(i) object->state = ((object->state & ~3) | i)
36#define SET_WRITE_INDEX(i) object->state = ((object->state & ~(3 << 2)) | (i << 2))
37#define SET_SHARED_INDEX(i) object->state = ((object->state & ~(3 << 4)) | (i << 4))
38#define SET_DATA_AVAILABLE(i) object->state = ((object->state & ~(1 << 6)) | (i << 6))
39
40void triple_buffer_init(triple_buffer_object_t* object) {
41 object->state = 0;
42 SET_WRITE_INDEX(0);
43 SET_READ_INDEX(1);
44 SET_SHARED_INDEX(2);
45 SET_DATA_AVAILABLE(0);
46}
47
48void* triple_buffer_read_internal(uint16_t object_size, triple_buffer_object_t* object) {
49 serial_link_lock();
50 if (GET_DATA_AVAILABLE()) {
51 uint8_t shared_index = GET_SHARED_INDEX();
52 uint8_t read_index = GET_READ_INDEX();
53 SET_READ_INDEX(shared_index);
54 SET_SHARED_INDEX(read_index);
55 SET_DATA_AVAILABLE(false);
56 serial_link_unlock();
57 return object->buffer + object_size * shared_index;
58 } else {
59 serial_link_unlock();
60 return NULL;
61 }
62}
63
64void* triple_buffer_begin_write_internal(uint16_t object_size, triple_buffer_object_t* object) {
65 uint8_t write_index = GET_WRITE_INDEX();
66 return object->buffer + object_size * write_index;
67}
68
69void triple_buffer_end_write_internal(triple_buffer_object_t* object) {
70 serial_link_lock();
71 uint8_t shared_index = GET_SHARED_INDEX();
72 uint8_t write_index = GET_WRITE_INDEX();
73 SET_SHARED_INDEX(write_index);
74 SET_WRITE_INDEX(shared_index);
75 SET_DATA_AVAILABLE(true);
76 serial_link_unlock();
77}
diff --git a/quantum/serial_link/protocol/triple_buffered_object.h b/quantum/serial_link/protocol/triple_buffered_object.h
deleted file mode 100644
index 717d6d7b8..000000000
--- a/quantum/serial_link/protocol/triple_buffered_object.h
+++ /dev/null
@@ -1,44 +0,0 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2016 Fred Sundvik
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24
25#pragma once
26
27#include <stdint.h>
28
29typedef struct {
30 uint8_t state;
31 uint8_t buffer[] __attribute__((aligned(4)));
32} triple_buffer_object_t;
33
34void triple_buffer_init(triple_buffer_object_t* object);
35
36#define triple_buffer_begin_write(object) (typeof(*object.buffer[0])*)triple_buffer_begin_write_internal(sizeof(*object.buffer[0]), (triple_buffer_object_t*)object)
37
38#define triple_buffer_end_write(object) triple_buffer_end_write_internal((triple_buffer_object_t*)object)
39
40#define triple_buffer_read(object) (typeof(*object.buffer[0])*)triple_buffer_read_internal(sizeof(*object.buffer[0]), (triple_buffer_object_t*)object)
41
42void* triple_buffer_begin_write_internal(uint16_t object_size, triple_buffer_object_t* object);
43void triple_buffer_end_write_internal(triple_buffer_object_t* object);
44void* triple_buffer_read_internal(uint16_t object_size, triple_buffer_object_t* object);
diff --git a/quantum/serial_link/system/serial_link.c b/quantum/serial_link/system/serial_link.c
deleted file mode 100644
index 6363f8ff3..000000000
--- a/quantum/serial_link/system/serial_link.c
+++ /dev/null
@@ -1,250 +0,0 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2016 Fred Sundvik
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24#include "report.h"
25#include "host_driver.h"
26#include "serial_link/system/serial_link.h"
27#include <hal.h>
28#include "serial_link/protocol/byte_stuffer.h"
29#include "serial_link/protocol/transport.h"
30#include "serial_link/protocol/frame_router.h"
31#include "matrix.h"
32#include "sync_timer.h"
33#include <stdbool.h>
34#include "print.h"
35#include "config.h"
36
37#define SYNC_TIMER_OFFSET 2
38
39static event_source_t new_data_event;
40static bool serial_link_connected;
41static bool is_master = false;
42
43static uint8_t keyboard_leds(void);
44static void send_keyboard(report_keyboard_t* report);
45static void send_mouse(report_mouse_t* report);
46static void send_system(uint16_t data);
47static void send_consumer(uint16_t data);
48
49host_driver_t serial_driver = {keyboard_leds, send_keyboard, send_mouse, send_system, send_consumer};
50
51// Define these in your Config.h file
52#ifndef SERIAL_LINK_BAUD
53# error "Serial link baud is not set"
54#endif
55
56#ifndef SERIAL_LINK_THREAD_PRIORITY
57# error "Serial link thread priority not set"
58#endif
59
60static SerialConfig config = {.sc_speed = SERIAL_LINK_BAUD};
61
62//#define DEBUG_LINK_ERRORS
63
64static uint32_t read_from_serial(SerialDriver* driver, uint8_t link) {
65 const uint32_t buffer_size = 16;
66 uint8_t buffer[buffer_size];
67 uint32_t bytes_read = sdAsynchronousRead(driver, buffer, buffer_size);
68 uint8_t* current = buffer;
69 uint8_t* end = current + bytes_read;
70 while (current < end) {
71 byte_stuffer_recv_byte(link, *current);
72 current++;
73 }
74 return bytes_read;
75}
76
77static void print_error(char* str, eventflags_t flags, SerialDriver* driver) {
78#ifdef DEBUG_LINK_ERRORS
79 if (flags & SD_PARITY_ERROR) {
80 print(str);
81 print(" Parity error\n");
82 }
83 if (flags & SD_FRAMING_ERROR) {
84 print(str);
85 print(" Framing error\n");
86 }
87 if (flags & SD_OVERRUN_ERROR) {
88 print(str);
89 uint32_t size = qSpaceI(&(driver->iqueue));
90 xprintf(" Overrun error, queue size %d\n", size);
91 }
92 if (flags & SD_NOISE_ERROR) {
93 print(str);
94 print(" Noise error\n");
95 }
96 if (flags & SD_BREAK_DETECTED) {
97 print(str);
98 print(" Break detected\n");
99 }
100#else
101 (void)str;
102 (void)flags;
103 (void)driver;
104#endif
105}
106
107bool is_serial_link_master(void) { return is_master; }
108
109// TODO: Optimize the stack size, this is probably way too big
110static THD_WORKING_AREA(serialThreadStack, 1024);
111static THD_FUNCTION(serialThread, arg) {
112 (void)arg;
113 event_listener_t new_data_listener;
114 event_listener_t sd1_listener;
115 event_listener_t sd2_listener;
116 chEvtRegister(&new_data_event, &new_data_listener, 0);
117 eventflags_t events = CHN_INPUT_AVAILABLE | SD_PARITY_ERROR | SD_FRAMING_ERROR | SD_OVERRUN_ERROR | SD_NOISE_ERROR | SD_BREAK_DETECTED;
118 chEvtRegisterMaskWithFlags(chnGetEventSource(&SD1), &sd1_listener, EVENT_MASK(1), events);
119 chEvtRegisterMaskWithFlags(chnGetEventSource(&SD2), &sd2_listener, EVENT_MASK(2), events);
120 bool need_wait = false;
121 while (true) {
122 eventflags_t flags1 = 0;
123 eventflags_t flags2 = 0;
124 if (need_wait) {
125 eventmask_t mask = chEvtWaitAnyTimeout(ALL_EVENTS, TIME_MS2I(1000));
126 if (mask & EVENT_MASK(1)) {
127 flags1 = chEvtGetAndClearFlags(&sd1_listener);
128 print_error("DOWNLINK", flags1, &SD1);
129 }
130 if (mask & EVENT_MASK(2)) {
131 flags2 = chEvtGetAndClearFlags(&sd2_listener);
132 print_error("UPLINK", flags2, &SD2);
133 }
134 }
135
136 // Always stay as master, even if the USB goes into sleep mode
137 is_master |= usbGetDriverStateI(&USBD1) == USB_ACTIVE;
138 router_set_master(is_master);
139
140 need_wait = true;
141 need_wait &= read_from_serial(&SD2, UP_LINK) == 0;
142 need_wait &= read_from_serial(&SD1, DOWN_LINK) == 0;
143 update_transport();
144 }
145}
146
147void send_data(uint8_t link, const uint8_t* data, uint16_t size) {
148 if (link == DOWN_LINK) {
149 sdWrite(&SD1, data, size);
150 } else {
151 sdWrite(&SD2, data, size);
152 }
153}
154
155static systime_t last_update = 0;
156
157typedef struct {
158 matrix_row_t rows[MATRIX_ROWS];
159} matrix_object_t;
160
161static matrix_object_t last_matrix = {};
162
163SLAVE_TO_MASTER_OBJECT(keyboard_matrix, matrix_object_t);
164MASTER_TO_ALL_SLAVES_OBJECT(serial_link_connected, bool);
165#ifndef DISABLE_SYNC_TIMER
166MASTER_TO_ALL_SLAVES_OBJECT(sync_timer, uint32_t);
167#endif
168
169static remote_object_t* remote_objects[] = {
170 REMOTE_OBJECT(serial_link_connected),
171 REMOTE_OBJECT(keyboard_matrix),
172#ifndef DISABLE_SYNC_TIMER
173 REMOTE_OBJECT(sync_timer),
174#endif
175};
176
177void init_serial_link(void) {
178 serial_link_connected = false;
179 init_serial_link_hal();
180 add_remote_objects(remote_objects, sizeof(remote_objects) / sizeof(remote_object_t*));
181 init_byte_stuffer();
182 sdStart(&SD1, &config);
183 sdStart(&SD2, &config);
184 chEvtObjectInit(&new_data_event);
185 (void)chThdCreateStatic(serialThreadStack, sizeof(serialThreadStack), SERIAL_LINK_THREAD_PRIORITY, serialThread, NULL);
186}
187
188void matrix_set_remote(matrix_row_t* rows, uint8_t index);
189
190void serial_link_update(void) {
191 if (read_serial_link_connected()) {
192 serial_link_connected = true;
193 }
194
195 matrix_object_t matrix;
196 bool changed = false;
197 for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
198 matrix.rows[i] = matrix_get_row(i);
199 changed |= matrix.rows[i] != last_matrix.rows[i];
200 }
201
202 systime_t current_time = chVTGetSystemTimeX();
203 systime_t delta = current_time - last_update;
204 if (changed || delta > TIME_US2I(5000)) {
205 last_update = current_time;
206 last_matrix = matrix;
207 matrix_object_t* m = begin_write_keyboard_matrix();
208 for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
209 m->rows[i] = matrix.rows[i];
210 }
211 end_write_keyboard_matrix();
212
213 *begin_write_serial_link_connected() = true;
214 end_write_serial_link_connected();
215
216#ifndef DISABLE_SYNC_TIMER
217 *begin_write_sync_timer() = sync_timer_read32() + SYNC_TIMER_OFFSET;
218 end_write_sync_timer();
219#endif
220 }
221
222 matrix_object_t* m = read_keyboard_matrix(0);
223 if (m) {
224 matrix_set_remote(m->rows, 0);
225 }
226
227#ifndef DISABLE_SYNC_TIMER
228 uint32_t* t = read_sync_timer();
229 if (t) {
230 sync_timer_update(*t);
231 }
232#endif
233}
234
235void signal_data_written(void) { chEvtBroadcast(&new_data_event); }
236
237bool is_serial_link_connected(void) { return serial_link_connected; }
238
239host_driver_t* get_serial_link_driver(void) { return &serial_driver; }
240
241// NOTE: The driver does nothing, because the master handles everything
242uint8_t keyboard_leds(void) { return 0; }
243
244void send_keyboard(report_keyboard_t* report) { (void)report; }
245
246void send_mouse(report_mouse_t* report) { (void)report; }
247
248void send_system(uint16_t data) { (void)data; }
249
250void send_consumer(uint16_t data) { (void)data; }
diff --git a/quantum/serial_link/system/serial_link.h b/quantum/serial_link/system/serial_link.h
deleted file mode 100644
index adc1f6e93..000000000
--- a/quantum/serial_link/system/serial_link.h
+++ /dev/null
@@ -1,54 +0,0 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2016 Fred Sundvik
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24
25#pragma once
26
27#include "host_driver.h"
28#include <stdbool.h>
29
30void init_serial_link(void);
31void init_serial_link_hal(void);
32bool is_serial_link_connected(void);
33bool is_serial_link_master(void);
34host_driver_t* get_serial_link_driver(void);
35void serial_link_update(void);
36
37#if defined(PROTOCOL_CHIBIOS)
38# include <ch.h>
39
40static inline void serial_link_lock(void) { chSysLock(); }
41
42static inline void serial_link_unlock(void) { chSysUnlock(); }
43
44void signal_data_written(void);
45
46#else
47
48inline void serial_link_lock(void) {}
49
50inline void serial_link_unlock(void) {}
51
52void signal_data_written(void);
53
54#endif
diff --git a/quantum/serial_link/tests/Makefile b/quantum/serial_link/tests/Makefile
deleted file mode 100644
index 11dd355b2..000000000
--- a/quantum/serial_link/tests/Makefile
+++ /dev/null
@@ -1,61 +0,0 @@
1# The MIT License (MIT)
2#
3# Copyright (c) 2016 Fred Sundvik
4#
5# Permission is hereby granted, free of charge, to any person obtaining a copy
6# of this software and associated documentation files (the "Software"), to deal
7# in the Software without restriction, including without limitation the rights
8# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9# copies of the Software, and to permit persons to whom the Software is
10# furnished to do so, subject to the following conditions:
11#
12# The above copyright notice and this permission notice shall be included in all
13# copies or substantial portions of the Software.
14#
15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21# SOFTWARE.
22
23CC = gcc
24CFLAGS =
25INCLUDES = -I. -I../../
26LDFLAGS = -L$(BUILDDIR)/cgreen/build-c/src -shared
27LDLIBS = -lcgreen
28UNITOBJ = $(BUILDDIR)/serialtest/unitobj
29DEPDIR = $(BUILDDIR)/serialtest/unit.d
30UNITTESTS = $(BUILDDIR)/serialtest/unittests
31DEPFLAGS = -MT $@ -MMD -MP -MF $(DEPDIR)/$*.Td
32EXT = .so
33UNAME := $(shell uname)
34ifneq (, $(findstring MINGW, $(UNAME)))
35 EXT = .dll
36endif
37ifneq (, $(findstring CYGWIN, $(UNAME)))
38 EXT = .dll
39endif
40
41SRC = $(wildcard *.c)
42TESTFILES = $(patsubst %.c, $(UNITTESTS)/%$(EXT), $(SRC))
43$(shell mkdir -p $(DEPDIR) >/dev/null)
44
45test: $(TESTFILES)
46 @$(BUILDDIR)/cgreen/build-c/tools/cgreen-runner --color $(TESTFILES)
47
48$(UNITTESTS)/%$(EXT): $(UNITOBJ)/%.o
49 @mkdir -p $(UNITTESTS)
50 $(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS)
51
52$(UNITOBJ)/%.o : %.c
53$(UNITOBJ)/%.o: %.c $(DEPDIR)/%.d
54 @mkdir -p $(UNITOBJ)
55 $(CC) $(CFLAGS) $(DEPFLAGS) $(INCLUDES) -c $< -o $@
56 @mv -f $(DEPDIR)/$*.Td $(DEPDIR)/$*.d
57
58$(DEPDIR)/%.d: ;
59.PRECIOUS: $(DEPDIR)/%.d
60
61-include $(patsubst %,$(DEPDIR)/%.d,$(basename $(SRC)))
diff --git a/quantum/serial_link/tests/byte_stuffer_tests.cpp b/quantum/serial_link/tests/byte_stuffer_tests.cpp
deleted file mode 100644
index 9e4e1768f..000000000
--- a/quantum/serial_link/tests/byte_stuffer_tests.cpp
+++ /dev/null
@@ -1,450 +0,0 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2016 Fred Sundvik
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24
25#include "gtest/gtest.h"
26#include "gmock/gmock.h"
27#include <vector>
28#include <algorithm>
29extern "C" {
30#include "serial_link/protocol/byte_stuffer.h"
31#include "serial_link/protocol/frame_validator.h"
32#include "serial_link/protocol/physical.h"
33}
34
35using testing::_;
36using testing::Args;
37using testing::ElementsAreArray;
38
39class ByteStuffer : public ::testing::Test {
40 public:
41 ByteStuffer() {
42 Instance = this;
43 init_byte_stuffer();
44 }
45
46 ~ByteStuffer() { Instance = nullptr; }
47
48 MOCK_METHOD3(validator_recv_frame, void(uint8_t link, uint8_t* data, uint16_t size));
49
50 void send_data(uint8_t link, const uint8_t* data, uint16_t size) { std::copy(data, data + size, std::back_inserter(sent_data)); }
51 std::vector<uint8_t> sent_data;
52
53 static ByteStuffer* Instance;
54};
55
56ByteStuffer* ByteStuffer::Instance = nullptr;
57
58extern "C" {
59void validator_recv_frame(uint8_t link, uint8_t* data, uint16_t size) { ByteStuffer::Instance->validator_recv_frame(link, data, size); }
60
61void send_data(uint8_t link, const uint8_t* data, uint16_t size) { ByteStuffer::Instance->send_data(link, data, size); }
62}
63
64TEST_F(ByteStuffer, receives_no_frame_for_a_single_zero_byte) {
65 EXPECT_CALL(*this, validator_recv_frame(_, _, _)).Times(0);
66 byte_stuffer_recv_byte(0, 0);
67}
68
69TEST_F(ByteStuffer, receives_no_frame_for_a_single_FF_byte) {
70 EXPECT_CALL(*this, validator_recv_frame(_, _, _)).Times(0);
71 byte_stuffer_recv_byte(0, 0xFF);
72}
73
74TEST_F(ByteStuffer, receives_no_frame_for_a_single_random_byte) {
75 EXPECT_CALL(*this, validator_recv_frame(_, _, _)).Times(0);
76 byte_stuffer_recv_byte(0, 0x4A);
77}
78
79TEST_F(ByteStuffer, receives_no_frame_for_a_zero_length_frame) {
80 EXPECT_CALL(*this, validator_recv_frame(_, _, _)).Times(0);
81 byte_stuffer_recv_byte(0, 1);
82 byte_stuffer_recv_byte(0, 0);
83}
84
85TEST_F(ByteStuffer, receives_single_byte_valid_frame) {
86 uint8_t expected[] = {0x37};
87 EXPECT_CALL(*this, validator_recv_frame(_, _, _)).With(Args<1, 2>(ElementsAreArray(expected)));
88 byte_stuffer_recv_byte(0, 2);
89 byte_stuffer_recv_byte(0, 0x37);
90 byte_stuffer_recv_byte(0, 0);
91}
92TEST_F(ByteStuffer, receives_three_bytes_valid_frame) {
93 uint8_t expected[] = {0x37, 0x99, 0xFF};
94 EXPECT_CALL(*this, validator_recv_frame(_, _, _)).With(Args<1, 2>(ElementsAreArray(expected)));
95 byte_stuffer_recv_byte(0, 4);
96 byte_stuffer_recv_byte(0, 0x37);
97 byte_stuffer_recv_byte(0, 0x99);
98 byte_stuffer_recv_byte(0, 0xFF);
99 byte_stuffer_recv_byte(0, 0);
100}
101
102TEST_F(ByteStuffer, receives_single_zero_valid_frame) {
103 uint8_t expected[] = {0};
104 EXPECT_CALL(*this, validator_recv_frame(_, _, _)).With(Args<1, 2>(ElementsAreArray(expected)));
105 byte_stuffer_recv_byte(0, 1);
106 byte_stuffer_recv_byte(0, 1);
107 byte_stuffer_recv_byte(0, 0);
108}
109
110TEST_F(ByteStuffer, receives_valid_frame_with_zeroes) {
111 uint8_t expected[] = {5, 0, 3, 0};
112 EXPECT_CALL(*this, validator_recv_frame(_, _, _)).With(Args<1, 2>(ElementsAreArray(expected)));
113 byte_stuffer_recv_byte(0, 2);
114 byte_stuffer_recv_byte(0, 5);
115 byte_stuffer_recv_byte(0, 2);
116 byte_stuffer_recv_byte(0, 3);
117 byte_stuffer_recv_byte(0, 1);
118 byte_stuffer_recv_byte(0, 0);
119}
120
121TEST_F(ByteStuffer, receives_two_valid_frames) {
122 uint8_t expected1[] = {5, 0};
123 uint8_t expected2[] = {3};
124 EXPECT_CALL(*this, validator_recv_frame(_, _, _)).With(Args<1, 2>(ElementsAreArray(expected1)));
125 EXPECT_CALL(*this, validator_recv_frame(_, _, _)).With(Args<1, 2>(ElementsAreArray(expected2)));
126 byte_stuffer_recv_byte(1, 2);
127 byte_stuffer_recv_byte(1, 5);
128 byte_stuffer_recv_byte(1, 1);
129 byte_stuffer_recv_byte(1, 0);
130 byte_stuffer_recv_byte(1, 2);
131 byte_stuffer_recv_byte(1, 3);
132 byte_stuffer_recv_byte(1, 0);
133}
134
135TEST_F(ByteStuffer, receives_valid_frame_after_unexpected_zero) {
136 uint8_t expected[] = {5, 7};
137 EXPECT_CALL(*this, validator_recv_frame(_, _, _)).With(Args<1, 2>(ElementsAreArray(expected)));
138 byte_stuffer_recv_byte(1, 3);
139 byte_stuffer_recv_byte(1, 1);
140 byte_stuffer_recv_byte(1, 0);
141 byte_stuffer_recv_byte(1, 3);
142 byte_stuffer_recv_byte(1, 5);
143 byte_stuffer_recv_byte(1, 7);
144 byte_stuffer_recv_byte(1, 0);
145}
146
147TEST_F(ByteStuffer, receives_valid_frame_after_unexpected_non_zero) {
148 uint8_t expected[] = {5, 7};
149 EXPECT_CALL(*this, validator_recv_frame(_, _, _)).With(Args<1, 2>(ElementsAreArray(expected)));
150 byte_stuffer_recv_byte(0, 2);
151 byte_stuffer_recv_byte(0, 9);
152 byte_stuffer_recv_byte(0, 4); // This should have been zero
153 byte_stuffer_recv_byte(0, 0);
154 byte_stuffer_recv_byte(0, 3);
155 byte_stuffer_recv_byte(0, 5);
156 byte_stuffer_recv_byte(0, 7);
157 byte_stuffer_recv_byte(0, 0);
158}
159
160TEST_F(ByteStuffer, receives_a_valid_frame_with_over254_non_zeroes_and_then_end_of_frame) {
161 uint8_t expected[254];
162 int i;
163 for (i = 0; i < 254; i++) {
164 expected[i] = i + 1;
165 }
166 EXPECT_CALL(*this, validator_recv_frame(_, _, _)).With(Args<1, 2>(ElementsAreArray(expected)));
167 byte_stuffer_recv_byte(0, 0xFF);
168 for (i = 0; i < 254; i++) {
169 byte_stuffer_recv_byte(0, i + 1);
170 }
171 byte_stuffer_recv_byte(0, 0);
172}
173
174TEST_F(ByteStuffer, receives_a_valid_frame_with_over254_non_zeroes_next_byte_is_non_zero) {
175 uint8_t expected[255];
176 int i;
177 for (i = 0; i < 254; i++) {
178 expected[i] = i + 1;
179 }
180 expected[254] = 7;
181 EXPECT_CALL(*this, validator_recv_frame(_, _, _)).With(Args<1, 2>(ElementsAreArray(expected)));
182 byte_stuffer_recv_byte(0, 0xFF);
183 for (i = 0; i < 254; i++) {
184 byte_stuffer_recv_byte(0, i + 1);
185 }
186 byte_stuffer_recv_byte(0, 2);
187 byte_stuffer_recv_byte(0, 7);
188 byte_stuffer_recv_byte(0, 0);
189}
190
191TEST_F(ByteStuffer, receives_a_valid_frame_with_over254_non_zeroes_next_byte_is_zero) {
192 uint8_t expected[255];
193 int i;
194 for (i = 0; i < 254; i++) {
195 expected[i] = i + 1;
196 }
197 expected[254] = 0;
198 EXPECT_CALL(*this, validator_recv_frame(_, _, _)).With(Args<1, 2>(ElementsAreArray(expected)));
199 byte_stuffer_recv_byte(0, 0xFF);
200 for (i = 0; i < 254; i++) {
201 byte_stuffer_recv_byte(0, i + 1);
202 }
203 byte_stuffer_recv_byte(0, 1);
204 byte_stuffer_recv_byte(0, 1);
205 byte_stuffer_recv_byte(0, 0);
206}
207
208TEST_F(ByteStuffer, receives_two_long_frames_and_some_more) {
209 uint8_t expected[515];
210 int i;
211 int j;
212 for (j = 0; j < 2; j++) {
213 for (i = 0; i < 254; i++) {
214 expected[i + 254 * j] = i + 1;
215 }
216 }
217 for (i = 0; i < 7; i++) {
218 expected[254 * 2 + i] = i + 1;
219 }
220 EXPECT_CALL(*this, validator_recv_frame(_, _, _)).With(Args<1, 2>(ElementsAreArray(expected)));
221 byte_stuffer_recv_byte(0, 0xFF);
222 for (i = 0; i < 254; i++) {
223 byte_stuffer_recv_byte(0, i + 1);
224 }
225 byte_stuffer_recv_byte(0, 0xFF);
226 for (i = 0; i < 254; i++) {
227 byte_stuffer_recv_byte(0, i + 1);
228 }
229 byte_stuffer_recv_byte(0, 8);
230 byte_stuffer_recv_byte(0, 1);
231 byte_stuffer_recv_byte(0, 2);
232 byte_stuffer_recv_byte(0, 3);
233 byte_stuffer_recv_byte(0, 4);
234 byte_stuffer_recv_byte(0, 5);
235 byte_stuffer_recv_byte(0, 6);
236 byte_stuffer_recv_byte(0, 7);
237 byte_stuffer_recv_byte(0, 0);
238}
239
240TEST_F(ByteStuffer, receives_an_all_zeros_frame_that_is_maximum_size) {
241 uint8_t expected[MAX_FRAME_SIZE] = {};
242 EXPECT_CALL(*this, validator_recv_frame(_, _, _)).With(Args<1, 2>(ElementsAreArray(expected)));
243 int i;
244 byte_stuffer_recv_byte(0, 1);
245 for (i = 0; i < MAX_FRAME_SIZE; i++) {
246 byte_stuffer_recv_byte(0, 1);
247 }
248 byte_stuffer_recv_byte(0, 0);
249}
250
251TEST_F(ByteStuffer, doesnt_recv_a_frame_thats_too_long_all_zeroes) {
252 uint8_t expected[1] = {0};
253 EXPECT_CALL(*this, validator_recv_frame(_, _, _)).Times(0);
254 int i;
255 byte_stuffer_recv_byte(0, 1);
256 for (i = 0; i < MAX_FRAME_SIZE; i++) {
257 byte_stuffer_recv_byte(0, 1);
258 }
259 byte_stuffer_recv_byte(0, 1);
260 byte_stuffer_recv_byte(0, 0);
261}
262
263TEST_F(ByteStuffer, received_frame_is_aborted_when_its_too_long) {
264 uint8_t expected[1] = {1};
265 EXPECT_CALL(*this, validator_recv_frame(_, _, _)).With(Args<1, 2>(ElementsAreArray(expected)));
266 int i;
267 byte_stuffer_recv_byte(0, 1);
268 for (i = 0; i < MAX_FRAME_SIZE; i++) {
269 byte_stuffer_recv_byte(0, 1);
270 }
271 byte_stuffer_recv_byte(0, 2);
272 byte_stuffer_recv_byte(0, 1);
273 byte_stuffer_recv_byte(0, 0);
274}
275
276TEST_F(ByteStuffer, does_nothing_when_sending_zero_size_frame) {
277 EXPECT_EQ(sent_data.size(), 0);
278 byte_stuffer_send_frame(0, NULL, 0);
279}
280
281TEST_F(ByteStuffer, send_one_byte_frame) {
282 uint8_t data[] = {5};
283 byte_stuffer_send_frame(1, data, 1);
284 uint8_t expected[] = {2, 5, 0};
285 EXPECT_THAT(sent_data, ElementsAreArray(expected));
286}
287
288TEST_F(ByteStuffer, sends_two_byte_frame) {
289 uint8_t data[] = {5, 0x77};
290 byte_stuffer_send_frame(0, data, 2);
291 uint8_t expected[] = {3, 5, 0x77, 0};
292 EXPECT_THAT(sent_data, ElementsAreArray(expected));
293}
294
295TEST_F(ByteStuffer, sends_one_byte_frame_with_zero) {
296 uint8_t data[] = {0};
297 byte_stuffer_send_frame(0, data, 1);
298 uint8_t expected[] = {1, 1, 0};
299 EXPECT_THAT(sent_data, ElementsAreArray(expected));
300}
301
302TEST_F(ByteStuffer, sends_two_byte_frame_starting_with_zero) {
303 uint8_t data[] = {0, 9};
304 byte_stuffer_send_frame(1, data, 2);
305 uint8_t expected[] = {1, 2, 9, 0};
306 EXPECT_THAT(sent_data, ElementsAreArray(expected));
307}
308
309TEST_F(ByteStuffer, sends_two_byte_frame_starting_with_non_zero) {
310 uint8_t data[] = {9, 0};
311 byte_stuffer_send_frame(1, data, 2);
312 uint8_t expected[] = {2, 9, 1, 0};
313 EXPECT_THAT(sent_data, ElementsAreArray(expected));
314}
315
316TEST_F(ByteStuffer, sends_three_byte_frame_zero_in_the_middle) {
317 uint8_t data[] = {9, 0, 0x68};
318 byte_stuffer_send_frame(0, data, 3);
319 uint8_t expected[] = {2, 9, 2, 0x68, 0};
320 EXPECT_THAT(sent_data, ElementsAreArray(expected));
321}
322
323TEST_F(ByteStuffer, sends_three_byte_frame_data_in_the_middle) {
324 uint8_t data[] = {0, 0x55, 0};
325 byte_stuffer_send_frame(0, data, 3);
326 uint8_t expected[] = {1, 2, 0x55, 1, 0};
327 EXPECT_THAT(sent_data, ElementsAreArray(expected));
328}
329
330TEST_F(ByteStuffer, sends_three_byte_frame_with_all_zeroes) {
331 uint8_t data[] = {0, 0, 0};
332 byte_stuffer_send_frame(0, data, 3);
333 uint8_t expected[] = {1, 1, 1, 1, 0};
334 EXPECT_THAT(sent_data, ElementsAreArray(expected));
335}
336
337TEST_F(ByteStuffer, sends_frame_with_254_non_zeroes) {
338 uint8_t data[254];
339 int i;
340 for (i = 0; i < 254; i++) {
341 data[i] = i + 1;
342 }
343 byte_stuffer_send_frame(0, data, 254);
344 uint8_t expected[256];
345 expected[0] = 0xFF;
346 for (i = 1; i < 255; i++) {
347 expected[i] = i;
348 }
349 expected[255] = 0;
350 EXPECT_THAT(sent_data, ElementsAreArray(expected));
351}
352
353TEST_F(ByteStuffer, sends_frame_with_255_non_zeroes) {
354 uint8_t data[255];
355 int i;
356 for (i = 0; i < 255; i++) {
357 data[i] = i + 1;
358 }
359 byte_stuffer_send_frame(0, data, 255);
360 uint8_t expected[258];
361 expected[0] = 0xFF;
362 for (i = 1; i < 255; i++) {
363 expected[i] = i;
364 }
365 expected[255] = 2;
366 expected[256] = 255;
367 expected[257] = 0;
368 EXPECT_THAT(sent_data, ElementsAreArray(expected));
369}
370
371TEST_F(ByteStuffer, sends_frame_with_254_non_zeroes_followed_by_zero) {
372 uint8_t data[255];
373 int i;
374 for (i = 0; i < 254; i++) {
375 data[i] = i + 1;
376 }
377 data[254] = 0;
378 byte_stuffer_send_frame(0, data, 255);
379 uint8_t expected[258];
380 expected[0] = 0xFF;
381 for (i = 1; i < 255; i++) {
382 expected[i] = i;
383 }
384 expected[255] = 1;
385 expected[256] = 1;
386 expected[257] = 0;
387 EXPECT_THAT(sent_data, ElementsAreArray(expected));
388}
389
390TEST_F(ByteStuffer, sends_and_receives_full_roundtrip_small_packet) {
391 uint8_t original_data[] = {1, 2, 3};
392 byte_stuffer_send_frame(0, original_data, sizeof(original_data));
393 EXPECT_CALL(*this, validator_recv_frame(_, _, _)).With(Args<1, 2>(ElementsAreArray(original_data)));
394 int i;
395 for (auto& d : sent_data) {
396 byte_stuffer_recv_byte(1, d);
397 }
398}
399
400TEST_F(ByteStuffer, sends_and_receives_full_roundtrip_small_packet_with_zeros) {
401 uint8_t original_data[] = {1, 0, 3, 0, 0, 9};
402 byte_stuffer_send_frame(1, original_data, sizeof(original_data));
403 EXPECT_CALL(*this, validator_recv_frame(_, _, _)).With(Args<1, 2>(ElementsAreArray(original_data)));
404 int i;
405 for (auto& d : sent_data) {
406 byte_stuffer_recv_byte(1, d);
407 }
408}
409
410TEST_F(ByteStuffer, sends_and_receives_full_roundtrip_254_bytes) {
411 uint8_t original_data[254];
412 int i;
413 for (i = 0; i < 254; i++) {
414 original_data[i] = i + 1;
415 }
416 byte_stuffer_send_frame(0, original_data, sizeof(original_data));
417 EXPECT_CALL(*this, validator_recv_frame(_, _, _)).With(Args<1, 2>(ElementsAreArray(original_data)));
418 for (auto& d : sent_data) {
419 byte_stuffer_recv_byte(1, d);
420 }
421}
422
423TEST_F(ByteStuffer, sends_and_receives_full_roundtrip_256_bytes) {
424 uint8_t original_data[256];
425 int i;
426 for (i = 0; i < 254; i++) {
427 original_data[i] = i + 1;
428 }
429 original_data[254] = 22;
430 original_data[255] = 23;
431 byte_stuffer_send_frame(0, original_data, sizeof(original_data));
432 EXPECT_CALL(*this, validator_recv_frame(_, _, _)).With(Args<1, 2>(ElementsAreArray(original_data)));
433 for (auto& d : sent_data) {
434 byte_stuffer_recv_byte(1, d);
435 }
436}
437
438TEST_F(ByteStuffer, sends_and_receives_full_roundtrip_254_bytes_and_then_zero) {
439 uint8_t original_data[255];
440 int i;
441 for (i = 0; i < 254; i++) {
442 original_data[i] = i + 1;
443 }
444 original_data[254] = 0;
445 byte_stuffer_send_frame(0, original_data, sizeof(original_data));
446 EXPECT_CALL(*this, validator_recv_frame(_, _, _)).With(Args<1, 2>(ElementsAreArray(original_data)));
447 for (auto& d : sent_data) {
448 byte_stuffer_recv_byte(1, d);
449 }
450}
diff --git a/quantum/serial_link/tests/frame_router_tests.cpp b/quantum/serial_link/tests/frame_router_tests.cpp
deleted file mode 100644
index f76dfb33d..000000000
--- a/quantum/serial_link/tests/frame_router_tests.cpp
+++ /dev/null
@@ -1,204 +0,0 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2016 Fred Sundvik
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24
25#include "gtest/gtest.h"
26#include "gmock/gmock.h"
27#include <array>
28extern "C" {
29#include "serial_link/protocol/transport.h"
30#include "serial_link/protocol/byte_stuffer.h"
31#include "serial_link/protocol/frame_router.h"
32}
33
34using testing::_;
35using testing::Args;
36using testing::ElementsAreArray;
37
38class FrameRouter : public testing::Test {
39 public:
40 FrameRouter() : current_router_buffer(nullptr) {
41 Instance = this;
42 init_byte_stuffer();
43 }
44
45 ~FrameRouter() { Instance = nullptr; }
46
47 void send_data(uint8_t link, const uint8_t* data, uint16_t size) {
48 auto& buffer = current_router_buffer->send_buffers[link];
49 std::copy(data, data + size, std::back_inserter(buffer));
50 }
51
52 void receive_data(uint8_t link, uint8_t* data, uint16_t size) {
53 int i;
54 for (i = 0; i < size; i++) {
55 byte_stuffer_recv_byte(link, data[i]);
56 }
57 }
58
59 void activate_router(uint8_t num) {
60 current_router_buffer = router_buffers + num;
61 router_set_master(num == 0);
62 }
63
64 void simulate_transport(uint8_t from, uint8_t to) {
65 activate_router(to);
66 if (from > to) {
67 receive_data(DOWN_LINK, router_buffers[from].send_buffers[UP_LINK].data(), router_buffers[from].send_buffers[UP_LINK].size());
68 } else if (to > from) {
69 receive_data(UP_LINK, router_buffers[from].send_buffers[DOWN_LINK].data(), router_buffers[from].send_buffers[DOWN_LINK].size());
70 }
71 }
72
73 MOCK_METHOD3(transport_recv_frame, void(uint8_t from, uint8_t* data, uint16_t size));
74
75 std::vector<uint8_t> received_data;
76
77 struct router_buffer {
78 std::vector<uint8_t> send_buffers[2];
79 };
80
81 router_buffer router_buffers[8];
82 router_buffer* current_router_buffer;
83
84 static FrameRouter* Instance;
85};
86
87FrameRouter* FrameRouter::Instance = nullptr;
88
89typedef struct {
90 std::array<uint8_t, 4> data;
91 uint8_t extra[16];
92} frame_buffer_t;
93
94extern "C" {
95void send_data(uint8_t link, const uint8_t* data, uint16_t size) { FrameRouter::Instance->send_data(link, data, size); }
96
97void transport_recv_frame(uint8_t from, uint8_t* data, uint16_t size) { FrameRouter::Instance->transport_recv_frame(from, data, size); }
98}
99
100TEST_F(FrameRouter, master_broadcast_is_received_by_everyone) {
101 frame_buffer_t data;
102 data.data = {0xAB, 0x70, 0x55, 0xBB};
103 activate_router(0);
104 router_send_frame(0xFF, (uint8_t*)&data, 4);
105 EXPECT_GT(router_buffers[0].send_buffers[DOWN_LINK].size(), 0);
106 EXPECT_EQ(router_buffers[0].send_buffers[UP_LINK].size(), 0);
107 EXPECT_CALL(*this, transport_recv_frame(0, _, _)).With(Args<1, 2>(ElementsAreArray(data.data)));
108 simulate_transport(0, 1);
109 EXPECT_GT(router_buffers[1].send_buffers[DOWN_LINK].size(), 0);
110 EXPECT_EQ(router_buffers[1].send_buffers[UP_LINK].size(), 0);
111
112 EXPECT_CALL(*this, transport_recv_frame(0, _, _)).With(Args<1, 2>(ElementsAreArray(data.data)));
113 simulate_transport(1, 2);
114 EXPECT_GT(router_buffers[2].send_buffers[DOWN_LINK].size(), 0);
115 EXPECT_EQ(router_buffers[2].send_buffers[UP_LINK].size(), 0);
116}
117
118TEST_F(FrameRouter, master_send_is_received_by_targets) {
119 frame_buffer_t data;
120 data.data = {0xAB, 0x70, 0x55, 0xBB};
121 activate_router(0);
122 router_send_frame((1 << 1) | (1 << 2), (uint8_t*)&data, 4);
123 EXPECT_GT(router_buffers[0].send_buffers[DOWN_LINK].size(), 0);
124 EXPECT_EQ(router_buffers[0].send_buffers[UP_LINK].size(), 0);
125
126 simulate_transport(0, 1);
127 EXPECT_GT(router_buffers[1].send_buffers[DOWN_LINK].size(), 0);
128 EXPECT_EQ(router_buffers[1].send_buffers[UP_LINK].size(), 0);
129
130 EXPECT_CALL(*this, transport_recv_frame(0, _, _)).With(Args<1, 2>(ElementsAreArray(data.data)));
131 simulate_transport(1, 2);
132 EXPECT_GT(router_buffers[2].send_buffers[DOWN_LINK].size(), 0);
133 EXPECT_EQ(router_buffers[2].send_buffers[UP_LINK].size(), 0);
134
135 EXPECT_CALL(*this, transport_recv_frame(0, _, _)).With(Args<1, 2>(ElementsAreArray(data.data)));
136 simulate_transport(2, 3);
137 EXPECT_GT(router_buffers[3].send_buffers[DOWN_LINK].size(), 0);
138 EXPECT_EQ(router_buffers[3].send_buffers[UP_LINK].size(), 0);
139}
140
141TEST_F(FrameRouter, first_link_sends_to_master) {
142 frame_buffer_t data;
143 data.data = {0xAB, 0x70, 0x55, 0xBB};
144 activate_router(1);
145 router_send_frame(0, (uint8_t*)&data, 4);
146 EXPECT_GT(router_buffers[1].send_buffers[UP_LINK].size(), 0);
147 EXPECT_EQ(router_buffers[1].send_buffers[DOWN_LINK].size(), 0);
148
149 EXPECT_CALL(*this, transport_recv_frame(1, _, _)).With(Args<1, 2>(ElementsAreArray(data.data)));
150 simulate_transport(1, 0);
151 EXPECT_EQ(router_buffers[0].send_buffers[DOWN_LINK].size(), 0);
152 EXPECT_EQ(router_buffers[0].send_buffers[UP_LINK].size(), 0);
153}
154
155TEST_F(FrameRouter, second_link_sends_to_master) {
156 frame_buffer_t data;
157 data.data = {0xAB, 0x70, 0x55, 0xBB};
158 activate_router(2);
159 router_send_frame(0, (uint8_t*)&data, 4);
160 EXPECT_GT(router_buffers[2].send_buffers[UP_LINK].size(), 0);
161 EXPECT_EQ(router_buffers[2].send_buffers[DOWN_LINK].size(), 0);
162
163 simulate_transport(2, 1);
164 EXPECT_GT(router_buffers[1].send_buffers[UP_LINK].size(), 0);
165 EXPECT_EQ(router_buffers[1].send_buffers[DOWN_LINK].size(), 0);
166
167 EXPECT_CALL(*this, transport_recv_frame(2, _, _)).With(Args<1, 2>(ElementsAreArray(data.data)));
168 simulate_transport(1, 0);
169 EXPECT_EQ(router_buffers[0].send_buffers[DOWN_LINK].size(), 0);
170 EXPECT_EQ(router_buffers[0].send_buffers[UP_LINK].size(), 0);
171}
172
173TEST_F(FrameRouter, master_sends_to_master_does_nothing) {
174 frame_buffer_t data;
175 data.data = {0xAB, 0x70, 0x55, 0xBB};
176 activate_router(0);
177 router_send_frame(0, (uint8_t*)&data, 4);
178 EXPECT_EQ(router_buffers[0].send_buffers[UP_LINK].size(), 0);
179 EXPECT_EQ(router_buffers[0].send_buffers[DOWN_LINK].size(), 0);
180}
181
182TEST_F(FrameRouter, link_sends_to_other_link_does_nothing) {
183 frame_buffer_t data;
184 data.data = {0xAB, 0x70, 0x55, 0xBB};
185 activate_router(1);
186 router_send_frame(2, (uint8_t*)&data, 4);
187 EXPECT_EQ(router_buffers[1].send_buffers[UP_LINK].size(), 0);
188 EXPECT_EQ(router_buffers[1].send_buffers[DOWN_LINK].size(), 0);
189}
190
191TEST_F(FrameRouter, master_receives_on_uplink_does_nothing) {
192 frame_buffer_t data;
193 data.data = {0xAB, 0x70, 0x55, 0xBB};
194 activate_router(1);
195 router_send_frame(0, (uint8_t*)&data, 4);
196 EXPECT_GT(router_buffers[1].send_buffers[UP_LINK].size(), 0);
197 EXPECT_EQ(router_buffers[1].send_buffers[DOWN_LINK].size(), 0);
198
199 EXPECT_CALL(*this, transport_recv_frame(_, _, _)).Times(0);
200 activate_router(0);
201 receive_data(UP_LINK, router_buffers[1].send_buffers[UP_LINK].data(), router_buffers[1].send_buffers[UP_LINK].size());
202 EXPECT_EQ(router_buffers[0].send_buffers[UP_LINK].size(), 0);
203 EXPECT_EQ(router_buffers[0].send_buffers[DOWN_LINK].size(), 0);
204}
diff --git a/quantum/serial_link/tests/frame_validator_tests.cpp b/quantum/serial_link/tests/frame_validator_tests.cpp
deleted file mode 100644
index 43dc57b63..000000000
--- a/quantum/serial_link/tests/frame_validator_tests.cpp
+++ /dev/null
@@ -1,100 +0,0 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2016 Fred Sundvik
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24
25#include "gtest/gtest.h"
26#include "gmock/gmock.h"
27extern "C" {
28#include "serial_link/protocol/frame_validator.h"
29}
30
31using testing::_;
32using testing::Args;
33using testing::ElementsAreArray;
34
35class FrameValidator : public testing::Test {
36 public:
37 FrameValidator() { Instance = this; }
38
39 ~FrameValidator() { Instance = nullptr; }
40
41 MOCK_METHOD3(route_incoming_frame, void(uint8_t link, uint8_t* data, uint16_t size));
42 MOCK_METHOD3(byte_stuffer_send_frame, void(uint8_t link, uint8_t* data, uint16_t size));
43
44 static FrameValidator* Instance;
45};
46
47FrameValidator* FrameValidator::Instance = nullptr;
48
49extern "C" {
50void route_incoming_frame(uint8_t link, uint8_t* data, uint16_t size) { FrameValidator::Instance->route_incoming_frame(link, data, size); }
51
52void byte_stuffer_send_frame(uint8_t link, uint8_t* data, uint16_t size) { FrameValidator::Instance->byte_stuffer_send_frame(link, data, size); }
53}
54
55TEST_F(FrameValidator, doesnt_validate_frames_under_5_bytes) {
56 EXPECT_CALL(*this, route_incoming_frame(_, _, _)).Times(0);
57 uint8_t data[] = {1, 2};
58 validator_recv_frame(0, 0, 1);
59 validator_recv_frame(0, data, 2);
60 validator_recv_frame(0, data, 3);
61 validator_recv_frame(0, data, 4);
62}
63
64TEST_F(FrameValidator, validates_one_byte_frame_with_correct_crc) {
65 uint8_t data[] = {0x44, 0x04, 0x6A, 0xB3, 0xA3};
66 EXPECT_CALL(*this, route_incoming_frame(_, _, _)).With(Args<1, 2>(ElementsAreArray(data, 1)));
67 validator_recv_frame(0, data, 5);
68}
69
70TEST_F(FrameValidator, does_not_validate_one_byte_frame_with_incorrect_crc) {
71 uint8_t data[] = {0x44, 0, 0, 0, 0};
72 EXPECT_CALL(*this, route_incoming_frame(_, _, _)).Times(0);
73 validator_recv_frame(1, data, 5);
74}
75
76TEST_F(FrameValidator, validates_four_byte_frame_with_correct_crc) {
77 uint8_t data[] = {0x44, 0x10, 0xFF, 0x00, 0x74, 0x4E, 0x30, 0xBA};
78 EXPECT_CALL(*this, route_incoming_frame(_, _, _)).With(Args<1, 2>(ElementsAreArray(data, 4)));
79 validator_recv_frame(1, data, 8);
80}
81
82TEST_F(FrameValidator, validates_five_byte_frame_with_correct_crc) {
83 uint8_t data[] = {1, 2, 3, 4, 5, 0xF4, 0x99, 0x0B, 0x47};
84 EXPECT_CALL(*this, route_incoming_frame(_, _, _)).With(Args<1, 2>(ElementsAreArray(data, 5)));
85 validator_recv_frame(0, data, 9);
86}
87
88TEST_F(FrameValidator, sends_one_byte_with_correct_crc) {
89 uint8_t original[] = {0x44, 0, 0, 0, 0};
90 uint8_t expected[] = {0x44, 0x04, 0x6A, 0xB3, 0xA3};
91 EXPECT_CALL(*this, byte_stuffer_send_frame(_, _, _)).With(Args<1, 2>(ElementsAreArray(expected)));
92 validator_send_frame(0, original, 1);
93}
94
95TEST_F(FrameValidator, sends_five_bytes_with_correct_crc) {
96 uint8_t original[] = {1, 2, 3, 4, 5, 0, 0, 0, 0};
97 uint8_t expected[] = {1, 2, 3, 4, 5, 0xF4, 0x99, 0x0B, 0x47};
98 EXPECT_CALL(*this, byte_stuffer_send_frame(_, _, _)).With(Args<1, 2>(ElementsAreArray(expected)));
99 validator_send_frame(0, original, 5);
100}
diff --git a/quantum/serial_link/tests/rules.mk b/quantum/serial_link/tests/rules.mk
deleted file mode 100644
index b81515bc5..000000000
--- a/quantum/serial_link/tests/rules.mk
+++ /dev/null
@@ -1,22 +0,0 @@
1serial_link_byte_stuffer_SRC :=\
2 $(SERIAL_PATH)/tests/byte_stuffer_tests.cpp \
3 $(SERIAL_PATH)/protocol/byte_stuffer.c
4
5serial_link_frame_validator_SRC := \
6 $(SERIAL_PATH)/tests/frame_validator_tests.cpp \
7 $(SERIAL_PATH)/protocol/frame_validator.c
8
9serial_link_frame_router_SRC := \
10 $(SERIAL_PATH)/tests/frame_router_tests.cpp \
11 $(SERIAL_PATH)/protocol/byte_stuffer.c \
12 $(SERIAL_PATH)/protocol/frame_validator.c \
13 $(SERIAL_PATH)/protocol/frame_router.c
14
15serial_link_triple_buffered_object_SRC := \
16 $(SERIAL_PATH)/tests/triple_buffered_object_tests.cpp \
17 $(SERIAL_PATH)/protocol/triple_buffered_object.c
18
19serial_link_transport_SRC := \
20 $(SERIAL_PATH)/tests/transport_tests.cpp \
21 $(SERIAL_PATH)/protocol/transport.c \
22 $(SERIAL_PATH)/protocol/triple_buffered_object.c
diff --git a/quantum/serial_link/tests/testlist.mk b/quantum/serial_link/tests/testlist.mk
deleted file mode 100644
index c5edaf478..000000000
--- a/quantum/serial_link/tests/testlist.mk
+++ /dev/null
@@ -1,6 +0,0 @@
1TEST_LIST +=\
2 serial_link_byte_stuffer\
3 serial_link_frame_validator\
4 serial_link_frame_router\
5 serial_link_triple_buffered_object\
6 serial_link_transport
diff --git a/quantum/serial_link/tests/transport_tests.cpp b/quantum/serial_link/tests/transport_tests.cpp
deleted file mode 100644
index cfd111046..000000000
--- a/quantum/serial_link/tests/transport_tests.cpp
+++ /dev/null
@@ -1,184 +0,0 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2016 Fred Sundvik
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24
25#include "gtest/gtest.h"
26#include "gmock/gmock.h"
27
28using testing::_;
29using testing::Args;
30using testing::ElementsAreArray;
31
32extern "C" {
33#include "serial_link/protocol/transport.h"
34}
35
36struct test_object1 {
37 uint32_t test;
38};
39
40struct test_object2 {
41 uint32_t test1;
42 uint32_t test2;
43};
44
45MASTER_TO_ALL_SLAVES_OBJECT(master_to_slave, test_object1);
46MASTER_TO_SINGLE_SLAVE_OBJECT(master_to_single_slave, test_object1);
47SLAVE_TO_MASTER_OBJECT(slave_to_master, test_object1);
48
49static remote_object_t* test_remote_objects[] = {
50 REMOTE_OBJECT(master_to_slave),
51 REMOTE_OBJECT(master_to_single_slave),
52 REMOTE_OBJECT(slave_to_master),
53};
54
55class Transport : public testing::Test {
56 public:
57 Transport() {
58 Instance = this;
59 add_remote_objects(test_remote_objects, sizeof(test_remote_objects) / sizeof(remote_object_t*));
60 }
61
62 ~Transport() {
63 Instance = nullptr;
64 reinitialize_serial_link_transport();
65 }
66
67 MOCK_METHOD0(signal_data_written, void());
68 MOCK_METHOD1(router_send_frame, void(uint8_t destination));
69
70 void router_send_frame(uint8_t destination, uint8_t* data, uint16_t size) {
71 router_send_frame(destination);
72 std::copy(data, data + size, std::back_inserter(sent_data));
73 }
74
75 static Transport* Instance;
76
77 std::vector<uint8_t> sent_data;
78};
79
80Transport* Transport::Instance = nullptr;
81
82extern "C" {
83void signal_data_written(void) { Transport::Instance->signal_data_written(); }
84
85void router_send_frame(uint8_t destination, uint8_t* data, uint16_t size) { Transport::Instance->router_send_frame(destination, data, size); }
86}
87
88TEST_F(Transport, write_to_local_signals_an_event) {
89 begin_write_master_to_slave();
90 EXPECT_CALL(*this, signal_data_written());
91 end_write_master_to_slave();
92 begin_write_slave_to_master();
93 EXPECT_CALL(*this, signal_data_written());
94 end_write_slave_to_master();
95 begin_write_master_to_single_slave(1);
96 EXPECT_CALL(*this, signal_data_written());
97 end_write_master_to_single_slave(1);
98}
99
100TEST_F(Transport, writes_from_master_to_all_slaves) {
101 update_transport();
102 test_object1* obj = begin_write_master_to_slave();
103 obj->test = 5;
104 EXPECT_CALL(*this, signal_data_written());
105 end_write_master_to_slave();
106 EXPECT_CALL(*this, router_send_frame(0xFF));
107 update_transport();
108 transport_recv_frame(0, sent_data.data(), sent_data.size());
109 test_object1* obj2 = read_master_to_slave();
110 EXPECT_NE(obj2, nullptr);
111 EXPECT_EQ(obj2->test, 5);
112}
113
114TEST_F(Transport, writes_from_slave_to_master) {
115 update_transport();
116 test_object1* obj = begin_write_slave_to_master();
117 obj->test = 7;
118 EXPECT_CALL(*this, signal_data_written());
119 end_write_slave_to_master();
120 EXPECT_CALL(*this, router_send_frame(0));
121 update_transport();
122 transport_recv_frame(3, sent_data.data(), sent_data.size());
123 test_object1* obj2 = read_slave_to_master(2);
124 EXPECT_EQ(read_slave_to_master(0), nullptr);
125 EXPECT_NE(obj2, nullptr);
126 EXPECT_EQ(obj2->test, 7);
127}
128
129TEST_F(Transport, writes_from_master_to_single_slave) {
130 update_transport();
131 test_object1* obj = begin_write_master_to_single_slave(3);
132 obj->test = 7;
133 EXPECT_CALL(*this, signal_data_written());
134 end_write_master_to_single_slave(3);
135 EXPECT_CALL(*this, router_send_frame(4));
136 update_transport();
137 transport_recv_frame(0, sent_data.data(), sent_data.size());
138 test_object1* obj2 = read_master_to_single_slave();
139 EXPECT_NE(obj2, nullptr);
140 EXPECT_EQ(obj2->test, 7);
141}
142
143TEST_F(Transport, ignores_object_with_invalid_id) {
144 update_transport();
145 test_object1* obj = begin_write_master_to_single_slave(3);
146 obj->test = 7;
147 EXPECT_CALL(*this, signal_data_written());
148 end_write_master_to_single_slave(3);
149 EXPECT_CALL(*this, router_send_frame(4));
150 update_transport();
151 sent_data[sent_data.size() - 1] = 44;
152 transport_recv_frame(0, sent_data.data(), sent_data.size());
153 test_object1* obj2 = read_master_to_single_slave();
154 EXPECT_EQ(obj2, nullptr);
155}
156
157TEST_F(Transport, ignores_object_with_size_too_small) {
158 update_transport();
159 test_object1* obj = begin_write_master_to_slave();
160 obj->test = 7;
161 EXPECT_CALL(*this, signal_data_written());
162 end_write_master_to_slave();
163 EXPECT_CALL(*this, router_send_frame(_));
164 update_transport();
165 sent_data[sent_data.size() - 2] = 0;
166 transport_recv_frame(0, sent_data.data(), sent_data.size() - 1);
167 test_object1* obj2 = read_master_to_slave();
168 EXPECT_EQ(obj2, nullptr);
169}
170
171TEST_F(Transport, ignores_object_with_size_too_big) {
172 update_transport();
173 test_object1* obj = begin_write_master_to_slave();
174 obj->test = 7;
175 EXPECT_CALL(*this, signal_data_written());
176 end_write_master_to_slave();
177 EXPECT_CALL(*this, router_send_frame(_));
178 update_transport();
179 sent_data.resize(sent_data.size() + 22);
180 sent_data[sent_data.size() - 1] = 0;
181 transport_recv_frame(0, sent_data.data(), sent_data.size());
182 test_object1* obj2 = read_master_to_slave();
183 EXPECT_EQ(obj2, nullptr);
184}
diff --git a/quantum/serial_link/tests/triple_buffered_object_tests.cpp b/quantum/serial_link/tests/triple_buffered_object_tests.cpp
deleted file mode 100644
index 8de9bfdeb..000000000
--- a/quantum/serial_link/tests/triple_buffered_object_tests.cpp
+++ /dev/null
@@ -1,80 +0,0 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2016 Fred Sundvik
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24
25#include "gtest/gtest.h"
26extern "C" {
27#include "serial_link/protocol/triple_buffered_object.h"
28}
29
30struct test_object {
31 uint8_t state;
32 uint32_t buffer[3];
33};
34
35test_object test_object;
36
37class TripleBufferedObject : public testing::Test {
38 public:
39 TripleBufferedObject() { triple_buffer_init((triple_buffer_object_t*)&test_object); }
40};
41
42TEST_F(TripleBufferedObject, writes_and_reads_object) {
43 *triple_buffer_begin_write(&test_object) = 0x3456ABCC;
44 triple_buffer_end_write(&test_object);
45 EXPECT_EQ(*triple_buffer_read(&test_object), 0x3456ABCC);
46}
47
48TEST_F(TripleBufferedObject, does_not_read_empty) { EXPECT_EQ(triple_buffer_read(&test_object), nullptr); }
49
50TEST_F(TripleBufferedObject, writes_twice_and_reads_object) {
51 *triple_buffer_begin_write(&test_object) = 0x3456ABCC;
52 triple_buffer_end_write(&test_object);
53 *triple_buffer_begin_write(&test_object) = 0x44778899;
54 triple_buffer_end_write(&test_object);
55 EXPECT_EQ(*triple_buffer_read(&test_object), 0x44778899);
56}
57
58TEST_F(TripleBufferedObject, performs_another_write_in_the_middle_of_read) {
59 *triple_buffer_begin_write(&test_object) = 1;
60 triple_buffer_end_write(&test_object);
61 uint32_t* read = triple_buffer_read(&test_object);
62 *triple_buffer_begin_write(&test_object) = 2;
63 triple_buffer_end_write(&test_object);
64 EXPECT_EQ(*read, 1);
65 EXPECT_EQ(*triple_buffer_read(&test_object), 2);
66 EXPECT_EQ(triple_buffer_read(&test_object), nullptr);
67}
68
69TEST_F(TripleBufferedObject, performs_two_writes_in_the_middle_of_read) {
70 *triple_buffer_begin_write(&test_object) = 1;
71 triple_buffer_end_write(&test_object);
72 uint32_t* read = triple_buffer_read(&test_object);
73 *triple_buffer_begin_write(&test_object) = 2;
74 triple_buffer_end_write(&test_object);
75 *triple_buffer_begin_write(&test_object) = 3;
76 triple_buffer_end_write(&test_object);
77 EXPECT_EQ(*read, 1);
78 EXPECT_EQ(*triple_buffer_read(&test_object), 3);
79 EXPECT_EQ(triple_buffer_read(&test_object), nullptr);
80}
diff --git a/quantum/split_common/transactions.c b/quantum/split_common/transactions.c
index fd676f072..3ff87710e 100644
--- a/quantum/split_common/transactions.c
+++ b/quantum/split_common/transactions.c
@@ -42,8 +42,8 @@
42 { &dummy, 0, 0, sizeof_member(split_shared_memory_t, member), offsetof(split_shared_memory_t, member), cb } 42 { &dummy, 0, 0, sizeof_member(split_shared_memory_t, member), offsetof(split_shared_memory_t, member), cb }
43#define trans_target2initiator_initializer(member) trans_target2initiator_initializer_cb(member, NULL) 43#define trans_target2initiator_initializer(member) trans_target2initiator_initializer_cb(member, NULL)
44 44
45#define transport_write(id, data, length) transport_execute_transaction(id, data, length, NULL, 0) 45#define transport_write(id, data, length) transport_execute_transaction(id, data, length, NULL, 0)
46#define transport_read(id, data, length) transport_execute_transaction(id, NULL, 0, data, length) 46#define transport_read(id, data, length) transport_execute_transaction(id, NULL, 0, data, length)
47 47
48#if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER) 48#if defined(SPLIT_TRANSACTION_IDS_KB) || defined(SPLIT_TRANSACTION_IDS_USER)
49// Forward-declare the RPC callback handlers 49// Forward-declare the RPC callback handlers
@@ -157,8 +157,8 @@ static void master_matrix_handlers_slave(matrix_row_t master_matrix[], matrix_ro
157 memcpy(master_matrix, split_shmem->mmatrix.matrix, sizeof(split_shmem->mmatrix.matrix)); 157 memcpy(master_matrix, split_shmem->mmatrix.matrix, sizeof(split_shmem->mmatrix.matrix));
158} 158}
159 159
160# define TRANSACTIONS_MASTER_MATRIX_MASTER() TRANSACTION_HANDLER_MASTER(master_matrix) 160# define TRANSACTIONS_MASTER_MATRIX_MASTER() TRANSACTION_HANDLER_MASTER(master_matrix)
161# define TRANSACTIONS_MASTER_MATRIX_SLAVE() TRANSACTION_HANDLER_SLAVE(master_matrix) 161# define TRANSACTIONS_MASTER_MATRIX_SLAVE() TRANSACTION_HANDLER_SLAVE(master_matrix)
162# define TRANSACTIONS_MASTER_MATRIX_REGISTRATIONS [PUT_MASTER_MATRIX] = trans_initiator2target_initializer(mmatrix.matrix), 162# define TRANSACTIONS_MASTER_MATRIX_REGISTRATIONS [PUT_MASTER_MATRIX] = trans_initiator2target_initializer(mmatrix.matrix),
163 163
164#else // SPLIT_TRANSPORT_MIRROR 164#else // SPLIT_TRANSPORT_MIRROR
@@ -235,8 +235,8 @@ static void sync_timer_handlers_slave(matrix_row_t master_matrix[], matrix_row_t
235 } 235 }
236} 236}
237 237
238# define TRANSACTIONS_SYNC_TIMER_MASTER() TRANSACTION_HANDLER_MASTER(sync_timer) 238# define TRANSACTIONS_SYNC_TIMER_MASTER() TRANSACTION_HANDLER_MASTER(sync_timer)
239# define TRANSACTIONS_SYNC_TIMER_SLAVE() TRANSACTION_HANDLER_SLAVE(sync_timer) 239# define TRANSACTIONS_SYNC_TIMER_SLAVE() TRANSACTION_HANDLER_SLAVE(sync_timer)
240# define TRANSACTIONS_SYNC_TIMER_REGISTRATIONS [PUT_SYNC_TIMER] = trans_initiator2target_initializer(sync_timer), 240# define TRANSACTIONS_SYNC_TIMER_REGISTRATIONS [PUT_SYNC_TIMER] = trans_initiator2target_initializer(sync_timer),
241 241
242#else // DISABLE_SYNC_TIMER 242#else // DISABLE_SYNC_TIMER
@@ -300,8 +300,8 @@ static void led_state_handlers_slave(matrix_row_t master_matrix[], matrix_row_t
300 set_split_host_keyboard_leds(split_shmem->led_state); 300 set_split_host_keyboard_leds(split_shmem->led_state);
301} 301}
302 302
303# define TRANSACTIONS_LED_STATE_MASTER() TRANSACTION_HANDLER_MASTER(led_state) 303# define TRANSACTIONS_LED_STATE_MASTER() TRANSACTION_HANDLER_MASTER(led_state)
304# define TRANSACTIONS_LED_STATE_SLAVE() TRANSACTION_HANDLER_SLAVE(led_state) 304# define TRANSACTIONS_LED_STATE_SLAVE() TRANSACTION_HANDLER_SLAVE(led_state)
305# define TRANSACTIONS_LED_STATE_REGISTRATIONS [PUT_LED_STATE] = trans_initiator2target_initializer(led_state), 305# define TRANSACTIONS_LED_STATE_REGISTRATIONS [PUT_LED_STATE] = trans_initiator2target_initializer(led_state),
306 306
307#else // SPLIT_LED_STATE_ENABLE 307#else // SPLIT_LED_STATE_ENABLE
@@ -357,8 +357,8 @@ static void mods_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave
357# endif 357# endif
358} 358}
359 359
360# define TRANSACTIONS_MODS_MASTER() TRANSACTION_HANDLER_MASTER(mods) 360# define TRANSACTIONS_MODS_MASTER() TRANSACTION_HANDLER_MASTER(mods)
361# define TRANSACTIONS_MODS_SLAVE() TRANSACTION_HANDLER_SLAVE(mods) 361# define TRANSACTIONS_MODS_SLAVE() TRANSACTION_HANDLER_SLAVE(mods)
362# define TRANSACTIONS_MODS_REGISTRATIONS [PUT_MODS] = trans_initiator2target_initializer(mods), 362# define TRANSACTIONS_MODS_REGISTRATIONS [PUT_MODS] = trans_initiator2target_initializer(mods),
363 363
364#else // SPLIT_MODS_ENABLE 364#else // SPLIT_MODS_ENABLE
@@ -382,8 +382,8 @@ static bool backlight_handlers_master(matrix_row_t master_matrix[], matrix_row_t
382 382
383static void backlight_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { backlight_set(split_shmem->backlight_level); } 383static void backlight_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { backlight_set(split_shmem->backlight_level); }
384 384
385# define TRANSACTIONS_BACKLIGHT_MASTER() TRANSACTION_HANDLER_MASTER(backlight) 385# define TRANSACTIONS_BACKLIGHT_MASTER() TRANSACTION_HANDLER_MASTER(backlight)
386# define TRANSACTIONS_BACKLIGHT_SLAVE() TRANSACTION_HANDLER_SLAVE(backlight) 386# define TRANSACTIONS_BACKLIGHT_SLAVE() TRANSACTION_HANDLER_SLAVE(backlight)
387# define TRANSACTIONS_BACKLIGHT_REGISTRATIONS [PUT_BACKLIGHT] = trans_initiator2target_initializer(backlight_level), 387# define TRANSACTIONS_BACKLIGHT_REGISTRATIONS [PUT_BACKLIGHT] = trans_initiator2target_initializer(backlight_level),
388 388
389#else // BACKLIGHT_ENABLE 389#else // BACKLIGHT_ENABLE
@@ -419,8 +419,8 @@ static void rgblight_handlers_slave(matrix_row_t master_matrix[], matrix_row_t s
419 } 419 }
420} 420}
421 421
422# define TRANSACTIONS_RGBLIGHT_MASTER() TRANSACTION_HANDLER_MASTER(rgblight) 422# define TRANSACTIONS_RGBLIGHT_MASTER() TRANSACTION_HANDLER_MASTER(rgblight)
423# define TRANSACTIONS_RGBLIGHT_SLAVE() TRANSACTION_HANDLER_SLAVE(rgblight) 423# define TRANSACTIONS_RGBLIGHT_SLAVE() TRANSACTION_HANDLER_SLAVE(rgblight)
424# define TRANSACTIONS_RGBLIGHT_REGISTRATIONS [PUT_RGBLIGHT] = trans_initiator2target_initializer(rgblight_sync), 424# define TRANSACTIONS_RGBLIGHT_REGISTRATIONS [PUT_RGBLIGHT] = trans_initiator2target_initializer(rgblight_sync),
425 425
426#else // defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT) 426#else // defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
@@ -449,8 +449,8 @@ static void led_matrix_handlers_slave(matrix_row_t master_matrix[], matrix_row_t
449 led_matrix_set_suspend_state(split_shmem->led_matrix_sync.led_suspend_state); 449 led_matrix_set_suspend_state(split_shmem->led_matrix_sync.led_suspend_state);
450} 450}
451 451
452# define TRANSACTIONS_LED_MATRIX_MASTER() TRANSACTION_HANDLER_MASTER(led_matrix) 452# define TRANSACTIONS_LED_MATRIX_MASTER() TRANSACTION_HANDLER_MASTER(led_matrix)
453# define TRANSACTIONS_LED_MATRIX_SLAVE() TRANSACTION_HANDLER_SLAVE(led_matrix) 453# define TRANSACTIONS_LED_MATRIX_SLAVE() TRANSACTION_HANDLER_SLAVE(led_matrix)
454# define TRANSACTIONS_LED_MATRIX_REGISTRATIONS [PUT_LED_MATRIX] = trans_initiator2target_initializer(led_matrix_sync), 454# define TRANSACTIONS_LED_MATRIX_REGISTRATIONS [PUT_LED_MATRIX] = trans_initiator2target_initializer(led_matrix_sync),
455 455
456#else // defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT) 456#else // defined(LED_MATRIX_ENABLE) && defined(LED_MATRIX_SPLIT)
@@ -479,8 +479,8 @@ static void rgb_matrix_handlers_slave(matrix_row_t master_matrix[], matrix_row_t
479 rgb_matrix_set_suspend_state(split_shmem->rgb_matrix_sync.rgb_suspend_state); 479 rgb_matrix_set_suspend_state(split_shmem->rgb_matrix_sync.rgb_suspend_state);
480} 480}
481 481
482# define TRANSACTIONS_RGB_MATRIX_MASTER() TRANSACTION_HANDLER_MASTER(rgb_matrix) 482# define TRANSACTIONS_RGB_MATRIX_MASTER() TRANSACTION_HANDLER_MASTER(rgb_matrix)
483# define TRANSACTIONS_RGB_MATRIX_SLAVE() TRANSACTION_HANDLER_SLAVE(rgb_matrix) 483# define TRANSACTIONS_RGB_MATRIX_SLAVE() TRANSACTION_HANDLER_SLAVE(rgb_matrix)
484# define TRANSACTIONS_RGB_MATRIX_REGISTRATIONS [PUT_RGB_MATRIX] = trans_initiator2target_initializer(rgb_matrix_sync), 484# define TRANSACTIONS_RGB_MATRIX_REGISTRATIONS [PUT_RGB_MATRIX] = trans_initiator2target_initializer(rgb_matrix_sync),
485 485
486#else // defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT) 486#else // defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_SPLIT)
@@ -504,8 +504,8 @@ static bool wpm_handlers_master(matrix_row_t master_matrix[], matrix_row_t slave
504 504
505static void wpm_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { set_current_wpm(split_shmem->current_wpm); } 505static void wpm_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { set_current_wpm(split_shmem->current_wpm); }
506 506
507# define TRANSACTIONS_WPM_MASTER() TRANSACTION_HANDLER_MASTER(wpm) 507# define TRANSACTIONS_WPM_MASTER() TRANSACTION_HANDLER_MASTER(wpm)
508# define TRANSACTIONS_WPM_SLAVE() TRANSACTION_HANDLER_SLAVE(wpm) 508# define TRANSACTIONS_WPM_SLAVE() TRANSACTION_HANDLER_SLAVE(wpm)
509# define TRANSACTIONS_WPM_REGISTRATIONS [PUT_WPM] = trans_initiator2target_initializer(current_wpm), 509# define TRANSACTIONS_WPM_REGISTRATIONS [PUT_WPM] = trans_initiator2target_initializer(current_wpm),
510 510
511#else // defined(WPM_ENABLE) && defined(SPLIT_WPM_ENABLE) 511#else // defined(WPM_ENABLE) && defined(SPLIT_WPM_ENABLE)
@@ -535,8 +535,8 @@ static void oled_handlers_slave(matrix_row_t master_matrix[], matrix_row_t slave
535 } 535 }
536} 536}
537 537
538# define TRANSACTIONS_OLED_MASTER() TRANSACTION_HANDLER_MASTER(oled) 538# define TRANSACTIONS_OLED_MASTER() TRANSACTION_HANDLER_MASTER(oled)
539# define TRANSACTIONS_OLED_SLAVE() TRANSACTION_HANDLER_SLAVE(oled) 539# define TRANSACTIONS_OLED_SLAVE() TRANSACTION_HANDLER_SLAVE(oled)
540# define TRANSACTIONS_OLED_REGISTRATIONS [PUT_OLED] = trans_initiator2target_initializer(current_oled_state), 540# define TRANSACTIONS_OLED_REGISTRATIONS [PUT_OLED] = trans_initiator2target_initializer(current_oled_state),
541 541
542#else // defined(OLED_ENABLE) && defined(SPLIT_OLED_ENABLE) 542#else // defined(OLED_ENABLE) && defined(SPLIT_OLED_ENABLE)
@@ -566,8 +566,8 @@ static void st7565_handlers_slave(matrix_row_t master_matrix[], matrix_row_t sla
566 } 566 }
567} 567}
568 568
569# define TRANSACTIONS_ST7565_MASTER() TRANSACTION_HANDLER_MASTER(st7565) 569# define TRANSACTIONS_ST7565_MASTER() TRANSACTION_HANDLER_MASTER(st7565)
570# define TRANSACTIONS_ST7565_SLAVE() TRANSACTION_HANDLER_SLAVE(st7565) 570# define TRANSACTIONS_ST7565_SLAVE() TRANSACTION_HANDLER_SLAVE(st7565)
571# define TRANSACTIONS_ST7565_REGISTRATIONS [PUT_ST7565] = trans_initiator2target_initializer(current_st7565_state), 571# define TRANSACTIONS_ST7565_REGISTRATIONS [PUT_ST7565] = trans_initiator2target_initializer(current_st7565_state),
572 572
573#else // defined(ST7565_ENABLE) && defined(SPLIT_ST7565_ENABLE) 573#else // defined(ST7565_ENABLE) && defined(SPLIT_ST7565_ENABLE)
diff --git a/quantum/sync_timer.c b/quantum/sync_timer.c
new file mode 100644
index 000000000..de24b463b
--- /dev/null
+++ b/quantum/sync_timer.c
@@ -0,0 +1,58 @@
1/*
2Copyright (C) 2020 Ryan Caltabiano <https://github.com/XScorpion2>
3
4Permission is hereby granted, free of charge, to any person obtaining a copy of
5this software and associated documentation files (the "Software"), to deal in
6the Software without restriction, including without limitation the rights to
7use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
8of the Software, and to permit persons to whom the Software is furnished to do
9so, subject to the following conditions:
10
11The above copyright notice and this permission notice shall be included in all
12copies or substantial portions of the Software.
13
14If you happen to meet one of the copyright holders in a bar you are obligated
15to buy them one pint of beer.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23SOFTWARE.
24*/
25
26#include "sync_timer.h"
27#include "keyboard.h"
28
29#if defined(SPLIT_KEYBOARD) && !defined(DISABLE_SYNC_TIMER)
30volatile int32_t sync_timer_ms;
31
32void sync_timer_init(void) { sync_timer_ms = 0; }
33
34void sync_timer_update(uint32_t time) {
35 if (is_keyboard_master()) return;
36 sync_timer_ms = time - timer_read32();
37}
38
39uint16_t sync_timer_read(void) {
40 if (is_keyboard_master()) return timer_read();
41 return sync_timer_read32();
42}
43
44uint32_t sync_timer_read32(void) {
45 if (is_keyboard_master()) return timer_read32();
46 return sync_timer_ms + timer_read32();
47}
48
49uint16_t sync_timer_elapsed(uint16_t last) {
50 if (is_keyboard_master()) return timer_elapsed(last);
51 return TIMER_DIFF_16(sync_timer_read(), last);
52}
53
54uint32_t sync_timer_elapsed32(uint32_t last) {
55 if (is_keyboard_master()) return timer_elapsed32(last);
56 return TIMER_DIFF_32(sync_timer_read32(), last);
57}
58#endif
diff --git a/quantum/sync_timer.h b/quantum/sync_timer.h
new file mode 100644
index 000000000..9ddef45bb
--- /dev/null
+++ b/quantum/sync_timer.h
@@ -0,0 +1,54 @@
1/*
2Copyright (C) 2020 Ryan Caltabiano <https://github.com/XScorpion2>
3
4Permission is hereby granted, free of charge, to any person obtaining a copy of
5this software and associated documentation files (the "Software"), to deal in
6the Software without restriction, including without limitation the rights to
7use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
8of the Software, and to permit persons to whom the Software is furnished to do
9so, subject to the following conditions:
10
11The above copyright notice and this permission notice shall be included in all
12copies or substantial portions of the Software.
13
14If you happen to meet one of the copyright holders in a bar you are obligated
15to buy them one pint of beer.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23SOFTWARE.
24*/
25
26#pragma once
27
28#include <stdint.h>
29#include "timer.h"
30
31#ifdef __cplusplus
32extern "C" {
33#endif
34
35#if defined(SPLIT_KEYBOARD) && !defined(DISABLE_SYNC_TIMER)
36void sync_timer_init(void);
37void sync_timer_update(uint32_t time);
38uint16_t sync_timer_read(void);
39uint32_t sync_timer_read32(void);
40uint16_t sync_timer_elapsed(uint16_t last);
41uint32_t sync_timer_elapsed32(uint32_t last);
42#else
43# define sync_timer_init()
44# define sync_timer_clear()
45# define sync_timer_update(t)
46# define sync_timer_read() timer_read()
47# define sync_timer_read32() timer_read32()
48# define sync_timer_elapsed(t) timer_elapsed(t)
49# define sync_timer_elapsed32(t) timer_elapsed32(t)
50#endif
51
52#ifdef __cplusplus
53}
54#endif
diff --git a/quantum/virtser.h b/quantum/virtser.h
new file mode 100644
index 000000000..df7e87984
--- /dev/null
+++ b/quantum/virtser.h
@@ -0,0 +1,9 @@
1#pragma once
2
3void virtser_init(void);
4
5/* Define this function in your code to process incoming bytes */
6void virtser_recv(const uint8_t ch);
7
8/* Call this to send a character over the Virtual Serial Device */
9void virtser_send(const uint8_t byte);
diff --git a/quantum/visualizer/LICENSE.md b/quantum/visualizer/LICENSE.md
deleted file mode 100644
index 22d4c3f08..000000000
--- a/quantum/visualizer/LICENSE.md
+++ /dev/null
@@ -1,29 +0,0 @@
1The files in this project are licensed under the MIT license
2It uses the following libraries
3uGFX - with it's own license, see the license.html file in the uGFX subfolder for more information
4tmk_core - is indirectly used and not included in the repository. It's licensed under the GPLv2 license
5Chibios - which is used by tmk_core is licensed under GPLv3.
6
7Therefore the effective license for any project using the library is GPLv3
8
9The MIT License (MIT)
10
11Copyright (c) 2016 Fred Sundvik
12
13Permission is hereby granted, free of charge, to any person obtaining a copy
14of this software and associated documentation files (the "Software"), to deal
15in the Software without restriction, including without limitation the rights
16to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17copies of the Software, and to permit persons to whom the Software is
18furnished to do so, subject to the following conditions:
19
20The above copyright notice and this permission notice shall be included in all
21copies or substantial portions of the Software.
22
23THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29SOFTWARE.
diff --git a/quantum/visualizer/common_gfxconf.h b/quantum/visualizer/common_gfxconf.h
deleted file mode 100644
index e0735b37d..000000000
--- a/quantum/visualizer/common_gfxconf.h
+++ /dev/null
@@ -1,354 +0,0 @@
1/**
2 * This file has a different license to the rest of the uGFX system.
3 * You can copy, modify and distribute this file as you see fit.
4 * You do not need to publish your source modifications to this file.
5 * The only thing you are not permitted to do is to relicense it
6 * under a different license.
7 */
8
9/**
10 * Copy this file into your project directory and rename it as gfxconf.h
11 * Edit your copy to turn on the uGFX features you want to use.
12 * The values below are the defaults.
13 *
14 * Only remove the comments from lines where you want to change the
15 * default value. This allows definitions to be included from
16 * driver makefiles when required and provides the best future
17 * compatibility for your project.
18 *
19 * Please use spaces instead of tabs in this file.
20 */
21
22#pragma once
23
24///////////////////////////////////////////////////////////////////////////
25// GFX - Compatibility options //
26///////////////////////////////////////////////////////////////////////////
27//#define GFX_COMPAT_V2 GFXON
28//#define GFX_COMPAT_OLDCOLORS GFXON
29
30///////////////////////////////////////////////////////////////////////////
31// GOS - One of these must be defined, preferably in your Makefile //
32///////////////////////////////////////////////////////////////////////////
33//#define GFX_USE_OS_CHIBIOS GFXOFF
34//#define GFX_USE_OS_FREERTOS GFXOFF
35// #define GFX_FREERTOS_USE_TRACE GFXOFF
36//#define GFX_USE_OS_WIN32 GFXOFF
37//#define GFX_USE_OS_LINUX GFXOFF
38//#define GFX_USE_OS_OSX GFXOFF
39//#define GFX_USE_OS_ECOS GFXOFF
40//#define GFX_USE_OS_RAWRTOS GFXOFF
41//#define GFX_USE_OS_ARDUINO GFXOFF
42//#define GFX_USE_OS_KEIL GFXOFF
43//#define GFX_USE_OS_RTX5 GFXOFF
44//#define GFX_USE_OS_CMSIS GFXOFF
45//#define GFX_USE_OS_CMSIS2 GFXOFF
46//#define GFX_USE_OS_RAW32 GFXOFF
47//#define GFX_USE_OS_ZEPHYR GFXOFF
48//#define GFX_USE_OS_NIOS GFXOFF
49//#define GFX_USE_OS_QT GFXOFF
50// #define INTERRUPTS_OFF() optional_code
51// #define INTERRUPTS_ON() optional_code
52
53// Options that (should where relevant) apply to all operating systems
54#define GFX_NO_INLINE GFXON
55// #define GFX_COMPILER GFX_COMPILER_UNKNOWN
56// #define GFX_SHOW_COMPILER GFXOFF
57// #define GFX_CPU GFX_CPU_UNKNOWN
58// #define GFX_CPU_NO_ALIGNMENT_FAULTS GFXOFF
59// #define GFX_CPU_ENDIAN GFX_CPU_ENDIAN_UNKNOWN
60// #define GFX_OS_HEAP_SIZE 0
61// #define GFX_OS_NO_INIT GFXOFF
62// #define GFX_OS_INIT_NO_WARNING GFXOFF
63// #define GFX_OS_PRE_INIT_FUNCTION myHardwareInitRoutine
64// #define GFX_OS_EXTRA_INIT_FUNCTION myOSInitRoutine
65// #define GFX_OS_EXTRA_DEINIT_FUNCTION myOSDeInitRoutine
66// #define GFX_OS_CALL_UGFXMAIN GFXOFF
67// #define GFX_OS_UGFXMAIN_STACKSIZE 0
68// #define GFX_EMULATE_MALLOC GFXOFF
69// #define GFX_MEM_LT64K GFXOFF
70
71///////////////////////////////////////////////////////////////////////////
72// GDISP //
73///////////////////////////////////////////////////////////////////////////
74#define GFX_USE_GDISP GFXON
75
76//#define GDISP_NEED_AUTOFLUSH GFXOFF
77//#define GDISP_NEED_TIMERFLUSH GFXOFF
78//#define GDISP_NEED_VALIDATION GFXON
79//#define GDISP_NEED_CLIP GFXON
80#define GDISP_NEED_CIRCLE GFXON
81//#define GDISP_NEED_DUALCIRCLE GFXOFF
82#define GDISP_NEED_ELLIPSE GFXON
83#define GDISP_NEED_ARC GFXON
84#define GDISP_NEED_ARCSECTORS GFXON
85#define GDISP_NEED_CONVEX_POLYGON GFXON
86//#define GDISP_NEED_SCROLL GFXOFF
87#define GDISP_NEED_PIXELREAD GFXON
88#define GDISP_NEED_CONTROL GFXON
89//#define GDISP_NEED_QUERY GFXOFF
90//#define GDISP_NEED_MULTITHREAD GFXOFF
91//#define GDISP_NEED_STREAMING GFXOFF
92#define GDISP_NEED_TEXT GFXON
93// #define GDISP_NEED_TEXT_WORDWRAP GFXOFF
94// #define GDISP_NEED_TEXT_BOXPADLR 1
95// #define GDISP_NEED_TEXT_BOXPADTB 1
96// #define GDISP_NEED_ANTIALIAS GFXOFF
97// #define GDISP_NEED_UTF8 GFXOFF
98#define GDISP_NEED_TEXT_KERNING GFXON
99// #define GDISP_INCLUDE_FONT_UI1 GFXOFF
100// #define GDISP_INCLUDE_FONT_UI2 GFXOFF // The smallest preferred font.
101// #define GDISP_INCLUDE_FONT_LARGENUMBERS GFXOFF
102// #define GDISP_INCLUDE_FONT_DEJAVUSANS10 GFXOFF
103// #define GDISP_INCLUDE_FONT_DEJAVUSANS12 GFXOFF
104// #define GDISP_INCLUDE_FONT_DEJAVUSANS16 GFXOFF
105// #define GDISP_INCLUDE_FONT_DEJAVUSANS20 GFXOFF
106// #define GDISP_INCLUDE_FONT_DEJAVUSANS24 GFXOFF
107// #define GDISP_INCLUDE_FONT_DEJAVUSANS32 GFXOFF
108#define GDISP_INCLUDE_FONT_DEJAVUSANSBOLD12 GFXON
109// #define GDISP_INCLUDE_FONT_FIXED_10X20 GFXOFF
110// #define GDISP_INCLUDE_FONT_FIXED_7X14 GFXOFF
111#define GDISP_INCLUDE_FONT_FIXED_5X8 GFXON
112// #define GDISP_INCLUDE_FONT_DEJAVUSANS12_AA GFXOFF
113// #define GDISP_INCLUDE_FONT_DEJAVUSANS16_AA GFXOFF
114// #define GDISP_INCLUDE_FONT_DEJAVUSANS20_AA GFXOFF
115// #define GDISP_INCLUDE_FONT_DEJAVUSANS24_AA GFXOFF
116// #define GDISP_INCLUDE_FONT_DEJAVUSANS32_AA GFXOFF
117// #define GDISP_INCLUDE_FONT_DEJAVUSANSBOLD12_AA GFXOFF
118// #define GDISP_INCLUDE_USER_FONTS GFXOFF
119
120//#define GDISP_NEED_IMAGE GFXOFF
121// #define GDISP_NEED_IMAGE_NATIVE GFXOFF
122// #define GDISP_NEED_IMAGE_GIF GFXOFF
123// #define GDISP_IMAGE_GIF_BLIT_BUFFER_SIZE 32
124// #define GDISP_NEED_IMAGE_BMP GFXOFF
125// #define GDISP_NEED_IMAGE_BMP_1 GFXON
126// #define GDISP_NEED_IMAGE_BMP_4 GFXON
127// #define GDISP_NEED_IMAGE_BMP_4_RLE GFXON
128// #define GDISP_NEED_IMAGE_BMP_8 GFXON
129// #define GDISP_NEED_IMAGE_BMP_8_RLE GFXON
130// #define GDISP_NEED_IMAGE_BMP_16 GFXON
131// #define GDISP_NEED_IMAGE_BMP_24 GFXON
132// #define GDISP_NEED_IMAGE_BMP_32 GFXON
133// #define GDISP_IMAGE_BMP_BLIT_BUFFER_SIZE 32
134// #define GDISP_NEED_IMAGE_JPG GFXOFF
135// #define GDISP_NEED_IMAGE_PNG GFXOFF
136// #define GDISP_NEED_IMAGE_PNG_INTERLACED GFXOFF
137// #define GDISP_NEED_IMAGE_PNG_TRANSPARENCY GFXON
138// #define GDISP_NEED_IMAGE_PNG_BACKGROUND GFXON
139// #define GDISP_NEED_IMAGE_PNG_ALPHACLIFF 32
140// #define GDISP_NEED_IMAGE_PNG_PALETTE_124 GFXON
141// #define GDISP_NEED_IMAGE_PNG_PALETTE_8 GFXON
142// #define GDISP_NEED_IMAGE_PNG_GRAYSCALE_124 GFXON
143// #define GDISP_NEED_IMAGE_PNG_GRAYSCALE_8 GFXON
144// #define GDISP_NEED_IMAGE_PNG_GRAYSCALE_16 GFXON
145// #define GDISP_NEED_IMAGE_PNG_GRAYALPHA_8 GFXON
146// #define GDISP_NEED_IMAGE_PNG_GRAYALPHA_16 GFXON
147// #define GDISP_NEED_IMAGE_PNG_RGB_8 GFXON
148// #define GDISP_NEED_IMAGE_PNG_RGB_16 GFXON
149// #define GDISP_NEED_IMAGE_PNG_RGBALPHA_8 GFXON
150// #define GDISP_NEED_IMAGE_PNG_RGBALPHA_16 GFXON
151// #define GDISP_IMAGE_PNG_BLIT_BUFFER_SIZE 32
152// #define GDISP_IMAGE_PNG_FILE_BUFFER_SIZE 8
153// #define GDISP_IMAGE_PNG_Z_BUFFER_SIZE 32768
154// #define GDISP_NEED_IMAGE_ACCOUNTING GFXOFF
155
156//#define GDISP_NEED_PIXMAP GFXOFF
157// #define GDISP_NEED_PIXMAP_IMAGE GFXOFF
158
159//#define GDISP_DEFAULT_ORIENTATION gOrientationLandscape // If not defined the native hardware orientation is used.
160//#define GDISP_LINEBUF_SIZE 128
161//#define GDISP_STARTUP_COLOR GFX_BLACK
162#define GDISP_NEED_STARTUP_LOGO GFXOFF
163
164//#define GDISP_TOTAL_DISPLAYS 1
165
166//#define GDISP_DRIVER_LIST GDISPVMT_Win32, GDISPVMT_Win32
167#ifdef GDISP_DRIVER_LIST
168// // For code and speed optimization define as GFXON or GFXOFF if all controllers have the same capability
169# define GDISP_HARDWARE_STREAM_WRITE GFXOFF
170# define GDISP_HARDWARE_STREAM_READ GFXOFF
171# define GDISP_HARDWARE_STREAM_POS GFXOFF
172# define GDISP_HARDWARE_DRAWPIXEL GFXON
173# define GDISP_HARDWARE_CLEARS GFXOFF
174# define GDISP_HARDWARE_FILLS GFXOFF
175//#define GDISP_HARDWARE_BITFILLS GFXOFF
176# define GDISP_HARDWARE_SCROLL GFXOFF
177# define GDISP_HARDWARE_PIXELREAD GFXON
178# define GDISP_HARDWARE_CONTROL GFXON
179# define GDISP_HARDWARE_QUERY GFXOFF
180# define GDISP_HARDWARE_CLIP GFXOFF
181
182# define GDISP_PIXELFORMAT GDISP_PIXELFORMAT_RGB888
183#endif
184
185#define GDISP_USE_GFXNET GFXOFF
186// #define GDISP_GFXNET_PORT 13001
187// #define GDISP_GFXNET_CUSTOM_LWIP_STARTUP GFXOFF
188// #define GDISP_DONT_WAIT_FOR_NET_DISPLAY GFXOFF
189// #define GDISP_GFXNET_UNSAFE_SOCKETS GFXOFF
190
191///////////////////////////////////////////////////////////////////////////
192// GWIN //
193///////////////////////////////////////////////////////////////////////////
194#define GFX_USE_GWIN GFXOFF
195
196//#define GWIN_NEED_WINDOWMANAGER GFXOFF
197// #define GWIN_REDRAW_IMMEDIATE GFXOFF
198// #define GWIN_REDRAW_SINGLEOP GFXOFF
199// #define GWIN_NEED_FLASHING GFXOFF
200// #define GWIN_FLASHING_PERIOD 250
201
202//#define GWIN_NEED_CONSOLE GFXOFF
203// #define GWIN_CONSOLE_USE_HISTORY GFXOFF
204// #define GWIN_CONSOLE_HISTORY_AVERAGING GFXOFF
205// #define GWIN_CONSOLE_HISTORY_ATCREATE GFXOFF
206// #define GWIN_CONSOLE_ESCSEQ GFXOFF
207// #define GWIN_CONSOLE_USE_BASESTREAM GFXOFF
208// #define GWIN_CONSOLE_USE_FLOAT GFXOFF
209//#define GWIN_NEED_GRAPH GFXOFF
210//#define GWIN_NEED_GL3D GFXOFF
211
212//#define GWIN_NEED_WIDGET GFXOFF
213//#define GWIN_FOCUS_HIGHLIGHT_WIDTH 1
214// #define GWIN_NEED_LABEL GFXOFF
215// #define GWIN_LABEL_ATTRIBUTE GFXOFF
216// #define GWIN_NEED_BUTTON GFXOFF
217// #define GWIN_BUTTON_LAZY_RELEASE GFXOFF
218// #define GWIN_NEED_SLIDER GFXOFF
219// #define GWIN_SLIDER_NOSNAP GFXOFF
220// #define GWIN_SLIDER_DEAD_BAND 5
221// #define GWIN_SLIDER_TOGGLE_INC 20
222// #define GWIN_NEED_CHECKBOX GFXOFF
223// #define GWIN_NEED_IMAGE GFXOFF
224// #define GWIN_NEED_IMAGE_ANIMATION GFXOFF
225// #define GWIN_NEED_RADIO GFXOFF
226// #define GWIN_NEED_LIST GFXOFF
227// #define GWIN_NEED_LIST_IMAGES GFXOFF
228// #define GWIN_NEED_PROGRESSBAR GFXOFF
229// #define GWIN_PROGRESSBAR_AUTO GFXOFF
230// #define GWIN_NEED_KEYBOARD GFXOFF
231// #define GWIN_KEYBOARD_DEFAULT_LAYOUT VirtualKeyboard_English1
232// #define GWIN_NEED_KEYBOARD_ENGLISH1 GFXON
233// #define GWIN_NEED_TEXTEDIT GFXOFF
234// #define GWIN_FLAT_STYLING GFXOFF
235// #define GWIN_WIDGET_TAGS GFXOFF
236
237//#define GWIN_NEED_CONTAINERS GFXOFF
238// #define GWIN_NEED_CONTAINER GFXOFF
239// #define GWIN_NEED_FRAME GFXOFF
240// #define GWIN_NEED_TABSET GFXOFF
241// #define GWIN_TABSET_TABHEIGHT 18
242
243///////////////////////////////////////////////////////////////////////////
244// GTRANS //
245///////////////////////////////////////////////////////////////////////////
246//#define GFX_USE_GTRANS GFXOFF
247
248///////////////////////////////////////////////////////////////////////////
249// GEVENT //
250///////////////////////////////////////////////////////////////////////////
251#define GFX_USE_GEVENT GFXON
252
253//#define GEVENT_ASSERT_NO_RESOURCE GFXOFF
254//#define GEVENT_MAXIMUM_SIZE 32
255//#define GEVENT_MAX_SOURCE_LISTENERS 32
256
257///////////////////////////////////////////////////////////////////////////
258// GTIMER //
259///////////////////////////////////////////////////////////////////////////
260#define GFX_USE_GTIMER GFXOFF
261
262//#define GTIMER_THREAD_PRIORITY gThreadpriorityHigh
263//#define GTIMER_THREAD_WORKAREA_SIZE 2048
264
265///////////////////////////////////////////////////////////////////////////
266// GQUEUE //
267///////////////////////////////////////////////////////////////////////////
268#define GFX_USE_GQUEUE GFXOFF
269
270//#define GQUEUE_NEED_ASYNC GFXOFF
271//#define GQUEUE_NEED_GSYNC GFXOFF
272//#define GQUEUE_NEED_FSYNC GFXOFF
273//#define GQUEUE_NEED_BUFFERS GFXOFF
274
275///////////////////////////////////////////////////////////////////////////
276// GINPUT //
277///////////////////////////////////////////////////////////////////////////
278#define GFX_USE_GINPUT GFXOFF
279
280//#define GINPUT_NEED_MOUSE GFXOFF
281// #define GINPUT_TOUCH_STARTRAW GFXOFF
282// #define GINPUT_TOUCH_NOTOUCH GFXOFF
283// #define GINPUT_TOUCH_NOCALIBRATE GFXOFF
284// #define GINPUT_TOUCH_NOCALIBRATE_GUI GFXOFF
285// #define GINPUT_MOUSE_POLL_PERIOD 25
286// #define GINPUT_MOUSE_CLICK_TIME 300
287// #define GINPUT_TOUCH_CXTCLICK_TIME 700
288// #define GINPUT_TOUCH_USER_CALIBRATION_LOAD GFXOFF
289// #define GINPUT_TOUCH_USER_CALIBRATION_SAVE GFXOFF
290// #define GMOUSE_DRIVER_LIST GMOUSEVMT_Win32, GMOUSEVMT_Win32
291// #define GINPUT_TOUCH_CALIBRATION_FONT1 "* Double"
292// #define GINPUT_TOUCH_CALIBRATION_FONT2 "* Narrow"
293// #define GINPUT_TOUCH_CALIBRATION_TITLE "Calibration"
294// #define GINPUT_TOUCH_CALIBRATION_ERROR "Calibration Failed!"
295//#define GINPUT_NEED_KEYBOARD GFXOFF
296// #define GINPUT_KEYBOARD_POLL_PERIOD 200
297// #define GKEYBOARD_DRIVER_LIST GKEYBOARDVMT_Win32, GKEYBOARDVMT_Win32
298// #define GKEYBOARD_LAYOUT_OFF GFXOFF
299// #define GKEYBOARD_LAYOUT_SCANCODE2_US GFXOFF
300//#define GINPUT_NEED_TOGGLE GFXOFF
301//#define GINPUT_NEED_DIAL GFXOFF
302
303///////////////////////////////////////////////////////////////////////////
304// GFILE //
305///////////////////////////////////////////////////////////////////////////
306#define GFX_USE_GFILE GFXOFF
307
308//#define GFILE_NEED_PRINTG GFXOFF
309//#define GFILE_NEED_SCANG GFXOFF
310//#define GFILE_NEED_STRINGS GFXOFF
311//#define GFILE_NEED_FILELISTS GFXOFF
312//#define GFILE_NEED_STDIO GFXOFF
313//#define GFILE_NEED_NOAUTOMOUNT GFXOFF
314//#define GFILE_NEED_NOAUTOSYNC GFXOFF
315
316//#define GFILE_NEED_MEMFS GFXOFF
317//#define GFILE_NEED_ROMFS GFXOFF
318//#define GFILE_NEED_RAMFS GFXOFF
319//#define GFILE_NEED_FATFS GFXOFF
320//#define GFILE_NEED_NATIVEFS GFXOFF
321//#define GFILE_NEED_CHBIOSFS GFXOFF
322//#define GFILE_NEED_USERFS GFXOFF
323
324//#define GFILE_ALLOW_FLOATS GFXOFF
325//#define GFILE_ALLOW_DEVICESPECIFIC GFXOFF
326//#define GFILE_MAX_GFILES 3
327
328///////////////////////////////////////////////////////////////////////////
329// GADC //
330///////////////////////////////////////////////////////////////////////////
331#define GFX_USE_GADC GFXOFF
332// #define GADC_MAX_LOWSPEED_DEVICES 4
333
334///////////////////////////////////////////////////////////////////////////
335// GAUDIO //
336///////////////////////////////////////////////////////////////////////////
337#define GFX_USE_GAUDIO GFXOFF
338// #define GAUDIO_NEED_PLAY GFXOFF
339// #define GAUDIO_NEED_RECORD GFXOFF
340
341///////////////////////////////////////////////////////////////////////////
342// GMISC //
343///////////////////////////////////////////////////////////////////////////
344#define GFX_USE_GMISC GFXON
345
346//#define GMISC_NEED_ARRAYOPS GFXOFF
347//#define GMISC_NEED_FASTTRIG GFXOFF
348//#define GMISC_NEED_FIXEDTRIG GFXOFF
349//#define GMISC_NEED_INVSQRT GFXOFF
350// #define GMISC_INVSQRT_MIXED_ENDIAN GFXOFF
351// #define GMISC_INVSQRT_REAL_SLOW GFXOFF
352#define GMISC_NEED_MATRIXFLOAT2D GFXON
353#define GMISC_NEED_MATRIXFIXED2D GFXOFF
354//#define GMISC_NEED_HITTEST_POLY GFXOFF
diff --git a/quantum/visualizer/default_animations.c b/quantum/visualizer/default_animations.c
deleted file mode 100644
index 2f43c67cc..000000000
--- a/quantum/visualizer/default_animations.c
+++ /dev/null
@@ -1,177 +0,0 @@
1/* Copyright 2017 Fred Sundvik
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#if defined(VISUALIZER_ENABLE)
18
19# include "default_animations.h"
20# include "visualizer.h"
21# ifdef LCD_ENABLE
22# include "lcd_keyframes.h"
23# endif
24# ifdef LCD_BACKLIGHT_ENABLE
25# include "lcd_backlight_keyframes.h"
26# endif
27
28# ifdef BACKLIGHT_ENABLE
29# include "led_backlight_keyframes.h"
30# endif
31
32# include "visualizer_keyframes.h"
33
34# if defined(LCD_ENABLE) || defined(LCD_BACKLIGHT_ENABLE) || defined(BACKLIGHT_ENABLE)
35
36static bool keyframe_enable(keyframe_animation_t* animation, visualizer_state_t* state) {
37# ifdef LCD_ENABLE
38 lcd_keyframe_enable(animation, state);
39# endif
40# ifdef LCD_BACKLIGHT_ENABLE
41 lcd_backlight_keyframe_enable(animation, state);
42# endif
43# ifdef BACKLIGHT_ENABLE
44 led_backlight_keyframe_enable(animation, state);
45# endif
46 return false;
47}
48
49static bool keyframe_disable(keyframe_animation_t* animation, visualizer_state_t* state) {
50# ifdef LCD_ENABLE
51 lcd_keyframe_disable(animation, state);
52# endif
53# ifdef LCD_BACKLIGHT_ENABLE
54 lcd_backlight_keyframe_disable(animation, state);
55# endif
56# ifdef BACKLIGHT_ENABLE
57 led_backlight_keyframe_disable(animation, state);
58# endif
59 return false;
60}
61
62static bool keyframe_fade_in(keyframe_animation_t* animation, visualizer_state_t* state) {
63 bool ret = false;
64# ifdef LCD_BACKLIGHT_ENABLE
65 ret |= lcd_backlight_keyframe_animate_color(animation, state);
66# endif
67# ifdef BACKLIGHT_ENABLE
68 ret |= led_backlight_keyframe_fade_in_all(animation, state);
69# endif
70 return ret;
71}
72
73static bool keyframe_fade_out(keyframe_animation_t* animation, visualizer_state_t* state) {
74 bool ret = false;
75# ifdef LCD_BACKLIGHT_ENABLE
76 ret |= lcd_backlight_keyframe_animate_color(animation, state);
77# endif
78# ifdef BACKLIGHT_ENABLE
79 ret |= led_backlight_keyframe_fade_out_all(animation, state);
80# endif
81 return ret;
82}
83
84// Don't worry, if the startup animation is long, you can use the keyboard like normal
85// during that time
86keyframe_animation_t default_startup_animation = {
87# if LCD_ENABLE
88 .num_frames = 3,
89# else
90 .num_frames = 2,
91# endif
92 .loop = false,
93 .frame_lengths = {0,
94# if LCD_ENABLE
95 0,
96# endif
97 gfxMillisecondsToTicks(5000)},
98 .frame_functions =
99 {
100 keyframe_enable,
101# if LCD_ENABLE
102 lcd_keyframe_draw_logo,
103# endif
104 keyframe_fade_in,
105 },
106};
107
108keyframe_animation_t default_suspend_animation = {
109# if LCD_ENABLE
110 .num_frames = 3,
111# else
112 .num_frames = 2,
113# endif
114 .loop = false,
115 .frame_lengths =
116 {
117# if LCD_ENABLE
118 0,
119# endif
120 gfxMillisecondsToTicks(1000), 0},
121 .frame_functions =
122 {
123# if LCD_ENABLE
124 lcd_keyframe_display_layer_text,
125# endif
126 keyframe_fade_out,
127 keyframe_disable,
128 },
129};
130# endif
131
132# if defined(BACKLIGHT_ENABLE)
133# define CROSSFADE_TIME 1000
134# define GRADIENT_TIME 3000
135
136keyframe_animation_t led_test_animation = {
137 .num_frames = 14,
138 .loop = true,
139 .frame_lengths =
140 {
141 gfxMillisecondsToTicks(1000), // fade in
142 gfxMillisecondsToTicks(1000), // no op (leds on)
143 gfxMillisecondsToTicks(1000), // fade out
144 gfxMillisecondsToTicks(CROSSFADE_TIME), // crossfade
145 gfxMillisecondsToTicks(GRADIENT_TIME), // left to rigt (outside in)
146 gfxMillisecondsToTicks(CROSSFADE_TIME), // crossfade
147 gfxMillisecondsToTicks(GRADIENT_TIME), // top_to_bottom
148 0, // mirror leds
149 gfxMillisecondsToTicks(CROSSFADE_TIME), // crossfade
150 gfxMillisecondsToTicks(GRADIENT_TIME), // left_to_right (mirrored, so inside out)
151 gfxMillisecondsToTicks(CROSSFADE_TIME), // crossfade
152 gfxMillisecondsToTicks(GRADIENT_TIME), // top_to_bottom
153 0, // normal leds
154 gfxMillisecondsToTicks(CROSSFADE_TIME), // crossfade
155
156 },
157 .frame_functions =
158 {
159 led_backlight_keyframe_fade_in_all,
160 keyframe_no_operation,
161 led_backlight_keyframe_fade_out_all,
162 led_backlight_keyframe_crossfade,
163 led_backlight_keyframe_left_to_right_gradient,
164 led_backlight_keyframe_crossfade,
165 led_backlight_keyframe_top_to_bottom_gradient,
166 led_backlight_keyframe_mirror_orientation,
167 led_backlight_keyframe_crossfade,
168 led_backlight_keyframe_left_to_right_gradient,
169 led_backlight_keyframe_crossfade,
170 led_backlight_keyframe_top_to_bottom_gradient,
171 led_backlight_keyframe_normal_orientation,
172 led_backlight_keyframe_crossfade,
173 },
174};
175# endif
176
177#endif
diff --git a/quantum/visualizer/default_animations.h b/quantum/visualizer/default_animations.h
deleted file mode 100644
index 9accd8977..000000000
--- a/quantum/visualizer/default_animations.h
+++ /dev/null
@@ -1,27 +0,0 @@
1/* Copyright 2017 Fred Sundvik
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#pragma once
18
19#include "visualizer.h"
20
21// You can use these default animations, but of course you can also write your own custom ones instead
22extern keyframe_animation_t default_startup_animation;
23extern keyframe_animation_t default_suspend_animation;
24
25// An animation for testing and demonstrating the led support, should probably not be used for real world
26// cases
27extern keyframe_animation_t led_test_animation;
diff --git a/quantum/visualizer/lcd_backlight.c b/quantum/visualizer/lcd_backlight.c
deleted file mode 100644
index 23978974e..000000000
--- a/quantum/visualizer/lcd_backlight.c
+++ /dev/null
@@ -1,87 +0,0 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2016 Fred Sundvik
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24
25#include "lcd_backlight.h"
26#include <math.h>
27
28static uint8_t current_hue = 0;
29static uint8_t current_saturation = 0;
30static uint8_t current_intensity = 0;
31static uint8_t current_brightness = 0;
32
33void lcd_backlight_init(void) {
34 lcd_backlight_hal_init();
35 lcd_backlight_color(current_hue, current_saturation, current_intensity);
36}
37
38// This code is based on Brian Neltner's blogpost and example code
39// "Why every LED light should be using HSI colorspace".
40// http://blog.saikoled.com/post/43693602826/why-every-led-light-should-be-using-hsi
41static void hsi_to_rgb(float h, float s, float i, uint16_t* r_out, uint16_t* g_out, uint16_t* b_out) {
42 unsigned int r, g, b;
43 h = fmodf(h, 360.0f); // cycle h around to 0-360 degrees
44 h = 3.14159f * h / 180.0f; // Convert to radians.
45 s = s > 0.0f ? (s < 1.0f ? s : 1.0f) : 0.0f; // clamp s and i to interval [0,1]
46 i = i > 0.0f ? (i < 1.0f ? i : 1.0f) : 0.0f;
47
48 // Math! Thanks in part to Kyle Miller.
49 if (h < 2.09439f) {
50 r = 65535.0f * i / 3.0f * (1.0f + s * cos(h) / cosf(1.047196667f - h));
51 g = 65535.0f * i / 3.0f * (1.0f + s * (1.0f - cosf(h) / cos(1.047196667f - h)));
52 b = 65535.0f * i / 3.0f * (1.0f - s);
53 } else if (h < 4.188787) {
54 h = h - 2.09439;
55 g = 65535.0f * i / 3.0f * (1.0f + s * cosf(h) / cosf(1.047196667f - h));
56 b = 65535.0f * i / 3.0f * (1.0f + s * (1.0f - cosf(h) / cosf(1.047196667f - h)));
57 r = 65535.0f * i / 3.0f * (1.0f - s);
58 } else {
59 h = h - 4.188787;
60 b = 65535.0f * i / 3.0f * (1.0f + s * cosf(h) / cosf(1.047196667f - h));
61 r = 65535.0f * i / 3.0f * (1.0f + s * (1.0f - cosf(h) / cosf(1.047196667f - h)));
62 g = 65535.0f * i / 3.0f * (1.0f - s);
63 }
64 *r_out = r > 65535 ? 65535 : r;
65 *g_out = g > 65535 ? 65535 : g;
66 *b_out = b > 65535 ? 65535 : b;
67}
68
69void lcd_backlight_color(uint8_t hue, uint8_t saturation, uint8_t intensity) {
70 uint16_t r, g, b;
71 float hue_f = 360.0f * (float)hue / 255.0f;
72 float saturation_f = (float)saturation / 255.0f;
73 float intensity_f = (float)intensity / 255.0f;
74 intensity_f *= (float)current_brightness / 255.0f;
75 hsi_to_rgb(hue_f, saturation_f, intensity_f, &r, &g, &b);
76 current_hue = hue;
77 current_saturation = saturation;
78 current_intensity = intensity;
79 lcd_backlight_hal_color(r, g, b);
80}
81
82void lcd_backlight_brightness(uint8_t b) {
83 current_brightness = b;
84 lcd_backlight_color(current_hue, current_saturation, current_intensity);
85}
86
87uint8_t lcd_get_backlight_brightness(void) { return current_brightness; }
diff --git a/quantum/visualizer/lcd_backlight.h b/quantum/visualizer/lcd_backlight.h
deleted file mode 100644
index 4ea5b1463..000000000
--- a/quantum/visualizer/lcd_backlight.h
+++ /dev/null
@@ -1,43 +0,0 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2016 Fred Sundvik
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24
25#pragma once
26
27#include <stdint.h>
28
29// Helper macros for storing hue, staturation and intensity as unsigned integers
30#define LCD_COLOR(hue, saturation, intensity) (hue << 16 | saturation << 8 | intensity)
31#define LCD_HUE(color) ((color >> 16) & 0xFF)
32#define LCD_SAT(color) ((color >> 8) & 0xFF)
33#define LCD_INT(color) (color & 0xFF)
34
35static inline uint32_t change_lcd_color_intensity(uint32_t color, uint8_t new_intensity) { return (color & 0xFFFFFF00) | new_intensity; }
36
37void lcd_backlight_init(void);
38void lcd_backlight_color(uint8_t hue, uint8_t saturation, uint8_t intensity);
39void lcd_backlight_brightness(uint8_t b);
40uint8_t lcd_get_backlight_brightness(void);
41
42void lcd_backlight_hal_init(void);
43void lcd_backlight_hal_color(uint16_t r, uint16_t g, uint16_t b);
diff --git a/quantum/visualizer/lcd_backlight_keyframes.c b/quantum/visualizer/lcd_backlight_keyframes.c
deleted file mode 100644
index c13cce311..000000000
--- a/quantum/visualizer/lcd_backlight_keyframes.c
+++ /dev/null
@@ -1,69 +0,0 @@
1/* Copyright 2017 Fred Sundvik
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "lcd_backlight_keyframes.h"
18
19bool lcd_backlight_keyframe_animate_color(keyframe_animation_t* animation, visualizer_state_t* state) {
20 int frame_length = animation->frame_lengths[animation->current_frame];
21 int current_pos = frame_length - animation->time_left_in_frame;
22 uint8_t t_h = LCD_HUE(state->target_lcd_color);
23 uint8_t t_s = LCD_SAT(state->target_lcd_color);
24 uint8_t t_i = LCD_INT(state->target_lcd_color);
25 uint8_t p_h = LCD_HUE(state->prev_lcd_color);
26 uint8_t p_s = LCD_SAT(state->prev_lcd_color);
27 uint8_t p_i = LCD_INT(state->prev_lcd_color);
28
29 uint8_t d_h1 = t_h - p_h; // Modulo arithmetic since we want to wrap around
30 int d_h2 = t_h - p_h;
31 // Chose the shortest way around
32 int d_h = abs(d_h2) < d_h1 ? d_h2 : d_h1;
33 int d_s = t_s - p_s;
34 int d_i = t_i - p_i;
35
36 int hue = (d_h * current_pos) / frame_length;
37 int sat = (d_s * current_pos) / frame_length;
38 int intensity = (d_i * current_pos) / frame_length;
39 // dprintf("%X -> %X = %X\n", p_h, t_h, hue);
40 hue += p_h;
41 sat += p_s;
42 intensity += p_i;
43 state->current_lcd_color = LCD_COLOR(hue, sat, intensity);
44 lcd_backlight_color(LCD_HUE(state->current_lcd_color), LCD_SAT(state->current_lcd_color), LCD_INT(state->current_lcd_color));
45
46 return true;
47}
48
49bool lcd_backlight_keyframe_set_color(keyframe_animation_t* animation, visualizer_state_t* state) {
50 (void)animation;
51 state->prev_lcd_color = state->target_lcd_color;
52 state->current_lcd_color = state->target_lcd_color;
53 lcd_backlight_color(LCD_HUE(state->current_lcd_color), LCD_SAT(state->current_lcd_color), LCD_INT(state->current_lcd_color));
54 return false;
55}
56
57bool lcd_backlight_keyframe_disable(keyframe_animation_t* animation, visualizer_state_t* state) {
58 (void)animation;
59 (void)state;
60 lcd_backlight_hal_color(0, 0, 0);
61 return false;
62}
63
64bool lcd_backlight_keyframe_enable(keyframe_animation_t* animation, visualizer_state_t* state) {
65 (void)animation;
66 (void)state;
67 lcd_backlight_color(LCD_HUE(state->current_lcd_color), LCD_SAT(state->current_lcd_color), LCD_INT(state->current_lcd_color));
68 return false;
69}
diff --git a/quantum/visualizer/lcd_backlight_keyframes.h b/quantum/visualizer/lcd_backlight_keyframes.h
deleted file mode 100644
index 88768dd4a..000000000
--- a/quantum/visualizer/lcd_backlight_keyframes.h
+++ /dev/null
@@ -1,27 +0,0 @@
1/* Copyright 2017 Fred Sundvik
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#pragma once
18
19#include "visualizer.h"
20
21// Animates the LCD backlight color between the current color and the target color (of the state)
22bool lcd_backlight_keyframe_animate_color(keyframe_animation_t* animation, visualizer_state_t* state);
23// Sets the backlight color to the target color
24bool lcd_backlight_keyframe_set_color(keyframe_animation_t* animation, visualizer_state_t* state);
25
26bool lcd_backlight_keyframe_disable(keyframe_animation_t* animation, visualizer_state_t* state);
27bool lcd_backlight_keyframe_enable(keyframe_animation_t* animation, visualizer_state_t* state);
diff --git a/quantum/visualizer/lcd_keyframes.c b/quantum/visualizer/lcd_keyframes.c
deleted file mode 100644
index 1d6f3dca1..000000000
--- a/quantum/visualizer/lcd_keyframes.c
+++ /dev/null
@@ -1,184 +0,0 @@
1/* Copyright 2017 Fred Sundvik
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "lcd_keyframes.h"
18#include <string.h>
19#include "action_util.h"
20#include "led.h"
21#include "resources/resources.h"
22
23bool lcd_keyframe_display_layer_text(keyframe_animation_t* animation, visualizer_state_t* state) {
24 (void)animation;
25 gdispClear(White);
26 gdispDrawString(0, 10, state->layer_text, state->font_dejavusansbold12, Black);
27 return false;
28}
29
30static void format_layer_bitmap_string(uint16_t default_layer, uint16_t layer, char* buffer) {
31 for (int i = 0; i < 16; i++) {
32 uint32_t mask = (1u << i);
33 if (default_layer & mask) {
34 if (layer & mask) {
35 *buffer = 'B';
36 } else {
37 *buffer = 'D';
38 }
39 } else if (layer & mask) {
40 *buffer = '1';
41 } else {
42 *buffer = '0';
43 }
44 ++buffer;
45
46 if (i == 3 || i == 7 || i == 11) {
47 *buffer = ' ';
48 ++buffer;
49 }
50 }
51 *buffer = 0;
52}
53
54bool lcd_keyframe_display_layer_bitmap(keyframe_animation_t* animation, visualizer_state_t* state) {
55 (void)animation;
56 const char* layer_help = "1=On D=Default B=Both";
57 char layer_buffer[16 + 4]; // 3 spaces and one null terminator
58 gdispClear(White);
59 gdispDrawString(0, 0, layer_help, state->font_fixed5x8, Black);
60 format_layer_bitmap_string(state->status.default_layer, state->status.layer, layer_buffer);
61 gdispDrawString(0, 10, layer_buffer, state->font_fixed5x8, Black);
62 format_layer_bitmap_string(state->status.default_layer >> 16, state->status.layer >> 16, layer_buffer);
63 gdispDrawString(0, 20, layer_buffer, state->font_fixed5x8, Black);
64 return false;
65}
66
67static void format_mods_bitmap_string(uint8_t mods, char* buffer) {
68 *buffer = ' ';
69 ++buffer;
70
71 for (int i = 0; i < 8; i++) {
72 uint32_t mask = (1u << i);
73 if (mods & mask) {
74 *buffer = '1';
75 } else {
76 *buffer = '0';
77 }
78 ++buffer;
79
80 if (i == 3) {
81 *buffer = ' ';
82 ++buffer;
83 }
84 }
85 *buffer = 0;
86}
87
88bool lcd_keyframe_display_mods_bitmap(keyframe_animation_t* animation, visualizer_state_t* state) {
89 (void)animation;
90
91 const char* title = "Modifier states";
92 const char* mods_header = " CSAG CSAG ";
93 char status_buffer[12];
94
95 gdispClear(White);
96 gdispDrawString(0, 0, title, state->font_fixed5x8, Black);
97 gdispDrawString(0, 10, mods_header, state->font_fixed5x8, Black);
98 format_mods_bitmap_string(state->status.mods, status_buffer);
99 gdispDrawString(0, 20, status_buffer, state->font_fixed5x8, Black);
100
101 return false;
102}
103
104#define LED_STATE_STRING_SIZE sizeof("NUM CAPS SCRL COMP KANA")
105
106static void get_led_state_string(char* output, visualizer_state_t* state) {
107 uint8_t pos = 0;
108
109 if (state->status.leds & (1u << USB_LED_NUM_LOCK)) {
110 memcpy(output + pos, "NUM ", 4);
111 pos += 4;
112 }
113 if (state->status.leds & (1u << USB_LED_CAPS_LOCK)) {
114 memcpy(output + pos, "CAPS ", 5);
115 pos += 5;
116 }
117 if (state->status.leds & (1u << USB_LED_SCROLL_LOCK)) {
118 memcpy(output + pos, "SCRL ", 5);
119 pos += 5;
120 }
121 if (state->status.leds & (1u << USB_LED_COMPOSE)) {
122 memcpy(output + pos, "COMP ", 5);
123 pos += 5;
124 }
125 if (state->status.leds & (1u << USB_LED_KANA)) {
126 memcpy(output + pos, "KANA", 4);
127 pos += 4;
128 }
129 output[pos] = 0;
130}
131
132bool lcd_keyframe_display_led_states(keyframe_animation_t* animation, visualizer_state_t* state) {
133 (void)animation;
134 char output[LED_STATE_STRING_SIZE];
135 get_led_state_string(output, state);
136 gdispClear(White);
137 gdispDrawString(0, 10, output, state->font_dejavusansbold12, Black);
138 return false;
139}
140
141bool lcd_keyframe_display_layer_and_led_states(keyframe_animation_t* animation, visualizer_state_t* state) {
142 (void)animation;
143 gdispClear(White);
144 uint8_t y = 10;
145 if (state->status.leds) {
146 char output[LED_STATE_STRING_SIZE];
147 get_led_state_string(output, state);
148 gdispDrawString(0, 1, output, state->font_dejavusansbold12, Black);
149 y = 17;
150 }
151 gdispDrawString(0, y, state->layer_text, state->font_dejavusansbold12, Black);
152 return false;
153}
154
155bool lcd_keyframe_draw_logo(keyframe_animation_t* animation, visualizer_state_t* state) {
156 (void)state;
157 (void)animation;
158 // Read the uGFX documentation for information how to use the displays
159 // http://wiki.ugfx.org/index.php/Main_Page
160 gdispClear(Black);
161
162 // You can use static variables for things that can't be found in the animation
163 // or state structs, here we use the image
164
165 // gdispGBlitArea is a tricky function to use since it supports blitting part of the image
166 // if you have full screen image, then just use LCD_WIDTH and LCD_HEIGHT for both source and target dimensions
167 gdispGBlitArea(GDISP, 0, 0, 128, 32, 0, 0, LCD_WIDTH, (pixel_t*)resource_lcd_logo);
168
169 return false;
170}
171
172bool lcd_keyframe_disable(keyframe_animation_t* animation, visualizer_state_t* state) {
173 (void)animation;
174 (void)state;
175 gdispSetPowerMode(powerOff);
176 return false;
177}
178
179bool lcd_keyframe_enable(keyframe_animation_t* animation, visualizer_state_t* state) {
180 (void)animation;
181 (void)state;
182 gdispSetPowerMode(powerOn);
183 return false;
184}
diff --git a/quantum/visualizer/lcd_keyframes.h b/quantum/visualizer/lcd_keyframes.h
deleted file mode 100644
index b7125e832..000000000
--- a/quantum/visualizer/lcd_keyframes.h
+++ /dev/null
@@ -1,35 +0,0 @@
1/* Copyright 2017 Fred Sundvik
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#pragma once
18
19#include "visualizer.h"
20
21// Displays the layer text centered vertically on the screen
22bool lcd_keyframe_display_layer_text(keyframe_animation_t* animation, visualizer_state_t* state);
23// Displays a bitmap (0/1) of all the currently active layers
24bool lcd_keyframe_display_layer_bitmap(keyframe_animation_t* animation, visualizer_state_t* state);
25// Displays a bitmap (0/1) of all the currently active mods
26bool lcd_keyframe_display_mods_bitmap(keyframe_animation_t* animation, visualizer_state_t* state);
27// Displays the keyboard led states (CAPS (Caps lock), NUM (Num lock), SCRL (Scroll lock), COMP (Compose), KANA)
28bool lcd_keyframe_display_led_states(keyframe_animation_t* animation, visualizer_state_t* state);
29// Displays both the layer text and the led states
30bool lcd_keyframe_display_layer_and_led_states(keyframe_animation_t* animation, visualizer_state_t* state);
31// Displays the QMK logo on the LCD screen
32bool lcd_keyframe_draw_logo(keyframe_animation_t* animation, visualizer_state_t* state);
33
34bool lcd_keyframe_disable(keyframe_animation_t* animation, visualizer_state_t* state);
35bool lcd_keyframe_enable(keyframe_animation_t* animation, visualizer_state_t* state);
diff --git a/quantum/visualizer/led_backlight_keyframes.c b/quantum/visualizer/led_backlight_keyframes.c
deleted file mode 100644
index 338ada522..000000000
--- a/quantum/visualizer/led_backlight_keyframes.c
+++ /dev/null
@@ -1,143 +0,0 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2016 Fred Sundvik
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24#include "gfx.h"
25#include <math.h>
26#include "led_backlight_keyframes.h"
27
28static uint8_t fade_led_color(keyframe_animation_t* animation, int from, int to) {
29 int frame_length = animation->frame_lengths[animation->current_frame];
30 int current_pos = frame_length - animation->time_left_in_frame;
31 int delta = to - from;
32 int luma = (delta * current_pos) / frame_length;
33 luma += from;
34 return luma;
35}
36
37static void keyframe_fade_all_leds_from_to(keyframe_animation_t* animation, uint8_t from, uint8_t to) {
38 uint8_t luma = fade_led_color(animation, from, to);
39 color_t color = LUMA2COLOR(luma);
40 gdispGClear(LED_DISPLAY, color);
41}
42
43// TODO: Should be customizable per keyboard
44#define NUM_ROWS LED_HEIGHT
45#define NUM_COLS LED_WIDTH
46
47static uint8_t crossfade_start_frame[NUM_ROWS][NUM_COLS];
48static uint8_t crossfade_end_frame[NUM_ROWS][NUM_COLS];
49
50static uint8_t compute_gradient_color(float t, float index, float num) {
51 const float two_pi = M_PI * 2.0f;
52 float normalized_index = (1.0f - index / (num - 1.0f)) * two_pi;
53 float x = t * two_pi + normalized_index;
54 float v = 0.5 * (cosf(x) + 1.0f);
55 return (uint8_t)(255.0f * v);
56}
57
58bool led_backlight_keyframe_fade_in_all(keyframe_animation_t* animation, visualizer_state_t* state) {
59 (void)state;
60 keyframe_fade_all_leds_from_to(animation, 0, 255);
61 return true;
62}
63
64bool led_backlight_keyframe_fade_out_all(keyframe_animation_t* animation, visualizer_state_t* state) {
65 (void)state;
66 keyframe_fade_all_leds_from_to(animation, 255, 0);
67 return true;
68}
69
70bool led_backlight_keyframe_left_to_right_gradient(keyframe_animation_t* animation, visualizer_state_t* state) {
71 (void)state;
72 float frame_length = animation->frame_lengths[animation->current_frame];
73 float current_pos = frame_length - animation->time_left_in_frame;
74 float t = current_pos / frame_length;
75 for (int i = 0; i < NUM_COLS; i++) {
76 uint8_t color = compute_gradient_color(t, i, NUM_COLS);
77 gdispGDrawLine(LED_DISPLAY, i, 0, i, NUM_ROWS - 1, LUMA2COLOR(color));
78 }
79 return true;
80}
81
82bool led_backlight_keyframe_top_to_bottom_gradient(keyframe_animation_t* animation, visualizer_state_t* state) {
83 (void)state;
84 float frame_length = animation->frame_lengths[animation->current_frame];
85 float current_pos = frame_length - animation->time_left_in_frame;
86 float t = current_pos / frame_length;
87 for (int i = 0; i < NUM_ROWS; i++) {
88 uint8_t color = compute_gradient_color(t, i, NUM_ROWS);
89 gdispGDrawLine(LED_DISPLAY, 0, i, NUM_COLS - 1, i, LUMA2COLOR(color));
90 }
91 return true;
92}
93
94static void copy_current_led_state(uint8_t* dest) {
95 for (int i = 0; i < NUM_ROWS; i++) {
96 for (int j = 0; j < NUM_COLS; j++) {
97 dest[i * NUM_COLS + j] = gdispGGetPixelColor(LED_DISPLAY, j, i);
98 }
99 }
100}
101bool led_backlight_keyframe_crossfade(keyframe_animation_t* animation, visualizer_state_t* state) {
102 (void)state;
103 if (animation->first_update_of_frame) {
104 copy_current_led_state(&crossfade_start_frame[0][0]);
105 run_next_keyframe(animation, state);
106 copy_current_led_state(&crossfade_end_frame[0][0]);
107 }
108 for (int i = 0; i < NUM_ROWS; i++) {
109 for (int j = 0; j < NUM_COLS; j++) {
110 color_t color = LUMA2COLOR(fade_led_color(animation, crossfade_start_frame[i][j], crossfade_end_frame[i][j]));
111 gdispGDrawPixel(LED_DISPLAY, j, i, color);
112 }
113 }
114 return true;
115}
116
117bool led_backlight_keyframe_mirror_orientation(keyframe_animation_t* animation, visualizer_state_t* state) {
118 (void)state;
119 (void)animation;
120 gdispGSetOrientation(LED_DISPLAY, GDISP_ROTATE_180);
121 return false;
122}
123
124bool led_backlight_keyframe_normal_orientation(keyframe_animation_t* animation, visualizer_state_t* state) {
125 (void)state;
126 (void)animation;
127 gdispGSetOrientation(LED_DISPLAY, GDISP_ROTATE_0);
128 return false;
129}
130
131bool led_backlight_keyframe_disable(keyframe_animation_t* animation, visualizer_state_t* state) {
132 (void)state;
133 (void)animation;
134 gdispGSetPowerMode(LED_DISPLAY, powerOff);
135 return false;
136}
137
138bool led_backlight_keyframe_enable(keyframe_animation_t* animation, visualizer_state_t* state) {
139 (void)state;
140 (void)animation;
141 gdispGSetPowerMode(LED_DISPLAY, powerOn);
142 return false;
143}
diff --git a/quantum/visualizer/led_backlight_keyframes.h b/quantum/visualizer/led_backlight_keyframes.h
deleted file mode 100644
index 90153be5e..000000000
--- a/quantum/visualizer/led_backlight_keyframes.h
+++ /dev/null
@@ -1,40 +0,0 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2016 Fred Sundvik
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24
25#pragma once
26
27#include "visualizer.h"
28
29bool led_backlight_keyframe_fade_in_all(keyframe_animation_t* animation, visualizer_state_t* state);
30bool led_backlight_keyframe_fade_out_all(keyframe_animation_t* animation, visualizer_state_t* state);
31bool led_backlight_keyframe_left_to_right_gradient(keyframe_animation_t* animation, visualizer_state_t* state);
32bool led_backlight_keyframe_top_to_bottom_gradient(keyframe_animation_t* animation, visualizer_state_t* state);
33bool led_backlight_keyframe_crossfade(keyframe_animation_t* animation, visualizer_state_t* state);
34bool led_backlight_keyframe_mirror_orientation(keyframe_animation_t* animation, visualizer_state_t* state);
35bool led_backlight_keyframe_normal_orientation(keyframe_animation_t* animation, visualizer_state_t* state);
36
37bool led_backlight_keyframe_disable(keyframe_animation_t* animation, visualizer_state_t* state);
38bool led_backlight_keyframe_enable(keyframe_animation_t* animation, visualizer_state_t* state);
39
40extern keyframe_animation_t led_test_animation;
diff --git a/quantum/visualizer/readme.md b/quantum/visualizer/readme.md
deleted file mode 100644
index 298efb742..000000000
--- a/quantum/visualizer/readme.md
+++ /dev/null
@@ -1,18 +0,0 @@
1# A visualization library for the TMK keyboard firmware
2
3This library is designed to work together with the [TMK keyboard firmware](https://github.com/tmk/tmk_keyboard). Currently it only works for [Chibios](http://www.chibios.org/)
4 flavors, but it would be possible to add support for other configurations as well. The LCD display functionality is provided by the [uGFX library](https://ugfx.io/).
5
6## To use this library as a user
7You can and should modify the visualizer\_user.c file. Check the comments in the file for more information.
8
9## To add this library to custom keyboard projects
10
111. Add tmk_visualizer as a submodule to your project
121. Set VISUALIZER_DIR in the main keyboard project makefile to point to the submodule
131. Define LCD\_ENABLE and/or LCD\_BACKLIGHT\_ENABLE, to enable support
141. Include the visualizer.mk make file
151. Copy the files in the example\_integration folder to your keyboard project
161. All other files than the callback.c file are included automatically, so you will need to add callback.c to your makefile manually. If you already have a similar file in your project, you can just copy the functions instead of the whole file.
171. Edit the files to match your hardware. You might might want to read the Chibios and UGfx documentation, for more information.
181. If you enable LCD support you might also have to write a custom uGFX display driver, check the uGFX documentation for that. You probably also want to enable SPI support in your Chibios configuration.
diff --git a/quantum/visualizer/resources/lcd_logo.c b/quantum/visualizer/resources/lcd_logo.c
deleted file mode 100644
index 13bf734cb..000000000
--- a/quantum/visualizer/resources/lcd_logo.c
+++ /dev/null
@@ -1,45 +0,0 @@
1/* Copyright 2017 Fred Sundvik
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "resources.h"
18
19// clang-format off
20
21// To generate an image array like this
22// Ensure the image is 128 x 32 or smaller
23// Convert the bitmap to a C array using a program like http://www.riuson.com/lcd-image-converter/
24// Ensure the the conversion process produces a monochrome format array - 1 bit/pixel, left to right, top to bottom
25// Update array in the source code with the C array produced by the conversion program
26
27// The image below is generated from lcd_logo.png
28__attribute__((weak)) const uint8_t resource_lcd_logo[512] = {
29 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
30 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
31 0x00, 0x02, 0x92, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x92, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
32 0x00, 0x02, 0x92, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
33 0x00, 0x1F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
34 0x00, 0xFE, 0xEE, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0xEE, 0xF0, 0x01, 0xC6, 0x0D, 0x8C, 0x1F, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
35 0x00, 0xFE, 0xEE, 0xFE, 0x03, 0xE7, 0x1D, 0x9C, 0x1F, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0xEE, 0xF0, 0x06, 0x37, 0x1D, 0xB8, 0x18, 0x0B, 0x59, 0xC8, 0x09, 0xE5, 0x9E, 0x00,
36 0x00, 0x1E, 0xEE, 0xF0, 0x06, 0x37, 0xBD, 0xF0, 0x18, 0x6F, 0x7F, 0xEC, 0x9B, 0x37, 0xB3, 0x00, 0x00, 0xFE, 0xEE, 0xFE, 0x06, 0x37, 0xBD, 0xE0, 0x1F, 0x6C, 0x66, 0x6D, 0xD8, 0x36, 0x33, 0x00,
37 0x00, 0x1E, 0xEE, 0xF0, 0x06, 0x36, 0xED, 0xF0, 0x1F, 0x6C, 0x66, 0x6D, 0x59, 0xF6, 0x3E, 0x00, 0x00, 0x1F, 0x6D, 0xF0, 0x06, 0x36, 0xED, 0xB8, 0x18, 0x6C, 0x66, 0x67, 0x73, 0x36, 0x30, 0x00,
38 0x00, 0xFF, 0x83, 0xFE, 0x03, 0xE6, 0x4D, 0x9C, 0x18, 0x6C, 0x66, 0x67, 0x73, 0x36, 0x1F, 0x00, 0x00, 0x1F, 0xEF, 0xF0, 0x01, 0xC6, 0x0D, 0x8C, 0x18, 0x6C, 0x66, 0x62, 0x21, 0xD6, 0x0E, 0x00,
39 0x00, 0xFF, 0xEF, 0xFE, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF0, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
40 0x00, 0x1F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
41 0x00, 0x02, 0x92, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x92, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
42 0x00, 0x02, 0x92, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
43 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
44 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
45};
diff --git a/quantum/visualizer/resources/lcd_logo.png b/quantum/visualizer/resources/lcd_logo.png
deleted file mode 100644
index 178ef65f1..000000000
--- a/quantum/visualizer/resources/lcd_logo.png
+++ /dev/null
Binary files differ
diff --git a/quantum/visualizer/resources/resources.h b/quantum/visualizer/resources/resources.h
deleted file mode 100644
index 5178fbe55..000000000
--- a/quantum/visualizer/resources/resources.h
+++ /dev/null
@@ -1,23 +0,0 @@
1/* Copyright 2017 Fred Sundvik
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#pragma once
18
19#include <stdint.h>
20
21#ifdef LCD_ENABLE
22extern const uint8_t resource_lcd_logo[];
23#endif
diff --git a/quantum/visualizer/visualizer.c b/quantum/visualizer/visualizer.c
deleted file mode 100644
index 709affbb7..000000000
--- a/quantum/visualizer/visualizer.c
+++ /dev/null
@@ -1,483 +0,0 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2016 Fred Sundvik
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24
25#include "config.h"
26#include "visualizer.h"
27#include <string.h>
28#ifdef PROTOCOL_CHIBIOS
29# include <ch.h>
30#endif
31
32#include "gfx.h"
33
34#ifdef LCD_BACKLIGHT_ENABLE
35# include "lcd_backlight.h"
36#endif
37
38//#define DEBUG_VISUALIZER
39
40#ifdef DEBUG_VISUALIZER
41# include "debug.h"
42#else
43# include "nodebug.h"
44#endif
45
46#ifdef SERIAL_LINK_ENABLE
47# include "serial_link/protocol/transport.h"
48# include "serial_link/system/serial_link.h"
49#endif
50
51#include "action_util.h"
52
53// Define this in config.h
54#ifndef VISUALIZER_THREAD_PRIORITY
55// The visualizer needs gfx thread priorities
56# define VISUALIZER_THREAD_PRIORITY (NORMAL_PRIORITY - 2)
57#endif
58
59static visualizer_keyboard_status_t current_status = {.layer = 0xFFFFFFFF,
60 .default_layer = 0xFFFFFFFF,
61 .leds = 0xFFFFFFFF,
62#ifdef BACKLIGHT_ENABLE
63 .backlight_level = 0,
64#endif
65 .mods = 0xFF,
66 .suspended = false,
67#ifdef VISUALIZER_USER_DATA_SIZE
68 .user_data = {0}
69#endif
70};
71
72static bool same_status(visualizer_keyboard_status_t* status1, visualizer_keyboard_status_t* status2) {
73 return status1->layer == status2->layer && status1->default_layer == status2->default_layer && status1->mods == status2->mods && status1->leds == status2->leds && status1->suspended == status2->suspended
74#ifdef BACKLIGHT_ENABLE
75 && status1->backlight_level == status2->backlight_level
76#endif
77#ifdef VISUALIZER_USER_DATA_SIZE
78 && memcmp(status1->user_data, status2->user_data, VISUALIZER_USER_DATA_SIZE) == 0
79#endif
80 ;
81}
82
83static bool visualizer_enabled = false;
84
85#ifdef VISUALIZER_USER_DATA_SIZE
86static uint8_t user_data[VISUALIZER_USER_DATA_SIZE];
87#endif
88
89#define MAX_SIMULTANEOUS_ANIMATIONS 4
90static keyframe_animation_t* animations[MAX_SIMULTANEOUS_ANIMATIONS] = {};
91
92#ifdef SERIAL_LINK_ENABLE
93MASTER_TO_ALL_SLAVES_OBJECT(current_status, visualizer_keyboard_status_t);
94
95static remote_object_t* remote_objects[] = {
96 REMOTE_OBJECT(current_status),
97};
98
99#endif
100
101GDisplay* LCD_DISPLAY = 0;
102GDisplay* LED_DISPLAY = 0;
103
104#ifdef LCD_DISPLAY_NUMBER
105__attribute__((weak)) GDisplay* get_lcd_display(void) { return gdispGetDisplay(LCD_DISPLAY_NUMBER); }
106#endif
107
108#ifdef LED_DISPLAY_NUMBER
109__attribute__((weak)) GDisplay* get_led_display(void) { return gdispGetDisplay(LED_DISPLAY_NUMBER); }
110#endif
111
112void start_keyframe_animation(keyframe_animation_t* animation) {
113 animation->current_frame = -1;
114 animation->time_left_in_frame = 0;
115 animation->need_update = true;
116 int free_index = -1;
117 for (int i = 0; i < MAX_SIMULTANEOUS_ANIMATIONS; i++) {
118 if (animations[i] == animation) {
119 return;
120 }
121 if (free_index == -1 && animations[i] == NULL) {
122 free_index = i;
123 }
124 }
125 if (free_index != -1) {
126 animations[free_index] = animation;
127 }
128}
129
130void stop_keyframe_animation(keyframe_animation_t* animation) {
131 animation->current_frame = animation->num_frames;
132 animation->time_left_in_frame = 0;
133 animation->need_update = true;
134 animation->first_update_of_frame = false;
135 animation->last_update_of_frame = false;
136 for (int i = 0; i < MAX_SIMULTANEOUS_ANIMATIONS; i++) {
137 if (animations[i] == animation) {
138 animations[i] = NULL;
139 return;
140 }
141 }
142}
143
144void stop_all_keyframe_animations(void) {
145 for (int i = 0; i < MAX_SIMULTANEOUS_ANIMATIONS; i++) {
146 if (animations[i]) {
147 animations[i]->current_frame = animations[i]->num_frames;
148 animations[i]->time_left_in_frame = 0;
149 animations[i]->need_update = true;
150 animations[i]->first_update_of_frame = false;
151 animations[i]->last_update_of_frame = false;
152 animations[i] = NULL;
153 }
154 }
155}
156
157static uint8_t get_num_running_animations(void) {
158 uint8_t count = 0;
159 for (int i = 0; i < MAX_SIMULTANEOUS_ANIMATIONS; i++) {
160 count += animations[i] ? 1 : 0;
161 }
162 return count;
163}
164
165static bool update_keyframe_animation(keyframe_animation_t* animation, visualizer_state_t* state, systemticks_t delta, systemticks_t* sleep_time) {
166 // TODO: Clean up this messy code
167 dprintf("Animation frame%d, left %d, delta %d\n", animation->current_frame, animation->time_left_in_frame, delta);
168 if (animation->current_frame == animation->num_frames) {
169 animation->need_update = false;
170 return false;
171 }
172 if (animation->current_frame == -1) {
173 animation->current_frame = 0;
174 animation->time_left_in_frame = animation->frame_lengths[0];
175 animation->need_update = true;
176 animation->first_update_of_frame = true;
177 } else {
178 animation->time_left_in_frame -= delta;
179 while (animation->time_left_in_frame <= 0) {
180 int left = animation->time_left_in_frame;
181 if (animation->need_update) {
182 animation->time_left_in_frame = 0;
183 animation->last_update_of_frame = true;
184 (*animation->frame_functions[animation->current_frame])(animation, state);
185 animation->last_update_of_frame = false;
186 }
187 animation->current_frame++;
188 animation->need_update = true;
189 animation->first_update_of_frame = true;
190 if (animation->current_frame == animation->num_frames) {
191 if (animation->loop) {
192 animation->current_frame = 0;
193 } else {
194 stop_keyframe_animation(animation);
195 return false;
196 }
197 }
198 delta = -left;
199 animation->time_left_in_frame = animation->frame_lengths[animation->current_frame];
200 animation->time_left_in_frame -= delta;
201 }
202 }
203 if (animation->need_update) {
204 animation->need_update = (*animation->frame_functions[animation->current_frame])(animation, state);
205 animation->first_update_of_frame = false;
206 }
207
208 systemticks_t wanted_sleep = animation->need_update ? gfxMillisecondsToTicks(10) : (unsigned)animation->time_left_in_frame;
209 if (wanted_sleep < *sleep_time) {
210 *sleep_time = wanted_sleep;
211 }
212
213 return true;
214}
215
216void run_next_keyframe(keyframe_animation_t* animation, visualizer_state_t* state) {
217 int next_frame = animation->current_frame + 1;
218 if (next_frame == animation->num_frames) {
219 next_frame = 0;
220 }
221 keyframe_animation_t temp_animation = *animation;
222 temp_animation.current_frame = next_frame;
223 temp_animation.time_left_in_frame = animation->frame_lengths[next_frame];
224 temp_animation.first_update_of_frame = true;
225 temp_animation.last_update_of_frame = false;
226 temp_animation.need_update = false;
227 visualizer_state_t temp_state = *state;
228 (*temp_animation.frame_functions[next_frame])(&temp_animation, &temp_state);
229}
230
231// TODO: Optimize the stack size, this is probably way too big
232static DECLARE_THREAD_STACK(visualizerThreadStack, 1024);
233static DECLARE_THREAD_FUNCTION(visualizerThread, arg) {
234 (void)arg;
235
236 GListener event_listener;
237 geventListenerInit(&event_listener);
238 geventAttachSource(&event_listener, (GSourceHandle)&current_status, 0);
239
240 visualizer_keyboard_status_t initial_status = {
241 .default_layer = 0xFFFFFFFF,
242 .layer = 0xFFFFFFFF,
243 .mods = 0xFF,
244 .leds = 0xFFFFFFFF,
245 .suspended = false,
246#ifdef BACKLIGHT_ENABLE
247 .backlight_level = 0,
248#endif
249#ifdef VISUALIZER_USER_DATA_SIZE
250 .user_data = {0},
251#endif
252 };
253
254 visualizer_state_t state = {.status = initial_status,
255 .current_lcd_color = 0,
256#ifdef LCD_ENABLE
257 .font_fixed5x8 = gdispOpenFont("fixed_5x8"),
258 .font_dejavusansbold12 = gdispOpenFont("DejaVuSansBold12")
259#endif
260 };
261 initialize_user_visualizer(&state);
262 state.prev_lcd_color = state.current_lcd_color;
263
264#ifdef LCD_BACKLIGHT_ENABLE
265 lcd_backlight_color(LCD_HUE(state.current_lcd_color), LCD_SAT(state.current_lcd_color), LCD_INT(state.current_lcd_color));
266#endif
267
268 systemticks_t sleep_time = TIME_INFINITE;
269 systemticks_t current_time = gfxSystemTicks();
270 bool force_update = true;
271
272 while (true) {
273 systemticks_t new_time = gfxSystemTicks();
274 systemticks_t delta = new_time - current_time;
275 current_time = new_time;
276 bool enabled = visualizer_enabled;
277 if (force_update || !same_status(&state.status, &current_status)) {
278 force_update = false;
279#if BACKLIGHT_ENABLE
280 if (current_status.backlight_level != state.status.backlight_level) {
281 if (current_status.backlight_level != 0) {
282 gdispGSetPowerMode(LED_DISPLAY, powerOn);
283 uint16_t percent = (uint16_t)current_status.backlight_level * 100 / BACKLIGHT_LEVELS;
284 gdispGSetBacklight(LED_DISPLAY, percent);
285 } else {
286 gdispGSetPowerMode(LED_DISPLAY, powerOff);
287 }
288 state.status.backlight_level = current_status.backlight_level;
289 }
290#endif
291 if (visualizer_enabled) {
292 if (current_status.suspended) {
293 stop_all_keyframe_animations();
294 visualizer_enabled = false;
295 state.status = current_status;
296 user_visualizer_suspend(&state);
297 } else {
298 visualizer_keyboard_status_t prev_status = state.status;
299 state.status = current_status;
300 update_user_visualizer_state(&state, &prev_status);
301 }
302 state.prev_lcd_color = state.current_lcd_color;
303 }
304 }
305 if (!enabled && state.status.suspended && current_status.suspended == false) {
306 // Setting the status to the initial status will force an update
307 // when the visualizer is enabled again
308 state.status = initial_status;
309 state.status.suspended = false;
310 stop_all_keyframe_animations();
311 user_visualizer_resume(&state);
312 state.prev_lcd_color = state.current_lcd_color;
313 }
314 sleep_time = TIME_INFINITE;
315 for (int i = 0; i < MAX_SIMULTANEOUS_ANIMATIONS; i++) {
316 if (animations[i]) {
317 update_keyframe_animation(animations[i], &state, delta, &sleep_time);
318 }
319 }
320#ifdef BACKLIGHT_ENABLE
321 gdispGFlush(LED_DISPLAY);
322#endif
323
324#ifdef LCD_ENABLE
325 gdispGFlush(LCD_DISPLAY);
326#endif
327
328#ifdef EMULATOR
329 draw_emulator();
330#endif
331 // Enable the visualizer when the startup or the suspend animation has finished
332 if (!visualizer_enabled && state.status.suspended == false && get_num_running_animations() == 0) {
333 visualizer_enabled = true;
334 force_update = true;
335 sleep_time = 0;
336 }
337
338 systemticks_t after_update = gfxSystemTicks();
339 unsigned update_delta = after_update - current_time;
340 if (sleep_time != TIME_INFINITE) {
341 if (sleep_time > update_delta) {
342 sleep_time -= update_delta;
343 } else {
344 sleep_time = 0;
345 }
346 }
347 dprintf("Update took %d, last delta %d, sleep_time %d\n", update_delta, delta, sleep_time);
348#ifdef PROTOCOL_CHIBIOS
349 // The gEventWait function really takes milliseconds, even if the documentation says ticks.
350 // Unfortunately there's no generic ugfx conversion from system time to milliseconds,
351 // so let's do it in a platform dependent way.
352
353 // On windows the system ticks is the same as milliseconds anyway
354 if (sleep_time != TIME_INFINITE) {
355 sleep_time = TIME_I2MS(sleep_time);
356 }
357#endif
358 geventEventWait(&event_listener, sleep_time);
359 }
360#ifdef LCD_ENABLE
361 gdispCloseFont(state.font_fixed5x8);
362 gdispCloseFont(state.font_dejavusansbold12);
363#endif
364
365 return 0;
366}
367
368void visualizer_init(void) {
369 gfxInit();
370
371#ifdef LCD_BACKLIGHT_ENABLE
372 lcd_backlight_init();
373#endif
374
375#ifdef SERIAL_LINK_ENABLE
376 add_remote_objects(remote_objects, sizeof(remote_objects) / sizeof(remote_object_t*));
377#endif
378
379#ifdef LCD_ENABLE
380 LCD_DISPLAY = get_lcd_display();
381#endif
382
383#ifdef BACKLIGHT_ENABLE
384 LED_DISPLAY = get_led_display();
385#endif
386
387 // We are using a low priority thread, the idea is to have it run only
388 // when the main thread is sleeping during the matrix scanning
389 gfxThreadCreate(visualizerThreadStack, sizeof(visualizerThreadStack), VISUALIZER_THREAD_PRIORITY, visualizerThread, NULL);
390}
391
392void update_status(bool changed) {
393 if (changed) {
394 GSourceListener* listener = geventGetSourceListener((GSourceHandle)&current_status, NULL);
395 if (listener) {
396 geventSendEvent(listener);
397 }
398 }
399#ifdef SERIAL_LINK_ENABLE
400 static systime_t last_update = 0;
401 systime_t current_update = chVTGetSystemTimeX();
402 systime_t delta = current_update - last_update;
403 if (changed || delta > TIME_MS2I(10)) {
404 last_update = current_update;
405 visualizer_keyboard_status_t* r = begin_write_current_status();
406 *r = current_status;
407 end_write_current_status();
408 }
409#endif
410}
411
412uint8_t visualizer_get_mods() {
413 uint8_t mods = get_mods();
414
415#ifndef NO_ACTION_ONESHOT
416 if (!has_oneshot_mods_timed_out()) {
417 mods |= get_oneshot_mods();
418 }
419#endif
420 return mods;
421}
422
423#ifdef VISUALIZER_USER_DATA_SIZE
424void visualizer_set_user_data(void* u) { memcpy(user_data, u, VISUALIZER_USER_DATA_SIZE); }
425#endif
426
427void visualizer_update(layer_state_t default_state, layer_state_t state, uint8_t mods, uint32_t leds) {
428 // Note that there's a small race condition here, the thread could read
429 // a state where one of these are set but not the other. But this should
430 // not really matter as it will be fixed during the next loop step.
431 // Alternatively a mutex could be used instead of the volatile variables
432
433 bool changed = false;
434#ifdef SERIAL_LINK_ENABLE
435 if (is_serial_link_connected()) {
436 visualizer_keyboard_status_t* new_status = read_current_status();
437 if (new_status) {
438 if (!same_status(&current_status, new_status)) {
439 changed = true;
440 current_status = *new_status;
441 }
442 }
443 } else {
444#else
445 {
446#endif
447 visualizer_keyboard_status_t new_status = {
448 .layer = state,
449 .default_layer = default_state,
450 .mods = mods,
451 .leds = leds,
452#ifdef BACKLIGHT_ENABLE
453 .backlight_level = current_status.backlight_level,
454#endif
455 .suspended = current_status.suspended,
456 };
457#ifdef VISUALIZER_USER_DATA_SIZE
458 memcpy(new_status.user_data, user_data, VISUALIZER_USER_DATA_SIZE);
459#endif
460 if (!same_status(&current_status, &new_status)) {
461 changed = true;
462 current_status = new_status;
463 }
464 }
465 update_status(changed);
466}
467
468void visualizer_suspend(void) {
469 current_status.suspended = true;
470 update_status(true);
471}
472
473void visualizer_resume(void) {
474 current_status.suspended = false;
475 update_status(true);
476}
477
478#ifdef BACKLIGHT_ENABLE
479void backlight_set(uint8_t level) {
480 current_status.backlight_level = level;
481 update_status(true);
482}
483#endif
diff --git a/quantum/visualizer/visualizer.h b/quantum/visualizer/visualizer.h
deleted file mode 100644
index 627c80a30..000000000
--- a/quantum/visualizer/visualizer.h
+++ /dev/null
@@ -1,154 +0,0 @@
1/*
2The MIT License (MIT)
3
4Copyright (c) 2016 Fred Sundvik
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24
25#pragma once
26
27#include <stdlib.h>
28#include <stdint.h>
29#include <stdbool.h>
30
31#include "config.h"
32#include "gfx.h"
33#include "action_layer.h"
34
35#ifdef LCD_BACKLIGHT_ENABLE
36# include "lcd_backlight.h"
37#endif
38
39#ifdef BACKLIGHT_ENABLE
40# include "backlight.h"
41#endif
42
43// use this function to merge both real_mods and oneshot_mods in a uint16_t
44uint8_t visualizer_get_mods(void);
45
46// This need to be called once at the start
47void visualizer_init(void);
48// This should be called at every matrix scan
49void visualizer_update(layer_state_t default_state, layer_state_t state, uint8_t mods, uint32_t leds);
50
51// This should be called when the keyboard goes to suspend state
52void visualizer_suspend(void);
53// This should be called when the keyboard wakes up from suspend state
54void visualizer_resume(void);
55
56// These functions are week, so they can be overridden by the keyboard
57// if needed
58GDisplay* get_lcd_display(void);
59GDisplay* get_led_display(void);
60
61// For emulator builds, this function need to be implemented
62#ifdef EMULATOR
63void draw_emulator(void);
64#endif
65
66// If you need support for more than 16 keyframes per animation, you can change this
67#define MAX_VISUALIZER_KEY_FRAMES 16
68
69struct keyframe_animation_t;
70
71typedef struct {
72 layer_state_t layer;
73 layer_state_t default_layer;
74 uint32_t leds; // See led.h for available statuses
75 uint8_t mods;
76 bool suspended;
77#ifdef BACKLIGHT_ENABLE
78 uint8_t backlight_level;
79#endif
80#ifdef VISUALIZER_USER_DATA_SIZE
81 uint8_t user_data[VISUALIZER_USER_DATA_SIZE];
82#endif
83} visualizer_keyboard_status_t;
84
85// The state struct is used by the various keyframe functions
86// It's also used for setting the LCD color and layer text
87// from the user customized code
88typedef struct visualizer_state_t {
89 // The user code should primarily be modifying these
90 uint32_t target_lcd_color;
91 const char* layer_text;
92
93 // The user visualizer(and animation functions) can read these
94 visualizer_keyboard_status_t status;
95
96 // These are used by the animation functions
97 uint32_t current_lcd_color;
98 uint32_t prev_lcd_color;
99#ifdef LCD_ENABLE
100 gFont font_fixed5x8;
101 gFont font_dejavusansbold12;
102#endif
103} visualizer_state_t;
104
105// Any custom keyframe function should have this signature
106// return true to get continuous updates, otherwise you will only get one
107// update per frame
108typedef bool (*frame_func)(struct keyframe_animation_t*, visualizer_state_t*);
109
110// Represents a keyframe animation, so fields are internal to the system
111// while others are meant to be initialized by the user code
112typedef struct keyframe_animation_t {
113 // These should be initialized
114 int num_frames;
115 bool loop;
116 int frame_lengths[MAX_VISUALIZER_KEY_FRAMES];
117 frame_func frame_functions[MAX_VISUALIZER_KEY_FRAMES];
118
119 // Used internally by the system, and can also be read by
120 // keyframe update functions
121 int current_frame;
122 int time_left_in_frame;
123 bool first_update_of_frame;
124 bool last_update_of_frame;
125 bool need_update;
126
127} keyframe_animation_t;
128
129extern GDisplay* LCD_DISPLAY;
130extern GDisplay* LED_DISPLAY;
131
132void start_keyframe_animation(keyframe_animation_t* animation);
133void stop_keyframe_animation(keyframe_animation_t* animation);
134// This runs the next keyframe, but does not update the animation state
135// Useful for crossfades for example
136void run_next_keyframe(keyframe_animation_t* animation, visualizer_state_t* state);
137
138// The master can set userdata which will be transferred to the slave
139#ifdef VISUALIZER_USER_DATA_SIZE
140void visualizer_set_user_data(void* user_data);
141#endif
142
143// These functions have to be implemented by the user
144// Called regularly each time the state has changed (but not every scan loop)
145void update_user_visualizer_state(visualizer_state_t* state, visualizer_keyboard_status_t* prev_status);
146// Called when the computer goes to suspend, will also stop calling update_user_visualizer_state
147void user_visualizer_suspend(visualizer_state_t* state);
148// You have to start at least one animation as a response to the following two functions
149// When the animation has finished the visualizer will resume normal operation and start calling the
150// update_user_visualizer_state again
151// Called when the keyboard boots up
152void initialize_user_visualizer(visualizer_state_t* state);
153// Called when the computer resumes from a suspend
154void user_visualizer_resume(visualizer_state_t* state);
diff --git a/quantum/visualizer/visualizer.mk b/quantum/visualizer/visualizer.mk
deleted file mode 100644
index 4c961ac59..000000000
--- a/quantum/visualizer/visualizer.mk
+++ /dev/null
@@ -1,123 +0,0 @@
1# The MIT License (MIT)
2#
3# Copyright (c) 2016 Fred Sundvik
4#
5# Permission is hereby granted, free of charge, to any person obtaining a copy
6# of this software and associated documentation files (the "Software"), to deal
7# in the Software without restriction, including without limitation the rights
8# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9# copies of the Software, and to permit persons to whom the Software is
10# furnished to do so, subject to the following conditions:
11#
12# The above copyright notice and this permission notice shall be included in all
13# copies or substantial portions of the Software.
14#
15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21# SOFTWARE.
22
23define ADD_DRIVER
24 $(1)_DRIVER:=$(strip $($(1)_DRIVER))
25 $(1)_WIDTH:=$(strip $($(1)_WIDTH))
26 $(1)_HEIGHT:=$(strip $($(1)_HEIGHT))
27 ifeq ($($(1)_DRIVER),)
28 $$(error $(1)_DRIVER is not defined)
29 endif
30 ifeq ($($(1)_WIDTH),)
31 $$(error $(1)_WIDTH is not defined)
32 endif
33 ifeq ($($(1)_HEIGHT),)
34 $$(error $(1)_HEIGHT is not defined)
35 endif
36 OPT_DEFS+=-D$(1)_WIDTH=$($(1)_WIDTH)
37 OPT_DEFS+=-D$(1)_HEIGHT=$($(1)_HEIGHT)
38 GFXDEFS+=-D$(1)_WIDTH=$($(1)_WIDTH)
39 GFXDEFS+=-D$(1)_HEIGHT=$($(1)_HEIGHT)
40 $(1)_DISPLAY_NUMBER:=$$(words $$(GDISP_DRIVER_LIST))
41 OPT_DEFS+=-D$(1)_DISPLAY_NUMBER=$$($(1)_DISPLAY_NUMBER)
42 include $(TOP_DIR)/drivers/ugfx/gdisp/$($(1)_DRIVER)/driver.mk
43endef
44
45GDISP_DRIVER_LIST:=
46
47SRC += $(VISUALIZER_DIR)/visualizer.c \
48 $(VISUALIZER_DIR)/visualizer_keyframes.c
49EXTRAINCDIRS += $(GFXINC) $(VISUALIZER_DIR)
50GFXLIB = $(LIB_PATH)/ugfx
51VPATH += $(VISUALIZER_PATH)
52
53OPT_DEFS += -DVISUALIZER_ENABLE
54
55ifdef LCD_ENABLE
56OPT_DEFS += -DLCD_ENABLE
57ULIBS += -lm
58endif
59
60ifeq ($(strip $(LCD_ENABLE)), yes)
61 SRC += $(VISUALIZER_DIR)/lcd_keyframes.c
62 ifeq ($(strip $(LCD_BACKLIGHT_ENABLE)), yes)
63 OPT_DEFS += -DLCD_BACKLIGHT_ENABLE
64 SRC += $(VISUALIZER_DIR)/lcd_backlight.c
65 SRC += $(VISUALIZER_DIR)/lcd_backlight_keyframes.c
66 endif
67# Note, that the linker will strip out any resources that are not actually in use
68SRC += $(VISUALIZER_DIR)/resources/lcd_logo.c
69$(eval $(call ADD_DRIVER,LCD))
70endif
71
72ifeq ($(strip $(BACKLIGHT_ENABLE)), yes)
73SRC += $(VISUALIZER_DIR)/led_backlight_keyframes.c
74$(eval $(call ADD_DRIVER,LED))
75endif
76
77SRC += $(VISUALIZER_DIR)/default_animations.c
78
79include $(GFXLIB)/gfx.mk
80# For the common_gfxconf.h
81GFXINC += quantum/visualizer
82
83GFXSRC := $(patsubst $(TOP_DIR)/%,%,$(GFXSRC))
84GFXDEFS := $(patsubst %,-D%,$(patsubst -D%,%,$(GFXDEFS)))
85
86GDISP_LIST_COMMA=,
87GDISP_LIST_EMPTY=
88GDISP_LIST_SPACE=$(GDISP_LIST_EMPTY) $(GDISP_LIST_EMPTY)
89
90GDISP_DRIVER_LIST := $(strip $(GDISP_DRIVER_LIST))
91GDISP_DRIVER_LIST := $(subst $(GDISP_LIST_SPACE),$(GDISP_LIST_COMMA),$(GDISP_DRIVER_LIST))
92
93GFXDEFS +=-DGDISP_DRIVER_LIST="$(GDISP_DRIVER_LIST)"
94
95ifneq ("$(wildcard $(KEYMAP_PATH)/visualizer.c)","")
96 SRC += $(KEYMAP_PATH)/visualizer.c
97else
98 VISUALIZER_1 := $(KEYBOARD_PATH_1)/visualizer.c
99 VISUALIZER_2 := $(KEYBOARD_PATH_2)/visualizer.c
100 VISUALIZER_3 := $(KEYBOARD_PATH_3)/visualizer.c
101 VISUALIZER_4 := $(KEYBOARD_PATH_4)/visualizer.c
102 VISUALIZER_5 := $(KEYBOARD_PATH_5)/visualizer.c
103
104 ifneq ("$(wildcard $(VISUALIZER_5))","")
105 SRC += $(VISUALIZER_5)
106 endif
107 ifneq ("$(wildcard $(VISUALIZER_4))","")
108 SRC += $(VISUALIZER_4)
109 endif
110 ifneq ("$(wildcard $(VISUALIZER_3))","")
111 SRC += $(VISUALIZER_3)
112 endif
113 ifneq ("$(wildcard $(VISUALIZER_2))","")
114 SRC += $(VISUALIZER_2)
115 endif
116 ifneq ("$(wildcard $(VISUALIZER_1))","")
117 SRC += $(VISUALIZER_1)
118 endif
119endif
120
121ifdef EMULATOR
122UINCDIR += $(TMK_DIR)/common
123endif
diff --git a/quantum/visualizer/visualizer_keyframes.c b/quantum/visualizer/visualizer_keyframes.c
deleted file mode 100644
index 8f6a7e15a..000000000
--- a/quantum/visualizer/visualizer_keyframes.c
+++ /dev/null
@@ -1,23 +0,0 @@
1/* Copyright 2017 Fred Sundvik
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "visualizer_keyframes.h"
18
19bool keyframe_no_operation(keyframe_animation_t* animation, visualizer_state_t* state) {
20 (void)animation;
21 (void)state;
22 return false;
23}
diff --git a/quantum/visualizer/visualizer_keyframes.h b/quantum/visualizer/visualizer_keyframes.h
deleted file mode 100644
index c92ff1611..000000000
--- a/quantum/visualizer/visualizer_keyframes.h
+++ /dev/null
@@ -1,23 +0,0 @@
1/* Copyright 2017 Fred Sundvik
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#pragma once
18
19#include "visualizer.h"
20
21// Some predefined keyframe functions that can be used by the user code
22// Does nothing, useful for adding delays
23bool keyframe_no_operation(keyframe_animation_t* animation, visualizer_state_t* state);