rgb_ring.c (14052B)
1 /** 2 * @file rgb_ring.c 3 * @author astro 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_ring.h" 20 21 #include <stdint.h> 22 #include <stdbool.h> 23 #include <string.h> 24 #include "quantum.h" 25 #include "rgblight.h" 26 #include "timer.h" 27 #include "action.h" 28 #include "drivers/led/issi/is31fl3731.h" 29 #include "i2c_master.h" 30 31 32 #ifndef RGBLIGHT_ENABLE 33 #error "MUST enable rgblight" 34 #endif 35 // rgb ring leds setting 36 37 const is31fl3731_led_t PROGMEM g_is31fl3731_leds[IS31FL3731_LED_COUNT] = { 38 /* Refer to IS31 manual for these locations 39 * driver 40 * | R location 41 * | | G location 42 * | | | B location 43 * | | | | */ 44 {0, C1_1, C3_2, C4_2}, 45 {0, C1_2, C2_2, C4_3}, 46 {0, C1_3, C2_3, C3_3}, 47 {0, C1_4, C2_4, C3_4}, 48 {0, C1_5, C2_5, C3_5}, 49 {0, C1_6, C2_6, C3_6}, 50 {0, C1_7, C2_7, C3_7}, 51 {0, C1_8, C2_8, C3_8}, 52 53 {0, C9_1, C8_1, C7_1}, 54 {0, C9_2, C8_2, C7_2}, 55 {0, C9_3, C8_3, C7_3}, 56 {0, C9_4, C8_4, C7_4}, 57 {0, C9_5, C8_5, C7_5}, 58 {0, C9_6, C8_6, C7_6}, 59 {0, C9_7, C8_7, C6_6}, 60 {0, C9_8, C7_7, C6_7}, 61 62 {0, C1_9, C3_10, C4_10}, 63 {0, C1_10, C2_10, C4_11}, 64 {0, C1_11, C2_11, C3_11}, 65 {0, C1_12, C2_12, C3_12}, 66 }; 67 68 #define RING_OUTER_BEGIN 0 69 #define RING_OUTER_END 15 70 #define RING_OUTER_SIZE (RING_OUTER_END + 1 - RING_OUTER_BEGIN) 71 72 #define RING_INNER_BEGIN 16 73 #define RING_INNER_END 19 74 #define RING_INNER_SIZE (RING_INNER_END + 1 - RING_INNER_BEGIN) 75 76 #define SPEED_MAX 100 77 #define SPEED_STEP 10 78 79 typedef enum { 80 RING_STATE_INIT, 81 RING_STATE_QMK, 82 RING_STATE_CUSTOM, 83 } RING_STATE; 84 85 typedef enum { 86 RING_EFFECT_1, 87 RING_EFFECT_2, 88 RING_EFFECT_3, 89 RING_EFFECT_4, 90 RING_EFFECT_5, 91 RING_EFFECT_6, 92 RING_EFFECT_MAX 93 } RING_EFFECT; 94 95 typedef struct { 96 uint8_t state; 97 uint8_t effect; 98 uint8_t speed; 99 uint8_t outer_index; 100 uint8_t inner_index; 101 uint8_t effect_count; 102 uint8_t led_begin; 103 uint8_t led_end; 104 bool led_forward; 105 bool led_clear; 106 } rgb_ring_t; 107 108 static rgb_ring_t rgb_ring = { 109 .state = RING_STATE_INIT, 110 .effect = RING_EFFECT_1, 111 .speed = 10, 112 .outer_index = 0, 113 .inner_index = 0, 114 .effect_count = 0, 115 .led_begin = RING_OUTER_BEGIN, 116 .led_end = RING_OUTER_END, 117 .led_forward = true, 118 .led_clear = false, 119 }; 120 121 static void rgb_ring_reset(void) 122 { 123 rgb_ring.effect_count = 0; 124 rgb_ring.led_begin = RING_OUTER_BEGIN; 125 rgb_ring.led_end = RING_OUTER_END; 126 rgb_ring.led_forward = true; 127 rgb_ring.led_clear = false; 128 } 129 130 extern animation_status_t animation_status; 131 extern rgblight_config_t rgblight_config; 132 133 #define EFFECT_TEST_INTERVAL 50 134 #define EFFECT_TEST_COUNT 5 135 #define EFFECT_TEST_HUE_STEP 85 136 #define EFFECT_TEST_VAL_STEP 17 137 static void testing_mode(void) 138 { 139 if (timer_elapsed(animation_status.last_timer) > EFFECT_TEST_INTERVAL) { 140 hsv_t h = {rgblight_config.hue, rgblight_config.sat, rgblight_config.val}; 141 rgb_t c = hsv_to_rgb(h); 142 //is31fl3731_set_color_all(c.r, c.g, c.b); 143 is31fl3731_set_color_all(0, 0, 0); 144 is31fl3731_set_color(rgb_ring.outer_index+RING_OUTER_BEGIN, c.r, c.g, c.b); 145 h.v = EFFECT_TEST_VAL_STEP*rgb_ring.outer_index; 146 c = hsv_to_rgb(h); 147 for (uint8_t i = RING_INNER_BEGIN; i <= RING_INNER_END; i++) { 148 is31fl3731_set_color(i, c.r, c.g, c.b); 149 } 150 rgb_ring.outer_index = (rgb_ring.outer_index + 1) % RING_OUTER_SIZE; 151 //rgb_ring.inner_index = (rgb_ring.inner_index + 1) % RING_INNER_SIZE; 152 153 if (rgb_ring.outer_index == RING_OUTER_BEGIN) { 154 rgblight_config.hue += EFFECT_TEST_HUE_STEP; 155 rgb_ring.effect_count++; 156 } 157 animation_status.last_timer = timer_read(); 158 } 159 if (rgb_ring.effect_count > EFFECT_TEST_COUNT) { 160 rgb_ring_reset(); 161 rgb_ring.state = RING_STATE_QMK; 162 rgblight_set(); 163 } 164 } 165 166 static bool need_update(uint32_t max_interval) 167 { 168 uint32_t interval = timer_elapsed(animation_status.last_timer); 169 return (interval*rgb_ring.speed) > max_interval; 170 } 171 172 static void update_effect(uint32_t max_count) 173 { 174 if (rgb_ring.effect_count > max_count) { 175 rgb_ring_reset(); 176 rgb_ring.effect = (rgb_ring.effect + 1) % RING_EFFECT_MAX; 177 } 178 } 179 180 #define EFFECT_1_INTERVAL 1000 181 #define EFFECT_1_COUNT 64 182 #define EFFECT_1_HUE_STEP 15 183 184 static void ring_effect_no_1(void) 185 { 186 if (need_update(EFFECT_1_INTERVAL)) { 187 hsv_t h = {rgblight_config.hue, rgblight_config.sat, rgblight_config.val}; 188 for (uint8_t i = RING_OUTER_BEGIN; i <= RING_OUTER_END; i++) { 189 rgb_t c = hsv_to_rgb(h); 190 is31fl3731_set_color(i, c.r, c.g, c.b); 191 } 192 rgblight_config.hue += EFFECT_1_HUE_STEP; 193 rgb_ring.effect_count++; 194 animation_status.last_timer = timer_read(); 195 } 196 197 update_effect(EFFECT_1_COUNT); 198 } 199 200 #define EFFECT_2_INTERVAL 1000 201 #define EFFECT_2_COUNT 64 202 #define EFFECT_2_HUE_STEP 15 203 204 static void ring_effect_no_2(void) 205 { 206 if (need_update(EFFECT_2_INTERVAL)) { 207 is31fl3731_set_color_all(0, 0, 0); 208 hsv_t h = {rgblight_config.hue, rgblight_config.sat, rgblight_config.val}; 209 rgb_t c = hsv_to_rgb(h); 210 211 is31fl3731_set_color(rgb_ring.led_begin, c.r, c.g, c.b); 212 is31fl3731_set_color(rgb_ring.led_end, c.r, c.g, c.b); 213 214 rgb_ring.led_begin = (rgb_ring.led_begin + 1) % RING_OUTER_SIZE; 215 rgb_ring.led_end = (rgb_ring.led_end + RING_OUTER_SIZE - 1) % RING_OUTER_SIZE; 216 217 rgblight_config.hue += EFFECT_2_HUE_STEP; 218 rgb_ring.effect_count++; 219 animation_status.last_timer = timer_read(); 220 } 221 222 update_effect(EFFECT_2_COUNT); 223 } 224 225 #define EFFECT_3_INTERVAL 1000 226 #define EFFECT_3_COUNT 64 227 #define EFFECT_3_HUE_STEP 15 228 229 static void ring_effect_no_3(void) 230 { 231 if (rgb_ring.effect_count == 0) { 232 is31fl3731_set_color_all(0, 0, 0); 233 } 234 235 if (need_update(EFFECT_3_INTERVAL)) { 236 hsv_t h = {rgblight_config.hue, rgblight_config.sat, rgblight_config.val}; 237 238 if (rgb_ring.led_clear) { 239 is31fl3731_set_color(rgb_ring.led_begin, 0, 0, 0); 240 is31fl3731_set_color(rgb_ring.led_end, 0, 0, 0); 241 } else { 242 rgb_t c = hsv_to_rgb(h); 243 is31fl3731_set_color(rgb_ring.led_begin, c.r, c.g, c.b); 244 is31fl3731_set_color(rgb_ring.led_end, c.r, c.g, c.b); 245 } 246 247 rgb_ring.led_begin = (rgb_ring.led_begin + 1) % RING_OUTER_SIZE; 248 if (rgb_ring.led_begin == rgb_ring.led_end) { 249 if (rgb_ring.led_forward) { 250 rgb_ring.led_begin = RING_OUTER_BEGIN; 251 rgb_ring.led_end = RING_OUTER_END+1; 252 } else { 253 rgb_ring.led_begin = RING_OUTER_BEGIN + RING_OUTER_SIZE/2; 254 rgb_ring.led_end = RING_OUTER_END+1 - RING_OUTER_SIZE/2; 255 } 256 257 if (!rgb_ring.led_clear) { 258 rgb_ring.led_forward = !rgb_ring.led_forward; 259 } 260 261 rgb_ring.led_clear = !rgb_ring.led_clear; 262 } 263 264 rgb_ring.led_end = (rgb_ring.led_end + RING_OUTER_SIZE - 1) % RING_OUTER_SIZE; 265 266 rgblight_config.hue += EFFECT_3_HUE_STEP; 267 rgb_ring.effect_count++; 268 animation_status.last_timer = timer_read(); 269 } 270 271 update_effect(EFFECT_3_COUNT); 272 } 273 274 #define EFFECT_4_INTERVAL 1000 275 #define EFFECT_4_COUNT 64 276 #define EFFECT_4_STEP 3 277 static void ring_effect_no_4(void) 278 { 279 if (need_update(EFFECT_4_INTERVAL)) { 280 is31fl3731_set_color_all(0, 0, 0); 281 hsv_t h = {rgblight_config.hue, rgblight_config.sat, rgblight_config.val}; 282 rgb_t c = hsv_to_rgb(h); 283 284 is31fl3731_set_color(rgb_ring.led_begin, c.r, c.g, c.b); 285 is31fl3731_set_color(rgb_ring.led_end, c.r, c.g, c.b); 286 287 rgb_ring.led_begin = (rgb_ring.led_begin + EFFECT_4_STEP) % RING_OUTER_SIZE; 288 rgb_ring.led_end = (rgb_ring.led_end + RING_OUTER_SIZE - EFFECT_4_STEP) % RING_OUTER_SIZE; 289 290 rgblight_config.hue += EFFECT_1_HUE_STEP; 291 rgb_ring.effect_count++; 292 animation_status.last_timer = timer_read(); 293 } 294 295 update_effect(EFFECT_4_COUNT); 296 } 297 298 #define EFFECT_5_INTERVAL 1000 299 #define EFFECT_5_COUNT 64 300 #define EFFECT_5_HUE_STEP 16 301 static void ring_effect_no_5(void) 302 { 303 if (need_update(EFFECT_5_INTERVAL)) { 304 is31fl3731_set_color_all(0, 0, 0); 305 for (uint8_t i = RING_INNER_BEGIN; i <= RING_INNER_END; i++) { 306 hsv_t h = {rgblight_config.hue, rgblight_config.sat, rgblight_config.val}; 307 rgb_t c = hsv_to_rgb(h); 308 is31fl3731_set_color(i, c.r, c.g, c.b); 309 } 310 for (uint8_t i = RING_OUTER_BEGIN; i <= RING_OUTER_END; i++) { 311 hsv_t h = {rgblight_config.hue+EFFECT_5_HUE_STEP, rgblight_config.sat, rgblight_config.val}; 312 rgb_t c = hsv_to_rgb(h); 313 is31fl3731_set_color(i, c.r, c.g, c.b); 314 } 315 rgblight_config.hue += EFFECT_5_HUE_STEP; 316 rgb_ring.effect_count++; 317 animation_status.last_timer = timer_read(); 318 } 319 320 update_effect(EFFECT_5_COUNT); 321 } 322 323 #define EFFECT_6_INTERVAL 1000 324 #define EFFECT_6_COUNT 64 325 #define EFFECT_I_HUE_STEP 10 326 #define EFFECT_O_HUE_STEP 10 327 static void ring_effect_no_6(void) 328 { 329 if (need_update(EFFECT_6_INTERVAL)) { 330 is31fl3731_set_color_all(0, 0, 0); 331 for (uint8_t i = RING_INNER_BEGIN; i <= RING_INNER_END; i++) { 332 hsv_t h = {rgblight_config.hue+i*EFFECT_I_HUE_STEP, rgblight_config.sat, rgblight_config.val}; 333 rgb_t c = hsv_to_rgb(h); 334 is31fl3731_set_color(i, c.r, c.g, c.b); 335 } 336 for (uint8_t i = RING_OUTER_BEGIN; i <= RING_OUTER_END; i++) { 337 hsv_t h = {rgblight_config.hue+i*EFFECT_O_HUE_STEP, rgblight_config.sat, rgblight_config.val}; 338 rgb_t c = hsv_to_rgb(h); 339 is31fl3731_set_color(i, c.r, c.g, c.b); 340 } 341 rgblight_config.hue += EFFECT_I_HUE_STEP; 342 rgb_ring.effect_count++; 343 animation_status.last_timer = timer_read(); 344 } 345 346 update_effect(EFFECT_6_COUNT); 347 } 348 349 typedef void(*effect_fun)(void); 350 static effect_fun effect_funcs[RING_EFFECT_MAX] = { 351 ring_effect_no_1, 352 ring_effect_no_2, 353 ring_effect_no_3, 354 ring_effect_no_4, 355 ring_effect_no_5, 356 ring_effect_no_6, 357 }; 358 359 static void custom_effects(void) 360 { 361 effect_funcs[rgb_ring.effect](); 362 } 363 364 void flush_custom(void) { 365 if (rgb_ring.state != RING_STATE_QMK) { 366 return; 367 } 368 369 is31fl3731_flush(); 370 } 371 372 const rgblight_driver_t rgblight_driver = { 373 .init = is31fl3731_init_drivers, 374 .set_color = is31fl3731_set_color, 375 .set_color_all = is31fl3731_set_color_all, 376 .flush = flush_custom, 377 }; 378 379 380 void rgb_ring_task(void) 381 { 382 switch (rgb_ring.state) { 383 case RING_STATE_INIT: // testing mode 384 testing_mode(); 385 break; 386 case RING_STATE_QMK: // qmk effects 387 //rgblight_task(); 388 break; 389 case RING_STATE_CUSTOM: // custom effects 390 custom_effects(); 391 break; 392 default: 393 break; 394 }; 395 } 396 397 bool process_record_kb(uint16_t keycode, keyrecord_t *record) 398 { 399 if (record->event.pressed) { 400 switch(keycode) { 401 case QK_UNDERGLOW_MODE_NEXT: 402 if (rgb_ring.state == RING_STATE_INIT) { 403 // in testing mode, do nothing 404 return false; 405 } else if (rgb_ring.state == RING_STATE_CUSTOM) { 406 // switch to qmk mode 407 rgblight_config.mode = 1; 408 rgb_ring.state = RING_STATE_QMK; 409 rgblight_mode(rgblight_config.mode); 410 return false; 411 } else { 412 // in qmk mode, switch to custom mode? 413 if (rgblight_config.mode >= RGBLIGHT_MODES) { 414 rgb_ring.state = RING_STATE_CUSTOM; 415 return false; 416 } 417 } 418 break; 419 case QK_UNDERGLOW_MODE_PREVIOUS: 420 if (rgb_ring.state == RING_STATE_INIT) { 421 // in testing mode, do nothing 422 return false; 423 } else if (rgb_ring.state == RING_STATE_CUSTOM) { 424 // switch to qmk mode 425 rgblight_config.mode = RGBLIGHT_MODES; 426 rgb_ring.state = RING_STATE_QMK; 427 rgblight_mode(rgblight_config.mode); 428 return false; 429 } else { 430 // in qmk mode, switch to custom mode? 431 if (rgblight_config.mode <= 1) { 432 rgb_ring.state = RING_STATE_CUSTOM; 433 return false; 434 } 435 } 436 break; 437 case KC_F24: 438 if (rgb_ring.state == RING_STATE_QMK) { 439 rgb_ring.state = RING_STATE_CUSTOM; 440 rgb_ring_reset(); 441 return false; 442 } else if (rgb_ring.state == RING_STATE_CUSTOM) { 443 rgb_ring.state = RING_STATE_QMK; 444 return false; 445 } 446 break; 447 default: 448 break; 449 } 450 } 451 return process_record_user(keycode, record); 452 }