diff options
Diffstat (limited to 'quantum/rgblight/rgblight.c')
| -rw-r--r-- | quantum/rgblight/rgblight.c | 1390 |
1 files changed, 1390 insertions, 0 deletions
diff --git a/quantum/rgblight/rgblight.c b/quantum/rgblight/rgblight.c new file mode 100644 index 000000000..148dae78f --- /dev/null +++ b/quantum/rgblight/rgblight.c | |||
| @@ -0,0 +1,1390 @@ | |||
| 1 | /* Copyright 2016-2017 Yang Liu | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 2 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | #include <math.h> | ||
| 17 | #include <string.h> | ||
| 18 | #include <stdlib.h> | ||
| 19 | #include "wait.h" | ||
| 20 | #include "progmem.h" | ||
| 21 | #include "sync_timer.h" | ||
| 22 | #include "rgblight.h" | ||
| 23 | #include "color.h" | ||
| 24 | #include "debug.h" | ||
| 25 | #include "led_tables.h" | ||
| 26 | #include <lib/lib8tion/lib8tion.h> | ||
| 27 | #ifdef EEPROM_ENABLE | ||
| 28 | # include "eeprom.h" | ||
| 29 | #endif | ||
| 30 | #ifdef VELOCIKEY_ENABLE | ||
| 31 | # include "velocikey.h" | ||
| 32 | #endif | ||
| 33 | |||
| 34 | #ifndef MIN | ||
| 35 | # define MIN(a, b) (((a) < (b)) ? (a) : (b)) | ||
| 36 | #endif | ||
| 37 | #ifndef MAX | ||
| 38 | # define MAX(a, b) (((a) > (b)) ? (a) : (b)) | ||
| 39 | #endif | ||
| 40 | |||
| 41 | #ifdef RGBLIGHT_SPLIT | ||
| 42 | /* for split keyboard */ | ||
| 43 | # define RGBLIGHT_SPLIT_SET_CHANGE_MODE rgblight_status.change_flags |= RGBLIGHT_STATUS_CHANGE_MODE | ||
| 44 | # define RGBLIGHT_SPLIT_SET_CHANGE_HSVS rgblight_status.change_flags |= RGBLIGHT_STATUS_CHANGE_HSVS | ||
| 45 | # define RGBLIGHT_SPLIT_SET_CHANGE_MODEHSVS rgblight_status.change_flags |= (RGBLIGHT_STATUS_CHANGE_MODE | RGBLIGHT_STATUS_CHANGE_HSVS) | ||
| 46 | # define RGBLIGHT_SPLIT_SET_CHANGE_LAYERS rgblight_status.change_flags |= RGBLIGHT_STATUS_CHANGE_LAYERS | ||
| 47 | # define RGBLIGHT_SPLIT_SET_CHANGE_TIMER_ENABLE rgblight_status.change_flags |= RGBLIGHT_STATUS_CHANGE_TIMER | ||
| 48 | # define RGBLIGHT_SPLIT_ANIMATION_TICK rgblight_status.change_flags |= RGBLIGHT_STATUS_ANIMATION_TICK | ||
| 49 | #else | ||
| 50 | # define RGBLIGHT_SPLIT_SET_CHANGE_MODE | ||
| 51 | # define RGBLIGHT_SPLIT_SET_CHANGE_HSVS | ||
| 52 | # define RGBLIGHT_SPLIT_SET_CHANGE_MODEHSVS | ||
| 53 | # define RGBLIGHT_SPLIT_SET_CHANGE_LAYERS | ||
| 54 | # define RGBLIGHT_SPLIT_SET_CHANGE_TIMER_ENABLE | ||
| 55 | # define RGBLIGHT_SPLIT_ANIMATION_TICK | ||
| 56 | #endif | ||
| 57 | |||
| 58 | #define _RGBM_SINGLE_STATIC(sym) RGBLIGHT_MODE_##sym, | ||
| 59 | #define _RGBM_SINGLE_DYNAMIC(sym) | ||
| 60 | #define _RGBM_MULTI_STATIC(sym) RGBLIGHT_MODE_##sym, | ||
| 61 | #define _RGBM_MULTI_DYNAMIC(sym) | ||
| 62 | #define _RGBM_TMP_STATIC(sym, msym) RGBLIGHT_MODE_##sym, | ||
| 63 | #define _RGBM_TMP_DYNAMIC(sym, msym) | ||
| 64 | static uint8_t static_effect_table[] = { | ||
| 65 | #include "rgblight_modes.h" | ||
| 66 | }; | ||
| 67 | |||
| 68 | #define _RGBM_SINGLE_STATIC(sym) RGBLIGHT_MODE_##sym, | ||
| 69 | #define _RGBM_SINGLE_DYNAMIC(sym) RGBLIGHT_MODE_##sym, | ||
| 70 | #define _RGBM_MULTI_STATIC(sym) RGBLIGHT_MODE_##sym, | ||
| 71 | #define _RGBM_MULTI_DYNAMIC(sym) RGBLIGHT_MODE_##sym, | ||
| 72 | #define _RGBM_TMP_STATIC(sym, msym) RGBLIGHT_MODE_##msym, | ||
| 73 | #define _RGBM_TMP_DYNAMIC(sym, msym) RGBLIGHT_MODE_##msym, | ||
| 74 | static uint8_t mode_base_table[] = { | ||
| 75 | 0, // RGBLIGHT_MODE_zero | ||
| 76 | #include "rgblight_modes.h" | ||
| 77 | }; | ||
| 78 | |||
| 79 | #if !defined(RGBLIGHT_DEFAULT_MODE) | ||
| 80 | # define RGBLIGHT_DEFAULT_MODE RGBLIGHT_MODE_STATIC_LIGHT | ||
| 81 | #endif | ||
| 82 | |||
| 83 | #if !defined(RGBLIGHT_DEFAULT_HUE) | ||
| 84 | # define RGBLIGHT_DEFAULT_HUE 0 | ||
| 85 | #endif | ||
| 86 | |||
| 87 | #if !defined(RGBLIGHT_DEFAULT_SAT) | ||
| 88 | # define RGBLIGHT_DEFAULT_SAT UINT8_MAX | ||
| 89 | #endif | ||
| 90 | |||
| 91 | #if !defined(RGBLIGHT_DEFAULT_VAL) | ||
| 92 | # define RGBLIGHT_DEFAULT_VAL RGBLIGHT_LIMIT_VAL | ||
| 93 | #endif | ||
| 94 | |||
| 95 | #if !defined(RGBLIGHT_DEFAULT_SPD) | ||
| 96 | # define RGBLIGHT_DEFAULT_SPD 0 | ||
| 97 | #endif | ||
| 98 | |||
| 99 | static inline int is_static_effect(uint8_t mode) { return memchr(static_effect_table, mode, sizeof(static_effect_table)) != NULL; } | ||
| 100 | |||
| 101 | #ifdef RGBLIGHT_LED_MAP | ||
| 102 | const uint8_t led_map[] PROGMEM = RGBLIGHT_LED_MAP; | ||
| 103 | #endif | ||
| 104 | |||
| 105 | #ifdef RGBLIGHT_EFFECT_STATIC_GRADIENT | ||
| 106 | __attribute__((weak)) const uint8_t RGBLED_GRADIENT_RANGES[] PROGMEM = {255, 170, 127, 85, 64}; | ||
| 107 | #endif | ||
| 108 | |||
| 109 | rgblight_config_t rgblight_config; | ||
| 110 | rgblight_status_t rgblight_status = {.timer_enabled = false}; | ||
| 111 | bool is_rgblight_initialized = false; | ||
| 112 | |||
| 113 | #ifdef RGBLIGHT_SLEEP | ||
| 114 | static bool is_suspended; | ||
| 115 | static bool pre_suspend_enabled; | ||
| 116 | #endif | ||
| 117 | |||
| 118 | #ifdef RGBLIGHT_USE_TIMER | ||
| 119 | animation_status_t animation_status = {}; | ||
| 120 | #endif | ||
| 121 | |||
| 122 | #ifndef LED_ARRAY | ||
| 123 | LED_TYPE led[RGBLED_NUM]; | ||
| 124 | # define LED_ARRAY led | ||
| 125 | #endif | ||
| 126 | |||
| 127 | #ifdef RGBLIGHT_LAYERS | ||
| 128 | rgblight_segment_t const *const *rgblight_layers = NULL; | ||
| 129 | #endif | ||
| 130 | |||
| 131 | rgblight_ranges_t rgblight_ranges = {0, RGBLED_NUM, 0, RGBLED_NUM, RGBLED_NUM}; | ||
| 132 | |||
| 133 | void rgblight_set_clipping_range(uint8_t start_pos, uint8_t num_leds) { | ||
| 134 | rgblight_ranges.clipping_start_pos = start_pos; | ||
| 135 | rgblight_ranges.clipping_num_leds = num_leds; | ||
| 136 | } | ||
| 137 | |||
| 138 | void rgblight_set_effect_range(uint8_t start_pos, uint8_t num_leds) { | ||
| 139 | if (start_pos >= RGBLED_NUM) return; | ||
| 140 | if (start_pos + num_leds > RGBLED_NUM) return; | ||
| 141 | rgblight_ranges.effect_start_pos = start_pos; | ||
| 142 | rgblight_ranges.effect_end_pos = start_pos + num_leds; | ||
| 143 | rgblight_ranges.effect_num_leds = num_leds; | ||
| 144 | } | ||
| 145 | |||
| 146 | __attribute__((weak)) RGB rgblight_hsv_to_rgb(HSV hsv) { return hsv_to_rgb(hsv); } | ||
| 147 | |||
| 148 | void sethsv_raw(uint8_t hue, uint8_t sat, uint8_t val, LED_TYPE *led1) { | ||
| 149 | HSV hsv = {hue, sat, val}; | ||
| 150 | RGB rgb = rgblight_hsv_to_rgb(hsv); | ||
| 151 | setrgb(rgb.r, rgb.g, rgb.b, led1); | ||
| 152 | } | ||
| 153 | |||
| 154 | void sethsv(uint8_t hue, uint8_t sat, uint8_t val, LED_TYPE *led1) { sethsv_raw(hue, sat, val > RGBLIGHT_LIMIT_VAL ? RGBLIGHT_LIMIT_VAL : val, led1); } | ||
| 155 | |||
| 156 | void setrgb(uint8_t r, uint8_t g, uint8_t b, LED_TYPE *led1) { | ||
| 157 | led1->r = r; | ||
| 158 | led1->g = g; | ||
| 159 | led1->b = b; | ||
| 160 | #ifdef RGBW | ||
| 161 | led1->w = 0; | ||
| 162 | #endif | ||
| 163 | } | ||
| 164 | |||
| 165 | void rgblight_check_config(void) { | ||
| 166 | /* Add some out of bound checks for RGB light config */ | ||
| 167 | |||
| 168 | if (rgblight_config.mode < RGBLIGHT_MODE_STATIC_LIGHT) { | ||
| 169 | rgblight_config.mode = RGBLIGHT_MODE_STATIC_LIGHT; | ||
| 170 | } else if (rgblight_config.mode > RGBLIGHT_MODES) { | ||
| 171 | rgblight_config.mode = RGBLIGHT_MODES; | ||
| 172 | } | ||
| 173 | |||
| 174 | if (rgblight_config.val > RGBLIGHT_LIMIT_VAL) { | ||
| 175 | rgblight_config.val = RGBLIGHT_LIMIT_VAL; | ||
| 176 | } | ||
| 177 | } | ||
| 178 | |||
| 179 | uint32_t eeconfig_read_rgblight(void) { | ||
| 180 | #ifdef EEPROM_ENABLE | ||
| 181 | return eeprom_read_dword(EECONFIG_RGBLIGHT); | ||
| 182 | #else | ||
| 183 | return 0; | ||
| 184 | #endif | ||
| 185 | } | ||
| 186 | |||
| 187 | void eeconfig_update_rgblight(uint32_t val) { | ||
| 188 | #ifdef EEPROM_ENABLE | ||
| 189 | rgblight_check_config(); | ||
| 190 | eeprom_update_dword(EECONFIG_RGBLIGHT, val); | ||
| 191 | #endif | ||
| 192 | } | ||
| 193 | |||
| 194 | void eeconfig_update_rgblight_current(void) { eeconfig_update_rgblight(rgblight_config.raw); } | ||
| 195 | |||
| 196 | void eeconfig_update_rgblight_default(void) { | ||
| 197 | rgblight_config.enable = 1; | ||
| 198 | rgblight_config.mode = RGBLIGHT_DEFAULT_MODE; | ||
| 199 | rgblight_config.hue = RGBLIGHT_DEFAULT_HUE; | ||
| 200 | rgblight_config.sat = RGBLIGHT_DEFAULT_SAT; | ||
| 201 | rgblight_config.val = RGBLIGHT_DEFAULT_VAL; | ||
| 202 | rgblight_config.speed = RGBLIGHT_DEFAULT_SPD; | ||
| 203 | RGBLIGHT_SPLIT_SET_CHANGE_MODEHSVS; | ||
| 204 | eeconfig_update_rgblight(rgblight_config.raw); | ||
| 205 | } | ||
| 206 | |||
| 207 | void eeconfig_debug_rgblight(void) { | ||
| 208 | dprintf("rgblight_config EEPROM:\n"); | ||
| 209 | dprintf("rgblight_config.enable = %d\n", rgblight_config.enable); | ||
| 210 | dprintf("rghlight_config.mode = %d\n", rgblight_config.mode); | ||
| 211 | dprintf("rgblight_config.hue = %d\n", rgblight_config.hue); | ||
| 212 | dprintf("rgblight_config.sat = %d\n", rgblight_config.sat); | ||
| 213 | dprintf("rgblight_config.val = %d\n", rgblight_config.val); | ||
| 214 | dprintf("rgblight_config.speed = %d\n", rgblight_config.speed); | ||
| 215 | } | ||
| 216 | |||
| 217 | void rgblight_init(void) { | ||
| 218 | /* if already initialized, don't do it again. | ||
| 219 | If you must do it again, extern this and set to false, first. | ||
| 220 | This is a dirty, dirty hack until proper hooks can be added for keyboard startup. */ | ||
| 221 | if (is_rgblight_initialized) { | ||
| 222 | return; | ||
| 223 | } | ||
| 224 | |||
| 225 | dprintf("rgblight_init called.\n"); | ||
| 226 | dprintf("rgblight_init start!\n"); | ||
| 227 | if (!eeconfig_is_enabled()) { | ||
| 228 | dprintf("rgblight_init eeconfig is not enabled.\n"); | ||
| 229 | eeconfig_init(); | ||
| 230 | eeconfig_update_rgblight_default(); | ||
| 231 | } | ||
| 232 | rgblight_config.raw = eeconfig_read_rgblight(); | ||
| 233 | RGBLIGHT_SPLIT_SET_CHANGE_MODEHSVS; | ||
| 234 | if (!rgblight_config.mode) { | ||
| 235 | dprintf("rgblight_init rgblight_config.mode = 0. Write default values to EEPROM.\n"); | ||
| 236 | eeconfig_update_rgblight_default(); | ||
| 237 | rgblight_config.raw = eeconfig_read_rgblight(); | ||
| 238 | } | ||
| 239 | rgblight_check_config(); | ||
| 240 | |||
| 241 | eeconfig_debug_rgblight(); // display current eeprom values | ||
| 242 | |||
| 243 | rgblight_timer_init(); // setup the timer | ||
| 244 | |||
| 245 | if (rgblight_config.enable) { | ||
| 246 | rgblight_mode_noeeprom(rgblight_config.mode); | ||
| 247 | } | ||
| 248 | |||
| 249 | is_rgblight_initialized = true; | ||
| 250 | } | ||
| 251 | |||
| 252 | void rgblight_reload_from_eeprom(void) { | ||
| 253 | /* Reset back to what we have in eeprom */ | ||
| 254 | rgblight_config.raw = eeconfig_read_rgblight(); | ||
| 255 | RGBLIGHT_SPLIT_SET_CHANGE_MODEHSVS; | ||
| 256 | rgblight_check_config(); | ||
| 257 | eeconfig_debug_rgblight(); // display current eeprom values | ||
| 258 | if (rgblight_config.enable) { | ||
| 259 | rgblight_mode_noeeprom(rgblight_config.mode); | ||
| 260 | } | ||
| 261 | } | ||
| 262 | |||
| 263 | uint32_t rgblight_read_dword(void) { return rgblight_config.raw; } | ||
| 264 | |||
| 265 | void rgblight_update_dword(uint32_t dword) { | ||
| 266 | RGBLIGHT_SPLIT_SET_CHANGE_MODEHSVS; | ||
| 267 | rgblight_config.raw = dword; | ||
| 268 | if (rgblight_config.enable) | ||
| 269 | rgblight_mode_noeeprom(rgblight_config.mode); | ||
| 270 | else { | ||
| 271 | rgblight_timer_disable(); | ||
| 272 | rgblight_set(); | ||
| 273 | } | ||
| 274 | } | ||
| 275 | |||
| 276 | void rgblight_increase(void) { | ||
| 277 | uint8_t mode = 0; | ||
| 278 | if (rgblight_config.mode < RGBLIGHT_MODES) { | ||
| 279 | mode = rgblight_config.mode + 1; | ||
| 280 | } | ||
| 281 | rgblight_mode(mode); | ||
| 282 | } | ||
| 283 | void rgblight_decrease(void) { | ||
| 284 | uint8_t mode = 0; | ||
| 285 | // Mode will never be < 1. If it ever is, eeprom needs to be initialized. | ||
| 286 | if (rgblight_config.mode > RGBLIGHT_MODE_STATIC_LIGHT) { | ||
| 287 | mode = rgblight_config.mode - 1; | ||
| 288 | } | ||
| 289 | rgblight_mode(mode); | ||
| 290 | } | ||
| 291 | void rgblight_step_helper(bool write_to_eeprom) { | ||
| 292 | uint8_t mode = 0; | ||
| 293 | mode = rgblight_config.mode + 1; | ||
| 294 | if (mode > RGBLIGHT_MODES) { | ||
| 295 | mode = 1; | ||
| 296 | } | ||
| 297 | rgblight_mode_eeprom_helper(mode, write_to_eeprom); | ||
| 298 | } | ||
| 299 | void rgblight_step_noeeprom(void) { rgblight_step_helper(false); } | ||
| 300 | void rgblight_step(void) { rgblight_step_helper(true); } | ||
| 301 | void rgblight_step_reverse_helper(bool write_to_eeprom) { | ||
| 302 | uint8_t mode = 0; | ||
| 303 | mode = rgblight_config.mode - 1; | ||
| 304 | if (mode < 1) { | ||
| 305 | mode = RGBLIGHT_MODES; | ||
| 306 | } | ||
| 307 | rgblight_mode_eeprom_helper(mode, write_to_eeprom); | ||
| 308 | } | ||
| 309 | void rgblight_step_reverse_noeeprom(void) { rgblight_step_reverse_helper(false); } | ||
| 310 | void rgblight_step_reverse(void) { rgblight_step_reverse_helper(true); } | ||
| 311 | |||
| 312 | uint8_t rgblight_get_mode(void) { | ||
| 313 | if (!rgblight_config.enable) { | ||
| 314 | return false; | ||
| 315 | } | ||
| 316 | |||
| 317 | return rgblight_config.mode; | ||
| 318 | } | ||
| 319 | |||
| 320 | void rgblight_mode_eeprom_helper(uint8_t mode, bool write_to_eeprom) { | ||
| 321 | if (!rgblight_config.enable) { | ||
| 322 | return; | ||
| 323 | } | ||
| 324 | if (mode < RGBLIGHT_MODE_STATIC_LIGHT) { | ||
| 325 | rgblight_config.mode = RGBLIGHT_MODE_STATIC_LIGHT; | ||
| 326 | } else if (mode > RGBLIGHT_MODES) { | ||
| 327 | rgblight_config.mode = RGBLIGHT_MODES; | ||
| 328 | } else { | ||
| 329 | rgblight_config.mode = mode; | ||
| 330 | } | ||
| 331 | RGBLIGHT_SPLIT_SET_CHANGE_MODE; | ||
| 332 | if (write_to_eeprom) { | ||
| 333 | eeconfig_update_rgblight(rgblight_config.raw); | ||
| 334 | dprintf("rgblight mode [EEPROM]: %u\n", rgblight_config.mode); | ||
| 335 | } else { | ||
| 336 | dprintf("rgblight mode [NOEEPROM]: %u\n", rgblight_config.mode); | ||
| 337 | } | ||
| 338 | if (is_static_effect(rgblight_config.mode)) { | ||
| 339 | rgblight_timer_disable(); | ||
| 340 | } else { | ||
| 341 | rgblight_timer_enable(); | ||
| 342 | } | ||
| 343 | #ifdef RGBLIGHT_USE_TIMER | ||
| 344 | animation_status.restart = true; | ||
| 345 | #endif | ||
| 346 | rgblight_sethsv_noeeprom(rgblight_config.hue, rgblight_config.sat, rgblight_config.val); | ||
| 347 | } | ||
| 348 | |||
| 349 | void rgblight_mode(uint8_t mode) { rgblight_mode_eeprom_helper(mode, true); } | ||
| 350 | |||
| 351 | void rgblight_mode_noeeprom(uint8_t mode) { rgblight_mode_eeprom_helper(mode, false); } | ||
| 352 | |||
| 353 | void rgblight_toggle(void) { | ||
| 354 | dprintf("rgblight toggle [EEPROM]: rgblight_config.enable = %u\n", !rgblight_config.enable); | ||
| 355 | if (rgblight_config.enable) { | ||
| 356 | rgblight_disable(); | ||
| 357 | } else { | ||
| 358 | rgblight_enable(); | ||
| 359 | } | ||
| 360 | } | ||
| 361 | |||
| 362 | void rgblight_toggle_noeeprom(void) { | ||
| 363 | dprintf("rgblight toggle [NOEEPROM]: rgblight_config.enable = %u\n", !rgblight_config.enable); | ||
| 364 | if (rgblight_config.enable) { | ||
| 365 | rgblight_disable_noeeprom(); | ||
| 366 | } else { | ||
| 367 | rgblight_enable_noeeprom(); | ||
| 368 | } | ||
| 369 | } | ||
| 370 | |||
| 371 | void rgblight_enable(void) { | ||
| 372 | rgblight_config.enable = 1; | ||
| 373 | // No need to update EEPROM here. rgblight_mode() will do that, actually | ||
| 374 | // eeconfig_update_rgblight(rgblight_config.raw); | ||
| 375 | dprintf("rgblight enable [EEPROM]: rgblight_config.enable = %u\n", rgblight_config.enable); | ||
| 376 | rgblight_mode(rgblight_config.mode); | ||
| 377 | } | ||
| 378 | |||
| 379 | void rgblight_enable_noeeprom(void) { | ||
| 380 | rgblight_config.enable = 1; | ||
| 381 | dprintf("rgblight enable [NOEEPROM]: rgblight_config.enable = %u\n", rgblight_config.enable); | ||
| 382 | rgblight_mode_noeeprom(rgblight_config.mode); | ||
| 383 | } | ||
| 384 | |||
| 385 | void rgblight_disable(void) { | ||
| 386 | rgblight_config.enable = 0; | ||
| 387 | eeconfig_update_rgblight(rgblight_config.raw); | ||
| 388 | dprintf("rgblight disable [EEPROM]: rgblight_config.enable = %u\n", rgblight_config.enable); | ||
| 389 | rgblight_timer_disable(); | ||
| 390 | RGBLIGHT_SPLIT_SET_CHANGE_MODE; | ||
| 391 | wait_ms(50); | ||
| 392 | rgblight_set(); | ||
| 393 | } | ||
| 394 | |||
| 395 | void rgblight_disable_noeeprom(void) { | ||
| 396 | rgblight_config.enable = 0; | ||
| 397 | dprintf("rgblight disable [NOEEPROM]: rgblight_config.enable = %u\n", rgblight_config.enable); | ||
| 398 | rgblight_timer_disable(); | ||
| 399 | RGBLIGHT_SPLIT_SET_CHANGE_MODE; | ||
| 400 | wait_ms(50); | ||
| 401 | rgblight_set(); | ||
| 402 | } | ||
| 403 | |||
| 404 | bool rgblight_is_enabled(void) { return rgblight_config.enable; } | ||
| 405 | |||
| 406 | void rgblight_increase_hue_helper(bool write_to_eeprom) { | ||
| 407 | uint8_t hue = rgblight_config.hue + RGBLIGHT_HUE_STEP; | ||
| 408 | rgblight_sethsv_eeprom_helper(hue, rgblight_config.sat, rgblight_config.val, write_to_eeprom); | ||
| 409 | } | ||
| 410 | void rgblight_increase_hue_noeeprom(void) { rgblight_increase_hue_helper(false); } | ||
| 411 | void rgblight_increase_hue(void) { rgblight_increase_hue_helper(true); } | ||
| 412 | void rgblight_decrease_hue_helper(bool write_to_eeprom) { | ||
| 413 | uint8_t hue = rgblight_config.hue - RGBLIGHT_HUE_STEP; | ||
| 414 | rgblight_sethsv_eeprom_helper(hue, rgblight_config.sat, rgblight_config.val, write_to_eeprom); | ||
| 415 | } | ||
| 416 | void rgblight_decrease_hue_noeeprom(void) { rgblight_decrease_hue_helper(false); } | ||
| 417 | void rgblight_decrease_hue(void) { rgblight_decrease_hue_helper(true); } | ||
| 418 | void rgblight_increase_sat_helper(bool write_to_eeprom) { | ||
| 419 | uint8_t sat = qadd8(rgblight_config.sat, RGBLIGHT_SAT_STEP); | ||
| 420 | rgblight_sethsv_eeprom_helper(rgblight_config.hue, sat, rgblight_config.val, write_to_eeprom); | ||
| 421 | } | ||
| 422 | void rgblight_increase_sat_noeeprom(void) { rgblight_increase_sat_helper(false); } | ||
| 423 | void rgblight_increase_sat(void) { rgblight_increase_sat_helper(true); } | ||
| 424 | void rgblight_decrease_sat_helper(bool write_to_eeprom) { | ||
| 425 | uint8_t sat = qsub8(rgblight_config.sat, RGBLIGHT_SAT_STEP); | ||
| 426 | rgblight_sethsv_eeprom_helper(rgblight_config.hue, sat, rgblight_config.val, write_to_eeprom); | ||
| 427 | } | ||
| 428 | void rgblight_decrease_sat_noeeprom(void) { rgblight_decrease_sat_helper(false); } | ||
| 429 | void rgblight_decrease_sat(void) { rgblight_decrease_sat_helper(true); } | ||
| 430 | void rgblight_increase_val_helper(bool write_to_eeprom) { | ||
| 431 | uint8_t val = qadd8(rgblight_config.val, RGBLIGHT_VAL_STEP); | ||
| 432 | rgblight_sethsv_eeprom_helper(rgblight_config.hue, rgblight_config.sat, val, write_to_eeprom); | ||
| 433 | } | ||
| 434 | void rgblight_increase_val_noeeprom(void) { rgblight_increase_val_helper(false); } | ||
| 435 | void rgblight_increase_val(void) { rgblight_increase_val_helper(true); } | ||
| 436 | void rgblight_decrease_val_helper(bool write_to_eeprom) { | ||
| 437 | uint8_t val = qsub8(rgblight_config.val, RGBLIGHT_VAL_STEP); | ||
| 438 | rgblight_sethsv_eeprom_helper(rgblight_config.hue, rgblight_config.sat, val, write_to_eeprom); | ||
| 439 | } | ||
| 440 | void rgblight_decrease_val_noeeprom(void) { rgblight_decrease_val_helper(false); } | ||
| 441 | void rgblight_decrease_val(void) { rgblight_decrease_val_helper(true); } | ||
| 442 | |||
| 443 | void rgblight_increase_speed_helper(bool write_to_eeprom) { | ||
| 444 | if (rgblight_config.speed < 3) rgblight_config.speed++; | ||
| 445 | // RGBLIGHT_SPLIT_SET_CHANGE_HSVS; // NEED? | ||
| 446 | if (write_to_eeprom) { | ||
| 447 | eeconfig_update_rgblight(rgblight_config.raw); // EECONFIG needs to be increased to support this | ||
| 448 | } | ||
| 449 | } | ||
| 450 | void rgblight_increase_speed(void) { rgblight_increase_speed_helper(true); } | ||
| 451 | void rgblight_increase_speed_noeeprom(void) { rgblight_increase_speed_helper(false); } | ||
| 452 | |||
| 453 | void rgblight_decrease_speed_helper(bool write_to_eeprom) { | ||
| 454 | if (rgblight_config.speed > 0) rgblight_config.speed--; | ||
| 455 | // RGBLIGHT_SPLIT_SET_CHANGE_HSVS; // NEED?? | ||
| 456 | if (write_to_eeprom) { | ||
| 457 | eeconfig_update_rgblight(rgblight_config.raw); // EECONFIG needs to be increased to support this | ||
| 458 | } | ||
| 459 | } | ||
| 460 | void rgblight_decrease_speed(void) { rgblight_decrease_speed_helper(true); } | ||
| 461 | void rgblight_decrease_speed_noeeprom(void) { rgblight_decrease_speed_helper(false); } | ||
| 462 | |||
| 463 | void rgblight_sethsv_noeeprom_old(uint8_t hue, uint8_t sat, uint8_t val) { | ||
| 464 | if (rgblight_config.enable) { | ||
| 465 | LED_TYPE tmp_led; | ||
| 466 | sethsv(hue, sat, val, &tmp_led); | ||
| 467 | rgblight_setrgb(tmp_led.r, tmp_led.g, tmp_led.b); | ||
| 468 | } | ||
| 469 | } | ||
| 470 | |||
| 471 | void rgblight_sethsv_eeprom_helper(uint8_t hue, uint8_t sat, uint8_t val, bool write_to_eeprom) { | ||
| 472 | if (rgblight_config.enable) { | ||
| 473 | rgblight_status.base_mode = mode_base_table[rgblight_config.mode]; | ||
| 474 | if (rgblight_config.mode == RGBLIGHT_MODE_STATIC_LIGHT) { | ||
| 475 | // same static color | ||
| 476 | LED_TYPE tmp_led; | ||
| 477 | sethsv(hue, sat, val, &tmp_led); | ||
| 478 | rgblight_setrgb(tmp_led.r, tmp_led.g, tmp_led.b); | ||
| 479 | } else { | ||
| 480 | // all LEDs in same color | ||
| 481 | if (1 == 0) { // dummy | ||
| 482 | } | ||
| 483 | #ifdef RGBLIGHT_EFFECT_BREATHING | ||
| 484 | else if (rgblight_status.base_mode == RGBLIGHT_MODE_BREATHING) { | ||
| 485 | // breathing mode, ignore the change of val, use in memory value instead | ||
| 486 | val = rgblight_config.val; | ||
| 487 | } | ||
| 488 | #endif | ||
| 489 | #ifdef RGBLIGHT_EFFECT_RAINBOW_MOOD | ||
| 490 | else if (rgblight_status.base_mode == RGBLIGHT_MODE_RAINBOW_MOOD) { | ||
| 491 | // rainbow mood, ignore the change of hue | ||
| 492 | hue = rgblight_config.hue; | ||
| 493 | } | ||
| 494 | #endif | ||
| 495 | #ifdef RGBLIGHT_EFFECT_RAINBOW_SWIRL | ||
| 496 | else if (rgblight_status.base_mode == RGBLIGHT_MODE_RAINBOW_SWIRL) { | ||
| 497 | // rainbow swirl, ignore the change of hue | ||
| 498 | hue = rgblight_config.hue; | ||
| 499 | } | ||
| 500 | #endif | ||
| 501 | #ifdef RGBLIGHT_EFFECT_STATIC_GRADIENT | ||
| 502 | else if (rgblight_status.base_mode == RGBLIGHT_MODE_STATIC_GRADIENT) { | ||
| 503 | // static gradient | ||
| 504 | uint8_t delta = rgblight_config.mode - rgblight_status.base_mode; | ||
| 505 | bool direction = (delta % 2) == 0; | ||
| 506 | # ifdef __AVR__ | ||
| 507 | // probably due to how pgm_read_word is defined for ARM, but the ARM compiler really hates this line | ||
| 508 | uint8_t range = pgm_read_word(&RGBLED_GRADIENT_RANGES[delta / 2]); | ||
| 509 | # else | ||
| 510 | uint8_t range = RGBLED_GRADIENT_RANGES[delta / 2]; | ||
| 511 | # endif | ||
| 512 | for (uint8_t i = 0; i < rgblight_ranges.effect_num_leds; i++) { | ||
| 513 | uint8_t _hue = ((uint16_t)i * (uint16_t)range) / rgblight_ranges.effect_num_leds; | ||
| 514 | if (direction) { | ||
| 515 | _hue = hue + _hue; | ||
| 516 | } else { | ||
| 517 | _hue = hue - _hue; | ||
| 518 | } | ||
| 519 | dprintf("rgblight rainbow set hsv: %d,%d,%d,%u\n", i, _hue, direction, range); | ||
| 520 | sethsv(_hue, sat, val, (LED_TYPE *)&led[i + rgblight_ranges.effect_start_pos]); | ||
| 521 | } | ||
| 522 | rgblight_set(); | ||
| 523 | } | ||
| 524 | #endif | ||
| 525 | } | ||
| 526 | #ifdef RGBLIGHT_SPLIT | ||
| 527 | if (rgblight_config.hue != hue || rgblight_config.sat != sat || rgblight_config.val != val) { | ||
| 528 | RGBLIGHT_SPLIT_SET_CHANGE_HSVS; | ||
| 529 | } | ||
| 530 | #endif | ||
| 531 | rgblight_config.hue = hue; | ||
| 532 | rgblight_config.sat = sat; | ||
| 533 | rgblight_config.val = val; | ||
| 534 | if (write_to_eeprom) { | ||
| 535 | eeconfig_update_rgblight(rgblight_config.raw); | ||
| 536 | dprintf("rgblight set hsv [EEPROM]: %u,%u,%u\n", rgblight_config.hue, rgblight_config.sat, rgblight_config.val); | ||
| 537 | } else { | ||
| 538 | dprintf("rgblight set hsv [NOEEPROM]: %u,%u,%u\n", rgblight_config.hue, rgblight_config.sat, rgblight_config.val); | ||
| 539 | } | ||
| 540 | } | ||
| 541 | } | ||
| 542 | |||
| 543 | void rgblight_sethsv(uint8_t hue, uint8_t sat, uint8_t val) { rgblight_sethsv_eeprom_helper(hue, sat, val, true); } | ||
| 544 | |||
| 545 | void rgblight_sethsv_noeeprom(uint8_t hue, uint8_t sat, uint8_t val) { rgblight_sethsv_eeprom_helper(hue, sat, val, false); } | ||
| 546 | |||
| 547 | uint8_t rgblight_get_speed(void) { return rgblight_config.speed; } | ||
| 548 | |||
| 549 | void rgblight_set_speed_eeprom_helper(uint8_t speed, bool write_to_eeprom) { | ||
| 550 | rgblight_config.speed = speed; | ||
| 551 | if (write_to_eeprom) { | ||
| 552 | eeconfig_update_rgblight(rgblight_config.raw); // EECONFIG needs to be increased to support this | ||
| 553 | dprintf("rgblight set speed [EEPROM]: %u\n", rgblight_config.speed); | ||
| 554 | } else { | ||
| 555 | dprintf("rgblight set speed [NOEEPROM]: %u\n", rgblight_config.speed); | ||
| 556 | } | ||
| 557 | } | ||
| 558 | |||
| 559 | void rgblight_set_speed(uint8_t speed) { rgblight_set_speed_eeprom_helper(speed, true); } | ||
| 560 | |||
| 561 | void rgblight_set_speed_noeeprom(uint8_t speed) { rgblight_set_speed_eeprom_helper(speed, false); } | ||
| 562 | |||
| 563 | uint8_t rgblight_get_hue(void) { return rgblight_config.hue; } | ||
| 564 | |||
| 565 | uint8_t rgblight_get_sat(void) { return rgblight_config.sat; } | ||
| 566 | |||
| 567 | uint8_t rgblight_get_val(void) { return rgblight_config.val; } | ||
| 568 | |||
| 569 | HSV rgblight_get_hsv(void) { return (HSV){rgblight_config.hue, rgblight_config.sat, rgblight_config.val}; } | ||
| 570 | |||
| 571 | void rgblight_setrgb(uint8_t r, uint8_t g, uint8_t b) { | ||
| 572 | if (!rgblight_config.enable) { | ||
| 573 | return; | ||
| 574 | } | ||
| 575 | |||
| 576 | for (uint8_t i = rgblight_ranges.effect_start_pos; i < rgblight_ranges.effect_end_pos; i++) { | ||
| 577 | led[i].r = r; | ||
| 578 | led[i].g = g; | ||
| 579 | led[i].b = b; | ||
| 580 | #ifdef RGBW | ||
| 581 | led[i].w = 0; | ||
| 582 | #endif | ||
| 583 | } | ||
| 584 | rgblight_set(); | ||
| 585 | } | ||
| 586 | |||
| 587 | void rgblight_setrgb_at(uint8_t r, uint8_t g, uint8_t b, uint8_t index) { | ||
| 588 | if (!rgblight_config.enable || index >= RGBLED_NUM) { | ||
| 589 | return; | ||
| 590 | } | ||
| 591 | |||
| 592 | led[index].r = r; | ||
| 593 | led[index].g = g; | ||
| 594 | led[index].b = b; | ||
| 595 | #ifdef RGBW | ||
| 596 | led[index].w = 0; | ||
| 597 | #endif | ||
| 598 | rgblight_set(); | ||
| 599 | } | ||
| 600 | |||
| 601 | void rgblight_sethsv_at(uint8_t hue, uint8_t sat, uint8_t val, uint8_t index) { | ||
| 602 | if (!rgblight_config.enable) { | ||
| 603 | return; | ||
| 604 | } | ||
| 605 | |||
| 606 | LED_TYPE tmp_led; | ||
| 607 | sethsv(hue, sat, val, &tmp_led); | ||
| 608 | rgblight_setrgb_at(tmp_led.r, tmp_led.g, tmp_led.b, index); | ||
| 609 | } | ||
| 610 | |||
| 611 | #if defined(RGBLIGHT_EFFECT_BREATHING) || defined(RGBLIGHT_EFFECT_RAINBOW_MOOD) || defined(RGBLIGHT_EFFECT_RAINBOW_SWIRL) || defined(RGBLIGHT_EFFECT_SNAKE) || defined(RGBLIGHT_EFFECT_KNIGHT) || defined(RGBLIGHT_EFFECT_TWINKLE) | ||
| 612 | |||
| 613 | static uint8_t get_interval_time(const uint8_t *default_interval_address, uint8_t velocikey_min, uint8_t velocikey_max) { | ||
| 614 | return | ||
| 615 | # ifdef VELOCIKEY_ENABLE | ||
| 616 | velocikey_enabled() ? velocikey_match_speed(velocikey_min, velocikey_max) : | ||
| 617 | # endif | ||
| 618 | pgm_read_byte(default_interval_address); | ||
| 619 | } | ||
| 620 | |||
| 621 | #endif | ||
| 622 | |||
| 623 | void rgblight_setrgb_range(uint8_t r, uint8_t g, uint8_t b, uint8_t start, uint8_t end) { | ||
| 624 | if (!rgblight_config.enable || start < 0 || start >= end || end > RGBLED_NUM) { | ||
| 625 | return; | ||
| 626 | } | ||
| 627 | |||
| 628 | for (uint8_t i = start; i < end; i++) { | ||
| 629 | led[i].r = r; | ||
| 630 | led[i].g = g; | ||
| 631 | led[i].b = b; | ||
| 632 | #ifdef RGBW | ||
| 633 | led[i].w = 0; | ||
| 634 | #endif | ||
| 635 | } | ||
| 636 | rgblight_set(); | ||
| 637 | wait_ms(1); | ||
| 638 | } | ||
| 639 | |||
| 640 | void rgblight_sethsv_range(uint8_t hue, uint8_t sat, uint8_t val, uint8_t start, uint8_t end) { | ||
| 641 | if (!rgblight_config.enable) { | ||
| 642 | return; | ||
| 643 | } | ||
| 644 | |||
| 645 | LED_TYPE tmp_led; | ||
| 646 | sethsv(hue, sat, val, &tmp_led); | ||
| 647 | rgblight_setrgb_range(tmp_led.r, tmp_led.g, tmp_led.b, start, end); | ||
| 648 | } | ||
| 649 | |||
| 650 | #ifndef RGBLIGHT_SPLIT | ||
| 651 | void rgblight_setrgb_master(uint8_t r, uint8_t g, uint8_t b) { rgblight_setrgb_range(r, g, b, 0, (uint8_t)RGBLED_NUM / 2); } | ||
| 652 | |||
| 653 | void rgblight_setrgb_slave(uint8_t r, uint8_t g, uint8_t b) { rgblight_setrgb_range(r, g, b, (uint8_t)RGBLED_NUM / 2, (uint8_t)RGBLED_NUM); } | ||
| 654 | |||
| 655 | void rgblight_sethsv_master(uint8_t hue, uint8_t sat, uint8_t val) { rgblight_sethsv_range(hue, sat, val, 0, (uint8_t)RGBLED_NUM / 2); } | ||
| 656 | |||
| 657 | void rgblight_sethsv_slave(uint8_t hue, uint8_t sat, uint8_t val) { rgblight_sethsv_range(hue, sat, val, (uint8_t)RGBLED_NUM / 2, (uint8_t)RGBLED_NUM); } | ||
| 658 | #endif // ifndef RGBLIGHT_SPLIT | ||
| 659 | |||
| 660 | #ifdef RGBLIGHT_LAYERS | ||
| 661 | void rgblight_set_layer_state(uint8_t layer, bool enabled) { | ||
| 662 | rgblight_layer_mask_t mask = (rgblight_layer_mask_t)1 << layer; | ||
| 663 | if (enabled) { | ||
| 664 | rgblight_status.enabled_layer_mask |= mask; | ||
| 665 | } else { | ||
| 666 | rgblight_status.enabled_layer_mask &= ~mask; | ||
| 667 | } | ||
| 668 | RGBLIGHT_SPLIT_SET_CHANGE_LAYERS; | ||
| 669 | // Static modes don't have a ticker running to update the LEDs | ||
| 670 | if (rgblight_status.timer_enabled == false) { | ||
| 671 | rgblight_mode_noeeprom(rgblight_config.mode); | ||
| 672 | } | ||
| 673 | |||
| 674 | # ifdef RGBLIGHT_LAYERS_OVERRIDE_RGB_OFF | ||
| 675 | // If not enabled, then nothing else will actually set the LEDs... | ||
| 676 | if (!rgblight_config.enable) { | ||
| 677 | rgblight_set(); | ||
| 678 | } | ||
| 679 | # endif | ||
| 680 | } | ||
| 681 | |||
| 682 | bool rgblight_get_layer_state(uint8_t layer) { | ||
| 683 | rgblight_layer_mask_t mask = (rgblight_layer_mask_t)1 << layer; | ||
| 684 | return (rgblight_status.enabled_layer_mask & mask) != 0; | ||
| 685 | } | ||
| 686 | |||
| 687 | // Write any enabled LED layers into the buffer | ||
| 688 | static void rgblight_layers_write(void) { | ||
| 689 | # ifdef RGBLIGHT_LAYERS_RETAIN_VAL | ||
| 690 | uint8_t current_val = rgblight_get_val(); | ||
| 691 | # endif | ||
| 692 | uint8_t i = 0; | ||
| 693 | // For each layer | ||
| 694 | for (const rgblight_segment_t *const *layer_ptr = rgblight_layers; i < RGBLIGHT_MAX_LAYERS; layer_ptr++, i++) { | ||
| 695 | if (!rgblight_get_layer_state(i)) { | ||
| 696 | continue; // Layer is disabled | ||
| 697 | } | ||
| 698 | const rgblight_segment_t *segment_ptr = pgm_read_ptr(layer_ptr); | ||
| 699 | if (segment_ptr == NULL) { | ||
| 700 | break; // No more layers | ||
| 701 | } | ||
| 702 | // For each segment | ||
| 703 | while (1) { | ||
| 704 | rgblight_segment_t segment; | ||
| 705 | memcpy_P(&segment, segment_ptr, sizeof(rgblight_segment_t)); | ||
| 706 | if (segment.index == RGBLIGHT_END_SEGMENT_INDEX) { | ||
| 707 | break; // No more segments | ||
| 708 | } | ||
| 709 | // Write segment.count LEDs | ||
| 710 | LED_TYPE *const limit = &led[MIN(segment.index + segment.count, RGBLED_NUM)]; | ||
| 711 | for (LED_TYPE *led_ptr = &led[segment.index]; led_ptr < limit; led_ptr++) { | ||
| 712 | # ifdef RGBLIGHT_LAYERS_RETAIN_VAL | ||
| 713 | sethsv(segment.hue, segment.sat, current_val, led_ptr); | ||
| 714 | # else | ||
| 715 | sethsv(segment.hue, segment.sat, segment.val, led_ptr); | ||
| 716 | # endif | ||
| 717 | } | ||
| 718 | segment_ptr++; | ||
| 719 | } | ||
| 720 | } | ||
| 721 | } | ||
| 722 | |||
| 723 | # ifdef RGBLIGHT_LAYER_BLINK | ||
| 724 | rgblight_layer_mask_t _blinking_layer_mask = 0; | ||
| 725 | static uint16_t _repeat_timer; | ||
| 726 | static uint8_t _times_remaining; | ||
| 727 | static uint16_t _dur; | ||
| 728 | |||
| 729 | void rgblight_blink_layer(uint8_t layer, uint16_t duration_ms) { rgblight_blink_layer_repeat(layer, duration_ms, 1); } | ||
| 730 | |||
| 731 | void rgblight_blink_layer_repeat(uint8_t layer, uint16_t duration_ms, uint8_t times) { | ||
| 732 | _times_remaining = times * 2; | ||
| 733 | _dur = duration_ms; | ||
| 734 | |||
| 735 | rgblight_set_layer_state(layer, true); | ||
| 736 | _times_remaining--; | ||
| 737 | _blinking_layer_mask |= (rgblight_layer_mask_t)1 << layer; | ||
| 738 | _repeat_timer = sync_timer_read() + duration_ms; | ||
| 739 | } | ||
| 740 | |||
| 741 | void rgblight_blink_layer_repeat_helper(void) { | ||
| 742 | if (_blinking_layer_mask != 0 && timer_expired(sync_timer_read(), _repeat_timer)) { | ||
| 743 | for (uint8_t layer = 0; layer < RGBLIGHT_MAX_LAYERS; layer++) { | ||
| 744 | if ((_blinking_layer_mask & (rgblight_layer_mask_t)1 << layer) != 0 && _times_remaining > 0) { | ||
| 745 | if (_times_remaining % 2 == 1) { | ||
| 746 | rgblight_set_layer_state(layer, false); | ||
| 747 | } else { | ||
| 748 | rgblight_set_layer_state(layer, true); | ||
| 749 | } | ||
| 750 | _times_remaining--; | ||
| 751 | _repeat_timer = sync_timer_read() + _dur; | ||
| 752 | } | ||
| 753 | } | ||
| 754 | if (_times_remaining <= 0) { | ||
| 755 | _blinking_layer_mask = 0; | ||
| 756 | } | ||
| 757 | } | ||
| 758 | } | ||
| 759 | # endif | ||
| 760 | |||
| 761 | #endif | ||
| 762 | |||
| 763 | #ifdef RGBLIGHT_SLEEP | ||
| 764 | |||
| 765 | void rgblight_suspend(void) { | ||
| 766 | rgblight_timer_disable(); | ||
| 767 | if (!is_suspended) { | ||
| 768 | is_suspended = true; | ||
| 769 | pre_suspend_enabled = rgblight_config.enable; | ||
| 770 | |||
| 771 | # ifdef RGBLIGHT_LAYER_BLINK | ||
| 772 | // make sure any layer blinks don't come back after suspend | ||
| 773 | rgblight_status.enabled_layer_mask &= ~_blinking_layer_mask; | ||
| 774 | _blinking_layer_mask = 0; | ||
| 775 | # endif | ||
| 776 | |||
| 777 | rgblight_disable_noeeprom(); | ||
| 778 | } | ||
| 779 | } | ||
| 780 | |||
| 781 | void rgblight_wakeup(void) { | ||
| 782 | is_suspended = false; | ||
| 783 | |||
| 784 | if (pre_suspend_enabled) { | ||
| 785 | rgblight_enable_noeeprom(); | ||
| 786 | } | ||
| 787 | # ifdef RGBLIGHT_LAYERS_OVERRIDE_RGB_OFF | ||
| 788 | // Need this or else the LEDs won't be set | ||
| 789 | else if (rgblight_status.enabled_layer_mask != 0) { | ||
| 790 | rgblight_set(); | ||
| 791 | } | ||
| 792 | # endif | ||
| 793 | |||
| 794 | rgblight_timer_enable(); | ||
| 795 | } | ||
| 796 | |||
| 797 | #endif | ||
| 798 | |||
| 799 | __attribute__((weak)) void rgblight_call_driver(LED_TYPE *start_led, uint8_t num_leds) { ws2812_setleds(start_led, num_leds); } | ||
| 800 | |||
| 801 | #ifndef RGBLIGHT_CUSTOM_DRIVER | ||
| 802 | |||
| 803 | void rgblight_set(void) { | ||
| 804 | LED_TYPE *start_led; | ||
| 805 | uint8_t num_leds = rgblight_ranges.clipping_num_leds; | ||
| 806 | |||
| 807 | if (!rgblight_config.enable) { | ||
| 808 | for (uint8_t i = rgblight_ranges.effect_start_pos; i < rgblight_ranges.effect_end_pos; i++) { | ||
| 809 | led[i].r = 0; | ||
| 810 | led[i].g = 0; | ||
| 811 | led[i].b = 0; | ||
| 812 | # ifdef RGBW | ||
| 813 | led[i].w = 0; | ||
| 814 | # endif | ||
| 815 | } | ||
| 816 | } | ||
| 817 | |||
| 818 | # ifdef RGBLIGHT_LAYERS | ||
| 819 | if (rgblight_layers != NULL | ||
| 820 | # if !defined(RGBLIGHT_LAYERS_OVERRIDE_RGB_OFF) | ||
| 821 | && rgblight_config.enable | ||
| 822 | # elif defined(RGBLIGHT_SLEEP) | ||
| 823 | && !is_suspended | ||
| 824 | # endif | ||
| 825 | ) { | ||
| 826 | rgblight_layers_write(); | ||
| 827 | } | ||
| 828 | # endif | ||
| 829 | |||
| 830 | # ifdef RGBLIGHT_LED_MAP | ||
| 831 | LED_TYPE led0[RGBLED_NUM]; | ||
| 832 | for (uint8_t i = 0; i < RGBLED_NUM; i++) { | ||
| 833 | led0[i] = led[pgm_read_byte(&led_map[i])]; | ||
| 834 | } | ||
| 835 | start_led = led0 + rgblight_ranges.clipping_start_pos; | ||
| 836 | # else | ||
| 837 | start_led = led + rgblight_ranges.clipping_start_pos; | ||
| 838 | # endif | ||
| 839 | |||
| 840 | # ifdef RGBW | ||
| 841 | for (uint8_t i = 0; i < num_leds; i++) { | ||
| 842 | convert_rgb_to_rgbw(&start_led[i]); | ||
| 843 | } | ||
| 844 | # endif | ||
| 845 | rgblight_call_driver(start_led, num_leds); | ||
| 846 | } | ||
| 847 | #endif | ||
| 848 | |||
| 849 | #ifdef RGBLIGHT_SPLIT | ||
| 850 | /* for split keyboard master side */ | ||
| 851 | uint8_t rgblight_get_change_flags(void) { return rgblight_status.change_flags; } | ||
| 852 | |||
| 853 | void rgblight_clear_change_flags(void) { rgblight_status.change_flags = 0; } | ||
| 854 | |||
| 855 | void rgblight_get_syncinfo(rgblight_syncinfo_t *syncinfo) { | ||
| 856 | syncinfo->config = rgblight_config; | ||
| 857 | syncinfo->status = rgblight_status; | ||
| 858 | } | ||
| 859 | |||
| 860 | /* for split keyboard slave side */ | ||
| 861 | void rgblight_update_sync(rgblight_syncinfo_t *syncinfo, bool write_to_eeprom) { | ||
| 862 | # ifdef RGBLIGHT_LAYERS | ||
| 863 | if (syncinfo->status.change_flags & RGBLIGHT_STATUS_CHANGE_LAYERS) { | ||
| 864 | rgblight_status.enabled_layer_mask = syncinfo->status.enabled_layer_mask; | ||
| 865 | } | ||
| 866 | # endif | ||
| 867 | if (syncinfo->status.change_flags & RGBLIGHT_STATUS_CHANGE_MODE) { | ||
| 868 | if (syncinfo->config.enable) { | ||
| 869 | rgblight_config.enable = 1; // == rgblight_enable_noeeprom(); | ||
| 870 | rgblight_mode_eeprom_helper(syncinfo->config.mode, write_to_eeprom); | ||
| 871 | } else { | ||
| 872 | rgblight_disable_noeeprom(); | ||
| 873 | } | ||
| 874 | } | ||
| 875 | if (syncinfo->status.change_flags & RGBLIGHT_STATUS_CHANGE_HSVS) { | ||
| 876 | rgblight_sethsv_eeprom_helper(syncinfo->config.hue, syncinfo->config.sat, syncinfo->config.val, write_to_eeprom); | ||
| 877 | // rgblight_config.speed = config->speed; // NEED??? | ||
| 878 | } | ||
| 879 | # ifdef RGBLIGHT_USE_TIMER | ||
| 880 | if (syncinfo->status.change_flags & RGBLIGHT_STATUS_CHANGE_TIMER) { | ||
| 881 | if (syncinfo->status.timer_enabled) { | ||
| 882 | rgblight_timer_enable(); | ||
| 883 | } else { | ||
| 884 | rgblight_timer_disable(); | ||
| 885 | } | ||
| 886 | } | ||
| 887 | # ifndef RGBLIGHT_SPLIT_NO_ANIMATION_SYNC | ||
| 888 | if (syncinfo->status.change_flags & RGBLIGHT_STATUS_ANIMATION_TICK) { | ||
| 889 | animation_status.restart = true; | ||
| 890 | } | ||
| 891 | # endif /* RGBLIGHT_SPLIT_NO_ANIMATION_SYNC */ | ||
| 892 | # endif /* RGBLIGHT_USE_TIMER */ | ||
| 893 | } | ||
| 894 | #endif /* RGBLIGHT_SPLIT */ | ||
| 895 | |||
| 896 | #ifdef RGBLIGHT_USE_TIMER | ||
| 897 | |||
| 898 | typedef void (*effect_func_t)(animation_status_t *anim); | ||
| 899 | |||
| 900 | // Animation timer -- use system timer (AVR Timer0) | ||
| 901 | void rgblight_timer_init(void) { | ||
| 902 | rgblight_status.timer_enabled = false; | ||
| 903 | RGBLIGHT_SPLIT_SET_CHANGE_TIMER_ENABLE; | ||
| 904 | } | ||
| 905 | void rgblight_timer_enable(void) { | ||
| 906 | if (!is_static_effect(rgblight_config.mode)) { | ||
| 907 | rgblight_status.timer_enabled = true; | ||
| 908 | } | ||
| 909 | animation_status.last_timer = sync_timer_read(); | ||
| 910 | RGBLIGHT_SPLIT_SET_CHANGE_TIMER_ENABLE; | ||
| 911 | dprintf("rgblight timer enabled.\n"); | ||
| 912 | } | ||
| 913 | void rgblight_timer_disable(void) { | ||
| 914 | rgblight_status.timer_enabled = false; | ||
| 915 | RGBLIGHT_SPLIT_SET_CHANGE_TIMER_ENABLE; | ||
| 916 | dprintf("rgblight timer disable.\n"); | ||
| 917 | } | ||
| 918 | void rgblight_timer_toggle(void) { | ||
| 919 | dprintf("rgblight timer toggle.\n"); | ||
| 920 | if (rgblight_status.timer_enabled) { | ||
| 921 | rgblight_timer_disable(); | ||
| 922 | } else { | ||
| 923 | rgblight_timer_enable(); | ||
| 924 | } | ||
| 925 | } | ||
| 926 | |||
| 927 | void rgblight_show_solid_color(uint8_t r, uint8_t g, uint8_t b) { | ||
| 928 | rgblight_enable(); | ||
| 929 | rgblight_mode(RGBLIGHT_MODE_STATIC_LIGHT); | ||
| 930 | rgblight_setrgb(r, g, b); | ||
| 931 | } | ||
| 932 | |||
| 933 | static void rgblight_effect_dummy(animation_status_t *anim) { | ||
| 934 | // do nothing | ||
| 935 | /******** | ||
| 936 | dprintf("rgblight_task() what happened?\n"); | ||
| 937 | dprintf("is_static_effect %d\n", is_static_effect(rgblight_config.mode)); | ||
| 938 | dprintf("mode = %d, base_mode = %d, timer_enabled %d, ", | ||
| 939 | rgblight_config.mode, rgblight_status.base_mode, | ||
| 940 | rgblight_status.timer_enabled); | ||
| 941 | dprintf("last_timer = %d\n",anim->last_timer); | ||
| 942 | **/ | ||
| 943 | } | ||
| 944 | |||
| 945 | void rgblight_task(void) { | ||
| 946 | if (rgblight_status.timer_enabled) { | ||
| 947 | effect_func_t effect_func = rgblight_effect_dummy; | ||
| 948 | uint16_t interval_time = 2000; // dummy interval | ||
| 949 | uint8_t delta = rgblight_config.mode - rgblight_status.base_mode; | ||
| 950 | animation_status.delta = delta; | ||
| 951 | |||
| 952 | // static light mode, do nothing here | ||
| 953 | if (1 == 0) { // dummy | ||
| 954 | } | ||
| 955 | # ifdef RGBLIGHT_EFFECT_BREATHING | ||
| 956 | else if (rgblight_status.base_mode == RGBLIGHT_MODE_BREATHING) { | ||
| 957 | // breathing mode | ||
| 958 | interval_time = get_interval_time(&RGBLED_BREATHING_INTERVALS[delta], 1, 100); | ||
| 959 | effect_func = rgblight_effect_breathing; | ||
| 960 | } | ||
| 961 | # endif | ||
| 962 | # ifdef RGBLIGHT_EFFECT_RAINBOW_MOOD | ||
| 963 | else if (rgblight_status.base_mode == RGBLIGHT_MODE_RAINBOW_MOOD) { | ||
| 964 | // rainbow mood mode | ||
| 965 | interval_time = get_interval_time(&RGBLED_RAINBOW_MOOD_INTERVALS[delta], 5, 100); | ||
| 966 | effect_func = rgblight_effect_rainbow_mood; | ||
| 967 | } | ||
| 968 | # endif | ||
| 969 | # ifdef RGBLIGHT_EFFECT_RAINBOW_SWIRL | ||
| 970 | else if (rgblight_status.base_mode == RGBLIGHT_MODE_RAINBOW_SWIRL) { | ||
| 971 | // rainbow swirl mode | ||
| 972 | interval_time = get_interval_time(&RGBLED_RAINBOW_SWIRL_INTERVALS[delta / 2], 1, 100); | ||
| 973 | effect_func = rgblight_effect_rainbow_swirl; | ||
| 974 | } | ||
| 975 | # endif | ||
| 976 | # ifdef RGBLIGHT_EFFECT_SNAKE | ||
| 977 | else if (rgblight_status.base_mode == RGBLIGHT_MODE_SNAKE) { | ||
| 978 | // snake mode | ||
| 979 | interval_time = get_interval_time(&RGBLED_SNAKE_INTERVALS[delta / 2], 1, 200); | ||
| 980 | effect_func = rgblight_effect_snake; | ||
| 981 | } | ||
| 982 | # endif | ||
| 983 | # ifdef RGBLIGHT_EFFECT_KNIGHT | ||
| 984 | else if (rgblight_status.base_mode == RGBLIGHT_MODE_KNIGHT) { | ||
| 985 | // knight mode | ||
| 986 | interval_time = get_interval_time(&RGBLED_KNIGHT_INTERVALS[delta], 5, 100); | ||
| 987 | effect_func = rgblight_effect_knight; | ||
| 988 | } | ||
| 989 | # endif | ||
| 990 | # ifdef RGBLIGHT_EFFECT_CHRISTMAS | ||
| 991 | else if (rgblight_status.base_mode == RGBLIGHT_MODE_CHRISTMAS) { | ||
| 992 | // christmas mode | ||
| 993 | interval_time = RGBLIGHT_EFFECT_CHRISTMAS_INTERVAL; | ||
| 994 | effect_func = (effect_func_t)rgblight_effect_christmas; | ||
| 995 | } | ||
| 996 | # endif | ||
| 997 | # ifdef RGBLIGHT_EFFECT_RGB_TEST | ||
| 998 | else if (rgblight_status.base_mode == RGBLIGHT_MODE_RGB_TEST) { | ||
| 999 | // RGB test mode | ||
| 1000 | interval_time = pgm_read_word(&RGBLED_RGBTEST_INTERVALS[0]); | ||
| 1001 | effect_func = (effect_func_t)rgblight_effect_rgbtest; | ||
| 1002 | } | ||
| 1003 | # endif | ||
| 1004 | # ifdef RGBLIGHT_EFFECT_ALTERNATING | ||
| 1005 | else if (rgblight_status.base_mode == RGBLIGHT_MODE_ALTERNATING) { | ||
| 1006 | interval_time = 500; | ||
| 1007 | effect_func = (effect_func_t)rgblight_effect_alternating; | ||
| 1008 | } | ||
| 1009 | # endif | ||
| 1010 | # ifdef RGBLIGHT_EFFECT_TWINKLE | ||
| 1011 | else if (rgblight_status.base_mode == RGBLIGHT_MODE_TWINKLE) { | ||
| 1012 | interval_time = get_interval_time(&RGBLED_TWINKLE_INTERVALS[delta % 3], 5, 30); | ||
| 1013 | effect_func = (effect_func_t)rgblight_effect_twinkle; | ||
| 1014 | } | ||
| 1015 | # endif | ||
| 1016 | if (animation_status.restart) { | ||
| 1017 | animation_status.restart = false; | ||
| 1018 | animation_status.last_timer = sync_timer_read(); | ||
| 1019 | animation_status.pos16 = 0; // restart signal to local each effect | ||
| 1020 | } | ||
| 1021 | uint16_t now = sync_timer_read(); | ||
| 1022 | if (timer_expired(now, animation_status.last_timer)) { | ||
| 1023 | # if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC) | ||
| 1024 | static uint16_t report_last_timer = 0; | ||
| 1025 | static bool tick_flag = false; | ||
| 1026 | uint16_t oldpos16; | ||
| 1027 | if (tick_flag) { | ||
| 1028 | tick_flag = false; | ||
| 1029 | if (timer_expired(now, report_last_timer)) { | ||
| 1030 | report_last_timer += 30000; | ||
| 1031 | dprintf("rgblight animation tick report to slave\n"); | ||
| 1032 | RGBLIGHT_SPLIT_ANIMATION_TICK; | ||
| 1033 | } | ||
| 1034 | } | ||
| 1035 | oldpos16 = animation_status.pos16; | ||
| 1036 | # endif | ||
| 1037 | animation_status.last_timer += interval_time; | ||
| 1038 | effect_func(&animation_status); | ||
| 1039 | # if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC) | ||
| 1040 | if (animation_status.pos16 == 0 && oldpos16 != 0) { | ||
| 1041 | tick_flag = true; | ||
| 1042 | } | ||
| 1043 | # endif | ||
| 1044 | } | ||
| 1045 | } | ||
| 1046 | |||
| 1047 | # ifdef RGBLIGHT_LAYER_BLINK | ||
| 1048 | rgblight_blink_layer_repeat_helper(); | ||
| 1049 | # endif | ||
| 1050 | } | ||
| 1051 | |||
| 1052 | #endif /* RGBLIGHT_USE_TIMER */ | ||
| 1053 | |||
| 1054 | #if defined(RGBLIGHT_EFFECT_BREATHING) || defined(RGBLIGHT_EFFECT_TWINKLE) | ||
| 1055 | |||
| 1056 | # ifndef RGBLIGHT_EFFECT_BREATHE_CENTER | ||
| 1057 | # ifndef RGBLIGHT_BREATHE_TABLE_SIZE | ||
| 1058 | # define RGBLIGHT_BREATHE_TABLE_SIZE 256 // 256 or 128 or 64 | ||
| 1059 | # endif | ||
| 1060 | # include <rgblight_breathe_table.h> | ||
| 1061 | # endif | ||
| 1062 | |||
| 1063 | static uint8_t breathe_calc(uint8_t pos) { | ||
| 1064 | // http://sean.voisen.org/blog/2011/10/breathing-led-with-arduino/ | ||
| 1065 | # ifdef RGBLIGHT_EFFECT_BREATHE_TABLE | ||
| 1066 | return pgm_read_byte(&rgblight_effect_breathe_table[pos / table_scale]); | ||
| 1067 | # else | ||
| 1068 | return (exp(sin((pos / 255.0) * M_PI)) - RGBLIGHT_EFFECT_BREATHE_CENTER / M_E) * (RGBLIGHT_EFFECT_BREATHE_MAX / (M_E - 1 / M_E)); | ||
| 1069 | # endif | ||
| 1070 | } | ||
| 1071 | |||
| 1072 | #endif | ||
| 1073 | |||
| 1074 | // Effects | ||
| 1075 | #ifdef RGBLIGHT_EFFECT_BREATHING | ||
| 1076 | |||
| 1077 | __attribute__((weak)) const uint8_t RGBLED_BREATHING_INTERVALS[] PROGMEM = {30, 20, 10, 5}; | ||
| 1078 | |||
| 1079 | void rgblight_effect_breathing(animation_status_t *anim) { | ||
| 1080 | uint8_t val = breathe_calc(anim->pos); | ||
| 1081 | rgblight_sethsv_noeeprom_old(rgblight_config.hue, rgblight_config.sat, val); | ||
| 1082 | anim->pos = (anim->pos + 1); | ||
| 1083 | } | ||
| 1084 | #endif | ||
| 1085 | |||
| 1086 | #ifdef RGBLIGHT_EFFECT_RAINBOW_MOOD | ||
| 1087 | __attribute__((weak)) const uint8_t RGBLED_RAINBOW_MOOD_INTERVALS[] PROGMEM = {120, 60, 30}; | ||
| 1088 | |||
| 1089 | void rgblight_effect_rainbow_mood(animation_status_t *anim) { | ||
| 1090 | rgblight_sethsv_noeeprom_old(anim->current_hue, rgblight_config.sat, rgblight_config.val); | ||
| 1091 | anim->current_hue++; | ||
| 1092 | } | ||
| 1093 | #endif | ||
| 1094 | |||
| 1095 | #ifdef RGBLIGHT_EFFECT_RAINBOW_SWIRL | ||
| 1096 | # ifndef RGBLIGHT_RAINBOW_SWIRL_RANGE | ||
| 1097 | # define RGBLIGHT_RAINBOW_SWIRL_RANGE 255 | ||
| 1098 | # endif | ||
| 1099 | |||
| 1100 | __attribute__((weak)) const uint8_t RGBLED_RAINBOW_SWIRL_INTERVALS[] PROGMEM = {100, 50, 20}; | ||
| 1101 | |||
| 1102 | void rgblight_effect_rainbow_swirl(animation_status_t *anim) { | ||
| 1103 | uint8_t hue; | ||
| 1104 | uint8_t i; | ||
| 1105 | |||
| 1106 | for (i = 0; i < rgblight_ranges.effect_num_leds; i++) { | ||
| 1107 | hue = (RGBLIGHT_RAINBOW_SWIRL_RANGE / rgblight_ranges.effect_num_leds * i + anim->current_hue); | ||
| 1108 | sethsv(hue, rgblight_config.sat, rgblight_config.val, (LED_TYPE *)&led[i + rgblight_ranges.effect_start_pos]); | ||
| 1109 | } | ||
| 1110 | rgblight_set(); | ||
| 1111 | |||
| 1112 | if (anim->delta % 2) { | ||
| 1113 | anim->current_hue++; | ||
| 1114 | } else { | ||
| 1115 | anim->current_hue--; | ||
| 1116 | } | ||
| 1117 | } | ||
| 1118 | #endif | ||
| 1119 | |||
| 1120 | #ifdef RGBLIGHT_EFFECT_SNAKE | ||
| 1121 | __attribute__((weak)) const uint8_t RGBLED_SNAKE_INTERVALS[] PROGMEM = {100, 50, 20}; | ||
| 1122 | |||
| 1123 | void rgblight_effect_snake(animation_status_t *anim) { | ||
| 1124 | static uint8_t pos = 0; | ||
| 1125 | uint8_t i, j; | ||
| 1126 | int8_t k; | ||
| 1127 | int8_t increment = 1; | ||
| 1128 | |||
| 1129 | if (anim->delta % 2) { | ||
| 1130 | increment = -1; | ||
| 1131 | } | ||
| 1132 | |||
| 1133 | # if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC) | ||
| 1134 | if (anim->pos == 0) { // restart signal | ||
| 1135 | if (increment == 1) { | ||
| 1136 | pos = rgblight_ranges.effect_num_leds - 1; | ||
| 1137 | } else { | ||
| 1138 | pos = 0; | ||
| 1139 | } | ||
| 1140 | anim->pos = 1; | ||
| 1141 | } | ||
| 1142 | # endif | ||
| 1143 | |||
| 1144 | for (i = 0; i < rgblight_ranges.effect_num_leds; i++) { | ||
| 1145 | LED_TYPE *ledp = led + i + rgblight_ranges.effect_start_pos; | ||
| 1146 | ledp->r = 0; | ||
| 1147 | ledp->g = 0; | ||
| 1148 | ledp->b = 0; | ||
| 1149 | # ifdef RGBW | ||
| 1150 | ledp->w = 0; | ||
| 1151 | # endif | ||
| 1152 | for (j = 0; j < RGBLIGHT_EFFECT_SNAKE_LENGTH; j++) { | ||
| 1153 | k = pos + j * increment; | ||
| 1154 | if (k > RGBLED_NUM) { | ||
| 1155 | k = k % RGBLED_NUM; | ||
| 1156 | } | ||
| 1157 | if (k < 0) { | ||
| 1158 | k = k + rgblight_ranges.effect_num_leds; | ||
| 1159 | } | ||
| 1160 | if (i == k) { | ||
| 1161 | sethsv(rgblight_config.hue, rgblight_config.sat, (uint8_t)(rgblight_config.val * (RGBLIGHT_EFFECT_SNAKE_LENGTH - j) / RGBLIGHT_EFFECT_SNAKE_LENGTH), ledp); | ||
| 1162 | } | ||
| 1163 | } | ||
| 1164 | } | ||
| 1165 | rgblight_set(); | ||
| 1166 | if (increment == 1) { | ||
| 1167 | if (pos - 1 < 0) { | ||
| 1168 | pos = rgblight_ranges.effect_num_leds - 1; | ||
| 1169 | # if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC) | ||
| 1170 | anim->pos = 0; | ||
| 1171 | # endif | ||
| 1172 | } else { | ||
| 1173 | pos -= 1; | ||
| 1174 | # if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC) | ||
| 1175 | anim->pos = 1; | ||
| 1176 | # endif | ||
| 1177 | } | ||
| 1178 | } else { | ||
| 1179 | pos = (pos + 1) % rgblight_ranges.effect_num_leds; | ||
| 1180 | # if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC) | ||
| 1181 | anim->pos = pos; | ||
| 1182 | # endif | ||
| 1183 | } | ||
| 1184 | } | ||
| 1185 | #endif | ||
| 1186 | |||
| 1187 | #ifdef RGBLIGHT_EFFECT_KNIGHT | ||
| 1188 | __attribute__((weak)) const uint8_t RGBLED_KNIGHT_INTERVALS[] PROGMEM = {127, 63, 31}; | ||
| 1189 | |||
| 1190 | void rgblight_effect_knight(animation_status_t *anim) { | ||
| 1191 | static int8_t low_bound = 0; | ||
| 1192 | static int8_t high_bound = RGBLIGHT_EFFECT_KNIGHT_LENGTH - 1; | ||
| 1193 | static int8_t increment = 1; | ||
| 1194 | uint8_t i, cur; | ||
| 1195 | |||
| 1196 | # if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC) | ||
| 1197 | if (anim->pos == 0) { // restart signal | ||
| 1198 | anim->pos = 1; | ||
| 1199 | low_bound = 0; | ||
| 1200 | high_bound = RGBLIGHT_EFFECT_KNIGHT_LENGTH - 1; | ||
| 1201 | increment = 1; | ||
| 1202 | } | ||
| 1203 | # endif | ||
| 1204 | // Set all the LEDs to 0 | ||
| 1205 | for (i = rgblight_ranges.effect_start_pos; i < rgblight_ranges.effect_end_pos; i++) { | ||
| 1206 | led[i].r = 0; | ||
| 1207 | led[i].g = 0; | ||
| 1208 | led[i].b = 0; | ||
| 1209 | # ifdef RGBW | ||
| 1210 | led[i].w = 0; | ||
| 1211 | # endif | ||
| 1212 | } | ||
| 1213 | // Determine which LEDs should be lit up | ||
| 1214 | for (i = 0; i < RGBLIGHT_EFFECT_KNIGHT_LED_NUM; i++) { | ||
| 1215 | cur = (i + RGBLIGHT_EFFECT_KNIGHT_OFFSET) % rgblight_ranges.effect_num_leds + rgblight_ranges.effect_start_pos; | ||
| 1216 | |||
| 1217 | if (i >= low_bound && i <= high_bound) { | ||
| 1218 | sethsv(rgblight_config.hue, rgblight_config.sat, rgblight_config.val, (LED_TYPE *)&led[cur]); | ||
| 1219 | } else { | ||
| 1220 | led[cur].r = 0; | ||
| 1221 | led[cur].g = 0; | ||
| 1222 | led[cur].b = 0; | ||
| 1223 | # ifdef RGBW | ||
| 1224 | led[cur].w = 0; | ||
| 1225 | # endif | ||
| 1226 | } | ||
| 1227 | } | ||
| 1228 | rgblight_set(); | ||
| 1229 | |||
| 1230 | // Move from low_bound to high_bound changing the direction we increment each | ||
| 1231 | // time a boundary is hit. | ||
| 1232 | low_bound += increment; | ||
| 1233 | high_bound += increment; | ||
| 1234 | |||
| 1235 | if (high_bound <= 0 || low_bound >= RGBLIGHT_EFFECT_KNIGHT_LED_NUM - 1) { | ||
| 1236 | increment = -increment; | ||
| 1237 | # if defined(RGBLIGHT_SPLIT) && !defined(RGBLIGHT_SPLIT_NO_ANIMATION_SYNC) | ||
| 1238 | if (increment == 1) { | ||
| 1239 | anim->pos = 0; | ||
| 1240 | } | ||
| 1241 | # endif | ||
| 1242 | } | ||
| 1243 | } | ||
| 1244 | #endif | ||
| 1245 | |||
| 1246 | #ifdef RGBLIGHT_EFFECT_CHRISTMAS | ||
| 1247 | # define CUBED(x) ((x) * (x) * (x)) | ||
| 1248 | |||
| 1249 | /** | ||
| 1250 | * Christmas lights effect, with a smooth animation between red & green. | ||
| 1251 | */ | ||
| 1252 | void rgblight_effect_christmas(animation_status_t *anim) { | ||
| 1253 | static int8_t increment = 1; | ||
| 1254 | const uint8_t max_pos = 32; | ||
| 1255 | const uint8_t hue_green = 85; | ||
| 1256 | |||
| 1257 | uint32_t xa; | ||
| 1258 | uint8_t hue, val; | ||
| 1259 | uint8_t i; | ||
| 1260 | |||
| 1261 | // The effect works by animating anim->pos from 0 to 32 and back to 0. | ||
| 1262 | // The pos is used in a cubic bezier formula to ease-in-out between red and green, leaving the interpolated colors visible as short as possible. | ||
| 1263 | xa = CUBED((uint32_t)anim->pos); | ||
| 1264 | hue = ((uint32_t)hue_green) * xa / (xa + CUBED((uint32_t)(max_pos - anim->pos))); | ||
| 1265 | // Additionally, these interpolated colors get shown with a slightly darker value, to make them less prominent than the main colors. | ||
| 1266 | val = 255 - (3 * (hue < hue_green / 2 ? hue : hue_green - hue) / 2); | ||
| 1267 | |||
| 1268 | for (i = 0; i < rgblight_ranges.effect_num_leds; i++) { | ||
| 1269 | uint8_t local_hue = (i / RGBLIGHT_EFFECT_CHRISTMAS_STEP) % 2 ? hue : hue_green - hue; | ||
| 1270 | sethsv(local_hue, rgblight_config.sat, val, (LED_TYPE *)&led[i + rgblight_ranges.effect_start_pos]); | ||
| 1271 | } | ||
| 1272 | rgblight_set(); | ||
| 1273 | |||
| 1274 | if (anim->pos == 0) { | ||
| 1275 | increment = 1; | ||
| 1276 | } else if (anim->pos == max_pos) { | ||
| 1277 | increment = -1; | ||
| 1278 | } | ||
| 1279 | anim->pos += increment; | ||
| 1280 | } | ||
| 1281 | #endif | ||
| 1282 | |||
| 1283 | #ifdef RGBLIGHT_EFFECT_RGB_TEST | ||
| 1284 | __attribute__((weak)) const uint16_t RGBLED_RGBTEST_INTERVALS[] PROGMEM = {1024}; | ||
| 1285 | |||
| 1286 | void rgblight_effect_rgbtest(animation_status_t *anim) { | ||
| 1287 | static uint8_t maxval = 0; | ||
| 1288 | uint8_t g; | ||
| 1289 | uint8_t r; | ||
| 1290 | uint8_t b; | ||
| 1291 | |||
| 1292 | if (maxval == 0) { | ||
| 1293 | LED_TYPE tmp_led; | ||
| 1294 | sethsv(0, 255, RGBLIGHT_LIMIT_VAL, &tmp_led); | ||
| 1295 | maxval = tmp_led.r; | ||
| 1296 | } | ||
| 1297 | g = r = b = 0; | ||
| 1298 | switch (anim->pos) { | ||
| 1299 | case 0: | ||
| 1300 | r = maxval; | ||
| 1301 | break; | ||
| 1302 | case 1: | ||
| 1303 | g = maxval; | ||
| 1304 | break; | ||
| 1305 | case 2: | ||
| 1306 | b = maxval; | ||
| 1307 | break; | ||
| 1308 | } | ||
| 1309 | rgblight_setrgb(r, g, b); | ||
| 1310 | anim->pos = (anim->pos + 1) % 3; | ||
| 1311 | } | ||
| 1312 | #endif | ||
| 1313 | |||
| 1314 | #ifdef RGBLIGHT_EFFECT_ALTERNATING | ||
| 1315 | void rgblight_effect_alternating(animation_status_t *anim) { | ||
| 1316 | for (int i = 0; i < rgblight_ranges.effect_num_leds; i++) { | ||
| 1317 | LED_TYPE *ledp = led + i + rgblight_ranges.effect_start_pos; | ||
| 1318 | if (i < rgblight_ranges.effect_num_leds / 2 && anim->pos) { | ||
| 1319 | sethsv(rgblight_config.hue, rgblight_config.sat, rgblight_config.val, ledp); | ||
| 1320 | } else if (i >= rgblight_ranges.effect_num_leds / 2 && !anim->pos) { | ||
| 1321 | sethsv(rgblight_config.hue, rgblight_config.sat, rgblight_config.val, ledp); | ||
| 1322 | } else { | ||
| 1323 | sethsv(rgblight_config.hue, rgblight_config.sat, 0, ledp); | ||
| 1324 | } | ||
| 1325 | } | ||
| 1326 | rgblight_set(); | ||
| 1327 | anim->pos = (anim->pos + 1) % 2; | ||
| 1328 | } | ||
| 1329 | #endif | ||
| 1330 | |||
| 1331 | #ifdef RGBLIGHT_EFFECT_TWINKLE | ||
| 1332 | __attribute__((weak)) const uint8_t RGBLED_TWINKLE_INTERVALS[] PROGMEM = {30, 15, 5}; | ||
| 1333 | |||
| 1334 | typedef struct PACKED { | ||
| 1335 | HSV hsv; | ||
| 1336 | uint8_t life; | ||
| 1337 | uint8_t max_life; | ||
| 1338 | } TwinkleState; | ||
| 1339 | |||
| 1340 | static TwinkleState led_twinkle_state[RGBLED_NUM]; | ||
| 1341 | |||
| 1342 | void rgblight_effect_twinkle(animation_status_t *anim) { | ||
| 1343 | const bool random_color = anim->delta / 3; | ||
| 1344 | const bool restart = anim->pos == 0; | ||
| 1345 | anim->pos = 1; | ||
| 1346 | |||
| 1347 | const uint8_t bottom = breathe_calc(0); | ||
| 1348 | const uint8_t top = breathe_calc(127); | ||
| 1349 | |||
| 1350 | uint8_t frac(uint8_t n, uint8_t d) { return (uint16_t)255 * n / d; } | ||
| 1351 | uint8_t scale(uint16_t v, uint8_t scale) { return (v * scale) >> 8; } | ||
| 1352 | |||
| 1353 | for (uint8_t i = 0; i < rgblight_ranges.effect_num_leds; i++) { | ||
| 1354 | TwinkleState *t = &(led_twinkle_state[i]); | ||
| 1355 | HSV * c = &(t->hsv); | ||
| 1356 | |||
| 1357 | if (!random_color) { | ||
| 1358 | c->h = rgblight_config.hue; | ||
| 1359 | c->s = rgblight_config.sat; | ||
| 1360 | } | ||
| 1361 | |||
| 1362 | if (restart) { | ||
| 1363 | // Restart | ||
| 1364 | t->life = 0; | ||
| 1365 | c->v = 0; | ||
| 1366 | } else if (t->life) { | ||
| 1367 | // This LED is already on, either brightening or dimming | ||
| 1368 | t->life--; | ||
| 1369 | uint8_t unscaled = frac(breathe_calc(frac(t->life, t->max_life)) - bottom, top - bottom); | ||
| 1370 | c->v = scale(rgblight_config.val, unscaled); | ||
| 1371 | } else if (rand() < scale((uint16_t)RAND_MAX * RGBLIGHT_EFFECT_TWINKLE_PROBABILITY, 127 + rgblight_config.val / 2)) { | ||
| 1372 | // This LED is off, but was randomly selected to start brightening | ||
| 1373 | if (random_color) { | ||
| 1374 | c->h = rand() % 0xFF; | ||
| 1375 | c->s = (rand() % (rgblight_config.sat / 2)) + (rgblight_config.sat / 2); | ||
| 1376 | } | ||
| 1377 | c->v = 0; | ||
| 1378 | t->max_life = MAX(20, MIN(RGBLIGHT_EFFECT_TWINKLE_LIFE, rgblight_config.val)); | ||
| 1379 | t->life = t->max_life; | ||
| 1380 | } else { | ||
| 1381 | // This LED is off, and was NOT selected to start brightening | ||
| 1382 | } | ||
| 1383 | |||
| 1384 | LED_TYPE *ledp = led + i + rgblight_ranges.effect_start_pos; | ||
| 1385 | sethsv(c->h, c->s, c->v, ledp); | ||
| 1386 | } | ||
| 1387 | |||
| 1388 | rgblight_set(); | ||
| 1389 | } | ||
| 1390 | #endif | ||
