diff options
| author | James Young <18669334+noroadsleft@users.noreply.github.com> | 2020-11-28 12:02:18 -0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-11-28 12:02:18 -0800 |
| commit | c66df1664497546f32662409778731143e45a552 (patch) | |
| tree | da73a2d532a27685a31d932b3a44a707d4a3af81 /quantum | |
| parent | 15385d4113414d42bd062c60c9de5df797d3157f (diff) | |
| download | qmk_firmware-c66df1664497546f32662409778731143e45a552.tar.gz qmk_firmware-c66df1664497546f32662409778731143e45a552.zip | |
2020 November 28 Breaking Changes Update (#11053)
* Branch point for 2020 November 28 Breaking Change
* Remove matrix_col_t to allow MATRIX_ROWS > 32 (#10183)
* Add support for soft serial to ATmega32U2 (#10204)
* Change MIDI velocity implementation to allow direct control of velocity value (#9940)
* Add ability to build a subset of all keyboards based on platform.
* Actually use eeprom_driver_init().
* Make bootloader_jump weak for ChibiOS. (#10417)
* Joystick 16-bit support (#10439)
* Per-encoder resolutions (#10259)
* Share button state from mousekey to pointing_device (#10179)
* Add hotfix for chibios keyboards not wake (#10088)
* Add advanced/efficient RGB Matrix Indicators (#8564)
* Naming change.
* Support for STM32 GPIOF,G,H,I,J,K (#10206)
* Add milc as a dependency and remove the installed milc (#10563)
* ChibiOS upgrade: early init conversions (#10214)
* ChibiOS upgrade: configuration file migrator (#9952)
* Haptic and solenoid cleanup (#9700)
* XD75 cleanup (#10524)
* OLED display update interval support (#10388)
* Add definition based on currently-selected serial driver. (#10716)
* New feature: Retro Tapping per key (#10622)
* Allow for modification of output RGB values when using rgblight/rgb_matrix. (#10638)
* Add housekeeping task callbacks so that keyboards/keymaps are capable of executing code for each main loop iteration. (#10530)
* Rescale both ChibiOS and AVR backlighting.
* Reduce Helix keyboard build variation (#8669)
* Minor change to behavior allowing display updates to continue between task ticks (#10750)
* Some GPIO manipulations in matrix.c change to atomic. (#10491)
* qmk cformat (#10767)
* [Keyboard] Update the Speedo firmware for v3.0 (#10657)
* Maartenwut/Maarten namechange to evyd13/Evy (#10274)
* [quantum] combine repeated lines of code (#10837)
* Add step sequencer feature (#9703)
* aeboards/ext65 refactor (#10820)
* Refactor xelus/dawn60 for Rev2 later (#10584)
* add DEBUG_MATRIX_SCAN_RATE_ENABLE to common_features.mk (#10824)
* [Core] Added `add_oneshot_mods` & `del_oneshot_mods` (#10549)
* update chibios os usb for the otg driver (#8893)
* Remove HD44780 References, Part 4 (#10735)
* [Keyboard] Add Valor FRL TKL (+refactor) (#10512)
* Fix cursor position bug in oled_write_raw functions (#10800)
* Fixup version.h writing when using SKIP_VERSION=yes (#10972)
* Allow for certain code in the codebase assuming length of string. (#10974)
* Add AT90USB support for serial.c (#10706)
* Auto shift: support repeats and early registration (#9826)
* Rename ledmatrix.h to match .c file (#7949)
* Split RGB_MATRIX_ENABLE into _ENABLE and _DRIVER (#10231)
* Split LED_MATRIX_ENABLE into _ENABLE and _DRIVER (#10840)
* Merge point for 2020 Nov 28 Breaking Change
Diffstat (limited to 'quantum')
45 files changed, 1668 insertions, 122 deletions
diff --git a/quantum/backlight/backlight_avr.c b/quantum/backlight/backlight_avr.c index b3e882ffe..4d66da80b 100644 --- a/quantum/backlight/backlight_avr.c +++ b/quantum/backlight/backlight_avr.c | |||
| @@ -3,6 +3,11 @@ | |||
| 3 | #include "backlight_driver_common.h" | 3 | #include "backlight_driver_common.h" |
| 4 | #include "debug.h" | 4 | #include "debug.h" |
| 5 | 5 | ||
| 6 | // Maximum duty cycle limit | ||
| 7 | #ifndef BACKLIGHT_LIMIT_VAL | ||
| 8 | # define BACKLIGHT_LIMIT_VAL 255 | ||
| 9 | #endif | ||
| 10 | |||
| 6 | // This logic is a bit complex, we support 3 setups: | 11 | // This logic is a bit complex, we support 3 setups: |
| 7 | // | 12 | // |
| 8 | // 1. Hardware PWM when backlight is wired to a PWM pin. | 13 | // 1. Hardware PWM when backlight is wired to a PWM pin. |
| @@ -240,6 +245,9 @@ static uint16_t cie_lightness(uint16_t v) { | |||
| 240 | } | 245 | } |
| 241 | } | 246 | } |
| 242 | 247 | ||
| 248 | // rescale the supplied backlight value to be in terms of the value limit | ||
| 249 | static uint32_t rescale_limit_val(uint32_t val) { return (val * (BACKLIGHT_LIMIT_VAL + 1)) / 256; } | ||
| 250 | |||
| 243 | // range for val is [0..TIMER_TOP]. PWM pin is high while the timer count is below val. | 251 | // range for val is [0..TIMER_TOP]. PWM pin is high while the timer count is below val. |
| 244 | static inline void set_pwm(uint16_t val) { OCRxx = val; } | 252 | static inline void set_pwm(uint16_t val) { OCRxx = val; } |
| 245 | 253 | ||
| @@ -269,7 +277,7 @@ void backlight_set(uint8_t level) { | |||
| 269 | #endif | 277 | #endif |
| 270 | } | 278 | } |
| 271 | // Set the brightness | 279 | // Set the brightness |
| 272 | set_pwm(cie_lightness(TIMER_TOP * (uint32_t)level / BACKLIGHT_LEVELS)); | 280 | set_pwm(cie_lightness(rescale_limit_val(TIMER_TOP * (uint32_t)level / BACKLIGHT_LEVELS))); |
| 273 | } | 281 | } |
| 274 | 282 | ||
| 275 | void backlight_task(void) {} | 283 | void backlight_task(void) {} |
| @@ -375,7 +383,7 @@ ISR(TIMERx_OVF_vect) | |||
| 375 | breathing_interrupt_disable(); | 383 | breathing_interrupt_disable(); |
| 376 | } | 384 | } |
| 377 | 385 | ||
| 378 | set_pwm(cie_lightness(scale_backlight((uint16_t)pgm_read_byte(&breathing_table[index]) * 0x0101U))); | 386 | set_pwm(cie_lightness(rescale_limit_val(scale_backlight((uint16_t)pgm_read_byte(&breathing_table[index]) * 0x0101U)))); |
| 379 | } | 387 | } |
| 380 | 388 | ||
| 381 | #endif // BACKLIGHT_BREATHING | 389 | #endif // BACKLIGHT_BREATHING |
diff --git a/quantum/backlight/backlight_chibios.c b/quantum/backlight/backlight_chibios.c index 0fe812bf2..4d5a69e14 100644 --- a/quantum/backlight/backlight_chibios.c +++ b/quantum/backlight/backlight_chibios.c | |||
| @@ -3,6 +3,11 @@ | |||
| 3 | #include <hal.h> | 3 | #include <hal.h> |
| 4 | #include "debug.h" | 4 | #include "debug.h" |
| 5 | 5 | ||
| 6 | // Maximum duty cycle limit | ||
| 7 | #ifndef BACKLIGHT_LIMIT_VAL | ||
| 8 | # define BACKLIGHT_LIMIT_VAL 255 | ||
| 9 | #endif | ||
| 10 | |||
| 6 | // GPIOV2 && GPIOV3 | 11 | // GPIOV2 && GPIOV3 |
| 7 | #ifndef BACKLIGHT_PAL_MODE | 12 | #ifndef BACKLIGHT_PAL_MODE |
| 8 | # define BACKLIGHT_PAL_MODE 2 | 13 | # define BACKLIGHT_PAL_MODE 2 |
| @@ -58,6 +63,11 @@ static uint16_t cie_lightness(uint16_t v) { | |||
| 58 | } | 63 | } |
| 59 | } | 64 | } |
| 60 | 65 | ||
| 66 | static uint32_t rescale_limit_val(uint32_t val) { | ||
| 67 | // rescale the supplied backlight value to be in terms of the value limit | ||
| 68 | return (val * (BACKLIGHT_LIMIT_VAL + 1)) / 256; | ||
| 69 | } | ||
| 70 | |||
| 61 | void backlight_init_ports(void) { | 71 | void backlight_init_ports(void) { |
| 62 | #ifdef USE_GPIOV1 | 72 | #ifdef USE_GPIOV1 |
| 63 | palSetPadMode(PAL_PORT(BACKLIGHT_PIN), PAL_PAD(BACKLIGHT_PIN), PAL_MODE_STM32_ALTERNATE_PUSHPULL); | 73 | palSetPadMode(PAL_PORT(BACKLIGHT_PIN), PAL_PAD(BACKLIGHT_PIN), PAL_MODE_STM32_ALTERNATE_PUSHPULL); |
| @@ -85,7 +95,7 @@ void backlight_set(uint8_t level) { | |||
| 85 | pwmDisableChannel(&BACKLIGHT_PWM_DRIVER, BACKLIGHT_PWM_CHANNEL - 1); | 95 | pwmDisableChannel(&BACKLIGHT_PWM_DRIVER, BACKLIGHT_PWM_CHANNEL - 1); |
| 86 | } else { | 96 | } else { |
| 87 | // Turn backlight on | 97 | // Turn backlight on |
| 88 | uint32_t duty = (uint32_t)(cie_lightness(0xFFFF * (uint32_t)level / BACKLIGHT_LEVELS)); | 98 | uint32_t duty = (uint32_t)(cie_lightness(rescale_limit_val(0xFFFF * (uint32_t)level / BACKLIGHT_LEVELS))); |
| 89 | pwmEnableChannel(&BACKLIGHT_PWM_DRIVER, BACKLIGHT_PWM_CHANNEL - 1, PWM_FRACTION_TO_WIDTH(&BACKLIGHT_PWM_DRIVER, 0xFFFF, duty)); | 99 | pwmEnableChannel(&BACKLIGHT_PWM_DRIVER, BACKLIGHT_PWM_CHANNEL - 1, PWM_FRACTION_TO_WIDTH(&BACKLIGHT_PWM_DRIVER, 0xFFFF, duty)); |
| 90 | } | 100 | } |
| 91 | } | 101 | } |
| @@ -129,7 +139,7 @@ void breathing_callback(PWMDriver *pwmp) { | |||
| 129 | static uint16_t breathing_counter = 0; | 139 | static uint16_t breathing_counter = 0; |
| 130 | breathing_counter = (breathing_counter + 1) % (breathing_period * 256); | 140 | breathing_counter = (breathing_counter + 1) % (breathing_period * 256); |
| 131 | uint8_t index = breathing_counter / interval % BREATHING_STEPS; | 141 | uint8_t index = breathing_counter / interval % BREATHING_STEPS; |
| 132 | uint32_t duty = cie_lightness(scale_backlight(breathing_table[index] * 256)); | 142 | uint32_t duty = cie_lightness(rescale_limit_val(scale_backlight(breathing_table[index] * 256))); |
| 133 | 143 | ||
| 134 | chSysLockFromISR(); | 144 | chSysLockFromISR(); |
| 135 | pwmEnableChannelI(pwmp, BACKLIGHT_PWM_CHANNEL - 1, PWM_FRACTION_TO_WIDTH(&BACKLIGHT_PWM_DRIVER, 0xFFFF, duty)); | 145 | pwmEnableChannelI(pwmp, BACKLIGHT_PWM_CHANNEL - 1, PWM_FRACTION_TO_WIDTH(&BACKLIGHT_PWM_DRIVER, 0xFFFF, duty)); |
diff --git a/quantum/config_common.h b/quantum/config_common.h index c1e6698e5..2d9c70b08 100644 --- a/quantum/config_common.h +++ b/quantum/config_common.h | |||
| @@ -39,7 +39,7 @@ | |||
| 39 | # define PIND_ADDRESS 0x9 | 39 | # define PIND_ADDRESS 0x9 |
| 40 | # define PINE_ADDRESS 0xC | 40 | # define PINE_ADDRESS 0xC |
| 41 | # define PINF_ADDRESS 0xF | 41 | # define PINF_ADDRESS 0xF |
| 42 | # elif defined(__AVR_ATmega32U2__) || defined(__AVR_ATmega16U2__) | 42 | # elif defined(__AVR_ATmega32U2__) || defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__) |
| 43 | # define ADDRESS_BASE 0x00 | 43 | # define ADDRESS_BASE 0x00 |
| 44 | # define PINB_ADDRESS 0x3 | 44 | # define PINB_ADDRESS 0x3 |
| 45 | # define PINC_ADDRESS 0x6 | 45 | # define PINC_ADDRESS 0x6 |
| @@ -58,11 +58,6 @@ | |||
| 58 | # define PINC_ADDRESS 0x3 | 58 | # define PINC_ADDRESS 0x3 |
| 59 | # define PINB_ADDRESS 0x6 | 59 | # define PINB_ADDRESS 0x6 |
| 60 | # define PINA_ADDRESS 0x9 | 60 | # define PINA_ADDRESS 0x9 |
| 61 | # elif defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__) | ||
| 62 | # define ADDRESS_BASE 0x00 | ||
| 63 | # define PINB_ADDRESS 0x3 | ||
| 64 | # define PINC_ADDRESS 0x6 | ||
| 65 | # define PIND_ADDRESS 0x9 | ||
| 66 | # elif defined(__AVR_ATtiny85__) | 61 | # elif defined(__AVR_ATtiny85__) |
| 67 | # define ADDRESS_BASE 0x10 | 62 | # define ADDRESS_BASE 0x10 |
| 68 | # define PINB_ADDRESS 0x6 | 63 | # define PINB_ADDRESS 0x6 |
| @@ -284,6 +279,91 @@ | |||
| 284 | # define F13 PAL_LINE(GPIOF, 13) | 279 | # define F13 PAL_LINE(GPIOF, 13) |
| 285 | # define F14 PAL_LINE(GPIOF, 14) | 280 | # define F14 PAL_LINE(GPIOF, 14) |
| 286 | # define F15 PAL_LINE(GPIOF, 15) | 281 | # define F15 PAL_LINE(GPIOF, 15) |
| 282 | # define G0 PAL_LINE(GPIOG, 0) | ||
| 283 | # define G1 PAL_LINE(GPIOG, 1) | ||
| 284 | # define G2 PAL_LINE(GPIOG, 2) | ||
| 285 | # define G3 PAL_LINE(GPIOG, 3) | ||
| 286 | # define G4 PAL_LINE(GPIOG, 4) | ||
| 287 | # define G5 PAL_LINE(GPIOG, 5) | ||
| 288 | # define G6 PAL_LINE(GPIOG, 6) | ||
| 289 | # define G7 PAL_LINE(GPIOG, 7) | ||
| 290 | # define G8 PAL_LINE(GPIOG, 8) | ||
| 291 | # define G9 PAL_LINE(GPIOG, 9) | ||
| 292 | # define G10 PAL_LINE(GPIOG, 10) | ||
| 293 | # define G11 PAL_LINE(GPIOG, 11) | ||
| 294 | # define G12 PAL_LINE(GPIOG, 12) | ||
| 295 | # define G13 PAL_LINE(GPIOG, 13) | ||
| 296 | # define G14 PAL_LINE(GPIOG, 14) | ||
| 297 | # define G15 PAL_LINE(GPIOG, 15) | ||
| 298 | # define H0 PAL_LINE(GPIOH, 0) | ||
| 299 | # define H1 PAL_LINE(GPIOH, 1) | ||
| 300 | # define H2 PAL_LINE(GPIOH, 2) | ||
| 301 | # define H3 PAL_LINE(GPIOH, 3) | ||
| 302 | # define H4 PAL_LINE(GPIOH, 4) | ||
| 303 | # define H5 PAL_LINE(GPIOH, 5) | ||
| 304 | # define H6 PAL_LINE(GPIOH, 6) | ||
| 305 | # define H7 PAL_LINE(GPIOH, 7) | ||
| 306 | # define H8 PAL_LINE(GPIOH, 8) | ||
| 307 | # define H9 PAL_LINE(GPIOH, 9) | ||
| 308 | # define H10 PAL_LINE(GPIOH, 10) | ||
| 309 | # define H11 PAL_LINE(GPIOH, 11) | ||
| 310 | # define H12 PAL_LINE(GPIOH, 12) | ||
| 311 | # define H13 PAL_LINE(GPIOH, 13) | ||
| 312 | # define H14 PAL_LINE(GPIOH, 14) | ||
| 313 | # define H15 PAL_LINE(GPIOH, 15) | ||
| 314 | # define I0 PAL_LINE(GPIOI, 0) | ||
| 315 | # define I1 PAL_LINE(GPIOI, 1) | ||
| 316 | # define I2 PAL_LINE(GPIOI, 2) | ||
| 317 | # define I3 PAL_LINE(GPIOI, 3) | ||
| 318 | # define I4 PAL_LINE(GPIOI, 4) | ||
| 319 | # define I5 PAL_LINE(GPIOI, 5) | ||
| 320 | # define I6 PAL_LINE(GPIOI, 6) | ||
| 321 | # define I7 PAL_LINE(GPIOI, 7) | ||
| 322 | # define I8 PAL_LINE(GPIOI, 8) | ||
| 323 | # define I9 PAL_LINE(GPIOI, 9) | ||
| 324 | # define I10 PAL_LINE(GPIOI, 10) | ||
| 325 | # define I11 PAL_LINE(GPIOI, 11) | ||
| 326 | # define I12 PAL_LINE(GPIOI, 12) | ||
| 327 | # define I13 PAL_LINE(GPIOI, 13) | ||
| 328 | # define I14 PAL_LINE(GPIOI, 14) | ||
| 329 | # define I15 PAL_LINE(GPIOI, 15) | ||
| 330 | # define J0 PAL_LINE(GPIOJ, 0) | ||
| 331 | # define J1 PAL_LINE(GPIOJ, 1) | ||
| 332 | # define J2 PAL_LINE(GPIOJ, 2) | ||
| 333 | # define J3 PAL_LINE(GPIOJ, 3) | ||
| 334 | # define J4 PAL_LINE(GPIOJ, 4) | ||
| 335 | # define J5 PAL_LINE(GPIOJ, 5) | ||
| 336 | # define J6 PAL_LINE(GPIOJ, 6) | ||
| 337 | # define J7 PAL_LINE(GPIOJ, 7) | ||
| 338 | # define J8 PAL_LINE(GPIOJ, 8) | ||
| 339 | # define J9 PAL_LINE(GPIOJ, 9) | ||
| 340 | # define J10 PAL_LINE(GPIOJ, 10) | ||
| 341 | # define J11 PAL_LINE(GPIOJ, 11) | ||
| 342 | # define J12 PAL_LINE(GPIOJ, 12) | ||
| 343 | # define J13 PAL_LINE(GPIOJ, 13) | ||
| 344 | # define J14 PAL_LINE(GPIOJ, 14) | ||
| 345 | # define J15 PAL_LINE(GPIOJ, 15) | ||
| 346 | // Keyboards can `#define KEYBOARD_REQUIRES_GPIOK` if they need to access GPIO-K pins. These conflict with a whole | ||
| 347 | // bunch of layout definitions, so it's intentionally left out unless absolutely required -- in that case, the | ||
| 348 | // keyboard designer should use a different symbol when defining their layout macros. | ||
| 349 | # ifdef KEYBOARD_REQUIRES_GPIOK | ||
| 350 | # define K0 PAL_LINE(GPIOK, 0) | ||
| 351 | # define K1 PAL_LINE(GPIOK, 1) | ||
| 352 | # define K2 PAL_LINE(GPIOK, 2) | ||
| 353 | # define K3 PAL_LINE(GPIOK, 3) | ||
| 354 | # define K4 PAL_LINE(GPIOK, 4) | ||
| 355 | # define K5 PAL_LINE(GPIOK, 5) | ||
| 356 | # define K6 PAL_LINE(GPIOK, 6) | ||
| 357 | # define K7 PAL_LINE(GPIOK, 7) | ||
| 358 | # define K8 PAL_LINE(GPIOK, 8) | ||
| 359 | # define K9 PAL_LINE(GPIOK, 9) | ||
| 360 | # define K10 PAL_LINE(GPIOK, 10) | ||
| 361 | # define K11 PAL_LINE(GPIOK, 11) | ||
| 362 | # define K12 PAL_LINE(GPIOK, 12) | ||
| 363 | # define K13 PAL_LINE(GPIOK, 13) | ||
| 364 | # define K14 PAL_LINE(GPIOK, 14) | ||
| 365 | # define K15 PAL_LINE(GPIOK, 15) | ||
| 366 | # endif | ||
| 287 | # endif | 367 | # endif |
| 288 | #endif | 368 | #endif |
| 289 | 369 | ||
diff --git a/quantum/encoder.c b/quantum/encoder.c index 81ec1bb37..7ca31afed 100644 --- a/quantum/encoder.c +++ b/quantum/encoder.c | |||
| @@ -23,7 +23,7 @@ | |||
| 23 | // for memcpy | 23 | // for memcpy |
| 24 | #include <string.h> | 24 | #include <string.h> |
| 25 | 25 | ||
| 26 | #ifndef ENCODER_RESOLUTION | 26 | #if !defined(ENCODER_RESOLUTIONS) && !defined(ENCODER_RESOLUTION) |
| 27 | # define ENCODER_RESOLUTION 4 | 27 | # define ENCODER_RESOLUTION 4 |
| 28 | #endif | 28 | #endif |
| 29 | 29 | ||
| @@ -34,6 +34,9 @@ | |||
| 34 | #define NUMBER_OF_ENCODERS (sizeof(encoders_pad_a) / sizeof(pin_t)) | 34 | #define NUMBER_OF_ENCODERS (sizeof(encoders_pad_a) / sizeof(pin_t)) |
| 35 | static pin_t encoders_pad_a[] = ENCODERS_PAD_A; | 35 | static pin_t encoders_pad_a[] = ENCODERS_PAD_A; |
| 36 | static pin_t encoders_pad_b[] = ENCODERS_PAD_B; | 36 | static pin_t encoders_pad_b[] = ENCODERS_PAD_B; |
| 37 | #ifdef ENCODER_RESOLUTIONS | ||
| 38 | static uint8_t encoder_resolutions[] = ENCODER_RESOLUTIONS; | ||
| 39 | #endif | ||
| 37 | 40 | ||
| 38 | #ifndef ENCODER_DIRECTION_FLIP | 41 | #ifndef ENCODER_DIRECTION_FLIP |
| 39 | # define ENCODER_CLOCKWISE true | 42 | # define ENCODER_CLOCKWISE true |
| @@ -65,9 +68,15 @@ void encoder_init(void) { | |||
| 65 | if (!isLeftHand) { | 68 | if (!isLeftHand) { |
| 66 | const pin_t encoders_pad_a_right[] = ENCODERS_PAD_A_RIGHT; | 69 | const pin_t encoders_pad_a_right[] = ENCODERS_PAD_A_RIGHT; |
| 67 | const pin_t encoders_pad_b_right[] = ENCODERS_PAD_B_RIGHT; | 70 | const pin_t encoders_pad_b_right[] = ENCODERS_PAD_B_RIGHT; |
| 71 | # if defined(ENCODER_RESOLUTIONS_RIGHT) | ||
| 72 | const uint8_t encoder_resolutions_right[] = ENCODER_RESOLUTIONS_RIGHT; | ||
| 73 | # endif | ||
| 68 | for (uint8_t i = 0; i < NUMBER_OF_ENCODERS; i++) { | 74 | for (uint8_t i = 0; i < NUMBER_OF_ENCODERS; i++) { |
| 69 | encoders_pad_a[i] = encoders_pad_a_right[i]; | 75 | encoders_pad_a[i] = encoders_pad_a_right[i]; |
| 70 | encoders_pad_b[i] = encoders_pad_b_right[i]; | 76 | encoders_pad_b[i] = encoders_pad_b_right[i]; |
| 77 | # if defined(ENCODER_RESOLUTIONS_RIGHT) | ||
| 78 | encoder_resolutions[i] = encoder_resolutions_right[i]; | ||
| 79 | # endif | ||
| 71 | } | 80 | } |
| 72 | } | 81 | } |
| 73 | #endif | 82 | #endif |
| @@ -87,19 +96,26 @@ void encoder_init(void) { | |||
| 87 | 96 | ||
| 88 | static void encoder_update(int8_t index, uint8_t state) { | 97 | static void encoder_update(int8_t index, uint8_t state) { |
| 89 | uint8_t i = index; | 98 | uint8_t i = index; |
| 99 | |||
| 100 | #ifdef ENCODER_RESOLUTIONS | ||
| 101 | int8_t resolution = encoder_resolutions[i]; | ||
| 102 | #else | ||
| 103 | int8_t resolution = ENCODER_RESOLUTION; | ||
| 104 | #endif | ||
| 105 | |||
| 90 | #ifdef SPLIT_KEYBOARD | 106 | #ifdef SPLIT_KEYBOARD |
| 91 | index += thisHand; | 107 | index += thisHand; |
| 92 | #endif | 108 | #endif |
| 93 | encoder_pulses[i] += encoder_LUT[state & 0xF]; | 109 | encoder_pulses[i] += encoder_LUT[state & 0xF]; |
| 94 | if (encoder_pulses[i] >= ENCODER_RESOLUTION) { | 110 | if (encoder_pulses[i] >= resolution) { |
| 95 | encoder_value[index]++; | 111 | encoder_value[index]++; |
| 96 | encoder_update_kb(index, ENCODER_COUNTER_CLOCKWISE); | 112 | encoder_update_kb(index, ENCODER_COUNTER_CLOCKWISE); |
| 97 | } | 113 | } |
| 98 | if (encoder_pulses[i] <= -ENCODER_RESOLUTION) { // direction is arbitrary here, but this clockwise | 114 | if (encoder_pulses[i] <= -resolution) { // direction is arbitrary here, but this clockwise |
| 99 | encoder_value[index]--; | 115 | encoder_value[index]--; |
| 100 | encoder_update_kb(index, ENCODER_CLOCKWISE); | 116 | encoder_update_kb(index, ENCODER_CLOCKWISE); |
| 101 | } | 117 | } |
| 102 | encoder_pulses[i] %= ENCODER_RESOLUTION; | 118 | encoder_pulses[i] %= resolution; |
| 103 | } | 119 | } |
| 104 | 120 | ||
| 105 | void encoder_read(void) { | 121 | void encoder_read(void) { |
diff --git a/quantum/joystick.h b/quantum/joystick.h index a95472b9f..87dbc24af 100644 --- a/quantum/joystick.h +++ b/quantum/joystick.h | |||
| @@ -1,5 +1,9 @@ | |||
| 1 | #pragma once | 1 | #pragma once |
| 2 | 2 | ||
| 3 | #include "quantum.h" | ||
| 4 | |||
| 5 | #include <stdint.h> | ||
| 6 | |||
| 3 | #ifndef JOYSTICK_BUTTON_COUNT | 7 | #ifndef JOYSTICK_BUTTON_COUNT |
| 4 | # define JOYSTICK_BUTTON_COUNT 8 | 8 | # define JOYSTICK_BUTTON_COUNT 8 |
| 5 | #endif | 9 | #endif |
| @@ -8,9 +12,13 @@ | |||
| 8 | # define JOYSTICK_AXES_COUNT 4 | 12 | # define JOYSTICK_AXES_COUNT 4 |
| 9 | #endif | 13 | #endif |
| 10 | 14 | ||
| 11 | #include "quantum.h" | 15 | #ifndef JOYSTICK_AXES_RESOLUTION |
| 16 | # define JOYSTICK_AXES_RESOLUTION 8 | ||
| 17 | #elif JOYSTICK_AXES_RESOLUTION < 8 || JOYSTICK_AXES_RESOLUTION > 16 | ||
| 18 | # error JOYSTICK_AXES_RESOLUTION must be between 8 and 16 | ||
| 19 | #endif | ||
| 12 | 20 | ||
| 13 | #include <stdint.h> | 21 | #define JOYSTICK_RESOLUTION ((1L << (JOYSTICK_AXES_RESOLUTION - 1)) - 1) |
| 14 | 22 | ||
| 15 | // configure on input_pin of the joystick_axes array entry to JS_VIRTUAL_AXIS | 23 | // configure on input_pin of the joystick_axes array entry to JS_VIRTUAL_AXIS |
| 16 | // to prevent it from being read from the ADC. This allows outputing forged axis value. | 24 | // to prevent it from being read from the ADC. This allows outputing forged axis value. |
diff --git a/quantum/led_matrix.c b/quantum/led_matrix.c index 5c24c797a..eb523990a 100644 --- a/quantum/led_matrix.c +++ b/quantum/led_matrix.c | |||
| @@ -20,7 +20,7 @@ | |||
| 20 | #include <stdint.h> | 20 | #include <stdint.h> |
| 21 | #include <stdbool.h> | 21 | #include <stdbool.h> |
| 22 | #include "quantum.h" | 22 | #include "quantum.h" |
| 23 | #include "ledmatrix.h" | 23 | #include "led_matrix.h" |
| 24 | #include "progmem.h" | 24 | #include "progmem.h" |
| 25 | #include "config.h" | 25 | #include "config.h" |
| 26 | #include "eeprom.h" | 26 | #include "eeprom.h" |
diff --git a/quantum/ledmatrix.h b/quantum/led_matrix.h index 5867ba987..5867ba987 100644 --- a/quantum/ledmatrix.h +++ b/quantum/led_matrix.h | |||
diff --git a/quantum/led_matrix_drivers.c b/quantum/led_matrix_drivers.c index 6877bf4c6..9decaa33c 100644 --- a/quantum/led_matrix_drivers.c +++ b/quantum/led_matrix_drivers.c | |||
| @@ -18,7 +18,7 @@ | |||
| 18 | #include <stdint.h> | 18 | #include <stdint.h> |
| 19 | #include <stdbool.h> | 19 | #include <stdbool.h> |
| 20 | #include "quantum.h" | 20 | #include "quantum.h" |
| 21 | #include "ledmatrix.h" | 21 | #include "led_matrix.h" |
| 22 | 22 | ||
| 23 | /* Each driver needs to define a struct: | 23 | /* Each driver needs to define a struct: |
| 24 | * | 24 | * |
diff --git a/quantum/matrix.c b/quantum/matrix.c index c68c56cac..cab0d2ddc 100644 --- a/quantum/matrix.c +++ b/quantum/matrix.c | |||
| @@ -32,6 +32,19 @@ static const pin_t col_pins[MATRIX_COLS] = MATRIX_COL_PINS; | |||
| 32 | extern matrix_row_t raw_matrix[MATRIX_ROWS]; // raw values | 32 | extern matrix_row_t raw_matrix[MATRIX_ROWS]; // raw values |
| 33 | extern matrix_row_t matrix[MATRIX_ROWS]; // debounced values | 33 | extern matrix_row_t matrix[MATRIX_ROWS]; // debounced values |
| 34 | 34 | ||
| 35 | static inline void setPinOutput_writeLow(pin_t pin) { | ||
| 36 | ATOMIC_BLOCK_FORCEON { | ||
| 37 | setPinOutput(pin); | ||
| 38 | writePinLow(pin); | ||
| 39 | } | ||
| 40 | } | ||
| 41 | |||
| 42 | static inline void setPinInputHigh_atomic(pin_t pin) { | ||
| 43 | ATOMIC_BLOCK_FORCEON { | ||
| 44 | setPinInputHigh(pin); | ||
| 45 | } | ||
| 46 | } | ||
| 47 | |||
| 35 | // matrix code | 48 | // matrix code |
| 36 | 49 | ||
| 37 | #ifdef DIRECT_PINS | 50 | #ifdef DIRECT_PINS |
| @@ -70,22 +83,23 @@ static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row) | |||
| 70 | # if (DIODE_DIRECTION == COL2ROW) | 83 | # if (DIODE_DIRECTION == COL2ROW) |
| 71 | 84 | ||
| 72 | static void select_row(uint8_t row) { | 85 | static void select_row(uint8_t row) { |
| 73 | setPinOutput(row_pins[row]); | 86 | setPinOutput_writeLow(row_pins[row]); |
| 74 | writePinLow(row_pins[row]); | ||
| 75 | } | 87 | } |
| 76 | 88 | ||
| 77 | static void unselect_row(uint8_t row) { setPinInputHigh(row_pins[row]); } | 89 | static void unselect_row(uint8_t row) { |
| 90 | setPinInputHigh_atomic(row_pins[row]); | ||
| 91 | } | ||
| 78 | 92 | ||
| 79 | static void unselect_rows(void) { | 93 | static void unselect_rows(void) { |
| 80 | for (uint8_t x = 0; x < MATRIX_ROWS; x++) { | 94 | for (uint8_t x = 0; x < MATRIX_ROWS; x++) { |
| 81 | setPinInputHigh(row_pins[x]); | 95 | setPinInputHigh_atomic(row_pins[x]); |
| 82 | } | 96 | } |
| 83 | } | 97 | } |
| 84 | 98 | ||
| 85 | static void init_pins(void) { | 99 | static void init_pins(void) { |
| 86 | unselect_rows(); | 100 | unselect_rows(); |
| 87 | for (uint8_t x = 0; x < MATRIX_COLS; x++) { | 101 | for (uint8_t x = 0; x < MATRIX_COLS; x++) { |
| 88 | setPinInputHigh(col_pins[x]); | 102 | setPinInputHigh_atomic(col_pins[x]); |
| 89 | } | 103 | } |
| 90 | } | 104 | } |
| 91 | 105 | ||
| @@ -120,22 +134,23 @@ static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row) | |||
| 120 | # elif (DIODE_DIRECTION == ROW2COL) | 134 | # elif (DIODE_DIRECTION == ROW2COL) |
| 121 | 135 | ||
| 122 | static void select_col(uint8_t col) { | 136 | static void select_col(uint8_t col) { |
| 123 | setPinOutput(col_pins[col]); | 137 | setPinOutput_writeLow(col_pins[col]); |
| 124 | writePinLow(col_pins[col]); | ||
| 125 | } | 138 | } |
| 126 | 139 | ||
| 127 | static void unselect_col(uint8_t col) { setPinInputHigh(col_pins[col]); } | 140 | static void unselect_col(uint8_t col) { |
| 141 | setPinInputHigh_atomic(col_pins[col]); | ||
| 142 | } | ||
| 128 | 143 | ||
| 129 | static void unselect_cols(void) { | 144 | static void unselect_cols(void) { |
| 130 | for (uint8_t x = 0; x < MATRIX_COLS; x++) { | 145 | for (uint8_t x = 0; x < MATRIX_COLS; x++) { |
| 131 | setPinInputHigh(col_pins[x]); | 146 | setPinInputHigh_atomic(col_pins[x]); |
| 132 | } | 147 | } |
| 133 | } | 148 | } |
| 134 | 149 | ||
| 135 | static void init_pins(void) { | 150 | static void init_pins(void) { |
| 136 | unselect_cols(); | 151 | unselect_cols(); |
| 137 | for (uint8_t x = 0; x < MATRIX_ROWS; x++) { | 152 | for (uint8_t x = 0; x < MATRIX_ROWS; x++) { |
| 138 | setPinInputHigh(row_pins[x]); | 153 | setPinInputHigh_atomic(row_pins[x]); |
| 139 | } | 154 | } |
| 140 | } | 155 | } |
| 141 | 156 | ||
diff --git a/quantum/mcu_selection.mk b/quantum/mcu_selection.mk index 295dfd318..9518a6463 100644 --- a/quantum/mcu_selection.mk +++ b/quantum/mcu_selection.mk | |||
| @@ -318,6 +318,9 @@ ifneq (,$(filter $(MCU),atmega16u2 atmega32u2 atmega16u4 atmega32u4 at90usb646 a | |||
| 318 | ifeq (,$(filter $(NO_INTERRUPT_CONTROL_ENDPOINT),yes)) | 318 | ifeq (,$(filter $(NO_INTERRUPT_CONTROL_ENDPOINT),yes)) |
| 319 | OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT | 319 | OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT |
| 320 | endif | 320 | endif |
| 321 | ifneq (,$(filter $(MCU),atmega16u2 atmega32u2)) | ||
| 322 | NO_I2C = yes | ||
| 323 | endif | ||
| 321 | endif | 324 | endif |
| 322 | 325 | ||
| 323 | ifneq (,$(filter $(MCU),atmega32a)) | 326 | ifneq (,$(filter $(MCU),atmega32a)) |
diff --git a/quantum/process_keycode/process_auto_shift.c b/quantum/process_keycode/process_auto_shift.c index b1267922c..a2d315408 100644 --- a/quantum/process_keycode/process_auto_shift.c +++ b/quantum/process_keycode/process_auto_shift.c | |||
| @@ -16,48 +16,149 @@ | |||
| 16 | 16 | ||
| 17 | #ifdef AUTO_SHIFT_ENABLE | 17 | #ifdef AUTO_SHIFT_ENABLE |
| 18 | 18 | ||
| 19 | # include <stdbool.h> | ||
| 19 | # include <stdio.h> | 20 | # include <stdio.h> |
| 20 | 21 | ||
| 21 | # include "process_auto_shift.h" | 22 | # include "process_auto_shift.h" |
| 22 | 23 | ||
| 23 | static bool autoshift_enabled = true; | ||
| 24 | static uint16_t autoshift_time = 0; | 24 | static uint16_t autoshift_time = 0; |
| 25 | static uint16_t autoshift_timeout = AUTO_SHIFT_TIMEOUT; | 25 | static uint16_t autoshift_timeout = AUTO_SHIFT_TIMEOUT; |
| 26 | static uint16_t autoshift_lastkey = KC_NO; | 26 | static uint16_t autoshift_lastkey = KC_NO; |
| 27 | static struct { | ||
| 28 | // Whether autoshift is enabled. | ||
| 29 | bool enabled : 1; | ||
| 30 | // Whether the last auto-shifted key was released after the timeout. This | ||
| 31 | // is used to replicate the last key for a tap-then-hold. | ||
| 32 | bool lastshifted : 1; | ||
| 33 | // Whether an auto-shiftable key has been pressed but not processed. | ||
| 34 | bool in_progress : 1; | ||
| 35 | // Whether the auto-shifted keypress has been registered. | ||
| 36 | bool holding_shift : 1; | ||
| 37 | } autoshift_flags = {true, false, false, false}; | ||
| 38 | |||
| 39 | /** \brief Record the press of an autoshiftable key | ||
| 40 | * | ||
| 41 | * \return Whether the record should be further processed. | ||
| 42 | */ | ||
| 43 | static bool autoshift_press(uint16_t keycode, uint16_t now, keyrecord_t *record) { | ||
| 44 | if (!autoshift_flags.enabled) { | ||
| 45 | return true; | ||
| 46 | } | ||
| 47 | |||
| 48 | # ifndef AUTO_SHIFT_MODIFIERS | ||
| 49 | if (get_mods() & (~MOD_BIT(KC_LSFT))) { | ||
| 50 | return true; | ||
| 51 | } | ||
| 52 | # endif | ||
| 53 | # ifdef AUTO_SHIFT_REPEAT | ||
| 54 | const uint16_t elapsed = TIMER_DIFF_16(now, autoshift_time); | ||
| 55 | # ifndef AUTO_SHIFT_NO_AUTO_REPEAT | ||
| 56 | if (!autoshift_flags.lastshifted) { | ||
| 57 | # endif | ||
| 58 | if (elapsed < TAPPING_TERM && keycode == autoshift_lastkey) { | ||
| 59 | // Allow a tap-then-hold for keyrepeat. | ||
| 60 | if (!autoshift_flags.lastshifted) { | ||
| 61 | register_code(autoshift_lastkey); | ||
| 62 | } else { | ||
| 63 | // Simulate pressing the shift key. | ||
| 64 | add_weak_mods(MOD_BIT(KC_LSFT)); | ||
| 65 | register_code(autoshift_lastkey); | ||
| 66 | } | ||
| 67 | return false; | ||
| 68 | } | ||
| 69 | # ifndef AUTO_SHIFT_NO_AUTO_REPEAT | ||
| 70 | } | ||
| 71 | # endif | ||
| 72 | # endif | ||
| 27 | 73 | ||
| 28 | void autoshift_flush(void) { | 74 | // Record the keycode so we can simulate it later. |
| 29 | if (autoshift_lastkey != KC_NO) { | 75 | autoshift_lastkey = keycode; |
| 30 | uint16_t elapsed = timer_elapsed(autoshift_time); | 76 | autoshift_time = now; |
| 77 | autoshift_flags.in_progress = true; | ||
| 31 | 78 | ||
| 32 | if (elapsed > autoshift_timeout) { | 79 | # if !defined(NO_ACTION_ONESHOT) && !defined(NO_ACTION_TAPPING) |
| 33 | tap_code16(LSFT(autoshift_lastkey)); | 80 | clear_oneshot_layer_state(ONESHOT_OTHER_KEY_PRESSED); |
| 81 | # endif | ||
| 82 | return false; | ||
| 83 | } | ||
| 84 | |||
| 85 | /** \brief Registers an autoshiftable key under the right conditions | ||
| 86 | * | ||
| 87 | * If the autoshift delay has elapsed, register a shift and the key. | ||
| 88 | * | ||
| 89 | * If the autoshift key is released before the delay has elapsed, register the | ||
| 90 | * key without a shift. | ||
| 91 | */ | ||
| 92 | static void autoshift_end(uint16_t keycode, uint16_t now, bool matrix_trigger) { | ||
| 93 | // Called on key down with KC_NO, auto-shifted key up, and timeout. | ||
| 94 | if (autoshift_flags.in_progress) { | ||
| 95 | // Process the auto-shiftable key. | ||
| 96 | autoshift_flags.in_progress = false; | ||
| 97 | |||
| 98 | // Time since the initial press was recorded. | ||
| 99 | const uint16_t elapsed = TIMER_DIFF_16(now, autoshift_time); | ||
| 100 | if (elapsed < autoshift_timeout) { | ||
| 101 | register_code(autoshift_lastkey); | ||
| 102 | autoshift_flags.lastshifted = false; | ||
| 34 | } else { | 103 | } else { |
| 35 | tap_code(autoshift_lastkey); | 104 | // Simulate pressing the shift key. |
| 105 | add_weak_mods(MOD_BIT(KC_LSFT)); | ||
| 106 | register_code(autoshift_lastkey); | ||
| 107 | autoshift_flags.lastshifted = true; | ||
| 108 | # if defined(AUTO_SHIFT_REPEAT) && !defined(AUTO_SHIFT_NO_AUTO_REPEAT) | ||
| 109 | if (matrix_trigger) { | ||
| 110 | // Prevents release. | ||
| 111 | return; | ||
| 112 | } | ||
| 113 | # endif | ||
| 36 | } | 114 | } |
| 37 | 115 | ||
| 38 | autoshift_time = 0; | 116 | # if TAP_CODE_DELAY > 0 |
| 39 | autoshift_lastkey = KC_NO; | 117 | wait_ms(TAP_CODE_DELAY); |
| 118 | # endif | ||
| 119 | unregister_code(autoshift_lastkey); | ||
| 120 | del_weak_mods(MOD_BIT(KC_LSFT)); | ||
| 121 | } else { | ||
| 122 | // Release after keyrepeat. | ||
| 123 | unregister_code(keycode); | ||
| 124 | if (keycode == autoshift_lastkey) { | ||
| 125 | // This will only fire when the key was the last auto-shiftable | ||
| 126 | // pressed. That prevents aaaaBBBB then releasing a from unshifting | ||
| 127 | // later Bs (if B wasn't auto-shiftable). | ||
| 128 | del_weak_mods(MOD_BIT(KC_LSFT)); | ||
| 129 | } | ||
| 40 | } | 130 | } |
| 131 | send_keyboard_report(); // del_weak_mods doesn't send one. | ||
| 132 | // Roll the autoshift_time forward for detecting tap-and-hold. | ||
| 133 | autoshift_time = now; | ||
| 41 | } | 134 | } |
| 42 | 135 | ||
| 43 | void autoshift_on(uint16_t keycode) { | 136 | /** \brief Simulates auto-shifted key releases when timeout is hit |
| 44 | autoshift_time = timer_read(); | 137 | * |
| 45 | autoshift_lastkey = keycode; | 138 | * Can be called from \c matrix_scan_user so that auto-shifted keys are sent |
| 139 | * immediately after the timeout has expired, rather than waiting for the key | ||
| 140 | * to be released. | ||
| 141 | */ | ||
| 142 | void autoshift_matrix_scan(void) { | ||
| 143 | if (autoshift_flags.in_progress) { | ||
| 144 | const uint16_t now = timer_read(); | ||
| 145 | const uint16_t elapsed = TIMER_DIFF_16(now, autoshift_time); | ||
| 146 | if (elapsed >= autoshift_timeout) { | ||
| 147 | autoshift_end(autoshift_lastkey, now, true); | ||
| 148 | } | ||
| 149 | } | ||
| 46 | } | 150 | } |
| 47 | 151 | ||
| 48 | void autoshift_toggle(void) { | 152 | void autoshift_toggle(void) { |
| 49 | if (autoshift_enabled) { | 153 | autoshift_flags.enabled = !autoshift_flags.enabled; |
| 50 | autoshift_enabled = false; | 154 | del_weak_mods(MOD_BIT(KC_LSFT)); |
| 51 | autoshift_flush(); | ||
| 52 | } else { | ||
| 53 | autoshift_enabled = true; | ||
| 54 | } | ||
| 55 | } | 155 | } |
| 56 | 156 | ||
| 57 | void autoshift_enable(void) { autoshift_enabled = true; } | 157 | void autoshift_enable(void) { autoshift_flags.enabled = true; } |
| 158 | |||
| 58 | void autoshift_disable(void) { | 159 | void autoshift_disable(void) { |
| 59 | autoshift_enabled = false; | 160 | autoshift_flags.enabled = false; |
| 60 | autoshift_flush(); | 161 | del_weak_mods(MOD_BIT(KC_LSFT)); |
| 61 | } | 162 | } |
| 62 | 163 | ||
| 63 | # ifndef AUTO_SHIFT_NO_SETUP | 164 | # ifndef AUTO_SHIFT_NO_SETUP |
| @@ -70,19 +171,30 @@ void autoshift_timer_report(void) { | |||
| 70 | } | 171 | } |
| 71 | # endif | 172 | # endif |
| 72 | 173 | ||
| 73 | bool get_autoshift_state(void) { return autoshift_enabled; } | 174 | bool get_autoshift_state(void) { return autoshift_flags.enabled; } |
| 74 | 175 | ||
| 75 | uint16_t get_autoshift_timeout(void) { return autoshift_timeout; } | 176 | uint16_t get_autoshift_timeout(void) { return autoshift_timeout; } |
| 76 | 177 | ||
| 77 | void set_autoshift_timeout(uint16_t timeout) { autoshift_timeout = timeout; } | 178 | void set_autoshift_timeout(uint16_t timeout) { autoshift_timeout = timeout; } |
| 78 | 179 | ||
| 79 | bool process_auto_shift(uint16_t keycode, keyrecord_t *record) { | 180 | bool process_auto_shift(uint16_t keycode, keyrecord_t *record) { |
| 181 | // Note that record->event.time isn't reliable, see: | ||
| 182 | // https://github.com/qmk/qmk_firmware/pull/9826#issuecomment-733559550 | ||
| 183 | const uint16_t now = timer_read(); | ||
| 184 | |||
| 80 | if (record->event.pressed) { | 185 | if (record->event.pressed) { |
| 186 | if (autoshift_flags.in_progress) { | ||
| 187 | // Evaluate previous key if there is one. Doing this elsewhere is | ||
| 188 | // more complicated and easier to break. | ||
| 189 | autoshift_end(KC_NO, now, false); | ||
| 190 | } | ||
| 191 | // For pressing another key while keyrepeating shifted autoshift. | ||
| 192 | del_weak_mods(MOD_BIT(KC_LSFT)); | ||
| 193 | |||
| 81 | switch (keycode) { | 194 | switch (keycode) { |
| 82 | case KC_ASTG: | 195 | case KC_ASTG: |
| 83 | autoshift_toggle(); | 196 | autoshift_toggle(); |
| 84 | return true; | 197 | return true; |
| 85 | |||
| 86 | case KC_ASON: | 198 | case KC_ASON: |
| 87 | autoshift_enable(); | 199 | autoshift_enable(); |
| 88 | return true; | 200 | return true; |
| @@ -102,41 +214,28 @@ bool process_auto_shift(uint16_t keycode, keyrecord_t *record) { | |||
| 102 | autoshift_timer_report(); | 214 | autoshift_timer_report(); |
| 103 | return true; | 215 | return true; |
| 104 | # endif | 216 | # endif |
| 217 | } | ||
| 218 | } | ||
| 219 | |||
| 220 | switch (keycode) { | ||
| 105 | # ifndef NO_AUTO_SHIFT_ALPHA | 221 | # ifndef NO_AUTO_SHIFT_ALPHA |
| 106 | case KC_A ... KC_Z: | 222 | case KC_A ... KC_Z: |
| 107 | # endif | 223 | # endif |
| 108 | # ifndef NO_AUTO_SHIFT_NUMERIC | 224 | # ifndef NO_AUTO_SHIFT_NUMERIC |
| 109 | case KC_1 ... KC_0: | 225 | case KC_1 ... KC_0: |
| 110 | # endif | 226 | # endif |
| 111 | # ifndef NO_AUTO_SHIFT_SPECIAL | 227 | # ifndef NO_AUTO_SHIFT_SPECIAL |
| 112 | case KC_TAB: | 228 | case KC_TAB: |
| 113 | case KC_MINUS ... KC_SLASH: | 229 | case KC_MINUS ... KC_SLASH: |
| 114 | case KC_NONUS_BSLASH: | 230 | case KC_NONUS_BSLASH: |
| 115 | # endif | ||
| 116 | autoshift_flush(); | ||
| 117 | if (!autoshift_enabled) return true; | ||
| 118 | |||
| 119 | # ifndef AUTO_SHIFT_MODIFIERS | ||
| 120 | if (get_mods()) { | ||
| 121 | return true; | ||
| 122 | } | ||
| 123 | # endif | ||
| 124 | autoshift_on(keycode); | ||
| 125 | |||
| 126 | // We need some extra handling here for OSL edge cases | ||
| 127 | # if !defined(NO_ACTION_ONESHOT) && !defined(NO_ACTION_TAPPING) | ||
| 128 | clear_oneshot_layer_state(ONESHOT_OTHER_KEY_PRESSED); | ||
| 129 | # endif | 231 | # endif |
| 232 | if (record->event.pressed) { | ||
| 233 | return autoshift_press(keycode, now, record); | ||
| 234 | } else { | ||
| 235 | autoshift_end(keycode, now, false); | ||
| 130 | return false; | 236 | return false; |
| 131 | 237 | } | |
| 132 | default: | ||
| 133 | autoshift_flush(); | ||
| 134 | return true; | ||
| 135 | } | ||
| 136 | } else { | ||
| 137 | autoshift_flush(); | ||
| 138 | } | 238 | } |
| 139 | |||
| 140 | return true; | 239 | return true; |
| 141 | } | 240 | } |
| 142 | 241 | ||
diff --git a/quantum/process_keycode/process_auto_shift.h b/quantum/process_keycode/process_auto_shift.h index e86c4658e..5b2718f11 100644 --- a/quantum/process_keycode/process_auto_shift.h +++ b/quantum/process_keycode/process_auto_shift.h | |||
| @@ -30,3 +30,4 @@ void autoshift_toggle(void); | |||
| 30 | bool get_autoshift_state(void); | 30 | bool get_autoshift_state(void); |
| 31 | uint16_t get_autoshift_timeout(void); | 31 | uint16_t get_autoshift_timeout(void); |
| 32 | void set_autoshift_timeout(uint16_t timeout); | 32 | void set_autoshift_timeout(uint16_t timeout); |
| 33 | void autoshift_matrix_scan(void); | ||
diff --git a/quantum/process_keycode/process_joystick.c b/quantum/process_keycode/process_joystick.c index 5778a7434..3ffaf42bf 100644 --- a/quantum/process_keycode/process_joystick.c +++ b/quantum/process_keycode/process_joystick.c | |||
| @@ -129,17 +129,17 @@ bool process_joystick_analogread_quantum() { | |||
| 129 | // test the converted value against the lower range | 129 | // test the converted value against the lower range |
| 130 | int32_t ref = joystick_axes[axis_index].mid_digit; | 130 | int32_t ref = joystick_axes[axis_index].mid_digit; |
| 131 | int32_t range = joystick_axes[axis_index].min_digit; | 131 | int32_t range = joystick_axes[axis_index].min_digit; |
| 132 | int32_t ranged_val = ((axis_val - ref) * -127) / (range - ref); | 132 | int32_t ranged_val = ((axis_val - ref) * -JOYSTICK_RESOLUTION) / (range - ref); |
| 133 | 133 | ||
| 134 | if (ranged_val > 0) { | 134 | if (ranged_val > 0) { |
| 135 | // the value is in the higher range | 135 | // the value is in the higher range |
| 136 | range = joystick_axes[axis_index].max_digit; | 136 | range = joystick_axes[axis_index].max_digit; |
| 137 | ranged_val = ((axis_val - ref) * 127) / (range - ref); | 137 | ranged_val = ((axis_val - ref) * JOYSTICK_RESOLUTION) / (range - ref); |
| 138 | } | 138 | } |
| 139 | 139 | ||
| 140 | // clamp the result in the valid range | 140 | // clamp the result in the valid range |
| 141 | ranged_val = ranged_val < -127 ? -127 : ranged_val; | 141 | ranged_val = ranged_val < -JOYSTICK_RESOLUTION ? -JOYSTICK_RESOLUTION : ranged_val; |
| 142 | ranged_val = ranged_val > 127 ? 127 : ranged_val; | 142 | ranged_val = ranged_val > JOYSTICK_RESOLUTION ? JOYSTICK_RESOLUTION : ranged_val; |
| 143 | 143 | ||
| 144 | if (ranged_val != joystick_status.axes[axis_index]) { | 144 | if (ranged_val != joystick_status.axes[axis_index]) { |
| 145 | joystick_status.axes[axis_index] = ranged_val; | 145 | joystick_status.axes[axis_index] = ranged_val; |
diff --git a/quantum/process_keycode/process_midi.c b/quantum/process_keycode/process_midi.c index e52577014..8e2fb955e 100644 --- a/quantum/process_keycode/process_midi.c +++ b/quantum/process_keycode/process_midi.c | |||
| @@ -41,12 +41,12 @@ static int8_t midi_modulation_step; | |||
| 41 | static uint16_t midi_modulation_timer; | 41 | static uint16_t midi_modulation_timer; |
| 42 | midi_config_t midi_config; | 42 | midi_config_t midi_config; |
| 43 | 43 | ||
| 44 | inline uint8_t compute_velocity(uint8_t setting) { return (setting + 1) * (128 / (MIDI_VELOCITY_MAX - MIDI_VELOCITY_MIN + 1)); } | 44 | inline uint8_t compute_velocity(uint8_t setting) { return setting * (128 / (MIDI_VELOCITY_MAX - MIDI_VELOCITY_MIN)); } |
| 45 | 45 | ||
| 46 | void midi_init(void) { | 46 | void midi_init(void) { |
| 47 | midi_config.octave = MI_OCT_2 - MIDI_OCTAVE_MIN; | 47 | midi_config.octave = MI_OCT_2 - MIDI_OCTAVE_MIN; |
| 48 | midi_config.transpose = 0; | 48 | midi_config.transpose = 0; |
| 49 | midi_config.velocity = (MIDI_VELOCITY_MAX - MIDI_VELOCITY_MIN); | 49 | midi_config.velocity = 127; |
| 50 | midi_config.channel = 0; | 50 | midi_config.channel = 0; |
| 51 | midi_config.modulation_interval = 8; | 51 | midi_config.modulation_interval = 8; |
| 52 | 52 | ||
| @@ -66,7 +66,7 @@ bool process_midi(uint16_t keycode, keyrecord_t *record) { | |||
| 66 | case MIDI_TONE_MIN ... MIDI_TONE_MAX: { | 66 | case MIDI_TONE_MIN ... MIDI_TONE_MAX: { |
| 67 | uint8_t channel = midi_config.channel; | 67 | uint8_t channel = midi_config.channel; |
| 68 | uint8_t tone = keycode - MIDI_TONE_MIN; | 68 | uint8_t tone = keycode - MIDI_TONE_MIN; |
| 69 | uint8_t velocity = compute_velocity(midi_config.velocity); | 69 | uint8_t velocity = midi_config.velocity; |
| 70 | if (record->event.pressed) { | 70 | if (record->event.pressed) { |
| 71 | if (tone_status[tone] == MIDI_INVALID_NOTE) { | 71 | if (tone_status[tone] == MIDI_INVALID_NOTE) { |
| 72 | uint8_t note = midi_compute_note(keycode); | 72 | uint8_t note = midi_compute_note(keycode); |
| @@ -124,19 +124,30 @@ bool process_midi(uint16_t keycode, keyrecord_t *record) { | |||
| 124 | return false; | 124 | return false; |
| 125 | case MIDI_VELOCITY_MIN ... MIDI_VELOCITY_MAX: | 125 | case MIDI_VELOCITY_MIN ... MIDI_VELOCITY_MAX: |
| 126 | if (record->event.pressed) { | 126 | if (record->event.pressed) { |
| 127 | midi_config.velocity = keycode - MIDI_VELOCITY_MIN; | 127 | midi_config.velocity = compute_velocity(keycode - MIDI_VELOCITY_MIN); |
| 128 | dprintf("midi velocity %d\n", midi_config.velocity); | 128 | dprintf("midi velocity %d\n", midi_config.velocity); |
| 129 | } | 129 | } |
| 130 | return false; | 130 | return false; |
| 131 | case MI_VELD: | 131 | case MI_VELD: |
| 132 | if (record->event.pressed && midi_config.velocity > 0) { | 132 | if (record->event.pressed && midi_config.velocity > 0) { |
| 133 | midi_config.velocity--; | 133 | if (midi_config.velocity == 127) { |
| 134 | midi_config.velocity -= 10; | ||
| 135 | } else if (midi_config.velocity > 12) { | ||
| 136 | midi_config.velocity -= 13; | ||
| 137 | } else { | ||
| 138 | midi_config.velocity = 0; | ||
| 139 | } | ||
| 140 | |||
| 134 | dprintf("midi velocity %d\n", midi_config.velocity); | 141 | dprintf("midi velocity %d\n", midi_config.velocity); |
| 135 | } | 142 | } |
| 136 | return false; | 143 | return false; |
| 137 | case MI_VELU: | 144 | case MI_VELU: |
| 138 | if (record->event.pressed) { | 145 | if (record->event.pressed && midi_config.velocity < 127) { |
| 139 | midi_config.velocity++; | 146 | if (midi_config.velocity < 115) { |
| 147 | midi_config.velocity += 13; | ||
| 148 | } else { | ||
| 149 | midi_config.velocity = 127; | ||
| 150 | } | ||
| 140 | dprintf("midi velocity %d\n", midi_config.velocity); | 151 | dprintf("midi velocity %d\n", midi_config.velocity); |
| 141 | } | 152 | } |
| 142 | return false; | 153 | return false; |
diff --git a/quantum/process_keycode/process_midi.h b/quantum/process_keycode/process_midi.h index 0007b3ed2..ef5661dd4 100644 --- a/quantum/process_keycode/process_midi.h +++ b/quantum/process_keycode/process_midi.h | |||
| @@ -35,7 +35,7 @@ typedef union { | |||
| 35 | struct { | 35 | struct { |
| 36 | uint8_t octave : 4; | 36 | uint8_t octave : 4; |
| 37 | int8_t transpose : 4; | 37 | int8_t transpose : 4; |
| 38 | uint8_t velocity : 4; | 38 | uint8_t velocity : 7; |
| 39 | uint8_t channel : 4; | 39 | uint8_t channel : 4; |
| 40 | uint8_t modulation_interval : 4; | 40 | uint8_t modulation_interval : 4; |
| 41 | }; | 41 | }; |
diff --git a/quantum/process_keycode/process_sequencer.c b/quantum/process_keycode/process_sequencer.c new file mode 100644 index 000000000..334b4c009 --- /dev/null +++ b/quantum/process_keycode/process_sequencer.c | |||
| @@ -0,0 +1,62 @@ | |||
| 1 | /* Copyright 2020 Rodolphe Belouin | ||
| 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 "process_sequencer.h" | ||
| 18 | |||
| 19 | bool process_sequencer(uint16_t keycode, keyrecord_t *record) { | ||
| 20 | if (record->event.pressed) { | ||
| 21 | switch (keycode) { | ||
| 22 | case SQ_ON: | ||
| 23 | sequencer_on(); | ||
| 24 | return false; | ||
| 25 | case SQ_OFF: | ||
| 26 | sequencer_off(); | ||
| 27 | return false; | ||
| 28 | case SQ_TOG: | ||
| 29 | sequencer_toggle(); | ||
| 30 | return false; | ||
| 31 | case SQ_TMPD: | ||
| 32 | sequencer_decrease_tempo(); | ||
| 33 | return false; | ||
| 34 | case SQ_TMPU: | ||
| 35 | sequencer_increase_tempo(); | ||
| 36 | return false; | ||
| 37 | case SEQUENCER_RESOLUTION_MIN ... SEQUENCER_RESOLUTION_MAX: | ||
| 38 | sequencer_set_resolution(keycode - SEQUENCER_RESOLUTION_MIN); | ||
| 39 | return false; | ||
| 40 | case SQ_RESD: | ||
| 41 | sequencer_decrease_resolution(); | ||
| 42 | return false; | ||
| 43 | case SQ_RESU: | ||
| 44 | sequencer_increase_resolution(); | ||
| 45 | return false; | ||
| 46 | case SQ_SALL: | ||
| 47 | sequencer_set_all_steps_on(); | ||
| 48 | return false; | ||
| 49 | case SQ_SCLR: | ||
| 50 | sequencer_set_all_steps_off(); | ||
| 51 | return false; | ||
| 52 | case SEQUENCER_STEP_MIN ... SEQUENCER_STEP_MAX: | ||
| 53 | sequencer_toggle_step(keycode - SEQUENCER_STEP_MIN); | ||
| 54 | return false; | ||
| 55 | case SEQUENCER_TRACK_MIN ... SEQUENCER_TRACK_MAX: | ||
| 56 | sequencer_toggle_single_active_track(keycode - SEQUENCER_TRACK_MIN); | ||
| 57 | return false; | ||
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 61 | return true; | ||
| 62 | } | ||
diff --git a/quantum/process_keycode/process_sequencer.h b/quantum/process_keycode/process_sequencer.h new file mode 100644 index 000000000..2b85f2429 --- /dev/null +++ b/quantum/process_keycode/process_sequencer.h | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | /* Copyright 2020 Rodolphe Belouin | ||
| 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 "quantum.h" | ||
| 20 | |||
| 21 | bool process_sequencer(uint16_t keycode, keyrecord_t *record); | ||
diff --git a/quantum/quantum.c b/quantum/quantum.c index 0b2f98762..3ac0ed871 100644 --- a/quantum/quantum.c +++ b/quantum/quantum.c | |||
| @@ -58,6 +58,10 @@ float bell_song[][2] = SONG(TERMINAL_SOUND); | |||
| 58 | # endif | 58 | # endif |
| 59 | #endif | 59 | #endif |
| 60 | 60 | ||
| 61 | #ifdef AUTO_SHIFT_ENABLE | ||
| 62 | # include "process_auto_shift.h" | ||
| 63 | #endif | ||
| 64 | |||
| 61 | static void do_code16(uint16_t code, void (*f)(uint8_t)) { | 65 | static void do_code16(uint16_t code, void (*f)(uint8_t)) { |
| 62 | switch (code) { | 66 | switch (code) { |
| 63 | case QK_MODS ... QK_MODS_MAX: | 67 | case QK_MODS ... QK_MODS_MAX: |
| @@ -228,6 +232,9 @@ bool process_record_quantum(keyrecord_t *record) { | |||
| 228 | process_record_via(keycode, record) && | 232 | process_record_via(keycode, record) && |
| 229 | #endif | 233 | #endif |
| 230 | process_record_kb(keycode, record) && | 234 | process_record_kb(keycode, record) && |
| 235 | #if defined(SEQUENCER_ENABLE) | ||
| 236 | process_sequencer(keycode, record) && | ||
| 237 | #endif | ||
| 231 | #if defined(MIDI_ENABLE) && defined(MIDI_ADVANCED) | 238 | #if defined(MIDI_ENABLE) && defined(MIDI_ADVANCED) |
| 232 | process_midi(keycode, record) && | 239 | process_midi(keycode, record) && |
| 233 | #endif | 240 | #endif |
| @@ -636,6 +643,10 @@ void matrix_scan_quantum() { | |||
| 636 | matrix_scan_music(); | 643 | matrix_scan_music(); |
| 637 | #endif | 644 | #endif |
| 638 | 645 | ||
| 646 | #ifdef SEQUENCER_ENABLE | ||
| 647 | matrix_scan_sequencer(); | ||
| 648 | #endif | ||
| 649 | |||
| 639 | #ifdef TAP_DANCE_ENABLE | 650 | #ifdef TAP_DANCE_ENABLE |
| 640 | matrix_scan_tap_dance(); | 651 | matrix_scan_tap_dance(); |
| 641 | #endif | 652 | #endif |
| @@ -664,6 +675,10 @@ void matrix_scan_quantum() { | |||
| 664 | dip_switch_read(false); | 675 | dip_switch_read(false); |
| 665 | #endif | 676 | #endif |
| 666 | 677 | ||
| 678 | #ifdef AUTO_SHIFT_ENABLE | ||
| 679 | autoshift_matrix_scan(); | ||
| 680 | #endif | ||
| 681 | |||
| 667 | matrix_scan_kb(); | 682 | matrix_scan_kb(); |
| 668 | } | 683 | } |
| 669 | 684 | ||
diff --git a/quantum/quantum.h b/quantum/quantum.h index 0e452a062..cb0af306a 100644 --- a/quantum/quantum.h +++ b/quantum/quantum.h | |||
| @@ -31,7 +31,7 @@ | |||
| 31 | 31 | ||
| 32 | #ifdef BACKLIGHT_ENABLE | 32 | #ifdef BACKLIGHT_ENABLE |
| 33 | # ifdef LED_MATRIX_ENABLE | 33 | # ifdef LED_MATRIX_ENABLE |
| 34 | # include "ledmatrix.h" | 34 | # include "led_matrix.h" |
| 35 | # else | 35 | # else |
| 36 | # include "backlight.h" | 36 | # include "backlight.h" |
| 37 | # endif | 37 | # endif |
| @@ -68,6 +68,11 @@ extern layer_state_t default_layer_state; | |||
| 68 | extern layer_state_t layer_state; | 68 | extern layer_state_t layer_state; |
| 69 | #endif | 69 | #endif |
| 70 | 70 | ||
| 71 | #if defined(SEQUENCER_ENABLE) | ||
| 72 | # include "sequencer.h" | ||
| 73 | # include "process_sequencer.h" | ||
| 74 | #endif | ||
| 75 | |||
| 71 | #if defined(MIDI_ENABLE) && defined(MIDI_ADVANCED) | 76 | #if defined(MIDI_ENABLE) && defined(MIDI_ADVANCED) |
| 72 | # include "process_midi.h" | 77 | # include "process_midi.h" |
| 73 | #endif | 78 | #endif |
| @@ -220,6 +225,61 @@ typedef ioline_t pin_t; | |||
| 220 | # define togglePin(pin) palToggleLine(pin) | 225 | # define togglePin(pin) palToggleLine(pin) |
| 221 | #endif | 226 | #endif |
| 222 | 227 | ||
| 228 | // Atomic macro to help make GPIO and other controls atomic. | ||
| 229 | #ifdef IGNORE_ATOMIC_BLOCK | ||
| 230 | /* do nothing atomic macro */ | ||
| 231 | # define ATOMIC_BLOCK for (uint8_t __ToDo = 1; __ToDo; __ToDo = 0) | ||
| 232 | # define ATOMIC_BLOCK_RESTORESTATE ATOMIC_BLOCK | ||
| 233 | # define ATOMIC_BLOCK_FORCEON ATOMIC_BLOCK | ||
| 234 | |||
| 235 | #elif defined(__AVR__) | ||
| 236 | /* atomic macro for AVR */ | ||
| 237 | # include <util/atomic.h> | ||
| 238 | |||
| 239 | # define ATOMIC_BLOCK_RESTORESTATE ATOMIC_BLOCK(ATOMIC_RESTORESTATE) | ||
| 240 | # define ATOMIC_BLOCK_FORCEON ATOMIC_BLOCK(ATOMIC_FORCEON) | ||
| 241 | |||
| 242 | #elif defined(PROTOCOL_CHIBIOS) || defined(PROTOCOL_ARM_ATSAM) | ||
| 243 | /* atomic macro for ChibiOS / ARM ATSAM */ | ||
| 244 | # if defined(PROTOCOL_ARM_ATSAM) | ||
| 245 | # include "arm_atsam_protocol.h" | ||
| 246 | # endif | ||
| 247 | |||
| 248 | static __inline__ uint8_t __interrupt_disable__(void) { | ||
| 249 | # if defined(PROTOCOL_CHIBIOS) | ||
| 250 | chSysLock(); | ||
| 251 | # endif | ||
| 252 | # if defined(PROTOCOL_ARM_ATSAM) | ||
| 253 | __disable_irq(); | ||
| 254 | # endif | ||
| 255 | return 1; | ||
| 256 | } | ||
| 257 | |||
| 258 | static __inline__ void __interrupt_enable__(const uint8_t *__s) { | ||
| 259 | # if defined(PROTOCOL_CHIBIOS) | ||
| 260 | chSysUnlock(); | ||
| 261 | # endif | ||
| 262 | # if defined(PROTOCOL_ARM_ATSAM) | ||
| 263 | __enable_irq(); | ||
| 264 | # endif | ||
| 265 | __asm__ volatile("" ::: "memory"); | ||
| 266 | (void)__s; | ||
| 267 | } | ||
| 268 | |||
| 269 | # define ATOMIC_BLOCK(type) for (type, __ToDo = __interrupt_disable__(); __ToDo; __ToDo = 0) | ||
| 270 | # define ATOMIC_FORCEON uint8_t sreg_save __attribute__((__cleanup__(__interrupt_enable__))) = 0 | ||
| 271 | |||
| 272 | # define ATOMIC_BLOCK_RESTORESTATE _Static_assert(0, "ATOMIC_BLOCK_RESTORESTATE dose not implement") | ||
| 273 | # define ATOMIC_BLOCK_FORCEON ATOMIC_BLOCK(ATOMIC_FORCEON) | ||
| 274 | |||
| 275 | /* Other platform */ | ||
| 276 | #else | ||
| 277 | |||
| 278 | # define ATOMIC_BLOCK_RESTORESTATE _Static_assert(0, "ATOMIC_BLOCK_RESTORESTATE dose not implement") | ||
| 279 | # define ATOMIC_BLOCK_FORCEON _Static_assert(0, "ATOMIC_BLOCK_FORCEON dose not implement") | ||
| 280 | |||
| 281 | #endif | ||
| 282 | |||
| 223 | #define SEND_STRING(string) send_string_P(PSTR(string)) | 283 | #define SEND_STRING(string) send_string_P(PSTR(string)) |
| 224 | #define SEND_STRING_DELAY(string, interval) send_string_with_delay_P(PSTR(string), interval) | 284 | #define SEND_STRING_DELAY(string, interval) send_string_with_delay_P(PSTR(string), interval) |
| 225 | 285 | ||
diff --git a/quantum/quantum_keycodes.h b/quantum/quantum_keycodes.h index a0a7bc340..a2cc7b38d 100644 --- a/quantum/quantum_keycodes.h +++ b/quantum/quantum_keycodes.h | |||
| @@ -16,6 +16,10 @@ | |||
| 16 | #ifndef QUANTUM_KEYCODES_H | 16 | #ifndef QUANTUM_KEYCODES_H |
| 17 | #define QUANTUM_KEYCODES_H | 17 | #define QUANTUM_KEYCODES_H |
| 18 | 18 | ||
| 19 | #if defined(SEQUENCER_ENABLE) | ||
| 20 | # include "sequencer.h" | ||
| 21 | #endif | ||
| 22 | |||
| 19 | #ifndef MIDI_ENABLE_STRICT | 23 | #ifndef MIDI_ENABLE_STRICT |
| 20 | # define MIDI_ENABLE_STRICT 0 | 24 | # define MIDI_ENABLE_STRICT 0 |
| 21 | #endif | 25 | #endif |
| @@ -343,7 +347,8 @@ enum quantum_keycodes { | |||
| 343 | MI_TRNSU, // transpose up | 347 | MI_TRNSU, // transpose up |
| 344 | 348 | ||
| 345 | MIDI_VELOCITY_MIN, | 349 | MIDI_VELOCITY_MIN, |
| 346 | MI_VEL_1 = MIDI_VELOCITY_MIN, | 350 | MI_VEL_0 = MIDI_VELOCITY_MIN, |
| 351 | MI_VEL_1, | ||
| 347 | MI_VEL_2, | 352 | MI_VEL_2, |
| 348 | MI_VEL_3, | 353 | MI_VEL_3, |
| 349 | MI_VEL_4, | 354 | MI_VEL_4, |
| @@ -549,6 +554,37 @@ enum quantum_keycodes { | |||
| 549 | JS_BUTTON31, | 554 | JS_BUTTON31, |
| 550 | JS_BUTTON_MAX = JS_BUTTON31, | 555 | JS_BUTTON_MAX = JS_BUTTON31, |
| 551 | 556 | ||
| 557 | #if defined(SEQUENCER_ENABLE) | ||
| 558 | SQ_ON, | ||
| 559 | SQ_OFF, | ||
| 560 | SQ_TOG, | ||
| 561 | |||
| 562 | SQ_TMPD, // Decrease tempo | ||
| 563 | SQ_TMPU, // Increase tempo | ||
| 564 | |||
| 565 | SEQUENCER_RESOLUTION_MIN, | ||
| 566 | SEQUENCER_RESOLUTION_MAX = SEQUENCER_RESOLUTION_MIN + SEQUENCER_RESOLUTIONS, | ||
| 567 | SQ_RESD, // Decrease resolution | ||
| 568 | SQ_RESU, // Increase resolution | ||
| 569 | |||
| 570 | SQ_SALL, // All steps on | ||
| 571 | SQ_SCLR, // All steps off | ||
| 572 | SEQUENCER_STEP_MIN, | ||
| 573 | SEQUENCER_STEP_MAX = SEQUENCER_STEP_MIN + SEQUENCER_STEPS, | ||
| 574 | |||
| 575 | SEQUENCER_TRACK_MIN, | ||
| 576 | SEQUENCER_TRACK_MAX = SEQUENCER_TRACK_MIN + SEQUENCER_TRACKS, | ||
| 577 | |||
| 578 | /** | ||
| 579 | * Helpers to assign a keycode to a step, a resolution, or a track. | ||
| 580 | * Falls back to NOOP if n is out of range. | ||
| 581 | */ | ||
| 582 | # define SQ_S(n) (n < SEQUENCER_STEPS ? SEQUENCER_STEP_MIN + n : XXXXXXX) | ||
| 583 | # define SQ_R(n) (n < SEQUENCER_RESOLUTIONS ? SEQUENCER_RESOLUTION_MIN + n : XXXXXXX) | ||
| 584 | # define SQ_T(n) (n < SEQUENCER_TRACKS ? SEQUENCER_TRACK_MIN + n : XXXXXXX) | ||
| 585 | |||
| 586 | #endif | ||
| 587 | |||
| 552 | // always leave at the end | 588 | // always leave at the end |
| 553 | SAFE_RANGE | 589 | SAFE_RANGE |
| 554 | }; | 590 | }; |
diff --git a/quantum/rgb_matrix.c b/quantum/rgb_matrix.c index 802c5afce..f239bd582 100644 --- a/quantum/rgb_matrix.c +++ b/quantum/rgb_matrix.c | |||
| @@ -31,6 +31,8 @@ const point_t k_rgb_matrix_center = {112, 32}; | |||
| 31 | const point_t k_rgb_matrix_center = RGB_MATRIX_CENTER; | 31 | const point_t k_rgb_matrix_center = RGB_MATRIX_CENTER; |
| 32 | #endif | 32 | #endif |
| 33 | 33 | ||
| 34 | __attribute__((weak)) RGB rgb_matrix_hsv_to_rgb(HSV hsv) { return hsv_to_rgb(hsv); } | ||
| 35 | |||
| 34 | // Generic effect runners | 36 | // Generic effect runners |
| 35 | #include "rgb_matrix_runners/effect_runner_dx_dy_dist.h" | 37 | #include "rgb_matrix_runners/effect_runner_dx_dy_dist.h" |
| 36 | #include "rgb_matrix_runners/effect_runner_dx_dy.h" | 38 | #include "rgb_matrix_runners/effect_runner_dx_dy.h" |
| @@ -401,6 +403,10 @@ void rgb_matrix_task(void) { | |||
| 401 | break; | 403 | break; |
| 402 | case RENDERING: | 404 | case RENDERING: |
| 403 | rgb_task_render(effect); | 405 | rgb_task_render(effect); |
| 406 | if (!suspend_backlight) { | ||
| 407 | rgb_matrix_indicators(); | ||
| 408 | rgb_matrix_indicators_advanced(&rgb_effect_params); | ||
| 409 | } | ||
| 404 | break; | 410 | break; |
| 405 | case FLUSHING: | 411 | case FLUSHING: |
| 406 | rgb_task_flush(effect); | 412 | rgb_task_flush(effect); |
| @@ -409,10 +415,6 @@ void rgb_matrix_task(void) { | |||
| 409 | rgb_task_sync(); | 415 | rgb_task_sync(); |
| 410 | break; | 416 | break; |
| 411 | } | 417 | } |
| 412 | |||
| 413 | if (!suspend_backlight) { | ||
| 414 | rgb_matrix_indicators(); | ||
| 415 | } | ||
| 416 | } | 418 | } |
| 417 | 419 | ||
| 418 | void rgb_matrix_indicators(void) { | 420 | void rgb_matrix_indicators(void) { |
| @@ -424,6 +426,28 @@ __attribute__((weak)) void rgb_matrix_indicators_kb(void) {} | |||
| 424 | 426 | ||
| 425 | __attribute__((weak)) void rgb_matrix_indicators_user(void) {} | 427 | __attribute__((weak)) void rgb_matrix_indicators_user(void) {} |
| 426 | 428 | ||
| 429 | void rgb_matrix_indicators_advanced(effect_params_t *params) { | ||
| 430 | /* special handling is needed for "params->iter", since it's already been incremented. | ||
| 431 | * Could move the invocations to rgb_task_render, but then it's missing a few checks | ||
| 432 | * and not sure which would be better. Otherwise, this should be called from | ||
| 433 | * rgb_task_render, right before the iter++ line. | ||
| 434 | */ | ||
| 435 | #if defined(RGB_MATRIX_LED_PROCESS_LIMIT) && RGB_MATRIX_LED_PROCESS_LIMIT > 0 && RGB_MATRIX_LED_PROCESS_LIMIT < DRIVER_LED_TOTAL | ||
| 436 | uint8_t min = RGB_MATRIX_LED_PROCESS_LIMIT * (params->iter - 1); | ||
| 437 | uint8_t max = min + RGB_MATRIX_LED_PROCESS_LIMIT; | ||
| 438 | if (max > DRIVER_LED_TOTAL) max = DRIVER_LED_TOTAL; | ||
| 439 | #else | ||
| 440 | uint8_t min = 0; | ||
| 441 | uint8_t max = DRIVER_LED_TOTAL; | ||
| 442 | #endif | ||
| 443 | rgb_matrix_indicators_advanced_kb(min, max); | ||
| 444 | rgb_matrix_indicators_advanced_user(min, max); | ||
| 445 | } | ||
| 446 | |||
| 447 | __attribute__((weak)) void rgb_matrix_indicators_advanced_kb(uint8_t led_min, uint8_t led_max) {} | ||
| 448 | |||
| 449 | __attribute__((weak)) void rgb_matrix_indicators_advanced_user(uint8_t led_min, uint8_t led_max) {} | ||
| 450 | |||
| 427 | void rgb_matrix_init(void) { | 451 | void rgb_matrix_init(void) { |
| 428 | rgb_matrix_driver.init(); | 452 | rgb_matrix_driver.init(); |
| 429 | 453 | ||
diff --git a/quantum/rgb_matrix.h b/quantum/rgb_matrix.h index 733333349..771a1fcd3 100644 --- a/quantum/rgb_matrix.h +++ b/quantum/rgb_matrix.h | |||
| @@ -57,6 +57,11 @@ | |||
| 57 | uint8_t max = DRIVER_LED_TOTAL; | 57 | uint8_t max = DRIVER_LED_TOTAL; |
| 58 | #endif | 58 | #endif |
| 59 | 59 | ||
| 60 | #define RGB_MATRIX_INDICATOR_SET_COLOR(i, r, g, b) \ | ||
| 61 | if (i >= led_min && i <= led_max) { \ | ||
| 62 | rgb_matrix_set_color(i, r, g, b); \ | ||
| 63 | } | ||
| 64 | |||
| 60 | #define RGB_MATRIX_TEST_LED_FLAGS() \ | 65 | #define RGB_MATRIX_TEST_LED_FLAGS() \ |
| 61 | if (!HAS_ANY_FLAGS(g_led_config.flags[i], params->flags)) continue | 66 | if (!HAS_ANY_FLAGS(g_led_config.flags[i], params->flags)) continue |
| 62 | 67 | ||
| @@ -103,6 +108,10 @@ void rgb_matrix_indicators(void); | |||
| 103 | void rgb_matrix_indicators_kb(void); | 108 | void rgb_matrix_indicators_kb(void); |
| 104 | void rgb_matrix_indicators_user(void); | 109 | void rgb_matrix_indicators_user(void); |
| 105 | 110 | ||
| 111 | void rgb_matrix_indicators_advanced(effect_params_t *params); | ||
| 112 | void rgb_matrix_indicators_advanced_kb(uint8_t led_min, uint8_t led_max); | ||
| 113 | void rgb_matrix_indicators_advanced_user(uint8_t led_min, uint8_t led_max); | ||
| 114 | |||
| 106 | void rgb_matrix_init(void); | 115 | void rgb_matrix_init(void); |
| 107 | 116 | ||
| 108 | void rgb_matrix_set_suspend_state(bool state); | 117 | void rgb_matrix_set_suspend_state(bool state); |
diff --git a/quantum/rgb_matrix_animations/alpha_mods_anim.h b/quantum/rgb_matrix_animations/alpha_mods_anim.h index 0778ab209..426d88ef3 100644 --- a/quantum/rgb_matrix_animations/alpha_mods_anim.h +++ b/quantum/rgb_matrix_animations/alpha_mods_anim.h | |||
| @@ -7,9 +7,9 @@ bool ALPHAS_MODS(effect_params_t* params) { | |||
| 7 | RGB_MATRIX_USE_LIMITS(led_min, led_max); | 7 | RGB_MATRIX_USE_LIMITS(led_min, led_max); |
| 8 | 8 | ||
| 9 | HSV hsv = rgb_matrix_config.hsv; | 9 | HSV hsv = rgb_matrix_config.hsv; |
| 10 | RGB rgb1 = hsv_to_rgb(hsv); | 10 | RGB rgb1 = rgb_matrix_hsv_to_rgb(hsv); |
| 11 | hsv.h += rgb_matrix_config.speed; | 11 | hsv.h += rgb_matrix_config.speed; |
| 12 | RGB rgb2 = hsv_to_rgb(hsv); | 12 | RGB rgb2 = rgb_matrix_hsv_to_rgb(hsv); |
| 13 | 13 | ||
| 14 | for (uint8_t i = led_min; i < led_max; i++) { | 14 | for (uint8_t i = led_min; i < led_max; i++) { |
| 15 | RGB_MATRIX_TEST_LED_FLAGS(); | 15 | RGB_MATRIX_TEST_LED_FLAGS(); |
diff --git a/quantum/rgb_matrix_animations/breathing_anim.h b/quantum/rgb_matrix_animations/breathing_anim.h index 887425f9d..340bd93e5 100644 --- a/quantum/rgb_matrix_animations/breathing_anim.h +++ b/quantum/rgb_matrix_animations/breathing_anim.h | |||
| @@ -8,7 +8,7 @@ bool BREATHING(effect_params_t* params) { | |||
| 8 | HSV hsv = rgb_matrix_config.hsv; | 8 | HSV hsv = rgb_matrix_config.hsv; |
| 9 | uint16_t time = scale16by8(g_rgb_timer, rgb_matrix_config.speed / 8); | 9 | uint16_t time = scale16by8(g_rgb_timer, rgb_matrix_config.speed / 8); |
| 10 | hsv.v = scale8(abs8(sin8(time) - 128) * 2, hsv.v); | 10 | hsv.v = scale8(abs8(sin8(time) - 128) * 2, hsv.v); |
| 11 | RGB rgb = hsv_to_rgb(hsv); | 11 | RGB rgb = rgb_matrix_hsv_to_rgb(hsv); |
| 12 | for (uint8_t i = led_min; i < led_max; i++) { | 12 | for (uint8_t i = led_min; i < led_max; i++) { |
| 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); |
diff --git a/quantum/rgb_matrix_animations/gradient_left_right_anim.h b/quantum/rgb_matrix_animations/gradient_left_right_anim.h index 2eab2eb75..53dfd04e2 100644 --- a/quantum/rgb_matrix_animations/gradient_left_right_anim.h +++ b/quantum/rgb_matrix_animations/gradient_left_right_anim.h | |||
| @@ -12,7 +12,7 @@ bool GRADIENT_LEFT_RIGHT(effect_params_t* params) { | |||
| 12 | // The x range will be 0..224, map this to 0..7 | 12 | // The x range will be 0..224, map this to 0..7 |
| 13 | // Relies on hue being 8-bit and wrapping | 13 | // Relies on hue being 8-bit and wrapping |
| 14 | hsv.h = rgb_matrix_config.hsv.h + (scale * g_led_config.point[i].x >> 5); | 14 | hsv.h = rgb_matrix_config.hsv.h + (scale * g_led_config.point[i].x >> 5); |
| 15 | RGB rgb = 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 led_max < DRIVER_LED_TOTAL; |
diff --git a/quantum/rgb_matrix_animations/gradient_up_down_anim.h b/quantum/rgb_matrix_animations/gradient_up_down_anim.h index 0f1f8e23c..7e0d2898c 100644 --- a/quantum/rgb_matrix_animations/gradient_up_down_anim.h +++ b/quantum/rgb_matrix_animations/gradient_up_down_anim.h | |||
| @@ -12,7 +12,7 @@ bool GRADIENT_UP_DOWN(effect_params_t* params) { | |||
| 12 | // The y range will be 0..64, map this to 0..4 | 12 | // The y range will be 0..64, map this to 0..4 |
| 13 | // Relies on hue being 8-bit and wrapping | 13 | // Relies on hue being 8-bit and wrapping |
| 14 | hsv.h = rgb_matrix_config.hsv.h + scale * (g_led_config.point[i].y >> 4); | 14 | hsv.h = rgb_matrix_config.hsv.h + scale * (g_led_config.point[i].y >> 4); |
| 15 | RGB rgb = 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 led_max < DRIVER_LED_TOTAL; |
diff --git a/quantum/rgb_matrix_animations/jellybean_raindrops_anim.h b/quantum/rgb_matrix_animations/jellybean_raindrops_anim.h index ef2d1500b..9493b3850 100644 --- a/quantum/rgb_matrix_animations/jellybean_raindrops_anim.h +++ b/quantum/rgb_matrix_animations/jellybean_raindrops_anim.h | |||
| @@ -5,7 +5,7 @@ RGB_MATRIX_EFFECT(JELLYBEAN_RAINDROPS) | |||
| 5 | static void jellybean_raindrops_set_color(int i, effect_params_t* params) { | 5 | static void jellybean_raindrops_set_color(int i, effect_params_t* params) { |
| 6 | if (!HAS_ANY_FLAGS(g_led_config.flags[i], params->flags)) return; | 6 | if (!HAS_ANY_FLAGS(g_led_config.flags[i], params->flags)) return; |
| 7 | HSV hsv = {rand() & 0xFF, rand() & 0xFF, rgb_matrix_config.hsv.v}; | 7 | HSV hsv = {rand() & 0xFF, rand() & 0xFF, rgb_matrix_config.hsv.v}; |
| 8 | RGB rgb = hsv_to_rgb(hsv); | 8 | RGB rgb = rgb_matrix_hsv_to_rgb(hsv); |
| 9 | rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b); | 9 | rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b); |
| 10 | } | 10 | } |
| 11 | 11 | ||
diff --git a/quantum/rgb_matrix_animations/raindrops_anim.h b/quantum/rgb_matrix_animations/raindrops_anim.h index 6e1b5acb0..38359cdca 100644 --- a/quantum/rgb_matrix_animations/raindrops_anim.h +++ b/quantum/rgb_matrix_animations/raindrops_anim.h | |||
| @@ -15,7 +15,7 @@ static void raindrops_set_color(int i, effect_params_t* params) { | |||
| 15 | } | 15 | } |
| 16 | 16 | ||
| 17 | hsv.h = rgb_matrix_config.hsv.h + (deltaH * (rand() & 0x03)); | 17 | hsv.h = rgb_matrix_config.hsv.h + (deltaH * (rand() & 0x03)); |
| 18 | RGB rgb = hsv_to_rgb(hsv); | 18 | RGB rgb = rgb_matrix_hsv_to_rgb(hsv); |
| 19 | rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b); | 19 | rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b); |
| 20 | } | 20 | } |
| 21 | 21 | ||
diff --git a/quantum/rgb_matrix_animations/solid_color_anim.h b/quantum/rgb_matrix_animations/solid_color_anim.h index c8f5e70e7..79d63cf13 100644 --- a/quantum/rgb_matrix_animations/solid_color_anim.h +++ b/quantum/rgb_matrix_animations/solid_color_anim.h | |||
| @@ -4,7 +4,7 @@ RGB_MATRIX_EFFECT(SOLID_COLOR) | |||
| 4 | bool SOLID_COLOR(effect_params_t* params) { | 4 | bool SOLID_COLOR(effect_params_t* params) { |
| 5 | RGB_MATRIX_USE_LIMITS(led_min, led_max); | 5 | RGB_MATRIX_USE_LIMITS(led_min, led_max); |
| 6 | 6 | ||
| 7 | RGB rgb = hsv_to_rgb(rgb_matrix_config.hsv); | 7 | RGB rgb = rgb_matrix_hsv_to_rgb(rgb_matrix_config.hsv); |
| 8 | for (uint8_t i = led_min; i < led_max; i++) { | 8 | for (uint8_t i = led_min; i < led_max; i++) { |
| 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); |
diff --git a/quantum/rgb_matrix_animations/typing_heatmap_anim.h b/quantum/rgb_matrix_animations/typing_heatmap_anim.h index e82c1b49e..b855fdc19 100644 --- a/quantum/rgb_matrix_animations/typing_heatmap_anim.h +++ b/quantum/rgb_matrix_animations/typing_heatmap_anim.h | |||
| @@ -51,7 +51,7 @@ bool TYPING_HEATMAP(effect_params_t* params) { | |||
| 51 | if (!HAS_ANY_FLAGS(g_led_config.flags[led[j]], params->flags)) continue; | 51 | if (!HAS_ANY_FLAGS(g_led_config.flags[led[j]], params->flags)) continue; |
| 52 | 52 | ||
| 53 | HSV hsv = {170 - qsub8(val, 85), rgb_matrix_config.hsv.s, scale8((qadd8(170, val) - 170) * 3, rgb_matrix_config.hsv.v)}; | 53 | HSV hsv = {170 - qsub8(val, 85), rgb_matrix_config.hsv.s, scale8((qadd8(170, val) - 170) * 3, rgb_matrix_config.hsv.v)}; |
| 54 | RGB rgb = hsv_to_rgb(hsv); | 54 | RGB rgb = rgb_matrix_hsv_to_rgb(hsv); |
| 55 | rgb_matrix_set_color(led[j], rgb.r, rgb.g, rgb.b); | 55 | rgb_matrix_set_color(led[j], rgb.r, rgb.g, rgb.b); |
| 56 | } | 56 | } |
| 57 | 57 | ||
diff --git a/quantum/rgb_matrix_runners/effect_runner_dx_dy.h b/quantum/rgb_matrix_runners/effect_runner_dx_dy.h index 9d0c9fab1..4867609c8 100644 --- a/quantum/rgb_matrix_runners/effect_runner_dx_dy.h +++ b/quantum/rgb_matrix_runners/effect_runner_dx_dy.h | |||
| @@ -10,7 +10,7 @@ bool effect_runner_dx_dy(effect_params_t* params, dx_dy_f effect_func) { | |||
| 10 | RGB_MATRIX_TEST_LED_FLAGS(); | 10 | RGB_MATRIX_TEST_LED_FLAGS(); |
| 11 | int16_t dx = g_led_config.point[i].x - k_rgb_matrix_center.x; | 11 | int16_t dx = g_led_config.point[i].x - k_rgb_matrix_center.x; |
| 12 | int16_t dy = g_led_config.point[i].y - k_rgb_matrix_center.y; | 12 | int16_t dy = g_led_config.point[i].y - k_rgb_matrix_center.y; |
| 13 | RGB rgb = 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 led_max < DRIVER_LED_TOTAL; |
diff --git a/quantum/rgb_matrix_runners/effect_runner_dx_dy_dist.h b/quantum/rgb_matrix_runners/effect_runner_dx_dy_dist.h index 2824c8252..9545b418d 100644 --- a/quantum/rgb_matrix_runners/effect_runner_dx_dy_dist.h +++ b/quantum/rgb_matrix_runners/effect_runner_dx_dy_dist.h | |||
| @@ -11,7 +11,7 @@ bool effect_runner_dx_dy_dist(effect_params_t* params, dx_dy_dist_f effect_func) | |||
| 11 | int16_t dx = g_led_config.point[i].x - k_rgb_matrix_center.x; | 11 | int16_t dx = g_led_config.point[i].x - k_rgb_matrix_center.x; |
| 12 | int16_t dy = g_led_config.point[i].y - k_rgb_matrix_center.y; | 12 | int16_t dy = g_led_config.point[i].y - k_rgb_matrix_center.y; |
| 13 | uint8_t dist = sqrt16(dx * dx + dy * dy); | 13 | uint8_t dist = sqrt16(dx * dx + dy * dy); |
| 14 | RGB rgb = 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 led_max < DRIVER_LED_TOTAL; |
diff --git a/quantum/rgb_matrix_runners/effect_runner_i.h b/quantum/rgb_matrix_runners/effect_runner_i.h index 5e6bf5daa..95bfe8b39 100644 --- a/quantum/rgb_matrix_runners/effect_runner_i.h +++ b/quantum/rgb_matrix_runners/effect_runner_i.h | |||
| @@ -8,7 +8,7 @@ bool effect_runner_i(effect_params_t* params, i_f effect_func) { | |||
| 8 | uint8_t time = scale16by8(g_rgb_timer, rgb_matrix_config.speed / 4); | 8 | uint8_t time = scale16by8(g_rgb_timer, rgb_matrix_config.speed / 4); |
| 9 | for (uint8_t i = led_min; i < led_max; i++) { | 9 | for (uint8_t i = led_min; i < led_max; i++) { |
| 10 | RGB_MATRIX_TEST_LED_FLAGS(); | 10 | RGB_MATRIX_TEST_LED_FLAGS(); |
| 11 | RGB rgb = 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 led_max < DRIVER_LED_TOTAL; |
diff --git a/quantum/rgb_matrix_runners/effect_runner_reactive.h b/quantum/rgb_matrix_runners/effect_runner_reactive.h index 53e77e3fb..8485b61f3 100644 --- a/quantum/rgb_matrix_runners/effect_runner_reactive.h +++ b/quantum/rgb_matrix_runners/effect_runner_reactive.h | |||
| @@ -20,7 +20,7 @@ bool effect_runner_reactive(effect_params_t* params, reactive_f effect_func) { | |||
| 20 | } | 20 | } |
| 21 | 21 | ||
| 22 | uint16_t offset = scale16by8(tick, rgb_matrix_config.speed); | 22 | uint16_t offset = scale16by8(tick, rgb_matrix_config.speed); |
| 23 | RGB rgb = 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 led_max < DRIVER_LED_TOTAL; |
diff --git a/quantum/rgb_matrix_runners/effect_runner_reactive_splash.h b/quantum/rgb_matrix_runners/effect_runner_reactive_splash.h index b5d284a40..5c69d0fbb 100644 --- a/quantum/rgb_matrix_runners/effect_runner_reactive_splash.h +++ b/quantum/rgb_matrix_runners/effect_runner_reactive_splash.h | |||
| @@ -20,7 +20,7 @@ bool effect_runner_reactive_splash(uint8_t start, effect_params_t* params, react | |||
| 20 | hsv = effect_func(hsv, dx, dy, dist, tick); | 20 | hsv = effect_func(hsv, dx, dy, dist, tick); |
| 21 | } | 21 | } |
| 22 | hsv.v = scale8(hsv.v, rgb_matrix_config.hsv.v); | 22 | hsv.v = scale8(hsv.v, rgb_matrix_config.hsv.v); |
| 23 | RGB rgb = 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 led_max < DRIVER_LED_TOTAL; |
diff --git a/quantum/rgb_matrix_runners/effect_runner_sin_cos_i.h b/quantum/rgb_matrix_runners/effect_runner_sin_cos_i.h index 3fb7d4805..02351de51 100644 --- a/quantum/rgb_matrix_runners/effect_runner_sin_cos_i.h +++ b/quantum/rgb_matrix_runners/effect_runner_sin_cos_i.h | |||
| @@ -10,7 +10,7 @@ bool effect_runner_sin_cos_i(effect_params_t* params, sin_cos_i_f effect_func) { | |||
| 10 | int8_t sin_value = sin8(time) - 128; | 10 | int8_t sin_value = sin8(time) - 128; |
| 11 | for (uint8_t i = led_min; i < led_max; i++) { | 11 | for (uint8_t i = led_min; i < led_max; i++) { |
| 12 | RGB_MATRIX_TEST_LED_FLAGS(); | 12 | RGB_MATRIX_TEST_LED_FLAGS(); |
| 13 | RGB rgb = 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 led_max < DRIVER_LED_TOTAL; |
diff --git a/quantum/rgblight.c b/quantum/rgblight.c index 76bb6eb8c..7f9e330d3 100644 --- a/quantum/rgblight.c +++ b/quantum/rgblight.c | |||
| @@ -123,9 +123,11 @@ void rgblight_set_effect_range(uint8_t start_pos, uint8_t num_leds) { | |||
| 123 | rgblight_ranges.effect_num_leds = num_leds; | 123 | rgblight_ranges.effect_num_leds = num_leds; |
| 124 | } | 124 | } |
| 125 | 125 | ||
| 126 | __attribute__((weak)) RGB rgblight_hsv_to_rgb(HSV hsv) { return hsv_to_rgb(hsv); } | ||
| 127 | |||
| 126 | void sethsv_raw(uint8_t hue, uint8_t sat, uint8_t val, LED_TYPE *led1) { | 128 | void sethsv_raw(uint8_t hue, uint8_t sat, uint8_t val, LED_TYPE *led1) { |
| 127 | HSV hsv = {hue, sat, val}; | 129 | HSV hsv = {hue, sat, val}; |
| 128 | RGB rgb = hsv_to_rgb(hsv); | 130 | RGB rgb = rgblight_hsv_to_rgb(hsv); |
| 129 | setrgb(rgb.r, rgb.g, rgb.b, led1); | 131 | setrgb(rgb.r, rgb.g, rgb.b, led1); |
| 130 | } | 132 | } |
| 131 | 133 | ||
diff --git a/quantum/sequencer/sequencer.c b/quantum/sequencer/sequencer.c new file mode 100644 index 000000000..0eaf3a17a --- /dev/null +++ b/quantum/sequencer/sequencer.c | |||
| @@ -0,0 +1,275 @@ | |||
| 1 | /* Copyright 2020 Rodolphe Belouin | ||
| 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 "sequencer.h" | ||
| 18 | |||
| 19 | #ifdef MIDI_ENABLE | ||
| 20 | # include "process_midi.h" | ||
| 21 | #endif | ||
| 22 | |||
| 23 | #ifdef MIDI_MOCKED | ||
| 24 | # include "tests/midi_mock.h" | ||
| 25 | #endif | ||
| 26 | |||
| 27 | sequencer_config_t sequencer_config = { | ||
| 28 | false, // enabled | ||
| 29 | {false}, // steps | ||
| 30 | {0}, // track notes | ||
| 31 | 60, // tempo | ||
| 32 | SQ_RES_4, // resolution | ||
| 33 | }; | ||
| 34 | |||
| 35 | sequencer_state_t sequencer_internal_state = {0, 0, 0, 0, SEQUENCER_PHASE_ATTACK}; | ||
| 36 | |||
| 37 | bool is_sequencer_on(void) { return sequencer_config.enabled; } | ||
| 38 | |||
| 39 | void sequencer_on(void) { | ||
| 40 | dprintln("sequencer on"); | ||
| 41 | sequencer_config.enabled = true; | ||
| 42 | sequencer_internal_state.current_track = 0; | ||
| 43 | sequencer_internal_state.current_step = 0; | ||
| 44 | sequencer_internal_state.timer = timer_read(); | ||
| 45 | sequencer_internal_state.phase = SEQUENCER_PHASE_ATTACK; | ||
| 46 | } | ||
| 47 | |||
| 48 | void sequencer_off(void) { | ||
| 49 | dprintln("sequencer off"); | ||
| 50 | sequencer_config.enabled = false; | ||
| 51 | sequencer_internal_state.current_step = 0; | ||
| 52 | } | ||
| 53 | |||
| 54 | void sequencer_toggle(void) { | ||
| 55 | if (is_sequencer_on()) { | ||
| 56 | sequencer_off(); | ||
| 57 | } else { | ||
| 58 | sequencer_on(); | ||
| 59 | } | ||
| 60 | } | ||
| 61 | |||
| 62 | void sequencer_set_track_notes(const uint16_t track_notes[SEQUENCER_TRACKS]) { | ||
| 63 | for (uint8_t i = 0; i < SEQUENCER_TRACKS; i++) { | ||
| 64 | sequencer_config.track_notes[i] = track_notes[i]; | ||
| 65 | } | ||
| 66 | } | ||
| 67 | |||
| 68 | bool is_sequencer_track_active(uint8_t track) { return (sequencer_internal_state.active_tracks >> track) & true; } | ||
| 69 | |||
| 70 | void sequencer_set_track_activation(uint8_t track, bool value) { | ||
| 71 | if (value) { | ||
| 72 | sequencer_internal_state.active_tracks |= (1 << track); | ||
| 73 | } else { | ||
| 74 | sequencer_internal_state.active_tracks &= ~(1 << track); | ||
| 75 | } | ||
| 76 | dprintf("sequencer: track %d is %s\n", track, value ? "active" : "inactive"); | ||
| 77 | } | ||
| 78 | |||
| 79 | void sequencer_toggle_track_activation(uint8_t track) { sequencer_set_track_activation(track, !is_sequencer_track_active(track)); } | ||
| 80 | |||
| 81 | void sequencer_toggle_single_active_track(uint8_t track) { | ||
| 82 | if (is_sequencer_track_active(track)) { | ||
| 83 | sequencer_internal_state.active_tracks = 0; | ||
| 84 | } else { | ||
| 85 | sequencer_internal_state.active_tracks = 1 << track; | ||
| 86 | } | ||
| 87 | } | ||
| 88 | |||
| 89 | bool is_sequencer_step_on(uint8_t step) { return step < SEQUENCER_STEPS && (sequencer_config.steps[step] & sequencer_internal_state.active_tracks) > 0; } | ||
| 90 | |||
| 91 | bool is_sequencer_step_on_for_track(uint8_t step, uint8_t track) { return step < SEQUENCER_STEPS && (sequencer_config.steps[step] >> track) & true; } | ||
| 92 | |||
| 93 | void sequencer_set_step(uint8_t step, bool value) { | ||
| 94 | if (step < SEQUENCER_STEPS) { | ||
| 95 | if (value) { | ||
| 96 | sequencer_config.steps[step] |= sequencer_internal_state.active_tracks; | ||
| 97 | } else { | ||
| 98 | sequencer_config.steps[step] &= ~sequencer_internal_state.active_tracks; | ||
| 99 | } | ||
| 100 | dprintf("sequencer: step %d is %s\n", step, value ? "on" : "off"); | ||
| 101 | } else { | ||
| 102 | dprintf("sequencer: step %d is out of range\n", step); | ||
| 103 | } | ||
| 104 | } | ||
| 105 | |||
| 106 | void sequencer_toggle_step(uint8_t step) { | ||
| 107 | if (is_sequencer_step_on(step)) { | ||
| 108 | sequencer_set_step_off(step); | ||
| 109 | } else { | ||
| 110 | sequencer_set_step_on(step); | ||
| 111 | } | ||
| 112 | } | ||
| 113 | |||
| 114 | void sequencer_set_all_steps(bool value) { | ||
| 115 | for (uint8_t step = 0; step < SEQUENCER_STEPS; step++) { | ||
| 116 | if (value) { | ||
| 117 | sequencer_config.steps[step] |= sequencer_internal_state.active_tracks; | ||
| 118 | } else { | ||
| 119 | sequencer_config.steps[step] &= ~sequencer_internal_state.active_tracks; | ||
| 120 | } | ||
| 121 | } | ||
| 122 | dprintf("sequencer: all steps are %s\n", value ? "on" : "off"); | ||
| 123 | } | ||
| 124 | |||
| 125 | uint8_t sequencer_get_tempo(void) { return sequencer_config.tempo; } | ||
| 126 | |||
| 127 | void sequencer_set_tempo(uint8_t tempo) { | ||
| 128 | if (tempo > 0) { | ||
| 129 | sequencer_config.tempo = tempo; | ||
| 130 | dprintf("sequencer: tempo set to %d bpm\n", tempo); | ||
| 131 | } else { | ||
| 132 | dprintln("sequencer: cannot set tempo to 0"); | ||
| 133 | } | ||
| 134 | } | ||
| 135 | |||
| 136 | void sequencer_increase_tempo(void) { | ||
| 137 | // Handling potential uint8_t overflow | ||
| 138 | if (sequencer_config.tempo < UINT8_MAX) { | ||
| 139 | sequencer_set_tempo(sequencer_config.tempo + 1); | ||
| 140 | } else { | ||
| 141 | dprintf("sequencer: cannot set tempo above %d\n", UINT8_MAX); | ||
| 142 | } | ||
| 143 | } | ||
| 144 | |||
| 145 | void sequencer_decrease_tempo(void) { sequencer_set_tempo(sequencer_config.tempo - 1); } | ||
| 146 | |||
| 147 | sequencer_resolution_t sequencer_get_resolution(void) { return sequencer_config.resolution; } | ||
| 148 | |||
| 149 | void sequencer_set_resolution(sequencer_resolution_t resolution) { | ||
| 150 | if (resolution >= 0 && resolution < SEQUENCER_RESOLUTIONS) { | ||
| 151 | sequencer_config.resolution = resolution; | ||
| 152 | dprintf("sequencer: resolution set to %d\n", resolution); | ||
| 153 | } else { | ||
| 154 | dprintf("sequencer: resolution %d is out of range\n", resolution); | ||
| 155 | } | ||
| 156 | } | ||
| 157 | |||
| 158 | void sequencer_increase_resolution(void) { sequencer_set_resolution(sequencer_config.resolution + 1); } | ||
| 159 | |||
| 160 | void sequencer_decrease_resolution(void) { sequencer_set_resolution(sequencer_config.resolution - 1); } | ||
| 161 | |||
| 162 | uint8_t sequencer_get_current_step(void) { return sequencer_internal_state.current_step; } | ||
| 163 | |||
| 164 | void sequencer_phase_attack(void) { | ||
| 165 | dprintf("sequencer: step %d\n", sequencer_internal_state.current_step); | ||
| 166 | dprintf("sequencer: time %d\n", timer_read()); | ||
| 167 | |||
| 168 | if (sequencer_internal_state.current_track == 0) { | ||
| 169 | sequencer_internal_state.timer = timer_read(); | ||
| 170 | } | ||
| 171 | |||
| 172 | if (timer_elapsed(sequencer_internal_state.timer) < sequencer_internal_state.current_track * SEQUENCER_TRACK_THROTTLE) { | ||
| 173 | return; | ||
| 174 | } | ||
| 175 | |||
| 176 | #if defined(MIDI_ENABLE) || defined(MIDI_MOCKED) | ||
| 177 | if (is_sequencer_step_on_for_track(sequencer_internal_state.current_step, sequencer_internal_state.current_track)) { | ||
| 178 | process_midi_basic_noteon(midi_compute_note(sequencer_config.track_notes[sequencer_internal_state.current_track])); | ||
| 179 | } | ||
| 180 | #endif | ||
| 181 | |||
| 182 | if (sequencer_internal_state.current_track < SEQUENCER_TRACKS - 1) { | ||
| 183 | sequencer_internal_state.current_track++; | ||
| 184 | } else { | ||
| 185 | sequencer_internal_state.phase = SEQUENCER_PHASE_RELEASE; | ||
| 186 | } | ||
| 187 | } | ||
| 188 | |||
| 189 | void sequencer_phase_release(void) { | ||
| 190 | if (timer_elapsed(sequencer_internal_state.timer) < SEQUENCER_PHASE_RELEASE_TIMEOUT + sequencer_internal_state.current_track * SEQUENCER_TRACK_THROTTLE) { | ||
| 191 | return; | ||
| 192 | } | ||
| 193 | #if defined(MIDI_ENABLE) || defined(MIDI_MOCKED) | ||
| 194 | if (is_sequencer_step_on_for_track(sequencer_internal_state.current_step, sequencer_internal_state.current_track)) { | ||
| 195 | process_midi_basic_noteoff(midi_compute_note(sequencer_config.track_notes[sequencer_internal_state.current_track])); | ||
| 196 | } | ||
| 197 | #endif | ||
| 198 | if (sequencer_internal_state.current_track > 0) { | ||
| 199 | sequencer_internal_state.current_track--; | ||
| 200 | } else { | ||
| 201 | sequencer_internal_state.phase = SEQUENCER_PHASE_PAUSE; | ||
| 202 | } | ||
| 203 | } | ||
| 204 | |||
| 205 | void sequencer_phase_pause(void) { | ||
| 206 | if (timer_elapsed(sequencer_internal_state.timer) < sequencer_get_step_duration()) { | ||
| 207 | return; | ||
| 208 | } | ||
| 209 | |||
| 210 | sequencer_internal_state.current_step = (sequencer_internal_state.current_step + 1) % SEQUENCER_STEPS; | ||
| 211 | sequencer_internal_state.phase = SEQUENCER_PHASE_ATTACK; | ||
| 212 | } | ||
| 213 | |||
| 214 | void matrix_scan_sequencer(void) { | ||
| 215 | if (!sequencer_config.enabled) { | ||
| 216 | return; | ||
| 217 | } | ||
| 218 | |||
| 219 | if (sequencer_internal_state.phase == SEQUENCER_PHASE_PAUSE) { | ||
| 220 | sequencer_phase_pause(); | ||
| 221 | } | ||
| 222 | |||
| 223 | if (sequencer_internal_state.phase == SEQUENCER_PHASE_RELEASE) { | ||
| 224 | sequencer_phase_release(); | ||
| 225 | } | ||
| 226 | |||
| 227 | if (sequencer_internal_state.phase == SEQUENCER_PHASE_ATTACK) { | ||
| 228 | sequencer_phase_attack(); | ||
| 229 | } | ||
| 230 | } | ||
| 231 | |||
| 232 | uint16_t sequencer_get_beat_duration(void) { return get_beat_duration(sequencer_config.tempo); } | ||
| 233 | |||
| 234 | uint16_t sequencer_get_step_duration(void) { return get_step_duration(sequencer_config.tempo, sequencer_config.resolution); } | ||
| 235 | |||
| 236 | uint16_t get_beat_duration(uint8_t tempo) { | ||
| 237 | // Don’t crash in the unlikely case where the given tempo is 0 | ||
| 238 | if (tempo == 0) { | ||
| 239 | return get_beat_duration(60); | ||
| 240 | } | ||
| 241 | |||
| 242 | /** | ||
| 243 | * Given | ||
| 244 | * t = tempo and d = duration, both strictly greater than 0 | ||
| 245 | * When | ||
| 246 | * t beats / minute = 1 beat / d ms | ||
| 247 | * Then | ||
| 248 | * t beats / 60000ms = 1 beat / d ms | ||
| 249 | * d ms = 60000ms / t | ||
| 250 | */ | ||
| 251 | return 60000 / tempo; | ||
| 252 | } | ||
| 253 | |||
| 254 | uint16_t get_step_duration(uint8_t tempo, sequencer_resolution_t resolution) { | ||
| 255 | /** | ||
| 256 | * Resolution cheatsheet: | ||
| 257 | * 1/2 => 2 steps per 4 beats | ||
| 258 | * 1/2T => 3 steps per 4 beats | ||
| 259 | * 1/4 => 4 steps per 4 beats | ||
| 260 | * 1/4T => 6 steps per 4 beats | ||
| 261 | * 1/8 => 8 steps per 4 beats | ||
| 262 | * 1/8T => 12 steps per 4 beats | ||
| 263 | * 1/16 => 16 steps per 4 beats | ||
| 264 | * 1/16T => 24 steps per 4 beats | ||
| 265 | * 1/32 => 32 steps per 4 beats | ||
| 266 | * | ||
| 267 | * The number of steps for binary resolutions follows the powers of 2. | ||
| 268 | * The ternary variants are simply 1.5x faster. | ||
| 269 | */ | ||
| 270 | bool is_binary = resolution % 2 == 0; | ||
| 271 | uint8_t binary_steps = 2 << (resolution / 2); | ||
| 272 | uint16_t binary_step_duration = get_beat_duration(tempo) * 4 / binary_steps; | ||
| 273 | |||
| 274 | return is_binary ? binary_step_duration : 2 * binary_step_duration / 3; | ||
| 275 | } | ||
diff --git a/quantum/sequencer/sequencer.h b/quantum/sequencer/sequencer.h new file mode 100644 index 000000000..aeca7a1e9 --- /dev/null +++ b/quantum/sequencer/sequencer.h | |||
| @@ -0,0 +1,122 @@ | |||
| 1 | /* Copyright 2020 Rodolphe Belouin | ||
| 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 <stdbool.h> | ||
| 20 | #include "debug.h" | ||
| 21 | #include "timer.h" | ||
| 22 | |||
| 23 | // Maximum number of steps: 256 | ||
| 24 | #ifndef SEQUENCER_STEPS | ||
| 25 | # define SEQUENCER_STEPS 16 | ||
| 26 | #endif | ||
| 27 | |||
| 28 | // Maximum number of tracks: 8 | ||
| 29 | #ifndef SEQUENCER_TRACKS | ||
| 30 | # define SEQUENCER_TRACKS 8 | ||
| 31 | #endif | ||
| 32 | |||
| 33 | #ifndef SEQUENCER_TRACK_THROTTLE | ||
| 34 | # define SEQUENCER_TRACK_THROTTLE 3 | ||
| 35 | #endif | ||
| 36 | |||
| 37 | #ifndef SEQUENCER_PHASE_RELEASE_TIMEOUT | ||
| 38 | # define SEQUENCER_PHASE_RELEASE_TIMEOUT 30 | ||
| 39 | #endif | ||
| 40 | |||
| 41 | /** | ||
| 42 | * Make sure that the items of this enumeration follow the powers of 2, separated by a ternary variant. | ||
| 43 | * Check the implementation of `get_step_duration` for further explanation. | ||
| 44 | */ | ||
| 45 | typedef enum { SQ_RES_2, SQ_RES_2T, SQ_RES_4, SQ_RES_4T, SQ_RES_8, SQ_RES_8T, SQ_RES_16, SQ_RES_16T, SQ_RES_32, SEQUENCER_RESOLUTIONS } sequencer_resolution_t; | ||
| 46 | |||
| 47 | typedef struct { | ||
| 48 | bool enabled; | ||
| 49 | uint8_t steps[SEQUENCER_STEPS]; | ||
| 50 | uint16_t track_notes[SEQUENCER_TRACKS]; | ||
| 51 | uint8_t tempo; // Is a maximum tempo of 255 reasonable? | ||
| 52 | sequencer_resolution_t resolution; | ||
| 53 | } sequencer_config_t; | ||
| 54 | |||
| 55 | /** | ||
| 56 | * Because Digital Audio Workstations get overwhelmed when too many MIDI signals are sent concurrently, | ||
| 57 | * We use a "phase" state machine to delay some of the events. | ||
| 58 | */ | ||
| 59 | typedef enum sequencer_phase_t { | ||
| 60 | SEQUENCER_PHASE_ATTACK, // t=0ms, send the MIDI note on signal | ||
| 61 | SEQUENCER_PHASE_RELEASE, // t=SEQUENCER_PHASE_RELEASE_TIMEOUT ms, send the MIDI note off signal | ||
| 62 | SEQUENCER_PHASE_PAUSE // t=step duration ms, loop | ||
| 63 | } sequencer_phase_t; | ||
| 64 | |||
| 65 | typedef struct { | ||
| 66 | uint8_t active_tracks; | ||
| 67 | uint8_t current_track; | ||
| 68 | uint8_t current_step; | ||
| 69 | uint16_t timer; | ||
| 70 | sequencer_phase_t phase; | ||
| 71 | } sequencer_state_t; | ||
| 72 | |||
| 73 | extern sequencer_config_t sequencer_config; | ||
| 74 | |||
| 75 | // We expose the internal state to make the feature more "unit-testable" | ||
| 76 | extern sequencer_state_t sequencer_internal_state; | ||
| 77 | |||
| 78 | bool is_sequencer_on(void); | ||
| 79 | void sequencer_toggle(void); | ||
| 80 | void sequencer_on(void); | ||
| 81 | void sequencer_off(void); | ||
| 82 | |||
| 83 | void sequencer_set_track_notes(const uint16_t track_notes[SEQUENCER_TRACKS]); | ||
| 84 | |||
| 85 | bool is_sequencer_track_active(uint8_t track); | ||
| 86 | void sequencer_set_track_activation(uint8_t track, bool value); | ||
| 87 | void sequencer_toggle_track_activation(uint8_t track); | ||
| 88 | void sequencer_toggle_single_active_track(uint8_t track); | ||
| 89 | |||
| 90 | #define sequencer_activate_track(track) sequencer_set_track_activation(track, true) | ||
| 91 | #define sequencer_deactivate_track(track) sequencer_set_track_activation(track, false) | ||
| 92 | |||
| 93 | bool is_sequencer_step_on(uint8_t step); | ||
| 94 | bool is_sequencer_step_on_for_track(uint8_t step, uint8_t track); | ||
| 95 | void sequencer_set_step(uint8_t step, bool value); | ||
| 96 | void sequencer_toggle_step(uint8_t step); | ||
| 97 | void sequencer_set_all_steps(bool value); | ||
| 98 | |||
| 99 | #define sequencer_set_step_on(step) sequencer_set_step(step, true) | ||
| 100 | #define sequencer_set_step_off(step) sequencer_set_step(step, false) | ||
| 101 | #define sequencer_set_all_steps_on() sequencer_set_all_steps(true) | ||
| 102 | #define sequencer_set_all_steps_off() sequencer_set_all_steps(false) | ||
| 103 | |||
| 104 | uint8_t sequencer_get_tempo(void); | ||
| 105 | void sequencer_set_tempo(uint8_t tempo); | ||
| 106 | void sequencer_increase_tempo(void); | ||
| 107 | void sequencer_decrease_tempo(void); | ||
| 108 | |||
| 109 | sequencer_resolution_t sequencer_get_resolution(void); | ||
| 110 | void sequencer_set_resolution(sequencer_resolution_t resolution); | ||
| 111 | void sequencer_increase_resolution(void); | ||
| 112 | void sequencer_decrease_resolution(void); | ||
| 113 | |||
| 114 | uint8_t sequencer_get_current_step(void); | ||
| 115 | |||
| 116 | uint16_t sequencer_get_beat_duration(void); | ||
| 117 | uint16_t sequencer_get_step_duration(void); | ||
| 118 | |||
| 119 | uint16_t get_beat_duration(uint8_t tempo); | ||
| 120 | uint16_t get_step_duration(uint8_t tempo, sequencer_resolution_t resolution); | ||
| 121 | |||
| 122 | void matrix_scan_sequencer(void); | ||
diff --git a/quantum/sequencer/tests/midi_mock.c b/quantum/sequencer/tests/midi_mock.c new file mode 100644 index 000000000..236e16f9d --- /dev/null +++ b/quantum/sequencer/tests/midi_mock.c | |||
| @@ -0,0 +1,26 @@ | |||
| 1 | /* Copyright 2020 Rodolphe Belouin | ||
| 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 "midi_mock.h" | ||
| 18 | |||
| 19 | uint16_t last_noteon = 0; | ||
| 20 | uint16_t last_noteoff = 0; | ||
| 21 | |||
| 22 | uint16_t midi_compute_note(uint16_t keycode) { return keycode; } | ||
| 23 | |||
| 24 | void process_midi_basic_noteon(uint16_t note) { last_noteon = note; } | ||
| 25 | |||
| 26 | void process_midi_basic_noteoff(uint16_t note) { last_noteoff = note; } | ||
diff --git a/quantum/sequencer/tests/midi_mock.h b/quantum/sequencer/tests/midi_mock.h new file mode 100644 index 000000000..4d8c2eb30 --- /dev/null +++ b/quantum/sequencer/tests/midi_mock.h | |||
| @@ -0,0 +1,26 @@ | |||
| 1 | /* Copyright 2020 Rodolphe Belouin | ||
| 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 | extern uint16_t last_noteon; | ||
| 22 | extern uint16_t last_noteoff; | ||
| 23 | |||
| 24 | uint16_t midi_compute_note(uint16_t keycode); | ||
| 25 | void process_midi_basic_noteon(uint16_t note); | ||
| 26 | void process_midi_basic_noteoff(uint16_t note); | ||
diff --git a/quantum/sequencer/tests/rules.mk b/quantum/sequencer/tests/rules.mk new file mode 100644 index 000000000..76c221cf9 --- /dev/null +++ b/quantum/sequencer/tests/rules.mk | |||
| @@ -0,0 +1,11 @@ | |||
| 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) | ||
| 3 | # - Neither `make test:sequencer` or `make test:SEQUENCER` work when using SCREAMING_SNAKE_CASE | ||
| 4 | |||
| 5 | sequencer_DEFS := -DNO_DEBUG -DMIDI_MOCKED | ||
| 6 | |||
| 7 | sequencer_SRC := \ | ||
| 8 | $(QUANTUM_PATH)/sequencer/tests/midi_mock.c \ | ||
| 9 | $(QUANTUM_PATH)/sequencer/tests/sequencer_tests.cpp \ | ||
| 10 | $(QUANTUM_PATH)/sequencer/sequencer.c \ | ||
| 11 | $(TMK_PATH)/common/test/timer.c | ||
diff --git a/quantum/sequencer/tests/sequencer_tests.cpp b/quantum/sequencer/tests/sequencer_tests.cpp new file mode 100644 index 000000000..e81984e5b --- /dev/null +++ b/quantum/sequencer/tests/sequencer_tests.cpp | |||
| @@ -0,0 +1,590 @@ | |||
| 1 | /* Copyright 2020 Rodolphe Belouin | ||
| 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 "gtest/gtest.h" | ||
| 18 | |||
| 19 | extern "C" { | ||
| 20 | #include "sequencer.h" | ||
| 21 | #include "midi_mock.h" | ||
| 22 | #include "quantum/quantum_keycodes.h" | ||
| 23 | } | ||
| 24 | |||
| 25 | extern "C" { | ||
| 26 | void set_time(uint32_t t); | ||
| 27 | void advance_time(uint32_t ms); | ||
| 28 | } | ||
| 29 | |||
| 30 | class SequencerTest : public ::testing::Test { | ||
| 31 | protected: | ||
| 32 | void SetUp() override { | ||
| 33 | config_copy.enabled = sequencer_config.enabled; | ||
| 34 | |||
| 35 | for (int i = 0; i < SEQUENCER_STEPS; i++) { | ||
| 36 | config_copy.steps[i] = sequencer_config.steps[i]; | ||
| 37 | } | ||
| 38 | |||
| 39 | for (int i = 0; i < SEQUENCER_TRACKS; i++) { | ||
| 40 | config_copy.track_notes[i] = sequencer_config.track_notes[i]; | ||
| 41 | } | ||
| 42 | |||
| 43 | config_copy.tempo = sequencer_config.tempo; | ||
| 44 | config_copy.resolution = sequencer_config.resolution; | ||
| 45 | |||
| 46 | state_copy.active_tracks = sequencer_internal_state.active_tracks; | ||
| 47 | state_copy.current_track = sequencer_internal_state.current_track; | ||
| 48 | state_copy.current_step = sequencer_internal_state.current_step; | ||
| 49 | state_copy.timer = sequencer_internal_state.timer; | ||
| 50 | |||
| 51 | last_noteon = 0; | ||
| 52 | last_noteoff = 0; | ||
| 53 | |||
| 54 | set_time(0); | ||
| 55 | } | ||
| 56 | |||
| 57 | void TearDown() override { | ||
| 58 | sequencer_config.enabled = config_copy.enabled; | ||
| 59 | |||
| 60 | for (int i = 0; i < SEQUENCER_STEPS; i++) { | ||
| 61 | sequencer_config.steps[i] = config_copy.steps[i]; | ||
| 62 | } | ||
| 63 | |||
| 64 | for (int i = 0; i < SEQUENCER_TRACKS; i++) { | ||
| 65 | sequencer_config.track_notes[i] = config_copy.track_notes[i]; | ||
| 66 | } | ||
| 67 | |||
| 68 | sequencer_config.tempo = config_copy.tempo; | ||
| 69 | sequencer_config.resolution = config_copy.resolution; | ||
| 70 | |||
| 71 | sequencer_internal_state.active_tracks = state_copy.active_tracks; | ||
| 72 | sequencer_internal_state.current_track = state_copy.current_track; | ||
| 73 | sequencer_internal_state.current_step = state_copy.current_step; | ||
| 74 | sequencer_internal_state.timer = state_copy.timer; | ||
| 75 | } | ||
| 76 | |||
| 77 | sequencer_config_t config_copy; | ||
| 78 | sequencer_state_t state_copy; | ||
| 79 | }; | ||
| 80 | |||
| 81 | TEST_F(SequencerTest, TestOffByDefault) { EXPECT_EQ(is_sequencer_on(), false); } | ||
| 82 | |||
| 83 | TEST_F(SequencerTest, TestOn) { | ||
| 84 | sequencer_config.enabled = false; | ||
| 85 | |||
| 86 | sequencer_on(); | ||
| 87 | EXPECT_EQ(is_sequencer_on(), true); | ||
| 88 | |||
| 89 | // sequencer_on is idempotent | ||
| 90 | sequencer_on(); | ||
| 91 | EXPECT_EQ(is_sequencer_on(), true); | ||
| 92 | } | ||
| 93 | |||
| 94 | TEST_F(SequencerTest, TestOff) { | ||
| 95 | sequencer_config.enabled = true; | ||
| 96 | |||
| 97 | sequencer_off(); | ||
| 98 | EXPECT_EQ(is_sequencer_on(), false); | ||
| 99 | |||
| 100 | // sequencer_off is idempotent | ||
| 101 | sequencer_off(); | ||
| 102 | EXPECT_EQ(is_sequencer_on(), false); | ||
| 103 | } | ||
| 104 | |||
| 105 | TEST_F(SequencerTest, TestToggle) { | ||
| 106 | sequencer_config.enabled = false; | ||
| 107 | |||
| 108 | sequencer_toggle(); | ||
| 109 | EXPECT_EQ(is_sequencer_on(), true); | ||
| 110 | |||
| 111 | sequencer_toggle(); | ||
| 112 | EXPECT_EQ(is_sequencer_on(), false); | ||
| 113 | } | ||
| 114 | |||
| 115 | TEST_F(SequencerTest, TestNoActiveTrackByDefault) { | ||
| 116 | for (int i = 0; i < SEQUENCER_TRACKS; i++) { | ||
| 117 | EXPECT_EQ(is_sequencer_track_active(i), false); | ||
| 118 | } | ||
| 119 | } | ||
| 120 | |||
| 121 | TEST_F(SequencerTest, TestGetActiveTracks) { | ||
| 122 | sequencer_internal_state.active_tracks = (1 << 7) + (1 << 6) + (1 << 3) + (1 << 1) + (1 << 0); | ||
| 123 | |||
| 124 | EXPECT_EQ(is_sequencer_track_active(0), true); | ||
| 125 | EXPECT_EQ(is_sequencer_track_active(1), true); | ||
| 126 | EXPECT_EQ(is_sequencer_track_active(2), false); | ||
| 127 | EXPECT_EQ(is_sequencer_track_active(3), true); | ||
| 128 | EXPECT_EQ(is_sequencer_track_active(4), false); | ||
| 129 | EXPECT_EQ(is_sequencer_track_active(5), false); | ||
| 130 | EXPECT_EQ(is_sequencer_track_active(6), true); | ||
| 131 | EXPECT_EQ(is_sequencer_track_active(7), true); | ||
| 132 | } | ||
| 133 | |||
| 134 | TEST_F(SequencerTest, TestGetActiveTracksOutOfBound) { | ||
| 135 | sequencer_set_track_activation(-1, true); | ||
| 136 | sequencer_set_track_activation(8, true); | ||
| 137 | |||
| 138 | EXPECT_EQ(is_sequencer_track_active(-1), false); | ||
| 139 | EXPECT_EQ(is_sequencer_track_active(8), false); | ||
| 140 | } | ||
| 141 | |||
| 142 | TEST_F(SequencerTest, TestToggleTrackActivation) { | ||
| 143 | sequencer_internal_state.active_tracks = (1 << 7) + (1 << 6) + (1 << 3) + (1 << 1) + (1 << 0); | ||
| 144 | |||
| 145 | sequencer_toggle_track_activation(6); | ||
| 146 | |||
| 147 | EXPECT_EQ(is_sequencer_track_active(0), true); | ||
| 148 | EXPECT_EQ(is_sequencer_track_active(1), true); | ||
| 149 | EXPECT_EQ(is_sequencer_track_active(2), false); | ||
| 150 | EXPECT_EQ(is_sequencer_track_active(3), true); | ||
| 151 | EXPECT_EQ(is_sequencer_track_active(4), false); | ||
| 152 | EXPECT_EQ(is_sequencer_track_active(5), false); | ||
| 153 | EXPECT_EQ(is_sequencer_track_active(6), false); | ||
| 154 | EXPECT_EQ(is_sequencer_track_active(7), true); | ||
| 155 | } | ||
| 156 | |||
| 157 | TEST_F(SequencerTest, TestToggleSingleTrackActivation) { | ||
| 158 | sequencer_internal_state.active_tracks = (1 << 7) + (1 << 6) + (1 << 3) + (1 << 1) + (1 << 0); | ||
| 159 | |||
| 160 | sequencer_toggle_single_active_track(2); | ||
| 161 | |||
| 162 | EXPECT_EQ(is_sequencer_track_active(0), false); | ||
| 163 | EXPECT_EQ(is_sequencer_track_active(1), false); | ||
| 164 | EXPECT_EQ(is_sequencer_track_active(2), true); | ||
| 165 | EXPECT_EQ(is_sequencer_track_active(3), false); | ||
| 166 | EXPECT_EQ(is_sequencer_track_active(4), false); | ||
| 167 | EXPECT_EQ(is_sequencer_track_active(5), false); | ||
| 168 | EXPECT_EQ(is_sequencer_track_active(6), false); | ||
| 169 | EXPECT_EQ(is_sequencer_track_active(7), false); | ||
| 170 | } | ||
| 171 | |||
| 172 | TEST_F(SequencerTest, TestStepOffByDefault) { | ||
| 173 | for (int i = 0; i < SEQUENCER_STEPS; i++) { | ||
| 174 | EXPECT_EQ(is_sequencer_step_on(i), false); | ||
| 175 | } | ||
| 176 | } | ||
| 177 | |||
| 178 | TEST_F(SequencerTest, TestIsStepOffWithNoActiveTracks) { | ||
| 179 | sequencer_config.steps[3] = 0xFF; | ||
| 180 | EXPECT_EQ(is_sequencer_step_on(3), false); | ||
| 181 | } | ||
| 182 | |||
| 183 | TEST_F(SequencerTest, TestIsStepOffWithGivenActiveTracks) { | ||
| 184 | sequencer_set_track_activation(2, true); | ||
| 185 | sequencer_set_track_activation(3, true); | ||
| 186 | |||
| 187 | sequencer_config.steps[3] = (1 << 0) + (1 << 1); | ||
| 188 | |||
| 189 | // No active tracks have the step enabled, so it is off | ||
| 190 | EXPECT_EQ(is_sequencer_step_on(3), false); | ||
| 191 | } | ||
| 192 | |||
| 193 | TEST_F(SequencerTest, TestIsStepOnWithGivenActiveTracks) { | ||
| 194 | sequencer_set_track_activation(2, true); | ||
| 195 | sequencer_set_track_activation(3, true); | ||
| 196 | |||
| 197 | sequencer_config.steps[3] = (1 << 2); | ||
| 198 | |||
| 199 | // Track 2 has the step enabled, so it is on | ||
| 200 | EXPECT_EQ(is_sequencer_step_on(3), true); | ||
| 201 | } | ||
| 202 | |||
| 203 | TEST_F(SequencerTest, TestIsStepOffForGivenTrack) { | ||
| 204 | sequencer_config.steps[3] = 0x00; | ||
| 205 | EXPECT_EQ(is_sequencer_step_on_for_track(3, 5), false); | ||
| 206 | } | ||
| 207 | |||
| 208 | TEST_F(SequencerTest, TestIsStepOnForGivenTrack) { | ||
| 209 | sequencer_config.steps[3] = (1 << 5); | ||
| 210 | EXPECT_EQ(is_sequencer_step_on_for_track(3, 5), true); | ||
| 211 | } | ||
| 212 | |||
| 213 | TEST_F(SequencerTest, TestSetStepOn) { | ||
| 214 | sequencer_internal_state.active_tracks = (1 << 6) + (1 << 3) + (1 << 2); | ||
| 215 | sequencer_config.steps[2] = (1 << 5) + (1 << 2); | ||
| 216 | |||
| 217 | sequencer_set_step(2, true); | ||
| 218 | |||
| 219 | EXPECT_EQ(sequencer_config.steps[2], (1 << 6) + (1 << 5) + (1 << 3) + (1 << 2)); | ||
| 220 | } | ||
| 221 | |||
| 222 | TEST_F(SequencerTest, TestSetStepOff) { | ||
| 223 | sequencer_internal_state.active_tracks = (1 << 6) + (1 << 3) + (1 << 2); | ||
| 224 | sequencer_config.steps[2] = (1 << 5) + (1 << 2); | ||
| 225 | |||
| 226 | sequencer_set_step(2, false); | ||
| 227 | |||
| 228 | EXPECT_EQ(sequencer_config.steps[2], (1 << 5)); | ||
| 229 | } | ||
| 230 | |||
| 231 | TEST_F(SequencerTest, TestToggleStepOff) { | ||
| 232 | sequencer_internal_state.active_tracks = (1 << 6) + (1 << 3) + (1 << 2); | ||
| 233 | sequencer_config.steps[2] = (1 << 5) + (1 << 2); | ||
| 234 | |||
| 235 | sequencer_toggle_step(2); | ||
| 236 | |||
| 237 | EXPECT_EQ(sequencer_config.steps[2], (1 << 5)); | ||
| 238 | } | ||
| 239 | |||
| 240 | TEST_F(SequencerTest, TestToggleStepOn) { | ||
| 241 | sequencer_internal_state.active_tracks = (1 << 6) + (1 << 3) + (1 << 2); | ||
| 242 | sequencer_config.steps[2] = 0; | ||
| 243 | |||
| 244 | sequencer_toggle_step(2); | ||
| 245 | |||
| 246 | EXPECT_EQ(sequencer_config.steps[2], (1 << 6) + (1 << 3) + (1 << 2)); | ||
| 247 | } | ||
| 248 | |||
| 249 | TEST_F(SequencerTest, TestSetAllStepsOn) { | ||
| 250 | sequencer_internal_state.active_tracks = (1 << 6) + (1 << 3) + (1 << 2); | ||
| 251 | sequencer_config.steps[2] = (1 << 7) + (1 << 6); | ||
| 252 | sequencer_config.steps[4] = (1 << 3) + (1 << 1); | ||
| 253 | |||
| 254 | sequencer_set_all_steps(true); | ||
| 255 | |||
| 256 | EXPECT_EQ(sequencer_config.steps[2], (1 << 7) + (1 << 6) + (1 << 3) + (1 << 2)); | ||
| 257 | EXPECT_EQ(sequencer_config.steps[4], (1 << 6) + (1 << 3) + (1 << 2) + (1 << 1)); | ||
| 258 | } | ||
| 259 | |||
| 260 | TEST_F(SequencerTest, TestSetAllStepsOff) { | ||
| 261 | sequencer_internal_state.active_tracks = (1 << 6) + (1 << 3) + (1 << 2); | ||
| 262 | sequencer_config.steps[2] = (1 << 7) + (1 << 6); | ||
| 263 | sequencer_config.steps[4] = (1 << 3) + (1 << 1); | ||
| 264 | |||
| 265 | sequencer_set_all_steps(false); | ||
| 266 | |||
| 267 | EXPECT_EQ(sequencer_config.steps[2], (1 << 7)); | ||
| 268 | EXPECT_EQ(sequencer_config.steps[4], (1 << 1)); | ||
| 269 | } | ||
| 270 | |||
| 271 | TEST_F(SequencerTest, TestSetTempoZero) { | ||
| 272 | sequencer_config.tempo = 123; | ||
| 273 | |||
| 274 | sequencer_set_tempo(0); | ||
| 275 | |||
| 276 | EXPECT_EQ(sequencer_config.tempo, 123); | ||
| 277 | } | ||
| 278 | |||
| 279 | TEST_F(SequencerTest, TestIncreaseTempoMax) { | ||
| 280 | sequencer_config.tempo = UINT8_MAX; | ||
| 281 | |||
| 282 | sequencer_increase_tempo(); | ||
| 283 | |||
| 284 | EXPECT_EQ(sequencer_config.tempo, UINT8_MAX); | ||
| 285 | } | ||
| 286 | |||
| 287 | TEST_F(SequencerTest, TestSetResolutionLowerBound) { | ||
| 288 | sequencer_config.resolution = SQ_RES_4; | ||
| 289 | |||
| 290 | sequencer_set_resolution((sequencer_resolution_t)-1); | ||
| 291 | |||
| 292 | EXPECT_EQ(sequencer_config.resolution, SQ_RES_4); | ||
| 293 | } | ||
| 294 | |||
| 295 | TEST_F(SequencerTest, TestSetResolutionUpperBound) { | ||
| 296 | sequencer_config.resolution = SQ_RES_4; | ||
| 297 | |||
| 298 | sequencer_set_resolution(SEQUENCER_RESOLUTIONS); | ||
| 299 | |||
| 300 | EXPECT_EQ(sequencer_config.resolution, SQ_RES_4); | ||
| 301 | } | ||
| 302 | |||
| 303 | TEST_F(SequencerTest, TestGetBeatDuration) { | ||
| 304 | EXPECT_EQ(get_beat_duration(60), 1000); | ||
| 305 | EXPECT_EQ(get_beat_duration(120), 500); | ||
| 306 | EXPECT_EQ(get_beat_duration(240), 250); | ||
| 307 | EXPECT_EQ(get_beat_duration(0), 1000); | ||
| 308 | } | ||
| 309 | |||
| 310 | TEST_F(SequencerTest, TestGetStepDuration60) { | ||
| 311 | /** | ||
| 312 | * Resolution cheatsheet: | ||
| 313 | * 1/2 => 2 steps per 4 beats | ||
| 314 | * 1/2T => 3 steps per 4 beats | ||
| 315 | * 1/4 => 4 steps per 4 beats | ||
| 316 | * 1/4T => 6 steps per 4 beats | ||
| 317 | * 1/8 => 8 steps per 4 beats | ||
| 318 | * 1/8T => 12 steps per 4 beats | ||
| 319 | * 1/16 => 16 steps per 4 beats | ||
| 320 | * 1/16T => 24 steps per 4 beats | ||
| 321 | * 1/32 => 32 steps per 4 beats | ||
| 322 | * | ||
| 323 | * The number of steps for binary resolutions follows the powers of 2. | ||
| 324 | * The ternary variants are simply 1.5x faster. | ||
| 325 | */ | ||
| 326 | EXPECT_EQ(get_step_duration(60, SQ_RES_2), 2000); | ||
| 327 | EXPECT_EQ(get_step_duration(60, SQ_RES_4), 1000); | ||
| 328 | EXPECT_EQ(get_step_duration(60, SQ_RES_8), 500); | ||
| 329 | EXPECT_EQ(get_step_duration(60, SQ_RES_16), 250); | ||
| 330 | EXPECT_EQ(get_step_duration(60, SQ_RES_32), 125); | ||
| 331 | |||
| 332 | EXPECT_EQ(get_step_duration(60, SQ_RES_2T), 1333); | ||
| 333 | EXPECT_EQ(get_step_duration(60, SQ_RES_4T), 666); | ||
| 334 | EXPECT_EQ(get_step_duration(60, SQ_RES_8T), 333); | ||
| 335 | EXPECT_EQ(get_step_duration(60, SQ_RES_16T), 166); | ||
| 336 | } | ||
| 337 | |||
| 338 | TEST_F(SequencerTest, TestGetStepDuration120) { | ||
| 339 | /** | ||
| 340 | * Resolution cheatsheet: | ||
| 341 | * 1/2 => 2 steps per 4 beats | ||
| 342 | * 1/2T => 3 steps per 4 beats | ||
| 343 | * 1/4 => 4 steps per 4 beats | ||
| 344 | * 1/4T => 6 steps per 4 beats | ||
| 345 | * 1/8 => 8 steps per 4 beats | ||
| 346 | * 1/8T => 12 steps per 4 beats | ||
| 347 | * 1/16 => 16 steps per 4 beats | ||
| 348 | * 1/16T => 24 steps per 4 beats | ||
| 349 | * 1/32 => 32 steps per 4 beats | ||
| 350 | * | ||
| 351 | * The number of steps for binary resolutions follows the powers of 2. | ||
| 352 | * The ternary variants are simply 1.5x faster. | ||
| 353 | */ | ||
| 354 | EXPECT_EQ(get_step_duration(30, SQ_RES_2), 4000); | ||
| 355 | EXPECT_EQ(get_step_duration(30, SQ_RES_4), 2000); | ||
| 356 | EXPECT_EQ(get_step_duration(30, SQ_RES_8), 1000); | ||
| 357 | EXPECT_EQ(get_step_duration(30, SQ_RES_16), 500); | ||
| 358 | EXPECT_EQ(get_step_duration(30, SQ_RES_32), 250); | ||
| 359 | |||
| 360 | EXPECT_EQ(get_step_duration(30, SQ_RES_2T), 2666); | ||
| 361 | EXPECT_EQ(get_step_duration(30, SQ_RES_4T), 1333); | ||
| 362 | EXPECT_EQ(get_step_duration(30, SQ_RES_8T), 666); | ||
| 363 | EXPECT_EQ(get_step_duration(30, SQ_RES_16T), 333); | ||
| 364 | } | ||
| 365 | |||
| 366 | void setUpMatrixScanSequencerTest(void) { | ||
| 367 | sequencer_config.enabled = true; | ||
| 368 | sequencer_config.tempo = 120; | ||
| 369 | sequencer_config.resolution = SQ_RES_16; | ||
| 370 | |||
| 371 | // Configure the notes for each track | ||
| 372 | sequencer_config.track_notes[0] = MI_C; | ||
| 373 | sequencer_config.track_notes[1] = MI_D; | ||
| 374 | sequencer_config.track_notes[2] = MI_E; | ||
| 375 | sequencer_config.track_notes[3] = MI_F; | ||
| 376 | sequencer_config.track_notes[4] = MI_G; | ||
| 377 | sequencer_config.track_notes[5] = MI_A; | ||
| 378 | sequencer_config.track_notes[6] = MI_B; | ||
| 379 | sequencer_config.track_notes[7] = MI_C; | ||
| 380 | |||
| 381 | // Turn on some steps | ||
| 382 | sequencer_config.steps[0] = (1 << 0); | ||
| 383 | sequencer_config.steps[2] = (1 << 1) + (1 << 0); | ||
| 384 | } | ||
| 385 | |||
| 386 | TEST_F(SequencerTest, TestMatrixScanSequencerShouldAttackFirstTrackOfFirstStep) { | ||
| 387 | setUpMatrixScanSequencerTest(); | ||
| 388 | |||
| 389 | matrix_scan_sequencer(); | ||
| 390 | EXPECT_EQ(last_noteon, MI_C); | ||
| 391 | EXPECT_EQ(last_noteoff, 0); | ||
| 392 | } | ||
| 393 | |||
| 394 | TEST_F(SequencerTest, TestMatrixScanSequencerShouldAttackSecondTrackAfterFirstTrackOfFirstStep) { | ||
| 395 | setUpMatrixScanSequencerTest(); | ||
| 396 | |||
| 397 | matrix_scan_sequencer(); | ||
| 398 | EXPECT_EQ(sequencer_internal_state.current_step, 0); | ||
| 399 | EXPECT_EQ(sequencer_internal_state.current_track, 1); | ||
| 400 | EXPECT_EQ(sequencer_internal_state.phase, SEQUENCER_PHASE_ATTACK); | ||
| 401 | } | ||
| 402 | |||
| 403 | TEST_F(SequencerTest, TestMatrixScanSequencerShouldNotAttackInactiveTrackFirstStep) { | ||
| 404 | setUpMatrixScanSequencerTest(); | ||
| 405 | |||
| 406 | sequencer_internal_state.current_step = 0; | ||
| 407 | sequencer_internal_state.current_track = 1; | ||
| 408 | |||
| 409 | // Wait some time after the first track has been attacked | ||
| 410 | advance_time(SEQUENCER_TRACK_THROTTLE); | ||
| 411 | |||
| 412 | matrix_scan_sequencer(); | ||
| 413 | EXPECT_EQ(last_noteon, 0); | ||
| 414 | EXPECT_EQ(last_noteoff, 0); | ||
| 415 | } | ||
| 416 | |||
| 417 | TEST_F(SequencerTest, TestMatrixScanSequencerShouldAttackThirdTrackAfterSecondTrackOfFirstStep) { | ||
| 418 | setUpMatrixScanSequencerTest(); | ||
| 419 | |||
| 420 | sequencer_internal_state.current_step = 0; | ||
| 421 | sequencer_internal_state.current_track = 1; | ||
| 422 | |||
| 423 | // Wait some time after the second track has been attacked | ||
| 424 | advance_time(2 * SEQUENCER_TRACK_THROTTLE); | ||
| 425 | |||
| 426 | matrix_scan_sequencer(); | ||
| 427 | EXPECT_EQ(sequencer_internal_state.current_step, 0); | ||
| 428 | EXPECT_EQ(sequencer_internal_state.current_track, 2); | ||
| 429 | EXPECT_EQ(sequencer_internal_state.phase, SEQUENCER_PHASE_ATTACK); | ||
| 430 | } | ||
| 431 | |||
| 432 | TEST_F(SequencerTest, TestMatrixScanSequencerShouldEnterReleasePhaseAfterLastTrackHasBeenProcessedFirstStep) { | ||
| 433 | setUpMatrixScanSequencerTest(); | ||
| 434 | |||
| 435 | sequencer_internal_state.current_step = 0; | ||
| 436 | sequencer_internal_state.current_track = SEQUENCER_TRACKS - 1; | ||
| 437 | |||
| 438 | // Wait until all notes have been attacked | ||
| 439 | advance_time((SEQUENCER_TRACKS - 1) * SEQUENCER_TRACK_THROTTLE); | ||
| 440 | |||
| 441 | matrix_scan_sequencer(); | ||
| 442 | EXPECT_EQ(last_noteon, 0); | ||
| 443 | EXPECT_EQ(last_noteoff, 0); | ||
| 444 | EXPECT_EQ(sequencer_internal_state.current_step, 0); | ||
| 445 | EXPECT_EQ(sequencer_internal_state.current_track, SEQUENCER_TRACKS - 1); | ||
| 446 | EXPECT_EQ(sequencer_internal_state.phase, SEQUENCER_PHASE_RELEASE); | ||
| 447 | } | ||
| 448 | |||
| 449 | TEST_F(SequencerTest, TestMatrixScanSequencerShouldReleaseBackwards) { | ||
| 450 | setUpMatrixScanSequencerTest(); | ||
| 451 | |||
| 452 | sequencer_internal_state.current_step = 0; | ||
| 453 | sequencer_internal_state.current_track = SEQUENCER_TRACKS - 1; | ||
| 454 | sequencer_internal_state.phase = SEQUENCER_PHASE_RELEASE; | ||
| 455 | |||
| 456 | // Wait until all notes have been attacked | ||
| 457 | advance_time((SEQUENCER_TRACKS - 1) * SEQUENCER_TRACK_THROTTLE); | ||
| 458 | // + the release timeout | ||
| 459 | advance_time(SEQUENCER_PHASE_RELEASE_TIMEOUT); | ||
| 460 | |||
| 461 | matrix_scan_sequencer(); | ||
| 462 | EXPECT_EQ(sequencer_internal_state.current_step, 0); | ||
| 463 | EXPECT_EQ(sequencer_internal_state.current_track, SEQUENCER_TRACKS - 2); | ||
| 464 | EXPECT_EQ(sequencer_internal_state.phase, SEQUENCER_PHASE_RELEASE); | ||
| 465 | } | ||
| 466 | |||
| 467 | TEST_F(SequencerTest, TestMatrixScanSequencerShouldNotReleaseInactiveTrackFirstStep) { | ||
| 468 | setUpMatrixScanSequencerTest(); | ||
| 469 | |||
| 470 | sequencer_internal_state.current_step = 0; | ||
| 471 | sequencer_internal_state.current_track = SEQUENCER_TRACKS - 1; | ||
| 472 | sequencer_internal_state.phase = SEQUENCER_PHASE_RELEASE; | ||
| 473 | |||
| 474 | // Wait until all notes have been attacked | ||
| 475 | advance_time((SEQUENCER_TRACKS - 1) * SEQUENCER_TRACK_THROTTLE); | ||
| 476 | // + the release timeout | ||
| 477 | advance_time(SEQUENCER_PHASE_RELEASE_TIMEOUT); | ||
| 478 | |||
| 479 | matrix_scan_sequencer(); | ||
| 480 | EXPECT_EQ(last_noteon, 0); | ||
| 481 | EXPECT_EQ(last_noteoff, 0); | ||
| 482 | } | ||
| 483 | |||
| 484 | TEST_F(SequencerTest, TestMatrixScanSequencerShouldReleaseFirstTrackFirstStep) { | ||
| 485 | setUpMatrixScanSequencerTest(); | ||
| 486 | |||
| 487 | sequencer_internal_state.current_step = 0; | ||
| 488 | sequencer_internal_state.current_track = 0; | ||
| 489 | sequencer_internal_state.phase = SEQUENCER_PHASE_RELEASE; | ||
| 490 | |||
| 491 | // Wait until all notes have been attacked | ||
| 492 | advance_time((SEQUENCER_TRACKS - 1) * SEQUENCER_TRACK_THROTTLE); | ||
| 493 | // + the release timeout | ||
| 494 | advance_time(SEQUENCER_PHASE_RELEASE_TIMEOUT); | ||
| 495 | // + all the other notes have been released | ||
| 496 | advance_time((SEQUENCER_TRACKS - 1) * SEQUENCER_TRACK_THROTTLE); | ||
| 497 | |||
| 498 | matrix_scan_sequencer(); | ||
| 499 | EXPECT_EQ(last_noteon, 0); | ||
| 500 | EXPECT_EQ(last_noteoff, MI_C); | ||
| 501 | } | ||
| 502 | |||
| 503 | TEST_F(SequencerTest, TestMatrixScanSequencerShouldEnterPausePhaseAfterRelease) { | ||
| 504 | setUpMatrixScanSequencerTest(); | ||
| 505 | |||
| 506 | sequencer_internal_state.current_step = 0; | ||
| 507 | sequencer_internal_state.current_track = 0; | ||
| 508 | sequencer_internal_state.phase = SEQUENCER_PHASE_RELEASE; | ||
| 509 | |||
| 510 | // Wait until all notes have been attacked | ||
| 511 | advance_time((SEQUENCER_TRACKS - 1) * SEQUENCER_TRACK_THROTTLE); | ||
| 512 | // + the release timeout | ||
| 513 | advance_time(SEQUENCER_PHASE_RELEASE_TIMEOUT); | ||
| 514 | // + all the other notes have been released | ||
| 515 | advance_time((SEQUENCER_TRACKS - 1) * SEQUENCER_TRACK_THROTTLE); | ||
| 516 | |||
| 517 | matrix_scan_sequencer(); | ||
| 518 | EXPECT_EQ(sequencer_internal_state.current_step, 0); | ||
| 519 | EXPECT_EQ(sequencer_internal_state.current_track, 0); | ||
| 520 | EXPECT_EQ(sequencer_internal_state.phase, SEQUENCER_PHASE_PAUSE); | ||
| 521 | } | ||
| 522 | |||
| 523 | TEST_F(SequencerTest, TestMatrixScanSequencerShouldProcessFirstTrackOfSecondStepAfterPause) { | ||
| 524 | setUpMatrixScanSequencerTest(); | ||
| 525 | |||
| 526 | sequencer_internal_state.current_step = 0; | ||
| 527 | sequencer_internal_state.current_track = 0; | ||
| 528 | sequencer_internal_state.phase = SEQUENCER_PHASE_PAUSE; | ||
| 529 | |||
| 530 | // Wait until all notes have been attacked | ||
| 531 | advance_time((SEQUENCER_TRACKS - 1) * SEQUENCER_TRACK_THROTTLE); | ||
| 532 | // + the release timeout | ||
| 533 | advance_time(SEQUENCER_PHASE_RELEASE_TIMEOUT); | ||
| 534 | // + all the other notes have been released | ||
| 535 | advance_time((SEQUENCER_TRACKS - 1) * SEQUENCER_TRACK_THROTTLE); | ||
| 536 | // + the step duration (one 16th at tempo=120 lasts 125ms) | ||
| 537 | advance_time(125); | ||
| 538 | |||
| 539 | matrix_scan_sequencer(); | ||
| 540 | EXPECT_EQ(sequencer_internal_state.current_step, 1); | ||
| 541 | EXPECT_EQ(sequencer_internal_state.current_track, 1); | ||
| 542 | EXPECT_EQ(sequencer_internal_state.phase, SEQUENCER_PHASE_ATTACK); | ||
| 543 | } | ||
| 544 | |||
| 545 | TEST_F(SequencerTest, TestMatrixScanSequencerShouldProcessSecondTrackTooEarly) { | ||
| 546 | setUpMatrixScanSequencerTest(); | ||
| 547 | |||
| 548 | sequencer_internal_state.current_step = 2; | ||
| 549 | sequencer_internal_state.current_track = 1; | ||
| 550 | |||
| 551 | matrix_scan_sequencer(); | ||
| 552 | EXPECT_EQ(last_noteon, 0); | ||
| 553 | EXPECT_EQ(last_noteoff, 0); | ||
| 554 | } | ||
| 555 | |||
| 556 | TEST_F(SequencerTest, TestMatrixScanSequencerShouldProcessSecondTrackOnTime) { | ||
| 557 | setUpMatrixScanSequencerTest(); | ||
| 558 | |||
| 559 | sequencer_internal_state.current_step = 2; | ||
| 560 | sequencer_internal_state.current_track = 1; | ||
| 561 | |||
| 562 | // Wait until first track has been attacked | ||
| 563 | advance_time(SEQUENCER_TRACK_THROTTLE); | ||
| 564 | |||
| 565 | matrix_scan_sequencer(); | ||
| 566 | EXPECT_EQ(last_noteon, MI_D); | ||
| 567 | EXPECT_EQ(last_noteoff, 0); | ||
| 568 | } | ||
| 569 | |||
| 570 | TEST_F(SequencerTest, TestMatrixScanSequencerShouldLoopOnceSequenceIsOver) { | ||
| 571 | setUpMatrixScanSequencerTest(); | ||
| 572 | |||
| 573 | sequencer_internal_state.current_step = SEQUENCER_STEPS - 1; | ||
| 574 | sequencer_internal_state.current_track = 0; | ||
| 575 | sequencer_internal_state.phase = SEQUENCER_PHASE_PAUSE; | ||
| 576 | |||
| 577 | // Wait until all notes have been attacked | ||
| 578 | advance_time((SEQUENCER_TRACKS - 1) * SEQUENCER_TRACK_THROTTLE); | ||
| 579 | // + the release timeout | ||
| 580 | advance_time(SEQUENCER_PHASE_RELEASE_TIMEOUT); | ||
| 581 | // + all the other notes have been released | ||
| 582 | advance_time((SEQUENCER_TRACKS - 1) * SEQUENCER_TRACK_THROTTLE); | ||
| 583 | // + the step duration (one 16th at tempo=120 lasts 125ms) | ||
| 584 | advance_time(125); | ||
| 585 | |||
| 586 | matrix_scan_sequencer(); | ||
| 587 | EXPECT_EQ(sequencer_internal_state.current_step, 0); | ||
| 588 | EXPECT_EQ(sequencer_internal_state.current_track, 1); | ||
| 589 | EXPECT_EQ(sequencer_internal_state.phase, SEQUENCER_PHASE_ATTACK); | ||
| 590 | } | ||
diff --git a/quantum/sequencer/tests/testlist.mk b/quantum/sequencer/tests/testlist.mk new file mode 100644 index 000000000..bb3899110 --- /dev/null +++ b/quantum/sequencer/tests/testlist.mk | |||
| @@ -0,0 +1 @@ | |||
| TEST_LIST += sequencer | |||
diff --git a/quantum/split_common/matrix.c b/quantum/split_common/matrix.c index 5bad9db08..cd5a024c3 100644 --- a/quantum/split_common/matrix.c +++ b/quantum/split_common/matrix.c | |||
| @@ -45,6 +45,19 @@ uint8_t thisHand, thatHand; | |||
| 45 | // user-defined overridable functions | 45 | // user-defined overridable functions |
| 46 | __attribute__((weak)) void matrix_slave_scan_user(void) {} | 46 | __attribute__((weak)) void matrix_slave_scan_user(void) {} |
| 47 | 47 | ||
| 48 | static inline void setPinOutput_writeLow(pin_t pin) { | ||
| 49 | ATOMIC_BLOCK_FORCEON { | ||
| 50 | setPinOutput(pin); | ||
| 51 | writePinLow(pin); | ||
| 52 | } | ||
| 53 | } | ||
| 54 | |||
| 55 | static inline void setPinInputHigh_atomic(pin_t pin) { | ||
| 56 | ATOMIC_BLOCK_FORCEON { | ||
| 57 | setPinInputHigh(pin); | ||
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 48 | // matrix code | 61 | // matrix code |
| 49 | 62 | ||
| 50 | #ifdef DIRECT_PINS | 63 | #ifdef DIRECT_PINS |
| @@ -83,22 +96,23 @@ static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row) | |||
| 83 | # if (DIODE_DIRECTION == COL2ROW) | 96 | # if (DIODE_DIRECTION == COL2ROW) |
| 84 | 97 | ||
| 85 | static void select_row(uint8_t row) { | 98 | static void select_row(uint8_t row) { |
| 86 | setPinOutput(row_pins[row]); | 99 | setPinOutput_writeLow(row_pins[row]); |
| 87 | writePinLow(row_pins[row]); | ||
| 88 | } | 100 | } |
| 89 | 101 | ||
| 90 | static void unselect_row(uint8_t row) { setPinInputHigh(row_pins[row]); } | 102 | static void unselect_row(uint8_t row) { |
| 103 | setPinInputHigh_atomic(row_pins[row]); | ||
| 104 | } | ||
| 91 | 105 | ||
| 92 | static void unselect_rows(void) { | 106 | static void unselect_rows(void) { |
| 93 | for (uint8_t x = 0; x < ROWS_PER_HAND; x++) { | 107 | for (uint8_t x = 0; x < ROWS_PER_HAND; x++) { |
| 94 | setPinInputHigh(row_pins[x]); | 108 | setPinInputHigh_atomic(row_pins[x]); |
| 95 | } | 109 | } |
| 96 | } | 110 | } |
| 97 | 111 | ||
| 98 | static void init_pins(void) { | 112 | static void init_pins(void) { |
| 99 | unselect_rows(); | 113 | unselect_rows(); |
| 100 | for (uint8_t x = 0; x < MATRIX_COLS; x++) { | 114 | for (uint8_t x = 0; x < MATRIX_COLS; x++) { |
| 101 | setPinInputHigh(col_pins[x]); | 115 | setPinInputHigh_atomic(col_pins[x]); |
| 102 | } | 116 | } |
| 103 | } | 117 | } |
| 104 | 118 | ||
| @@ -133,22 +147,23 @@ static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row) | |||
| 133 | # elif (DIODE_DIRECTION == ROW2COL) | 147 | # elif (DIODE_DIRECTION == ROW2COL) |
| 134 | 148 | ||
| 135 | static void select_col(uint8_t col) { | 149 | static void select_col(uint8_t col) { |
| 136 | setPinOutput(col_pins[col]); | 150 | setPinOutput_writeLow(col_pins[col]); |
| 137 | writePinLow(col_pins[col]); | ||
| 138 | } | 151 | } |
| 139 | 152 | ||
| 140 | static void unselect_col(uint8_t col) { setPinInputHigh(col_pins[col]); } | 153 | static void unselect_col(uint8_t col) { |
| 154 | setPinInputHigh_atomic(col_pins[col]); | ||
| 155 | } | ||
| 141 | 156 | ||
| 142 | static void unselect_cols(void) { | 157 | static void unselect_cols(void) { |
| 143 | for (uint8_t x = 0; x < MATRIX_COLS; x++) { | 158 | for (uint8_t x = 0; x < MATRIX_COLS; x++) { |
| 144 | setPinInputHigh(col_pins[x]); | 159 | setPinInputHigh_atomic(col_pins[x]); |
| 145 | } | 160 | } |
| 146 | } | 161 | } |
| 147 | 162 | ||
| 148 | static void init_pins(void) { | 163 | static void init_pins(void) { |
| 149 | unselect_cols(); | 164 | unselect_cols(); |
| 150 | for (uint8_t x = 0; x < ROWS_PER_HAND; x++) { | 165 | for (uint8_t x = 0; x < ROWS_PER_HAND; x++) { |
| 151 | setPinInputHigh(row_pins[x]); | 166 | setPinInputHigh_atomic(row_pins[x]); |
| 152 | } | 167 | } |
| 153 | } | 168 | } |
| 154 | 169 | ||
