mxss_frontled.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. /* Copyright 2020 Jumail Mundekkat / MxBlue
  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. * Extended from the work done by fcoury: https://github.com/qmk/qmk_firmware/pull/4915
  17. */
  18. #include "mxss_frontled.h"
  19. #include "tmk_core/common/eeprom.h"
  20. #include "rgblight.h"
  21. #include "via.h"
  22. #include "version.h" // for QMK_BUILDDATE used in EEPROM magic
  23. // Variables for controlling front LED application
  24. uint8_t fled_mode; // Mode for front LEDs
  25. uint8_t fled_val; // Brightness for front leds (0 - 255)
  26. LED_TYPE fleds[2]; // Front LED rgb values for indicator mode use
  27. // Layer indicator colors
  28. __attribute__ ((weak))
  29. hs_set layer_colors[FRONTLED_COLOR_MAXCNT];
  30. // Caps lock indicator color
  31. __attribute__ ((weak))
  32. hs_set caps_color;
  33. __attribute__ ((weak))
  34. size_t lc_size = sizeof(layer_colors) / sizeof(hs_set);
  35. void fled_init(void) {
  36. // If EEPROM config exists, load it
  37. // If VIA EEPROM exists, FLED config should too
  38. if (via_eeprom_is_valid()) {
  39. fled_load_conf();
  40. // Else, default config
  41. } else {
  42. // Default mode/brightness
  43. fled_mode = FLED_RGB;
  44. fled_val = 10 * FLED_VAL_STEP;
  45. // Default colors
  46. caps_color.hue = 0;
  47. caps_color.sat = 255;
  48. layer_colors[0].hue = 0;
  49. layer_colors[0].sat = 0;
  50. layer_colors[1].hue = 86;
  51. layer_colors[1].sat = 255;
  52. layer_colors[2].hue = 36;
  53. layer_colors[2].sat = 255;
  54. layer_colors[3].hue = 185;
  55. layer_colors[3].sat = 255;
  56. fled_update_conf(); // Store default config to EEPROM
  57. }
  58. // Set default values for leds
  59. setrgb(0, 0, 0, &fleds[0]);
  60. setrgb(0, 0, 0, &fleds[1]);
  61. // Handle lighting for indicator mode
  62. if (fled_mode == FLED_INDI) {
  63. fled_lock_update(host_keyboard_led_state());
  64. fled_layer_update(layer_state);
  65. }
  66. }
  67. void process_record_fled(uint16_t keycode, keyrecord_t *record) {
  68. // Handle custom keycodes for front LED operation
  69. switch (keycode) {
  70. case FLED_MOD: // Change between front LED operation modes (off, indicator, RGB)
  71. if (record->event.pressed)
  72. fled_mode_cycle();
  73. break;
  74. case FLED_VAI: // Increase the brightness of the front LEDs by FLED_VAL_STEP
  75. if (record->event.pressed)
  76. fled_val_increase();
  77. break;
  78. case FLED_VAD: // Decrease the brightness of the front LEDs by FLED_VAL_STEP
  79. if (record->event.pressed)
  80. fled_val_decrease();
  81. break;
  82. default:
  83. break; // Process all other keycodes normally
  84. }
  85. return;
  86. }
  87. void fled_load_conf(void) {
  88. // Load config
  89. fled_config fled_conf;
  90. fled_conf.raw = eeprom_read_byte(FRONTLED_CONF_ADDR);
  91. fled_mode = fled_conf.mode;
  92. fled_val = fled_conf.val * FLED_VAL_STEP;
  93. // Load color data
  94. uint8_t stored_cnt = eeprom_read_byte(FRONTLED_COLOR_CNT_ADDR);
  95. uint16_t *color_ptr = FRONTLED_COLOR_ADDR;
  96. caps_color.raw = eeprom_read_word(color_ptr); // Should always store at least 1 color
  97. for (uint8_t i = 1; i < stored_cnt; i++) {
  98. if (i == lc_size) // Can't load more layers than we have available
  99. break;
  100. layer_colors[i].raw = eeprom_read_word(&color_ptr[i]);
  101. }
  102. layer_colors[0].raw = 0; // hue = sat = 0 for layer 0
  103. }
  104. // Store current front led config in EEPROM
  105. void fled_update_conf(void)
  106. {
  107. // Create storage struct and set values
  108. fled_config conf;
  109. conf.mode = fled_mode;
  110. // Small hack to ensure max value is stored correctly
  111. if (fled_val == 255)
  112. conf.val = 256 / FLED_VAL_STEP;
  113. else
  114. conf.val = fled_val / FLED_VAL_STEP;
  115. // Store config
  116. eeprom_update_byte(FRONTLED_CONF_ADDR, conf.raw);
  117. // Store color data
  118. uint16_t *color_ptr = FRONTLED_COLOR_ADDR;
  119. eeprom_update_word(color_ptr, caps_color.raw);
  120. // Start from 1, layer 0 is not modifiable and therefore not persisted
  121. uint8_t i = 1;
  122. for (; i < lc_size; i++) {
  123. if (i == FRONTLED_COLOR_MAXCNT) // Can't store more than the EEPROM we have available
  124. break;
  125. eeprom_update_word(&color_ptr[i], layer_colors[i].raw);
  126. }
  127. eeprom_update_byte(FRONTLED_COLOR_CNT_ADDR, i); // For safety, store the count of colors stored
  128. }
  129. // Custom keycode functions
  130. void fled_mode_cycle(void)
  131. {
  132. // FLED -> FLED_RGB -> FLED_INDI
  133. switch (fled_mode) {
  134. case FLED_OFF:
  135. fled_mode = FLED_RGB;
  136. rgblight_timer_enable();
  137. break;
  138. case FLED_RGB:
  139. fled_mode = FLED_INDI;
  140. break;
  141. case FLED_INDI:
  142. fled_mode = FLED_OFF;
  143. break;
  144. }
  145. // Update stored config
  146. fled_update_conf();
  147. rgblight_set();
  148. }
  149. void fled_val_increase(void)
  150. {
  151. // Increase val by FLED_VAL_STEP, handling the upper edge case
  152. if (fled_val + FLED_VAL_STEP > 255)
  153. fled_val = 255;
  154. else
  155. fled_val += FLED_VAL_STEP;
  156. // Update stored config
  157. fled_update_conf();
  158. rgblight_set();
  159. }
  160. void fled_val_decrease(void)
  161. {
  162. // Decrease val by FLED_VAL_STEP, handling the lower edge case
  163. if (fled_val - FLED_VAL_STEP > 255)
  164. fled_val = 255;
  165. else
  166. fled_val -= FLED_VAL_STEP;
  167. // Update stored config
  168. fled_update_conf();
  169. rgblight_set();
  170. }
  171. void fled_layer_update(layer_state_t state) {
  172. // Determine and set colour of layer LED according to current layer
  173. // if hue = sat = 0, leave LED off
  174. uint8_t layer = get_highest_layer(state);
  175. if (layer < lc_size && !(layer_colors[layer].hue == 0 && layer_colors[layer].sat == 0)) {
  176. sethsv(layer_colors[layer].hue, layer_colors[layer].sat, fled_val, &fleds[1]);
  177. } else {
  178. setrgb(0, 0, 0, &fleds[1]);
  179. }
  180. }
  181. void fled_lock_update(led_t led_state) {
  182. // Set indicator LED appropriately, whether it is used or not
  183. if (led_state.caps_lock) {
  184. sethsv(caps_color.hue, caps_color.sat, fled_val, &fleds[0]);
  185. } else {
  186. setrgb(0, 0, 0, &fleds[0]);
  187. }
  188. rgblight_set();
  189. }
  190. void set_fled_layer_color(uint8_t layer, hs_set hs) {
  191. // Update layer colors and refresh LEDs
  192. layer_colors[layer] = hs;
  193. fled_layer_update(layer_state);
  194. fled_update_conf();
  195. }
  196. hs_set get_fled_layer_color(uint8_t layer) {
  197. return layer_colors[layer];
  198. }
  199. void set_fled_caps_color(hs_set hs) {
  200. // Update caplock color and refresh LEDs
  201. caps_color = hs;
  202. fled_lock_update(host_keyboard_led_state());
  203. fled_update_conf();
  204. }
  205. hs_set get_fled_caps_color(void) {
  206. return caps_color;
  207. }
  208. // Fallback eeprom functions if VIA is not enabled
  209. #ifndef VIA_ENABLE
  210. // Can be called in an overriding via_init_kb() to test if keyboard level code usage of
  211. // EEPROM is invalid and use/save defaults.
  212. bool via_eeprom_is_valid(void)
  213. {
  214. char *p = QMK_BUILDDATE; // e.g. "2019-11-05-11:29:54"
  215. uint8_t magic0 = ( ( p[2] & 0x0F ) << 4 ) | ( p[3] & 0x0F );
  216. uint8_t magic1 = ( ( p[5] & 0x0F ) << 4 ) | ( p[6] & 0x0F );
  217. uint8_t magic2 = ( ( p[8] & 0x0F ) << 4 ) | ( p[9] & 0x0F );
  218. return (eeprom_read_byte( (void*)VIA_EEPROM_MAGIC_ADDR+0 ) == magic0 &&
  219. eeprom_read_byte( (void*)VIA_EEPROM_MAGIC_ADDR+1 ) == magic1 &&
  220. eeprom_read_byte( (void*)VIA_EEPROM_MAGIC_ADDR+2 ) == magic2 );
  221. }
  222. #endif