rgb_matrix.c 32 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010
  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. #include "rgb_matrix.h"
  19. #include "progmem.h"
  20. #include "config.h"
  21. #include "eeprom.h"
  22. #include <string.h>
  23. #include <math.h>
  24. rgb_config_t rgb_matrix_config;
  25. #ifndef MAX
  26. #define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
  27. #endif
  28. #ifndef MIN
  29. #define MIN(a,b) ((a) < (b)? (a): (b))
  30. #endif
  31. #ifndef RGB_DISABLE_AFTER_TIMEOUT
  32. #define RGB_DISABLE_AFTER_TIMEOUT 0
  33. #endif
  34. #ifndef RGB_DISABLE_WHEN_USB_SUSPENDED
  35. #define RGB_DISABLE_WHEN_USB_SUSPENDED false
  36. #endif
  37. #ifndef EECONFIG_RGB_MATRIX
  38. #define EECONFIG_RGB_MATRIX EECONFIG_RGBLIGHT
  39. #endif
  40. #if !defined(RGB_MATRIX_MAXIMUM_BRIGHTNESS) || RGB_MATRIX_MAXIMUM_BRIGHTNESS > 255
  41. #define RGB_MATRIX_MAXIMUM_BRIGHTNESS 255
  42. #endif
  43. #ifndef RGB_DIGITAL_RAIN_DROPS
  44. // lower the number for denser effect/wider keyboard
  45. #define RGB_DIGITAL_RAIN_DROPS 24
  46. #endif
  47. #if !defined(DISABLE_RGB_MATRIX_RAINDROPS) || !defined(DISABLE_RGB_MATRIX_JELLYBEAN_RAINDROPS) || !defined(DISABLE_RGB_MATRIX_DIGITAL_RAIN)
  48. #define TRACK_PREVIOUS_EFFECT
  49. #endif
  50. bool g_suspend_state = false;
  51. // Global tick at 20 Hz
  52. uint32_t g_tick = 0;
  53. // Ticks since this key was last hit.
  54. uint8_t g_key_hit[DRIVER_LED_TOTAL];
  55. // Ticks since any key was last hit.
  56. uint32_t g_any_key_hit = 0;
  57. #ifndef PI
  58. #define PI 3.14159265
  59. #endif
  60. uint32_t eeconfig_read_rgb_matrix(void) {
  61. return eeprom_read_dword(EECONFIG_RGB_MATRIX);
  62. }
  63. void eeconfig_update_rgb_matrix(uint32_t val) {
  64. eeprom_update_dword(EECONFIG_RGB_MATRIX, val);
  65. }
  66. void eeconfig_update_rgb_matrix_default(void) {
  67. dprintf("eeconfig_update_rgb_matrix_default\n");
  68. rgb_matrix_config.enable = 1;
  69. #ifndef DISABLE_RGB_MATRIX_CYCLE_ALL
  70. rgb_matrix_config.mode = RGB_MATRIX_CYCLE_LEFT_RIGHT;
  71. #else
  72. // fallback to solid colors if RGB_MATRIX_CYCLE_LEFT_RIGHT is disabled in userspace
  73. rgb_matrix_config.mode = RGB_MATRIX_SOLID_COLOR;
  74. #endif
  75. rgb_matrix_config.hue = 0;
  76. rgb_matrix_config.sat = 255;
  77. rgb_matrix_config.val = RGB_MATRIX_MAXIMUM_BRIGHTNESS;
  78. rgb_matrix_config.speed = 0;
  79. eeconfig_update_rgb_matrix(rgb_matrix_config.raw);
  80. }
  81. void eeconfig_debug_rgb_matrix(void) {
  82. dprintf("rgb_matrix_config eprom\n");
  83. dprintf("rgb_matrix_config.enable = %d\n", rgb_matrix_config.enable);
  84. dprintf("rgb_matrix_config.mode = %d\n", rgb_matrix_config.mode);
  85. dprintf("rgb_matrix_config.hue = %d\n", rgb_matrix_config.hue);
  86. dprintf("rgb_matrix_config.sat = %d\n", rgb_matrix_config.sat);
  87. dprintf("rgb_matrix_config.val = %d\n", rgb_matrix_config.val);
  88. dprintf("rgb_matrix_config.speed = %d\n", rgb_matrix_config.speed);
  89. }
  90. // Last led hit
  91. #define LED_HITS_TO_REMEMBER 8
  92. uint8_t g_last_led_hit[LED_HITS_TO_REMEMBER] = {255};
  93. uint8_t g_last_led_count = 0;
  94. void map_row_column_to_led( uint8_t row, uint8_t column, uint8_t *led_i, uint8_t *led_count) {
  95. rgb_led led;
  96. *led_count = 0;
  97. for (uint8_t i = 0; i < DRIVER_LED_TOTAL; i++) {
  98. // map_index_to_led(i, &led);
  99. led = g_rgb_leds[i];
  100. if (row == led.matrix_co.row && column == led.matrix_co.col) {
  101. led_i[*led_count] = i;
  102. (*led_count)++;
  103. }
  104. }
  105. }
  106. void rgb_matrix_update_pwm_buffers(void) {
  107. rgb_matrix_driver.flush();
  108. }
  109. void rgb_matrix_set_color( int index, uint8_t red, uint8_t green, uint8_t blue ) {
  110. rgb_matrix_driver.set_color(index, red, green, blue);
  111. }
  112. void rgb_matrix_set_color_all( uint8_t red, uint8_t green, uint8_t blue ) {
  113. rgb_matrix_driver.set_color_all(red, green, blue);
  114. }
  115. bool process_rgb_matrix(uint16_t keycode, keyrecord_t *record) {
  116. if ( record->event.pressed ) {
  117. uint8_t led[8], led_count;
  118. map_row_column_to_led(record->event.key.row, record->event.key.col, led, &led_count);
  119. if (led_count > 0) {
  120. for (uint8_t i = LED_HITS_TO_REMEMBER; i > 1; i--) {
  121. g_last_led_hit[i - 1] = g_last_led_hit[i - 2];
  122. }
  123. g_last_led_hit[0] = led[0];
  124. g_last_led_count = MIN(LED_HITS_TO_REMEMBER, g_last_led_count + 1);
  125. }
  126. for(uint8_t i = 0; i < led_count; i++)
  127. g_key_hit[led[i]] = 0;
  128. g_any_key_hit = 0;
  129. } else {
  130. #ifdef RGB_MATRIX_KEYRELEASES
  131. uint8_t led[8], led_count;
  132. map_row_column_to_led(record->event.key.row, record->event.key.col, led, &led_count);
  133. for(uint8_t i = 0; i < led_count; i++)
  134. g_key_hit[led[i]] = 255;
  135. g_any_key_hit = 255;
  136. #endif
  137. }
  138. return true;
  139. }
  140. void rgb_matrix_set_suspend_state(bool state) {
  141. g_suspend_state = state;
  142. }
  143. void rgb_matrix_test(void) {
  144. // Mask out bits 4 and 5
  145. // Increase the factor to make the test animation slower (and reduce to make it faster)
  146. uint8_t factor = 10;
  147. switch ( (g_tick & (0b11 << factor)) >> factor )
  148. {
  149. case 0:
  150. {
  151. rgb_matrix_set_color_all( 20, 0, 0 );
  152. break;
  153. }
  154. case 1:
  155. {
  156. rgb_matrix_set_color_all( 0, 20, 0 );
  157. break;
  158. }
  159. case 2:
  160. {
  161. rgb_matrix_set_color_all( 0, 0, 20 );
  162. break;
  163. }
  164. case 3:
  165. {
  166. rgb_matrix_set_color_all( 20, 20, 20 );
  167. break;
  168. }
  169. }
  170. }
  171. // All LEDs off
  172. void rgb_matrix_all_off(void) {
  173. rgb_matrix_set_color_all( 0, 0, 0 );
  174. }
  175. // Solid color
  176. void rgb_matrix_solid_color(void) {
  177. HSV hsv = { .h = rgb_matrix_config.hue, .s = rgb_matrix_config.sat, .v = rgb_matrix_config.val };
  178. RGB rgb = hsv_to_rgb( hsv );
  179. rgb_matrix_set_color_all( rgb.r, rgb.g, rgb.b );
  180. }
  181. void rgb_matrix_solid_reactive(void) {
  182. // Relies on hue being 8-bit and wrapping
  183. for ( int i=0; i<DRIVER_LED_TOTAL; i++ )
  184. {
  185. uint16_t offset2 = g_key_hit[i]<<2;
  186. offset2 = (offset2<=130) ? (130-offset2) : 0;
  187. HSV hsv = { .h = rgb_matrix_config.hue+offset2, .s = 255, .v = rgb_matrix_config.val };
  188. RGB rgb = hsv_to_rgb( hsv );
  189. rgb_matrix_set_color( i, rgb.r, rgb.g, rgb.b );
  190. }
  191. }
  192. void rgb_matrix_solid_reactive_simple(void)
  193. {
  194. HSV hsv = {.h = rgb_matrix_config.hue, .s = rgb_matrix_config.sat, .v = rgb_matrix_config.val};
  195. RGB rgb;
  196. for (int i = 0; i < DRIVER_LED_TOTAL; i++) {
  197. uint16_t offset2 = g_key_hit[i] << 2;
  198. offset2 = (offset2 <= 255) ? (255 - offset2) : 0;
  199. hsv.v = offset2 * rgb_matrix_config.val / RGB_MATRIX_MAXIMUM_BRIGHTNESS;
  200. rgb = hsv_to_rgb(hsv);
  201. rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b);
  202. }
  203. }
  204. // alphas = color1, mods = color2
  205. void rgb_matrix_alphas_mods(void) {
  206. RGB rgb1 = hsv_to_rgb( (HSV){ .h = rgb_matrix_config.hue, .s = rgb_matrix_config.sat, .v = rgb_matrix_config.val } );
  207. RGB rgb2 = hsv_to_rgb( (HSV){ .h = (rgb_matrix_config.hue + 180) % 360, .s = rgb_matrix_config.sat, .v = rgb_matrix_config.val } );
  208. rgb_led led;
  209. for (int i = 0; i < DRIVER_LED_TOTAL; i++) {
  210. led = g_rgb_leds[i];
  211. if ( led.matrix_co.raw < 0xFF ) {
  212. if ( led.modifier )
  213. {
  214. rgb_matrix_set_color( i, rgb2.r, rgb2.g, rgb2.b );
  215. }
  216. else
  217. {
  218. rgb_matrix_set_color( i, rgb1.r, rgb1.g, rgb1.b );
  219. }
  220. }
  221. }
  222. }
  223. void rgb_matrix_gradient_up_down(void) {
  224. int16_t h1 = rgb_matrix_config.hue;
  225. int16_t h2 = (rgb_matrix_config.hue + 180) % 360;
  226. int16_t deltaH = h2 - h1;
  227. // Take the shortest path between hues
  228. if ( deltaH > 127 )
  229. {
  230. deltaH -= 256;
  231. }
  232. else if ( deltaH < -127 )
  233. {
  234. deltaH += 256;
  235. }
  236. // Divide delta by 4, this gives the delta per row
  237. deltaH /= 4;
  238. int16_t s1 = rgb_matrix_config.sat;
  239. int16_t s2 = rgb_matrix_config.hue;
  240. int16_t deltaS = ( s2 - s1 ) / 4;
  241. HSV hsv = { .h = 0, .s = 255, .v = rgb_matrix_config.val };
  242. RGB rgb;
  243. Point point;
  244. for ( int i=0; i<DRIVER_LED_TOTAL; i++ )
  245. {
  246. // map_led_to_point( i, &point );
  247. point = g_rgb_leds[i].point;
  248. // The y range will be 0..64, map this to 0..4
  249. uint8_t y = (point.y>>4);
  250. // Relies on hue being 8-bit and wrapping
  251. hsv.h = rgb_matrix_config.hue + ( deltaH * y );
  252. hsv.s = rgb_matrix_config.sat + ( deltaS * y );
  253. rgb = hsv_to_rgb( hsv );
  254. rgb_matrix_set_color( i, rgb.r, rgb.g, rgb.b );
  255. }
  256. }
  257. void rgb_matrix_raindrops(bool initialize) {
  258. int16_t h1 = rgb_matrix_config.hue;
  259. int16_t h2 = (rgb_matrix_config.hue + 180) % 360;
  260. int16_t deltaH = h2 - h1;
  261. deltaH /= 4;
  262. // Take the shortest path between hues
  263. if ( deltaH > 127 )
  264. {
  265. deltaH -= 256;
  266. }
  267. else if ( deltaH < -127 )
  268. {
  269. deltaH += 256;
  270. }
  271. int16_t s1 = rgb_matrix_config.sat;
  272. int16_t s2 = rgb_matrix_config.sat;
  273. int16_t deltaS = ( s2 - s1 ) / 4;
  274. HSV hsv;
  275. RGB rgb;
  276. // Change one LED every tick, make sure speed is not 0
  277. uint8_t led_to_change = ( g_tick & ( 0x0A / (rgb_matrix_config.speed == 0 ? 1 : rgb_matrix_config.speed) ) ) == 0 ? rand() % (DRIVER_LED_TOTAL) : 255;
  278. for ( int i=0; i<DRIVER_LED_TOTAL; i++ )
  279. {
  280. // If initialize, all get set to random colors
  281. // If not, all but one will stay the same as before.
  282. if ( initialize || i == led_to_change )
  283. {
  284. hsv.h = h1 + ( deltaH * ( rand() & 0x03 ) );
  285. hsv.s = s1 + ( deltaS * ( rand() & 0x03 ) );
  286. // Override brightness with global brightness control
  287. hsv.v = rgb_matrix_config.val;
  288. rgb = hsv_to_rgb( hsv );
  289. rgb_matrix_set_color( i, rgb.r, rgb.g, rgb.b );
  290. }
  291. }
  292. }
  293. void rgb_matrix_cycle_all(void) {
  294. uint8_t offset = ( g_tick << rgb_matrix_config.speed ) & 0xFF;
  295. rgb_led led;
  296. // Relies on hue being 8-bit and wrapping
  297. for ( int i=0; i<DRIVER_LED_TOTAL; i++ )
  298. {
  299. // map_index_to_led(i, &led);
  300. led = g_rgb_leds[i];
  301. if (led.matrix_co.raw < 0xFF) {
  302. uint16_t offset2 = g_key_hit[i]<<2;
  303. offset2 = (offset2<=63) ? (63-offset2) : 0;
  304. HSV hsv = { .h = offset+offset2, .s = 255, .v = rgb_matrix_config.val };
  305. RGB rgb = hsv_to_rgb( hsv );
  306. rgb_matrix_set_color( i, rgb.r, rgb.g, rgb.b );
  307. }
  308. }
  309. }
  310. void rgb_matrix_cycle_left_right(void) {
  311. uint8_t offset = ( g_tick << rgb_matrix_config.speed ) & 0xFF;
  312. HSV hsv = { .h = 0, .s = 255, .v = rgb_matrix_config.val };
  313. RGB rgb;
  314. Point point;
  315. rgb_led led;
  316. for ( int i=0; i<DRIVER_LED_TOTAL; i++ )
  317. {
  318. // map_index_to_led(i, &led);
  319. led = g_rgb_leds[i];
  320. if (led.matrix_co.raw < 0xFF) {
  321. uint16_t offset2 = g_key_hit[i]<<2;
  322. offset2 = (offset2<=63) ? (63-offset2) : 0;
  323. // map_led_to_point( i, &point );
  324. point = g_rgb_leds[i].point;
  325. // Relies on hue being 8-bit and wrapping
  326. hsv.h = point.x + offset + offset2;
  327. rgb = hsv_to_rgb( hsv );
  328. rgb_matrix_set_color( i, rgb.r, rgb.g, rgb.b );
  329. }
  330. }
  331. }
  332. void rgb_matrix_cycle_up_down(void) {
  333. uint8_t offset = ( g_tick << rgb_matrix_config.speed ) & 0xFF;
  334. HSV hsv = { .h = 0, .s = 255, .v = rgb_matrix_config.val };
  335. RGB rgb;
  336. Point point;
  337. rgb_led led;
  338. for ( int i=0; i<DRIVER_LED_TOTAL; i++ )
  339. {
  340. // map_index_to_led(i, &led);
  341. led = g_rgb_leds[i];
  342. if (led.matrix_co.raw < 0xFF) {
  343. uint16_t offset2 = g_key_hit[i]<<2;
  344. offset2 = (offset2<=63) ? (63-offset2) : 0;
  345. // map_led_to_point( i, &point );
  346. point = g_rgb_leds[i].point;
  347. // Relies on hue being 8-bit and wrapping
  348. hsv.h = point.y + offset + offset2;
  349. rgb = hsv_to_rgb( hsv );
  350. rgb_matrix_set_color( i, rgb.r, rgb.g, rgb.b );
  351. }
  352. }
  353. }
  354. void rgb_matrix_dual_beacon(void) {
  355. HSV hsv = { .h = rgb_matrix_config.hue, .s = rgb_matrix_config.sat, .v = rgb_matrix_config.val };
  356. RGB rgb;
  357. Point point;
  358. double cos_value = cos(g_tick * PI / 128) / 32;
  359. double sin_value = sin(g_tick * PI / 128) / 112;
  360. for (uint8_t i = 0; i < DRIVER_LED_TOTAL; i++) {
  361. point = g_rgb_leds[i].point;
  362. hsv.h = ((point.y - 32.0)* cos_value + (point.x - 112.0) * sin_value) * (180) + rgb_matrix_config.hue;
  363. rgb = hsv_to_rgb( hsv );
  364. rgb_matrix_set_color( i, rgb.r, rgb.g, rgb.b );
  365. }
  366. }
  367. void rgb_matrix_rainbow_beacon(void) {
  368. HSV hsv = { .h = rgb_matrix_config.hue, .s = rgb_matrix_config.sat, .v = rgb_matrix_config.val };
  369. RGB rgb;
  370. Point point;
  371. double cos_value = cos(g_tick * PI / 128);
  372. double sin_value = sin(g_tick * PI / 128);
  373. for (uint8_t i = 0; i < DRIVER_LED_TOTAL; i++) {
  374. point = g_rgb_leds[i].point;
  375. hsv.h = (1.5 * (rgb_matrix_config.speed == 0 ? 1 : rgb_matrix_config.speed)) * (point.y - 32.0)* cos_value + (1.5 * (rgb_matrix_config.speed == 0 ? 1 : rgb_matrix_config.speed)) * (point.x - 112.0) * sin_value + rgb_matrix_config.hue;
  376. rgb = hsv_to_rgb( hsv );
  377. rgb_matrix_set_color( i, rgb.r, rgb.g, rgb.b );
  378. }
  379. }
  380. void rgb_matrix_rainbow_pinwheels(void) {
  381. HSV hsv = { .h = rgb_matrix_config.hue, .s = rgb_matrix_config.sat, .v = rgb_matrix_config.val };
  382. RGB rgb;
  383. Point point;
  384. double cos_value = cos(g_tick * PI / 128);
  385. double sin_value = sin(g_tick * PI / 128);
  386. for (uint8_t i = 0; i < DRIVER_LED_TOTAL; i++) {
  387. point = g_rgb_leds[i].point;
  388. hsv.h = (2 * (rgb_matrix_config.speed == 0 ? 1 : rgb_matrix_config.speed)) * (point.y - 32.0)* cos_value + (2 * (rgb_matrix_config.speed == 0 ? 1 : rgb_matrix_config.speed)) * (66 - abs(point.x - 112.0)) * sin_value + rgb_matrix_config.hue;
  389. rgb = hsv_to_rgb( hsv );
  390. rgb_matrix_set_color( i, rgb.r, rgb.g, rgb.b );
  391. }
  392. }
  393. void rgb_matrix_rainbow_moving_chevron(void) {
  394. HSV hsv = { .h = rgb_matrix_config.hue, .s = rgb_matrix_config.sat, .v = rgb_matrix_config.val };
  395. RGB rgb;
  396. Point point;
  397. uint8_t r = 128;
  398. double cos_value = cos(r * PI / 128);
  399. double sin_value = sin(r * PI / 128);
  400. double multiplier = (g_tick / 256.0 * 224);
  401. for (uint8_t i = 0; i < DRIVER_LED_TOTAL; i++) {
  402. point = g_rgb_leds[i].point;
  403. hsv.h = (1.5 * (rgb_matrix_config.speed == 0 ? 1 : rgb_matrix_config.speed)) * abs(point.y - 32.0)* sin_value + (1.5 * (rgb_matrix_config.speed == 0 ? 1 : rgb_matrix_config.speed)) * (point.x - multiplier) * cos_value + rgb_matrix_config.hue;
  404. rgb = hsv_to_rgb( hsv );
  405. rgb_matrix_set_color( i, rgb.r, rgb.g, rgb.b );
  406. }
  407. }
  408. void rgb_matrix_jellybean_raindrops( bool initialize ) {
  409. HSV hsv;
  410. RGB rgb;
  411. // Change one LED every tick, make sure speed is not 0
  412. uint8_t led_to_change = ( g_tick & ( 0x0A / (rgb_matrix_config.speed == 0 ? 1 : rgb_matrix_config.speed) ) ) == 0 ? rand() % (DRIVER_LED_TOTAL) : 255;
  413. for ( int i=0; i<DRIVER_LED_TOTAL; i++ )
  414. {
  415. // If initialize, all get set to random colors
  416. // If not, all but one will stay the same as before.
  417. if ( initialize || i == led_to_change )
  418. {
  419. hsv.h = rand() & 0xFF;
  420. hsv.s = rand() & 0xFF;
  421. // Override brightness with global brightness control
  422. hsv.v = rgb_matrix_config.val;
  423. rgb = hsv_to_rgb( hsv );
  424. rgb_matrix_set_color( i, rgb.r, rgb.g, rgb.b );
  425. }
  426. }
  427. }
  428. void rgb_matrix_digital_rain( const bool initialize ) {
  429. // algorithm ported from https://github.com/tremby/Kaleidoscope-LEDEffect-DigitalRain
  430. const uint8_t drop_ticks = 28;
  431. const uint8_t pure_green_intensity = 0xd0;
  432. const uint8_t max_brightness_boost = 0xc0;
  433. const uint8_t max_intensity = 0xff;
  434. static uint8_t map[MATRIX_COLS][MATRIX_ROWS] = {{0}};
  435. static uint8_t drop = 0;
  436. if (initialize) {
  437. rgb_matrix_set_color_all(0, 0, 0);
  438. memset(map, 0, sizeof map);
  439. drop = 0;
  440. }
  441. for (uint8_t col = 0; col < MATRIX_COLS; col++) {
  442. for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
  443. if (row == 0 && drop == 0 && rand() < RAND_MAX / RGB_DIGITAL_RAIN_DROPS) {
  444. // top row, pixels have just fallen and we're
  445. // making a new rain drop in this column
  446. map[col][row] = max_intensity;
  447. }
  448. else if (map[col][row] > 0 && map[col][row] < max_intensity) {
  449. // neither fully bright nor dark, decay it
  450. map[col][row]--;
  451. }
  452. // set the pixel colour
  453. uint8_t led, led_count;
  454. map_row_column_to_led(row, col, &led, &led_count);
  455. if (map[col][row] > pure_green_intensity) {
  456. const uint8_t boost = (uint8_t) ((uint16_t) max_brightness_boost
  457. * (map[col][row] - pure_green_intensity) / (max_intensity - pure_green_intensity));
  458. rgb_matrix_set_color(led, boost, max_intensity, boost);
  459. }
  460. else {
  461. const uint8_t green = (uint8_t) ((uint16_t) max_intensity * map[col][row] / pure_green_intensity);
  462. rgb_matrix_set_color(led, 0, green, 0);
  463. }
  464. }
  465. }
  466. if (++drop > drop_ticks) {
  467. // reset drop timer
  468. drop = 0;
  469. for (uint8_t row = MATRIX_ROWS - 1; row > 0; row--) {
  470. for (uint8_t col = 0; col < MATRIX_COLS; col++) {
  471. // if ths is on the bottom row and bright allow decay
  472. if (row == MATRIX_ROWS - 1 && map[col][row] == max_intensity) {
  473. map[col][row]--;
  474. }
  475. // check if the pixel above is bright
  476. if (map[col][row - 1] == max_intensity) {
  477. // allow old bright pixel to decay
  478. map[col][row - 1]--;
  479. // make this pixel bright
  480. map[col][row] = max_intensity;
  481. }
  482. }
  483. }
  484. }
  485. }
  486. void rgb_matrix_multisplash(void) {
  487. // if (g_any_key_hit < 0xFF) {
  488. HSV hsv = { .h = rgb_matrix_config.hue, .s = rgb_matrix_config.sat, .v = rgb_matrix_config.val };
  489. RGB rgb;
  490. rgb_led led;
  491. for (uint8_t i = 0; i < DRIVER_LED_TOTAL; i++) {
  492. led = g_rgb_leds[i];
  493. uint16_t c = 0, d = 0;
  494. rgb_led last_led;
  495. // if (g_last_led_count) {
  496. for (uint8_t last_i = 0; last_i < g_last_led_count; last_i++) {
  497. last_led = g_rgb_leds[g_last_led_hit[last_i]];
  498. uint16_t dist = (uint16_t)sqrt(pow(led.point.x - last_led.point.x, 2) + pow(led.point.y - last_led.point.y, 2));
  499. uint16_t effect = (g_key_hit[g_last_led_hit[last_i]] << 2) - dist;
  500. c += MIN(MAX(effect, 0), 255);
  501. d += 255 - MIN(MAX(effect, 0), 255);
  502. }
  503. // } else {
  504. // d = 255;
  505. // }
  506. hsv.h = (rgb_matrix_config.hue + c) % 256;
  507. hsv.v = MAX(MIN(d, 255), 0);
  508. rgb = hsv_to_rgb( hsv );
  509. rgb_matrix_set_color( i, rgb.r, rgb.g, rgb.b );
  510. }
  511. // } else {
  512. // rgb_matrix_set_color_all( 0, 0, 0 );
  513. // }
  514. }
  515. void rgb_matrix_splash(void) {
  516. g_last_led_count = MIN(g_last_led_count, 1);
  517. rgb_matrix_multisplash();
  518. }
  519. void rgb_matrix_solid_multisplash(void) {
  520. // if (g_any_key_hit < 0xFF) {
  521. HSV hsv = { .h = rgb_matrix_config.hue, .s = rgb_matrix_config.sat, .v = rgb_matrix_config.val };
  522. RGB rgb;
  523. rgb_led led;
  524. for (uint8_t i = 0; i < DRIVER_LED_TOTAL; i++) {
  525. led = g_rgb_leds[i];
  526. uint16_t d = 0;
  527. rgb_led last_led;
  528. // if (g_last_led_count) {
  529. for (uint8_t last_i = 0; last_i < g_last_led_count; last_i++) {
  530. last_led = g_rgb_leds[g_last_led_hit[last_i]];
  531. uint16_t dist = (uint16_t)sqrt(pow(led.point.x - last_led.point.x, 2) + pow(led.point.y - last_led.point.y, 2));
  532. uint16_t effect = (g_key_hit[g_last_led_hit[last_i]] << 2) - dist;
  533. d += 255 - MIN(MAX(effect, 0), 255);
  534. }
  535. // } else {
  536. // d = 255;
  537. // }
  538. hsv.v = MAX(MIN(d, 255), 0);
  539. rgb = hsv_to_rgb( hsv );
  540. rgb_matrix_set_color( i, rgb.r, rgb.g, rgb.b );
  541. }
  542. // } else {
  543. // rgb_matrix_set_color_all( 0, 0, 0 );
  544. // }
  545. }
  546. void rgb_matrix_solid_splash(void) {
  547. g_last_led_count = MIN(g_last_led_count, 1);
  548. rgb_matrix_solid_multisplash();
  549. }
  550. // Needs eeprom access that we don't have setup currently
  551. void rgb_matrix_custom(void) {
  552. // HSV hsv;
  553. // RGB rgb;
  554. // for ( int i=0; i<DRIVER_LED_TOTAL; i++ )
  555. // {
  556. // backlight_get_key_color(i, &hsv);
  557. // // Override brightness with global brightness control
  558. // hsv.v = rgb_matrix_config.val;
  559. // rgb = hsv_to_rgb( hsv );
  560. // rgb_matrix_set_color( i, rgb.r, rgb.g, rgb.b );
  561. // }
  562. }
  563. void rgb_matrix_task(void) {
  564. #ifdef TRACK_PREVIOUS_EFFECT
  565. static uint8_t toggle_enable_last = 255;
  566. #endif
  567. if (!rgb_matrix_config.enable) {
  568. rgb_matrix_all_off();
  569. rgb_matrix_indicators();
  570. #ifdef TRACK_PREVIOUS_EFFECT
  571. toggle_enable_last = rgb_matrix_config.enable;
  572. #endif
  573. return;
  574. }
  575. // delay 1 second before driving LEDs or doing anything else
  576. static uint8_t startup_tick = 0;
  577. if ( startup_tick < 20 ) {
  578. startup_tick++;
  579. return;
  580. }
  581. g_tick++;
  582. if ( g_any_key_hit < 0xFFFFFFFF ) {
  583. g_any_key_hit++;
  584. }
  585. for ( int led = 0; led < DRIVER_LED_TOTAL; led++ ) {
  586. if ( g_key_hit[led] < 255 ) {
  587. if (g_key_hit[led] == 254)
  588. g_last_led_count = MAX(g_last_led_count - 1, 0);
  589. g_key_hit[led]++;
  590. }
  591. }
  592. // Factory default magic value
  593. if ( rgb_matrix_config.mode == 255 ) {
  594. rgb_matrix_test();
  595. return;
  596. }
  597. // Ideally we would also stop sending zeros to the LED driver PWM buffers
  598. // while suspended and just do a software shutdown. This is a cheap hack for now.
  599. bool suspend_backlight = ((g_suspend_state && RGB_DISABLE_WHEN_USB_SUSPENDED) ||
  600. (RGB_DISABLE_AFTER_TIMEOUT > 0 && g_any_key_hit > RGB_DISABLE_AFTER_TIMEOUT * 60 * 20));
  601. uint8_t effect = suspend_backlight ? 0 : rgb_matrix_config.mode;
  602. #ifdef TRACK_PREVIOUS_EFFECT
  603. // Keep track of the effect used last time,
  604. // detect change in effect, so each effect can
  605. // have an optional initialization.
  606. static uint8_t effect_last = 255;
  607. bool initialize = (effect != effect_last) || (rgb_matrix_config.enable != toggle_enable_last);
  608. effect_last = effect;
  609. toggle_enable_last = rgb_matrix_config.enable;
  610. #endif
  611. // this gets ticked at 20 Hz.
  612. // each effect can opt to do calculations
  613. // and/or request PWM buffer updates.
  614. switch ( effect ) {
  615. case RGB_MATRIX_SOLID_COLOR:
  616. rgb_matrix_solid_color();
  617. break;
  618. #ifndef DISABLE_RGB_MATRIX_ALPHAS_MODS
  619. case RGB_MATRIX_ALPHAS_MODS:
  620. rgb_matrix_alphas_mods();
  621. break;
  622. #endif
  623. #ifndef DISABLE_RGB_MATRIX_DUAL_BEACON
  624. case RGB_MATRIX_DUAL_BEACON:
  625. rgb_matrix_dual_beacon();
  626. break;
  627. #endif
  628. #ifndef DISABLE_RGB_MATRIX_GRADIENT_UP_DOWN
  629. case RGB_MATRIX_GRADIENT_UP_DOWN:
  630. rgb_matrix_gradient_up_down();
  631. break;
  632. #endif
  633. #ifndef DISABLE_RGB_MATRIX_RAINDROPS
  634. case RGB_MATRIX_RAINDROPS:
  635. rgb_matrix_raindrops( initialize );
  636. break;
  637. #endif
  638. #ifndef DISABLE_RGB_MATRIX_CYCLE_ALL
  639. case RGB_MATRIX_CYCLE_ALL:
  640. rgb_matrix_cycle_all();
  641. break;
  642. #endif
  643. #ifndef DISABLE_RGB_MATRIX_CYCLE_LEFT_RIGHT
  644. case RGB_MATRIX_CYCLE_LEFT_RIGHT:
  645. rgb_matrix_cycle_left_right();
  646. break;
  647. #endif
  648. #ifndef DISABLE_RGB_MATRIX_CYCLE_UP_DOWN
  649. case RGB_MATRIX_CYCLE_UP_DOWN:
  650. rgb_matrix_cycle_up_down();
  651. break;
  652. #endif
  653. #ifndef DISABLE_RGB_MATRIX_RAINBOW_BEACON
  654. case RGB_MATRIX_RAINBOW_BEACON:
  655. rgb_matrix_rainbow_beacon();
  656. break;
  657. #endif
  658. #ifndef DISABLE_RGB_MATRIX_RAINBOW_PINWHEELS
  659. case RGB_MATRIX_RAINBOW_PINWHEELS:
  660. rgb_matrix_rainbow_pinwheels();
  661. break;
  662. #endif
  663. #ifndef DISABLE_RGB_MATRIX_RAINBOW_MOVING_CHEVRON
  664. case RGB_MATRIX_RAINBOW_MOVING_CHEVRON:
  665. rgb_matrix_rainbow_moving_chevron();
  666. break;
  667. #endif
  668. #ifndef DISABLE_RGB_MATRIX_JELLYBEAN_RAINDROPS
  669. case RGB_MATRIX_JELLYBEAN_RAINDROPS:
  670. rgb_matrix_jellybean_raindrops( initialize );
  671. break;
  672. #endif
  673. #ifndef DISABLE_RGB_MATRIX_DIGITAL_RAIN
  674. case RGB_MATRIX_DIGITAL_RAIN:
  675. rgb_matrix_digital_rain( initialize );
  676. break;
  677. #endif
  678. #ifdef RGB_MATRIX_KEYPRESSES
  679. #ifndef DISABLE_RGB_MATRIX_SOLID_REACTIVE
  680. case RGB_MATRIX_SOLID_REACTIVE:
  681. rgb_matrix_solid_reactive();
  682. break;
  683. #endif
  684. #ifndef DISABLE_RGB_MATRIX_SOLID_REACTIVE_SIMPLE
  685. case RGB_MATRIX_SOLID_REACTIVE_SIMPLE:
  686. rgb_matrix_solid_reactive_simple();
  687. break;
  688. #endif
  689. #ifndef DISABLE_RGB_MATRIX_SPLASH
  690. case RGB_MATRIX_SPLASH:
  691. rgb_matrix_splash();
  692. break;
  693. #endif
  694. #ifndef DISABLE_RGB_MATRIX_MULTISPLASH
  695. case RGB_MATRIX_MULTISPLASH:
  696. rgb_matrix_multisplash();
  697. break;
  698. #endif
  699. #ifndef DISABLE_RGB_MATRIX_SOLID_SPLASH
  700. case RGB_MATRIX_SOLID_SPLASH:
  701. rgb_matrix_solid_splash();
  702. break;
  703. #endif
  704. #ifndef DISABLE_RGB_MATRIX_SOLID_MULTISPLASH
  705. case RGB_MATRIX_SOLID_MULTISPLASH:
  706. rgb_matrix_solid_multisplash();
  707. break;
  708. #endif
  709. #endif
  710. default:
  711. rgb_matrix_custom();
  712. break;
  713. }
  714. if ( ! suspend_backlight ) {
  715. rgb_matrix_indicators();
  716. }
  717. }
  718. void rgb_matrix_indicators(void) {
  719. rgb_matrix_indicators_kb();
  720. rgb_matrix_indicators_user();
  721. }
  722. __attribute__((weak))
  723. void rgb_matrix_indicators_kb(void) {}
  724. __attribute__((weak))
  725. void rgb_matrix_indicators_user(void) {}
  726. // void rgb_matrix_set_indicator_index( uint8_t *index, uint8_t row, uint8_t column )
  727. // {
  728. // if ( row >= MATRIX_ROWS )
  729. // {
  730. // // Special value, 255=none, 254=all
  731. // *index = row;
  732. // }
  733. // else
  734. // {
  735. // // This needs updated to something like
  736. // // uint8_t led[8], led_count;
  737. // // map_row_column_to_led(row,column,led,&led_count);
  738. // // for(uint8_t i = 0; i < led_count; i++)
  739. // map_row_column_to_led( row, column, index );
  740. // }
  741. // }
  742. void rgb_matrix_init(void) {
  743. rgb_matrix_driver.init();
  744. // TODO: put the 1 second startup delay here?
  745. // clear the key hits
  746. for ( int led=0; led<DRIVER_LED_TOTAL; led++ ) {
  747. g_key_hit[led] = 255;
  748. }
  749. if (!eeconfig_is_enabled()) {
  750. dprintf("rgb_matrix_init_drivers eeconfig is not enabled.\n");
  751. eeconfig_init();
  752. eeconfig_update_rgb_matrix_default();
  753. }
  754. rgb_matrix_config.raw = eeconfig_read_rgb_matrix();
  755. if (!rgb_matrix_config.mode) {
  756. dprintf("rgb_matrix_init_drivers rgb_matrix_config.mode = 0. Write default values to EEPROM.\n");
  757. eeconfig_update_rgb_matrix_default();
  758. rgb_matrix_config.raw = eeconfig_read_rgb_matrix();
  759. }
  760. eeconfig_debug_rgb_matrix(); // display current eeprom values
  761. }
  762. // Deals with the messy details of incrementing an integer
  763. static uint8_t increment( uint8_t value, uint8_t step, uint8_t min, uint8_t max ) {
  764. int16_t new_value = value;
  765. new_value += step;
  766. return MIN( MAX( new_value, min ), max );
  767. }
  768. static uint8_t decrement( uint8_t value, uint8_t step, uint8_t min, uint8_t max ) {
  769. int16_t new_value = value;
  770. new_value -= step;
  771. return MIN( MAX( new_value, min ), max );
  772. }
  773. // void *backlight_get_custom_key_color_eeprom_address( uint8_t led )
  774. // {
  775. // // 3 bytes per color
  776. // return EECONFIG_RGB_MATRIX + ( led * 3 );
  777. // }
  778. // void backlight_get_key_color( uint8_t led, HSV *hsv )
  779. // {
  780. // void *address = backlight_get_custom_key_color_eeprom_address( led );
  781. // hsv->h = eeprom_read_byte(address);
  782. // hsv->s = eeprom_read_byte(address+1);
  783. // hsv->v = eeprom_read_byte(address+2);
  784. // }
  785. // void backlight_set_key_color( uint8_t row, uint8_t column, HSV hsv )
  786. // {
  787. // uint8_t led[8], led_count;
  788. // map_row_column_to_led(row,column,led,&led_count);
  789. // for(uint8_t i = 0; i < led_count; i++) {
  790. // if ( led[i] < DRIVER_LED_TOTAL )
  791. // {
  792. // void *address = backlight_get_custom_key_color_eeprom_address(led[i]);
  793. // eeprom_update_byte(address, hsv.h);
  794. // eeprom_update_byte(address+1, hsv.s);
  795. // eeprom_update_byte(address+2, hsv.v);
  796. // }
  797. // }
  798. // }
  799. uint32_t rgb_matrix_get_tick(void) {
  800. return g_tick;
  801. }
  802. void rgb_matrix_toggle(void) {
  803. rgb_matrix_config.enable ^= 1;
  804. eeconfig_update_rgb_matrix(rgb_matrix_config.raw);
  805. }
  806. void rgb_matrix_enable(void) {
  807. rgb_matrix_config.enable = 1;
  808. eeconfig_update_rgb_matrix(rgb_matrix_config.raw);
  809. }
  810. void rgb_matrix_enable_noeeprom(void) {
  811. rgb_matrix_config.enable = 1;
  812. }
  813. void rgb_matrix_disable(void) {
  814. rgb_matrix_config.enable = 0;
  815. eeconfig_update_rgb_matrix(rgb_matrix_config.raw);
  816. }
  817. void rgb_matrix_disable_noeeprom(void) {
  818. rgb_matrix_config.enable = 0;
  819. }
  820. void rgb_matrix_step(void) {
  821. rgb_matrix_config.mode++;
  822. if (rgb_matrix_config.mode >= RGB_MATRIX_EFFECT_MAX)
  823. rgb_matrix_config.mode = 1;
  824. eeconfig_update_rgb_matrix(rgb_matrix_config.raw);
  825. }
  826. void rgb_matrix_step_reverse(void) {
  827. rgb_matrix_config.mode--;
  828. if (rgb_matrix_config.mode < 1)
  829. rgb_matrix_config.mode = RGB_MATRIX_EFFECT_MAX - 1;
  830. eeconfig_update_rgb_matrix(rgb_matrix_config.raw);
  831. }
  832. void rgb_matrix_increase_hue(void) {
  833. rgb_matrix_config.hue = increment( rgb_matrix_config.hue, 8, 0, 255 );
  834. eeconfig_update_rgb_matrix(rgb_matrix_config.raw);
  835. }
  836. void rgb_matrix_decrease_hue(void) {
  837. rgb_matrix_config.hue = decrement( rgb_matrix_config.hue, 8, 0, 255 );
  838. eeconfig_update_rgb_matrix(rgb_matrix_config.raw);
  839. }
  840. void rgb_matrix_increase_sat(void) {
  841. rgb_matrix_config.sat = increment( rgb_matrix_config.sat, 8, 0, 255 );
  842. eeconfig_update_rgb_matrix(rgb_matrix_config.raw);
  843. }
  844. void rgb_matrix_decrease_sat(void) {
  845. rgb_matrix_config.sat = decrement( rgb_matrix_config.sat, 8, 0, 255 );
  846. eeconfig_update_rgb_matrix(rgb_matrix_config.raw);
  847. }
  848. void rgb_matrix_increase_val(void) {
  849. rgb_matrix_config.val = increment( rgb_matrix_config.val, 8, 0, RGB_MATRIX_MAXIMUM_BRIGHTNESS );
  850. eeconfig_update_rgb_matrix(rgb_matrix_config.raw);
  851. }
  852. void rgb_matrix_decrease_val(void) {
  853. rgb_matrix_config.val = decrement( rgb_matrix_config.val, 8, 0, RGB_MATRIX_MAXIMUM_BRIGHTNESS );
  854. eeconfig_update_rgb_matrix(rgb_matrix_config.raw);
  855. }
  856. void rgb_matrix_increase_speed(void) {
  857. rgb_matrix_config.speed = increment( rgb_matrix_config.speed, 1, 0, 3 );
  858. eeconfig_update_rgb_matrix(rgb_matrix_config.raw);//EECONFIG needs to be increased to support this
  859. }
  860. void rgb_matrix_decrease_speed(void) {
  861. rgb_matrix_config.speed = decrement( rgb_matrix_config.speed, 1, 0, 3 );
  862. eeconfig_update_rgb_matrix(rgb_matrix_config.raw);//EECONFIG needs to be increased to support this
  863. }
  864. void rgb_matrix_mode(uint8_t mode) {
  865. rgb_matrix_config.mode = mode;
  866. eeconfig_update_rgb_matrix(rgb_matrix_config.raw);
  867. }
  868. void rgb_matrix_mode_noeeprom(uint8_t mode) {
  869. rgb_matrix_config.mode = mode;
  870. }
  871. uint8_t rgb_matrix_get_mode(void) {
  872. return rgb_matrix_config.mode;
  873. }
  874. void rgb_matrix_sethsv(uint16_t hue, uint8_t sat, uint8_t val) {
  875. rgb_matrix_config.hue = hue;
  876. rgb_matrix_config.sat = sat;
  877. rgb_matrix_config.val = val;
  878. eeconfig_update_rgb_matrix(rgb_matrix_config.raw);
  879. }
  880. void rgb_matrix_sethsv_noeeprom(uint16_t hue, uint8_t sat, uint8_t val) {
  881. rgb_matrix_config.hue = hue;
  882. rgb_matrix_config.sat = sat;
  883. rgb_matrix_config.val = val;
  884. }