qmk_firmware

QMK firmware for my keyboards (Corne, Sweep Ferris) and trackball (Ploopy Adept)
Log | Files | Refs | Submodules | LICENSE

rgb_matrix.c (28684B)


      1 /* Copyright 2017 Jason Williams
      2  * Copyright 2017 Jack Humbert
      3  * Copyright 2018 Yiancar
      4  *
      5  * This program is free software: you can redistribute it and/or modify
      6  * it under the terms of the GNU General Public License as published by
      7  * the Free Software Foundation, either version 2 of the License, or
      8  * (at your option) any later version.
      9  *
     10  * This program is distributed in the hope that it will be useful,
     11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13  * GNU General Public License for more details.
     14  *
     15  * You should have received a copy of the GNU General Public License
     16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
     17  */
     18 
     19 #include "rgb_matrix.h"
     20 #include "progmem.h"
     21 #include "eeconfig.h"
     22 #include "keyboard.h"
     23 #include "sync_timer.h"
     24 #include "debug.h"
     25 #include <string.h>
     26 #include <math.h>
     27 #include <stdlib.h>
     28 
     29 #include <lib/lib8tion/lib8tion.h>
     30 
     31 #ifndef RGB_MATRIX_CENTER
     32 const led_point_t k_rgb_matrix_center = {112, 32};
     33 #else
     34 const led_point_t k_rgb_matrix_center = RGB_MATRIX_CENTER;
     35 #endif
     36 
     37 __attribute__((weak)) rgb_t rgb_matrix_hsv_to_rgb(hsv_t hsv) {
     38     return hsv_to_rgb(hsv);
     39 }
     40 
     41 // Generic effect runners
     42 #include "rgb_matrix_runners.inc"
     43 
     44 // ------------------------------------------
     45 // -----Begin rgb effect includes macros-----
     46 #define RGB_MATRIX_EFFECT(name)
     47 #define RGB_MATRIX_CUSTOM_EFFECT_IMPLS
     48 
     49 #include "rgb_matrix_effects.inc"
     50 #ifdef COMMUNITY_MODULES_ENABLE
     51 #    include "rgb_matrix_community_modules.inc"
     52 #endif
     53 #ifdef RGB_MATRIX_CUSTOM_KB
     54 #    include "rgb_matrix_kb.inc"
     55 #endif
     56 #ifdef RGB_MATRIX_CUSTOM_USER
     57 #    include "rgb_matrix_user.inc"
     58 #endif
     59 
     60 #undef RGB_MATRIX_CUSTOM_EFFECT_IMPLS
     61 #undef RGB_MATRIX_EFFECT
     62 // -----End rgb effect includes macros-------
     63 // ------------------------------------------
     64 
     65 // globals
     66 rgb_config_t rgb_matrix_config; // TODO: would like to prefix this with g_ for global consistancy, do this in another pr
     67 uint32_t     g_rgb_timer;
     68 #ifdef RGB_MATRIX_FRAMEBUFFER_EFFECTS
     69 uint8_t g_rgb_frame_buffer[MATRIX_ROWS][MATRIX_COLS] = {{0}};
     70 #endif // RGB_MATRIX_FRAMEBUFFER_EFFECTS
     71 #ifdef RGB_MATRIX_KEYREACTIVE_ENABLED
     72 last_hit_t g_last_hit_tracker;
     73 #endif // RGB_MATRIX_KEYREACTIVE_ENABLED
     74 
     75 #ifndef RGB_MATRIX_FLAG_STEPS
     76 #    define RGB_MATRIX_FLAG_STEPS {LED_FLAG_ALL, LED_FLAG_KEYLIGHT | LED_FLAG_MODIFIER, LED_FLAG_UNDERGLOW, LED_FLAG_NONE}
     77 #endif
     78 static const uint8_t rgb_matrix_flag_steps[] = RGB_MATRIX_FLAG_STEPS;
     79 #define RGB_MATRIX_FLAG_STEPS_COUNT ARRAY_SIZE(rgb_matrix_flag_steps)
     80 
     81 // internals
     82 static bool            suspend_state      = false;
     83 static uint8_t         rgb_last_enable    = UINT8_MAX;
     84 static uint8_t         rgb_last_effect    = UINT8_MAX;
     85 static uint8_t         rgb_current_effect = 0;
     86 static effect_params_t rgb_effect_params  = {0, LED_FLAG_ALL, false};
     87 static rgb_task_states rgb_task_state     = SYNCING;
     88 
     89 // double buffers
     90 static uint32_t rgb_timer_buffer;
     91 #ifdef RGB_MATRIX_KEYREACTIVE_ENABLED
     92 static last_hit_t last_hit_buffer;
     93 #endif // RGB_MATRIX_KEYREACTIVE_ENABLED
     94 
     95 // split rgb matrix
     96 #if defined(RGB_MATRIX_SPLIT)
     97 const uint8_t k_rgb_matrix_split[2] = RGB_MATRIX_SPLIT;
     98 #endif
     99 
    100 EECONFIG_DEBOUNCE_HELPER(rgb_matrix, rgb_matrix_config);
    101 
    102 void eeconfig_force_flush_rgb_matrix(void) {
    103     eeconfig_flush_rgb_matrix(true);
    104 }
    105 
    106 void eeconfig_update_rgb_matrix_default(void) {
    107     dprintf("eeconfig_update_rgb_matrix_default\n");
    108     rgb_matrix_config.enable = RGB_MATRIX_DEFAULT_ON;
    109     rgb_matrix_config.mode   = RGB_MATRIX_DEFAULT_MODE;
    110     rgb_matrix_config.hsv    = (hsv_t){RGB_MATRIX_DEFAULT_HUE, RGB_MATRIX_DEFAULT_SAT, RGB_MATRIX_DEFAULT_VAL};
    111     rgb_matrix_config.speed  = RGB_MATRIX_DEFAULT_SPD;
    112     rgb_matrix_config.flags  = RGB_MATRIX_DEFAULT_FLAGS;
    113     eeconfig_flush_rgb_matrix(true);
    114 }
    115 
    116 void eeconfig_debug_rgb_matrix(void) {
    117     dprintf("rgb_matrix_config EEPROM\n");
    118     dprintf("rgb_matrix_config.enable = %d\n", rgb_matrix_config.enable);
    119 #ifdef RGB_MATRIX_MODE_NAME_ENABLE
    120     dprintf("rgb_matrix_config.mode = %d (%s)\n", rgb_matrix_config.mode, rgb_matrix_get_mode_name(rgb_matrix_config.mode));
    121 #else
    122     dprintf("rgb_matrix_config.mode = %d\n", rgb_matrix_config.mode);
    123 #endif // RGB_MATRIX_MODE_NAME_ENABLE
    124     dprintf("rgb_matrix_config.hsv.h = %d\n", rgb_matrix_config.hsv.h);
    125     dprintf("rgb_matrix_config.hsv.s = %d\n", rgb_matrix_config.hsv.s);
    126     dprintf("rgb_matrix_config.hsv.v = %d\n", rgb_matrix_config.hsv.v);
    127     dprintf("rgb_matrix_config.speed = %d\n", rgb_matrix_config.speed);
    128     dprintf("rgb_matrix_config.flags = %d\n", rgb_matrix_config.flags);
    129 }
    130 
    131 void rgb_matrix_reload_from_eeprom(void) {
    132     rgb_matrix_disable_noeeprom();
    133     /* Reset back to what we have in eeprom */
    134     eeconfig_init_rgb_matrix();
    135     eeconfig_debug_rgb_matrix(); // display current eeprom values
    136     if (rgb_matrix_config.enable) {
    137         rgb_matrix_mode_noeeprom(rgb_matrix_config.mode);
    138     }
    139 }
    140 
    141 __attribute__((weak)) uint8_t rgb_matrix_map_row_column_to_led_kb(uint8_t row, uint8_t column, uint8_t *led_i) {
    142     return 0;
    143 }
    144 
    145 uint8_t rgb_matrix_map_row_column_to_led(uint8_t row, uint8_t column, uint8_t *led_i) {
    146     uint8_t led_count = rgb_matrix_map_row_column_to_led_kb(row, column, led_i);
    147     uint8_t led_index = g_led_config.matrix_co[row][column];
    148     if (led_index != NO_LED) {
    149         led_i[led_count] = led_index;
    150         led_count++;
    151     }
    152     return led_count;
    153 }
    154 
    155 void rgb_matrix_update_pwm_buffers(void) {
    156     rgb_matrix_driver.flush();
    157 }
    158 
    159 __attribute__((weak)) int rgb_matrix_led_index(int index) {
    160 #if defined(RGB_MATRIX_SPLIT)
    161     if (!is_keyboard_left() && index >= k_rgb_matrix_split[0]) {
    162         return index - k_rgb_matrix_split[0];
    163     }
    164 #endif
    165     return index;
    166 }
    167 
    168 void rgb_matrix_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) {
    169     rgb_matrix_driver.set_color(rgb_matrix_led_index(index), red, green, blue);
    170 }
    171 
    172 void rgb_matrix_set_color_all(uint8_t red, uint8_t green, uint8_t blue) {
    173 #if defined(RGB_MATRIX_SPLIT)
    174     for (uint8_t i = 0; i < RGB_MATRIX_LED_COUNT; i++)
    175         rgb_matrix_set_color(i, red, green, blue);
    176 #else
    177     rgb_matrix_driver.set_color_all(red, green, blue);
    178 #endif
    179 }
    180 
    181 void rgb_matrix_handle_key_event(uint8_t row, uint8_t col, bool pressed) {
    182 #ifndef RGB_MATRIX_SPLIT
    183     if (!is_keyboard_master()) return;
    184 #endif
    185 
    186 #ifdef RGB_MATRIX_KEYREACTIVE_ENABLED
    187     uint8_t led[LED_HITS_TO_REMEMBER];
    188     uint8_t led_count = 0;
    189 
    190 #    if defined(RGB_MATRIX_KEYRELEASES)
    191     if (!pressed)
    192 #    elif defined(RGB_MATRIX_KEYPRESSES)
    193     if (pressed)
    194 #    endif // defined(RGB_MATRIX_KEYRELEASES)
    195     {
    196         led_count = rgb_matrix_map_row_column_to_led(row, col, led);
    197     }
    198 
    199     if (last_hit_buffer.count + led_count > LED_HITS_TO_REMEMBER) {
    200         memcpy(&last_hit_buffer.x[0], &last_hit_buffer.x[led_count], LED_HITS_TO_REMEMBER - led_count);
    201         memcpy(&last_hit_buffer.y[0], &last_hit_buffer.y[led_count], LED_HITS_TO_REMEMBER - led_count);
    202         memcpy(&last_hit_buffer.tick[0], &last_hit_buffer.tick[led_count], (LED_HITS_TO_REMEMBER - led_count) * 2); // 16 bit
    203         memcpy(&last_hit_buffer.index[0], &last_hit_buffer.index[led_count], LED_HITS_TO_REMEMBER - led_count);
    204         last_hit_buffer.count = LED_HITS_TO_REMEMBER - led_count;
    205     }
    206 
    207     for (uint8_t i = 0; i < led_count; i++) {
    208         uint8_t index                = last_hit_buffer.count;
    209         last_hit_buffer.x[index]     = g_led_config.point[led[i]].x;
    210         last_hit_buffer.y[index]     = g_led_config.point[led[i]].y;
    211         last_hit_buffer.index[index] = led[i];
    212         last_hit_buffer.tick[index]  = 0;
    213         last_hit_buffer.count++;
    214     }
    215 #endif // RGB_MATRIX_KEYREACTIVE_ENABLED
    216 
    217 #if defined(RGB_MATRIX_FRAMEBUFFER_EFFECTS) && defined(ENABLE_RGB_MATRIX_TYPING_HEATMAP)
    218 #    if defined(RGB_MATRIX_KEYRELEASES)
    219     if (!pressed)
    220 #    else
    221     if (pressed)
    222 #    endif // defined(RGB_MATRIX_KEYRELEASES)
    223     {
    224         if (rgb_matrix_config.mode == RGB_MATRIX_TYPING_HEATMAP) {
    225             process_rgb_matrix_typing_heatmap(row, col);
    226         }
    227     }
    228 #endif // defined(RGB_MATRIX_FRAMEBUFFER_EFFECTS) && defined(ENABLE_RGB_MATRIX_TYPING_HEATMAP)
    229 }
    230 
    231 void rgb_matrix_test(void) {
    232     // Mask out bits 4 and 5
    233     // Increase the factor to make the test animation slower (and reduce to make it faster)
    234     uint8_t factor = 10;
    235     switch ((g_rgb_timer & (0b11 << factor)) >> factor) {
    236         case 0: {
    237             rgb_matrix_set_color_all(20, 0, 0);
    238             break;
    239         }
    240         case 1: {
    241             rgb_matrix_set_color_all(0, 20, 0);
    242             break;
    243         }
    244         case 2: {
    245             rgb_matrix_set_color_all(0, 0, 20);
    246             break;
    247         }
    248         case 3: {
    249             rgb_matrix_set_color_all(20, 20, 20);
    250             break;
    251         }
    252     }
    253 }
    254 
    255 static bool rgb_matrix_none(effect_params_t *params) {
    256     if (!params->init) {
    257         return false;
    258     }
    259 
    260     rgb_matrix_set_color_all(0, 0, 0);
    261     return false;
    262 }
    263 
    264 static void rgb_task_timers(void) {
    265 #if defined(RGB_MATRIX_KEYREACTIVE_ENABLED)
    266     uint32_t deltaTime = sync_timer_elapsed32(rgb_timer_buffer);
    267 #endif // defined(RGB_MATRIX_KEYREACTIVE_ENABLED)
    268     rgb_timer_buffer = sync_timer_read32();
    269 
    270     // Update double buffer last hit timers
    271 #ifdef RGB_MATRIX_KEYREACTIVE_ENABLED
    272     uint8_t count = last_hit_buffer.count;
    273     for (uint8_t i = 0; i < count; ++i) {
    274         if (UINT16_MAX - deltaTime < last_hit_buffer.tick[i]) {
    275             last_hit_buffer.count--;
    276             continue;
    277         }
    278         last_hit_buffer.tick[i] += deltaTime;
    279     }
    280 #endif // RGB_MATRIX_KEYREACTIVE_ENABLED
    281 }
    282 
    283 static void rgb_task_sync(void) {
    284     eeconfig_flush_rgb_matrix(false);
    285     // next task
    286     if (sync_timer_elapsed32(g_rgb_timer) >= RGB_MATRIX_LED_FLUSH_LIMIT) rgb_task_state = STARTING;
    287 }
    288 
    289 static void rgb_task_start(void) {
    290     // reset iter
    291     rgb_effect_params.iter = 0;
    292 
    293     // update double buffers
    294     g_rgb_timer = rgb_timer_buffer;
    295 #ifdef RGB_MATRIX_KEYREACTIVE_ENABLED
    296     g_last_hit_tracker = last_hit_buffer;
    297 #endif // RGB_MATRIX_KEYREACTIVE_ENABLED
    298 
    299     // Ideally we would also stop sending zeros to the LED driver PWM buffers
    300     // while suspended and just do a software shutdown. This is a cheap hack for now.
    301     bool suspend_backlight = suspend_state ||
    302 #if RGB_MATRIX_TIMEOUT > 0
    303                              (last_input_activity_elapsed() > (uint32_t)RGB_MATRIX_TIMEOUT) ||
    304 #endif // RGB_MATRIX_TIMEOUT > 0
    305                              false;
    306 
    307     // Set effect to be renedered
    308     rgb_current_effect = suspend_backlight || !rgb_matrix_config.enable ? 0 : rgb_matrix_config.mode;
    309 
    310     // next task
    311     rgb_task_state = RENDERING;
    312 }
    313 
    314 static void rgb_task_render(uint8_t effect) {
    315     bool rendering         = false;
    316     rgb_effect_params.init = (effect != rgb_last_effect) || (rgb_matrix_config.enable != rgb_last_enable);
    317     if (rgb_effect_params.flags != rgb_matrix_config.flags) {
    318         rgb_effect_params.flags = rgb_matrix_config.flags;
    319         rgb_matrix_set_color_all(0, 0, 0);
    320     }
    321 
    322     // each effect can opt to do calculations
    323     // and/or request PWM buffer updates.
    324     switch (effect) {
    325         case RGB_MATRIX_NONE:
    326             rendering = rgb_matrix_none(&rgb_effect_params);
    327             break;
    328 
    329 // ---------------------------------------------
    330 // -----Begin rgb effect switch case macros-----
    331 #define RGB_MATRIX_EFFECT(name, ...)          \
    332     case RGB_MATRIX_##name:                   \
    333         rendering = name(&rgb_effect_params); \
    334         break;
    335 #include "rgb_matrix_effects.inc"
    336 #undef RGB_MATRIX_EFFECT
    337 
    338 #ifdef COMMUNITY_MODULES_ENABLE
    339 #    define RGB_MATRIX_EFFECT(name, ...)          \
    340         case RGB_MATRIX_COMMUNITY_MODULE_##name:  \
    341             rendering = name(&rgb_effect_params); \
    342             break;
    343 #    include "rgb_matrix_community_modules.inc"
    344 #    undef RGB_MATRIX_EFFECT
    345 #endif
    346 
    347 #if defined(RGB_MATRIX_CUSTOM_KB) || defined(RGB_MATRIX_CUSTOM_USER)
    348 #    define RGB_MATRIX_EFFECT(name, ...)          \
    349         case RGB_MATRIX_CUSTOM_##name:            \
    350             rendering = name(&rgb_effect_params); \
    351             break;
    352 #    ifdef RGB_MATRIX_CUSTOM_KB
    353 #        include "rgb_matrix_kb.inc"
    354 #    endif
    355 #    ifdef RGB_MATRIX_CUSTOM_USER
    356 #        include "rgb_matrix_user.inc"
    357 #    endif
    358 #    undef RGB_MATRIX_EFFECT
    359 #endif
    360             // -----End rgb effect switch case macros-------
    361             // ---------------------------------------------
    362 
    363         // Factory default magic value
    364         case UINT8_MAX: {
    365             rgb_matrix_test();
    366             rgb_task_state = FLUSHING;
    367         }
    368             return;
    369     }
    370 
    371     rgb_effect_params.iter++;
    372 
    373     // next task
    374     if (!rendering) {
    375         rgb_task_state = FLUSHING;
    376         if (!rgb_effect_params.init && effect == RGB_MATRIX_NONE) {
    377             // We only need to flush once if we are RGB_MATRIX_NONE
    378             rgb_task_state = SYNCING;
    379         }
    380     }
    381 }
    382 
    383 static void rgb_task_flush(uint8_t effect) {
    384     // update last trackers after the first full render so we can init over several frames
    385     rgb_last_effect = effect;
    386     rgb_last_enable = rgb_matrix_config.enable;
    387 
    388     // update pwm buffers
    389     rgb_matrix_update_pwm_buffers();
    390 
    391     // next task
    392     rgb_task_state = SYNCING;
    393 }
    394 
    395 void rgb_matrix_task(void) {
    396     rgb_task_timers();
    397 
    398     uint8_t effect = rgb_current_effect;
    399 
    400     switch (rgb_task_state) {
    401         case STARTING:
    402             rgb_task_start();
    403             break;
    404         case RENDERING:
    405             rgb_task_render(effect);
    406             if (effect) {
    407                 if (rgb_task_state == FLUSHING) { // ensure we only draw basic indicators once rendering is finished
    408                     rgb_matrix_indicators();
    409                 }
    410                 rgb_matrix_indicators_advanced(&rgb_effect_params);
    411             }
    412             break;
    413         case FLUSHING:
    414             rgb_task_flush(effect);
    415             break;
    416         case SYNCING:
    417             rgb_task_sync();
    418             break;
    419     }
    420 }
    421 
    422 __attribute__((weak)) bool rgb_matrix_indicators_modules(void) {
    423     return true;
    424 }
    425 
    426 void rgb_matrix_indicators(void) {
    427     rgb_matrix_indicators_modules();
    428     rgb_matrix_indicators_kb();
    429 }
    430 
    431 __attribute__((weak)) bool rgb_matrix_indicators_kb(void) {
    432     return rgb_matrix_indicators_user();
    433 }
    434 
    435 __attribute__((weak)) bool rgb_matrix_indicators_user(void) {
    436     return true;
    437 }
    438 
    439 struct rgb_matrix_limits_t rgb_matrix_get_limits(uint8_t iter) {
    440     struct rgb_matrix_limits_t limits = {0};
    441 #if defined(RGB_MATRIX_LED_PROCESS_LIMIT) && RGB_MATRIX_LED_PROCESS_LIMIT > 0 && RGB_MATRIX_LED_PROCESS_LIMIT < RGB_MATRIX_LED_COUNT
    442 #    if defined(RGB_MATRIX_SPLIT)
    443     limits.led_min_index = RGB_MATRIX_LED_PROCESS_LIMIT * (iter);
    444     limits.led_max_index = limits.led_min_index + RGB_MATRIX_LED_PROCESS_LIMIT;
    445     if (limits.led_max_index > RGB_MATRIX_LED_COUNT) limits.led_max_index = RGB_MATRIX_LED_COUNT;
    446     if (is_keyboard_left() && (limits.led_max_index > k_rgb_matrix_split[0])) limits.led_max_index = k_rgb_matrix_split[0];
    447     if (!(is_keyboard_left()) && (limits.led_min_index < k_rgb_matrix_split[0])) limits.led_min_index = k_rgb_matrix_split[0];
    448 #    else
    449     limits.led_min_index = RGB_MATRIX_LED_PROCESS_LIMIT * (iter);
    450     limits.led_max_index = limits.led_min_index + RGB_MATRIX_LED_PROCESS_LIMIT;
    451     if (limits.led_max_index > RGB_MATRIX_LED_COUNT) limits.led_max_index = RGB_MATRIX_LED_COUNT;
    452 #    endif
    453 #else
    454 #    if defined(RGB_MATRIX_SPLIT)
    455     limits.led_min_index = 0;
    456     limits.led_max_index = RGB_MATRIX_LED_COUNT;
    457     if (is_keyboard_left() && (limits.led_max_index > k_rgb_matrix_split[0])) limits.led_max_index = k_rgb_matrix_split[0];
    458     if (!(is_keyboard_left()) && (limits.led_min_index < k_rgb_matrix_split[0])) limits.led_min_index = k_rgb_matrix_split[0];
    459 #    else
    460     limits.led_min_index = 0;
    461     limits.led_max_index = RGB_MATRIX_LED_COUNT;
    462 #    endif
    463 #endif
    464     return limits;
    465 }
    466 
    467 __attribute__((weak)) bool rgb_matrix_indicators_advanced_modules(uint8_t led_min, uint8_t led_max) {
    468     return true;
    469 }
    470 
    471 void rgb_matrix_indicators_advanced(effect_params_t *params) {
    472     /* special handling is needed for "params->iter", since it's already been incremented.
    473      * Could move the invocations to rgb_task_render, but then it's missing a few checks
    474      * and not sure which would be better. Otherwise, this should be called from
    475      * rgb_task_render, right before the iter++ line.
    476      */
    477     RGB_MATRIX_USE_LIMITS_ITER(min, max, params->iter - 1);
    478     rgb_matrix_indicators_advanced_modules(min, max);
    479     rgb_matrix_indicators_advanced_kb(min, max);
    480 }
    481 
    482 __attribute__((weak)) bool rgb_matrix_indicators_advanced_kb(uint8_t led_min, uint8_t led_max) {
    483     return rgb_matrix_indicators_advanced_user(led_min, led_max);
    484 }
    485 
    486 __attribute__((weak)) bool rgb_matrix_indicators_advanced_user(uint8_t led_min, uint8_t led_max) {
    487     return true;
    488 }
    489 
    490 void rgb_matrix_init(void) {
    491     rgb_matrix_driver.init();
    492 
    493 #ifdef RGB_MATRIX_KEYREACTIVE_ENABLED
    494     g_last_hit_tracker.count = 0;
    495     for (uint8_t i = 0; i < LED_HITS_TO_REMEMBER; ++i) {
    496         g_last_hit_tracker.tick[i] = UINT16_MAX;
    497     }
    498 
    499     last_hit_buffer.count = 0;
    500     for (uint8_t i = 0; i < LED_HITS_TO_REMEMBER; ++i) {
    501         last_hit_buffer.tick[i] = UINT16_MAX;
    502     }
    503 #endif // RGB_MATRIX_KEYREACTIVE_ENABLED
    504 
    505     eeconfig_init_rgb_matrix();
    506     if (!rgb_matrix_config.mode) {
    507         dprintf("rgb_matrix_init_drivers rgb_matrix_config.mode = 0. Write default values to EEPROM.\n");
    508         eeconfig_update_rgb_matrix_default();
    509     }
    510     eeconfig_debug_rgb_matrix(); // display current eeprom values
    511 }
    512 
    513 void rgb_matrix_set_suspend_state(bool state) {
    514 #ifdef RGB_MATRIX_SLEEP
    515     if (state && !suspend_state) { // only run if turning off, and only once
    516         rgb_task_render(0);        // turn off all LEDs when suspending
    517         rgb_task_flush(0);         // and actually flash led state to LEDs
    518     }
    519     suspend_state = state;
    520 #endif
    521 }
    522 
    523 bool rgb_matrix_get_suspend_state(void) {
    524     return suspend_state;
    525 }
    526 
    527 void rgb_matrix_toggle_eeprom_helper(bool write_to_eeprom) {
    528     rgb_matrix_config.enable ^= 1;
    529     rgb_task_state = STARTING;
    530     eeconfig_flag_rgb_matrix(write_to_eeprom);
    531     dprintf("rgb matrix toggle [%s]: rgb_matrix_config.enable = %u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", rgb_matrix_config.enable);
    532 }
    533 void rgb_matrix_toggle_noeeprom(void) {
    534     rgb_matrix_toggle_eeprom_helper(false);
    535 }
    536 void rgb_matrix_toggle(void) {
    537     rgb_matrix_toggle_eeprom_helper(true);
    538 }
    539 
    540 void rgb_matrix_enable(void) {
    541     rgb_matrix_enable_noeeprom();
    542     eeconfig_flag_rgb_matrix(true);
    543 }
    544 
    545 void rgb_matrix_enable_noeeprom(void) {
    546     if (!rgb_matrix_config.enable) rgb_task_state = STARTING;
    547     rgb_matrix_config.enable = 1;
    548 }
    549 
    550 void rgb_matrix_disable(void) {
    551     rgb_matrix_disable_noeeprom();
    552     eeconfig_flag_rgb_matrix(true);
    553 }
    554 
    555 void rgb_matrix_disable_noeeprom(void) {
    556     if (rgb_matrix_config.enable) rgb_task_state = STARTING;
    557     rgb_matrix_config.enable = 0;
    558 }
    559 
    560 uint8_t rgb_matrix_is_enabled(void) {
    561     return rgb_matrix_config.enable;
    562 }
    563 
    564 void rgb_matrix_mode_eeprom_helper(uint8_t mode, bool write_to_eeprom) {
    565     if (!rgb_matrix_config.enable) {
    566         return;
    567     }
    568     if (mode < 1) {
    569         rgb_matrix_config.mode = 1;
    570     } else if (mode >= RGB_MATRIX_EFFECT_MAX) {
    571         rgb_matrix_config.mode = RGB_MATRIX_EFFECT_MAX - 1;
    572     } else {
    573         rgb_matrix_config.mode = mode;
    574     }
    575     rgb_task_state = STARTING;
    576     eeconfig_flag_rgb_matrix(write_to_eeprom);
    577 #ifdef RGB_MATRIX_MODE_NAME_ENABLE
    578     dprintf("rgb matrix mode [%s]: %u (%s)\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", (unsigned)rgb_matrix_config.mode, rgb_matrix_get_mode_name(rgb_matrix_config.mode));
    579 #else
    580     dprintf("rgb matrix mode [%s]: %u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", (unsigned)rgb_matrix_config.mode);
    581 #endif // RGB_MATRIX_MODE_NAME_ENABLE
    582 }
    583 void rgb_matrix_mode_noeeprom(uint8_t mode) {
    584     rgb_matrix_mode_eeprom_helper(mode, false);
    585 }
    586 void rgb_matrix_mode(uint8_t mode) {
    587     rgb_matrix_mode_eeprom_helper(mode, true);
    588 }
    589 
    590 uint8_t rgb_matrix_get_mode(void) {
    591     return rgb_matrix_config.mode;
    592 }
    593 
    594 void rgb_matrix_step_helper(bool write_to_eeprom) {
    595     uint8_t mode = rgb_matrix_config.mode + 1;
    596     rgb_matrix_mode_eeprom_helper((mode < RGB_MATRIX_EFFECT_MAX) ? mode : 1, write_to_eeprom);
    597 }
    598 void rgb_matrix_step_noeeprom(void) {
    599     rgb_matrix_step_helper(false);
    600 }
    601 void rgb_matrix_step(void) {
    602     rgb_matrix_step_helper(true);
    603 }
    604 
    605 void rgb_matrix_step_reverse_helper(bool write_to_eeprom) {
    606     uint8_t mode = rgb_matrix_config.mode - 1;
    607     rgb_matrix_mode_eeprom_helper((mode < 1) ? RGB_MATRIX_EFFECT_MAX - 1 : mode, write_to_eeprom);
    608 }
    609 void rgb_matrix_step_reverse_noeeprom(void) {
    610     rgb_matrix_step_reverse_helper(false);
    611 }
    612 void rgb_matrix_step_reverse(void) {
    613     rgb_matrix_step_reverse_helper(true);
    614 }
    615 
    616 void rgb_matrix_sethsv_eeprom_helper(uint16_t hue, uint8_t sat, uint8_t val, bool write_to_eeprom) {
    617     if (!rgb_matrix_config.enable) {
    618         return;
    619     }
    620     rgb_matrix_config.hsv.h = hue;
    621     rgb_matrix_config.hsv.s = sat;
    622     rgb_matrix_config.hsv.v = (val > RGB_MATRIX_MAXIMUM_BRIGHTNESS) ? RGB_MATRIX_MAXIMUM_BRIGHTNESS : val;
    623     eeconfig_flag_rgb_matrix(write_to_eeprom);
    624     dprintf("rgb matrix set hsv [%s]: %u,%u,%u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", rgb_matrix_config.hsv.h, rgb_matrix_config.hsv.s, rgb_matrix_config.hsv.v);
    625 }
    626 void rgb_matrix_sethsv_noeeprom(uint16_t hue, uint8_t sat, uint8_t val) {
    627     rgb_matrix_sethsv_eeprom_helper(hue, sat, val, false);
    628 }
    629 void rgb_matrix_sethsv(uint16_t hue, uint8_t sat, uint8_t val) {
    630     rgb_matrix_sethsv_eeprom_helper(hue, sat, val, true);
    631 }
    632 
    633 hsv_t rgb_matrix_get_hsv(void) {
    634     return rgb_matrix_config.hsv;
    635 }
    636 uint8_t rgb_matrix_get_hue(void) {
    637     return rgb_matrix_config.hsv.h;
    638 }
    639 uint8_t rgb_matrix_get_sat(void) {
    640     return rgb_matrix_config.hsv.s;
    641 }
    642 uint8_t rgb_matrix_get_val(void) {
    643     return rgb_matrix_config.hsv.v;
    644 }
    645 
    646 void rgb_matrix_increase_hue_helper(bool write_to_eeprom) {
    647     rgb_matrix_sethsv_eeprom_helper(rgb_matrix_config.hsv.h + RGB_MATRIX_HUE_STEP, rgb_matrix_config.hsv.s, rgb_matrix_config.hsv.v, write_to_eeprom);
    648 }
    649 void rgb_matrix_increase_hue_noeeprom(void) {
    650     rgb_matrix_increase_hue_helper(false);
    651 }
    652 void rgb_matrix_increase_hue(void) {
    653     rgb_matrix_increase_hue_helper(true);
    654 }
    655 
    656 void rgb_matrix_decrease_hue_helper(bool write_to_eeprom) {
    657     rgb_matrix_sethsv_eeprom_helper(rgb_matrix_config.hsv.h - RGB_MATRIX_HUE_STEP, rgb_matrix_config.hsv.s, rgb_matrix_config.hsv.v, write_to_eeprom);
    658 }
    659 void rgb_matrix_decrease_hue_noeeprom(void) {
    660     rgb_matrix_decrease_hue_helper(false);
    661 }
    662 void rgb_matrix_decrease_hue(void) {
    663     rgb_matrix_decrease_hue_helper(true);
    664 }
    665 
    666 void rgb_matrix_increase_sat_helper(bool write_to_eeprom) {
    667     rgb_matrix_sethsv_eeprom_helper(rgb_matrix_config.hsv.h, qadd8(rgb_matrix_config.hsv.s, RGB_MATRIX_SAT_STEP), rgb_matrix_config.hsv.v, write_to_eeprom);
    668 }
    669 void rgb_matrix_increase_sat_noeeprom(void) {
    670     rgb_matrix_increase_sat_helper(false);
    671 }
    672 void rgb_matrix_increase_sat(void) {
    673     rgb_matrix_increase_sat_helper(true);
    674 }
    675 
    676 void rgb_matrix_decrease_sat_helper(bool write_to_eeprom) {
    677     rgb_matrix_sethsv_eeprom_helper(rgb_matrix_config.hsv.h, qsub8(rgb_matrix_config.hsv.s, RGB_MATRIX_SAT_STEP), rgb_matrix_config.hsv.v, write_to_eeprom);
    678 }
    679 void rgb_matrix_decrease_sat_noeeprom(void) {
    680     rgb_matrix_decrease_sat_helper(false);
    681 }
    682 void rgb_matrix_decrease_sat(void) {
    683     rgb_matrix_decrease_sat_helper(true);
    684 }
    685 
    686 void rgb_matrix_increase_val_helper(bool write_to_eeprom) {
    687     rgb_matrix_sethsv_eeprom_helper(rgb_matrix_config.hsv.h, rgb_matrix_config.hsv.s, qadd8(rgb_matrix_config.hsv.v, RGB_MATRIX_VAL_STEP), write_to_eeprom);
    688 }
    689 void rgb_matrix_increase_val_noeeprom(void) {
    690     rgb_matrix_increase_val_helper(false);
    691 }
    692 void rgb_matrix_increase_val(void) {
    693     rgb_matrix_increase_val_helper(true);
    694 }
    695 
    696 void rgb_matrix_decrease_val_helper(bool write_to_eeprom) {
    697     rgb_matrix_sethsv_eeprom_helper(rgb_matrix_config.hsv.h, rgb_matrix_config.hsv.s, qsub8(rgb_matrix_config.hsv.v, RGB_MATRIX_VAL_STEP), write_to_eeprom);
    698 }
    699 void rgb_matrix_decrease_val_noeeprom(void) {
    700     rgb_matrix_decrease_val_helper(false);
    701 }
    702 void rgb_matrix_decrease_val(void) {
    703     rgb_matrix_decrease_val_helper(true);
    704 }
    705 
    706 void rgb_matrix_set_speed_eeprom_helper(uint8_t speed, bool write_to_eeprom) {
    707     rgb_matrix_config.speed = speed;
    708     eeconfig_flag_rgb_matrix(write_to_eeprom);
    709     dprintf("rgb matrix set speed [%s]: %u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", rgb_matrix_config.speed);
    710 }
    711 void rgb_matrix_set_speed_noeeprom(uint8_t speed) {
    712     rgb_matrix_set_speed_eeprom_helper(speed, false);
    713 }
    714 void rgb_matrix_set_speed(uint8_t speed) {
    715     rgb_matrix_set_speed_eeprom_helper(speed, true);
    716 }
    717 
    718 uint8_t rgb_matrix_get_speed(void) {
    719     return rgb_matrix_config.speed;
    720 }
    721 
    722 void rgb_matrix_increase_speed_helper(bool write_to_eeprom) {
    723     rgb_matrix_set_speed_eeprom_helper(qadd8(rgb_matrix_config.speed, RGB_MATRIX_SPD_STEP), write_to_eeprom);
    724 }
    725 void rgb_matrix_increase_speed_noeeprom(void) {
    726     rgb_matrix_increase_speed_helper(false);
    727 }
    728 void rgb_matrix_increase_speed(void) {
    729     rgb_matrix_increase_speed_helper(true);
    730 }
    731 
    732 void rgb_matrix_decrease_speed_helper(bool write_to_eeprom) {
    733     rgb_matrix_set_speed_eeprom_helper(qsub8(rgb_matrix_config.speed, RGB_MATRIX_SPD_STEP), write_to_eeprom);
    734 }
    735 void rgb_matrix_decrease_speed_noeeprom(void) {
    736     rgb_matrix_decrease_speed_helper(false);
    737 }
    738 void rgb_matrix_decrease_speed(void) {
    739     rgb_matrix_decrease_speed_helper(true);
    740 }
    741 
    742 void rgb_matrix_set_flags_eeprom_helper(led_flags_t flags, bool write_to_eeprom) {
    743     rgb_matrix_config.flags = flags;
    744     eeconfig_flag_rgb_matrix(write_to_eeprom);
    745     dprintf("rgb matrix set flags [%s]: %u\n", (write_to_eeprom) ? "EEPROM" : "NOEEPROM", rgb_matrix_config.flags);
    746 }
    747 
    748 led_flags_t rgb_matrix_get_flags(void) {
    749     return rgb_matrix_config.flags;
    750 }
    751 
    752 void rgb_matrix_set_flags(led_flags_t flags) {
    753     rgb_matrix_set_flags_eeprom_helper(flags, true);
    754 }
    755 
    756 void rgb_matrix_set_flags_noeeprom(led_flags_t flags) {
    757     rgb_matrix_set_flags_eeprom_helper(flags, false);
    758 }
    759 
    760 void rgb_matrix_flags_step_helper(bool write_to_eeprom) {
    761     led_flags_t flags = rgb_matrix_get_flags();
    762 
    763     uint8_t next = 0;
    764     for (uint8_t i = 0; i < RGB_MATRIX_FLAG_STEPS_COUNT; i++) {
    765         if (rgb_matrix_flag_steps[i] == flags) {
    766             next = i == RGB_MATRIX_FLAG_STEPS_COUNT - 1 ? 0 : i + 1;
    767             break;
    768         }
    769     }
    770 
    771     rgb_matrix_set_flags_eeprom_helper(rgb_matrix_flag_steps[next], write_to_eeprom);
    772 }
    773 
    774 void rgb_matrix_flags_step_noeeprom(void) {
    775     rgb_matrix_flags_step_helper(false);
    776 }
    777 
    778 void rgb_matrix_flags_step(void) {
    779     rgb_matrix_flags_step_helper(true);
    780 }
    781 
    782 void rgb_matrix_flags_step_reverse_helper(bool write_to_eeprom) {
    783     led_flags_t flags = rgb_matrix_get_flags();
    784 
    785     uint8_t next = 0;
    786     for (uint8_t i = 0; i < RGB_MATRIX_FLAG_STEPS_COUNT; i++) {
    787         if (rgb_matrix_flag_steps[i] == flags) {
    788             next = i == 0 ? RGB_MATRIX_FLAG_STEPS_COUNT - 1 : i - 1;
    789             break;
    790         }
    791     }
    792 
    793     rgb_matrix_set_flags_eeprom_helper(rgb_matrix_flag_steps[next], write_to_eeprom);
    794 }
    795 
    796 void rgb_matrix_flags_step_reverse_noeeprom(void) {
    797     rgb_matrix_flags_step_reverse_helper(false);
    798 }
    799 
    800 void rgb_matrix_flags_step_reverse(void) {
    801     rgb_matrix_flags_step_reverse_helper(true);
    802 }
    803 
    804 //----------------------------------------------------------
    805 // RGB Matrix naming
    806 #undef RGB_MATRIX_EFFECT
    807 #ifdef RGB_MATRIX_MODE_NAME_ENABLE
    808 const char *rgb_matrix_get_mode_name(uint8_t mode) {
    809     switch (mode) {
    810         case RGB_MATRIX_NONE:
    811             return "NONE";
    812 
    813 #    define RGB_MATRIX_EFFECT(name, ...) \
    814         case RGB_MATRIX_##name:          \
    815             return #name;
    816 #    include "rgb_matrix_effects.inc"
    817 #    undef RGB_MATRIX_EFFECT
    818 
    819 #    ifdef COMMUNITY_MODULES_ENABLE
    820 #        define RGB_MATRIX_EFFECT(name, ...)         \
    821             case RGB_MATRIX_COMMUNITY_MODULE_##name: \
    822                 return #name;
    823 #        include "rgb_matrix_community_modules.inc"
    824 #        undef RGB_MATRIX_EFFECT
    825 #    endif // COMMUNITY_MODULES_ENABLE
    826 
    827 #    if defined(RGB_MATRIX_CUSTOM_KB) || defined(RGB_MATRIX_CUSTOM_USER)
    828 #        define RGB_MATRIX_EFFECT(name, ...) \
    829             case RGB_MATRIX_CUSTOM_##name:   \
    830                 return #name;
    831 
    832 #        ifdef RGB_MATRIX_CUSTOM_KB
    833 #            include "rgb_matrix_kb.inc"
    834 #        endif // RGB_MATRIX_CUSTOM_KB
    835 
    836 #        ifdef RGB_MATRIX_CUSTOM_USER
    837 #            include "rgb_matrix_user.inc"
    838 #        endif // RGB_MATRIX_CUSTOM_USER
    839 
    840 #        undef RGB_MATRIX_EFFECT
    841 #    endif // RGB_MATRIX_CUSTOM_KB || RGB_MATRIX_CUSTOM_USER
    842 
    843         default:
    844             return "UNKNOWN";
    845     }
    846 }
    847 #    undef RGB_MATRIX_EFFECT
    848 #endif // RGB_MATRIX_MODE_NAME_ENABLE