wt_mono_backlight.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484
  1. /* Copyright 2018 Jason Williams (Wilba)
  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 "quantum.h"
  17. #include "wt_mono_backlight.h"
  18. #include "wt_rgb_backlight_api.h" // reuse these for now
  19. #include "wt_rgb_backlight_keycodes.h" // reuse these for now
  20. #include <avr/interrupt.h>
  21. #include "i2c_master.h"
  22. #include "progmem.h"
  23. #include "quantum/color.h"
  24. #include "eeprom.h"
  25. #include "via.h" // uses EEPROM address, lighting value IDs
  26. #define MONO_BACKLIGHT_CONFIG_EEPROM_ADDR (VIA_EEPROM_CUSTOM_CONFIG_ADDR)
  27. #if VIA_EEPROM_CUSTOM_CONFIG_SIZE == 0
  28. #error VIA_EEPROM_CUSTOM_CONFIG_SIZE was not defined to store backlight_config struct
  29. #endif
  30. #include "drivers/led/issi/is31fl3736.h"
  31. #define ISSI_ADDR_DEFAULT 0x50
  32. #define BACKLIGHT_EFFECT_MAX 3
  33. #ifndef MONO_BACKLIGHT_COLOR_1
  34. #define MONO_BACKLIGHT_COLOR_1 { .h = 0, .s = 255 }
  35. #endif
  36. backlight_config g_config = {
  37. .disable_when_usb_suspended = MONO_BACKLIGHT_DISABLE_WHEN_USB_SUSPENDED,
  38. .disable_after_timeout = MONO_BACKLIGHT_DISABLE_AFTER_TIMEOUT,
  39. .brightness = MONO_BACKLIGHT_BRIGHTNESS,
  40. .effect = MONO_BACKLIGHT_EFFECT,
  41. .effect_speed = MONO_BACKLIGHT_EFFECT_SPEED,
  42. .color_1 = MONO_BACKLIGHT_COLOR_1,
  43. };
  44. bool g_suspend_state = false;
  45. // Global tick at 20 Hz
  46. uint32_t g_tick = 0;
  47. // Ticks since any key was last hit.
  48. uint32_t g_any_key_hit = 0;
  49. void backlight_init_drivers(void)
  50. {
  51. // Initialize I2C
  52. i2c_init();
  53. IS31FL3736_init( ISSI_ADDR_DEFAULT );
  54. for ( uint8_t index = 0; index < 96; index++ ) {
  55. IS31FL3736_mono_set_led_control_register( index, true );
  56. }
  57. IS31FL3736_update_led_control_registers( ISSI_ADDR_DEFAULT, 0x00 );
  58. }
  59. void backlight_set_key_hit(uint8_t row, uint8_t column)
  60. {
  61. g_any_key_hit = 0;
  62. }
  63. // This is (F_CPU/1024) / 20 Hz
  64. // = 15625 Hz / 20 Hz
  65. // = 781
  66. #define TIMER3_TOP 781
  67. void backlight_timer_init(void)
  68. {
  69. static uint8_t backlight_timer_is_init = 0;
  70. if ( backlight_timer_is_init ) {
  71. return;
  72. }
  73. backlight_timer_is_init = 1;
  74. // Timer 3 setup
  75. TCCR3B = _BV(WGM32) | // CTC mode OCR3A as TOP
  76. _BV(CS32) | _BV(CS30); // prescale by /1024
  77. // Set TOP value
  78. uint8_t sreg = SREG;
  79. cli();
  80. OCR3AH = (TIMER3_TOP >> 8) & 0xff;
  81. OCR3AL = TIMER3_TOP & 0xff;
  82. SREG = sreg;
  83. }
  84. void backlight_timer_enable(void)
  85. {
  86. TIMSK3 |= _BV(OCIE3A);
  87. }
  88. void backlight_timer_disable(void)
  89. {
  90. TIMSK3 &= ~_BV(OCIE3A);
  91. }
  92. void backlight_set_suspend_state(bool state)
  93. {
  94. g_suspend_state = state;
  95. }
  96. void backlight_set_brightness_all( uint8_t value )
  97. {
  98. IS31FL3736_mono_set_brightness_all( value );
  99. }
  100. void backlight_effect_all_off(void)
  101. {
  102. IS31FL3736_mono_set_brightness_all( 0 );
  103. }
  104. void backlight_effect_all_on(void)
  105. {
  106. IS31FL3736_mono_set_brightness_all( g_config.brightness );
  107. }
  108. void backlight_effect_raindrops(bool initialize)
  109. {
  110. // Change one LED every tick
  111. uint8_t led_to_change = ( g_tick & 0x000 ) == 0 ? rand() % 96 : 255;
  112. for ( int i=0; i<96; i++ )
  113. {
  114. // If initialize, all get set to random brightness
  115. // If not, all but one will stay the same as before.
  116. if ( initialize || i == led_to_change )
  117. {
  118. IS31FL3736_mono_set_brightness(i, rand() & 0xFF );
  119. }
  120. }
  121. }
  122. void backlight_effect_cycle_all(void)
  123. {
  124. uint8_t offset = ( g_tick << g_config.effect_speed ) & 0xFF;
  125. backlight_set_brightness_all( offset );
  126. }
  127. // This runs after another backlight effect and replaces
  128. // colors already set
  129. void backlight_effect_indicators(void)
  130. {
  131. #if defined(MONO_BACKLIGHT_WT75_A)
  132. HSV hsv = { .h = g_config.color_1.h, .s = g_config.color_1.s, .v = g_config.brightness };
  133. RGB rgb = hsv_to_rgb( hsv );
  134. // SW7,CS8 = (6*8+7) = 55
  135. // SW8,CS8 = (7*8+7) = 63
  136. // SW9,CS8 = (8*8+7) = 71
  137. IS31FL3736_mono_set_brightness(55, rgb.r);
  138. IS31FL3736_mono_set_brightness(63, rgb.g);
  139. IS31FL3736_mono_set_brightness(71, rgb.b);
  140. #endif // MONO_BACKLIGHT_WT75_A
  141. // This pairs with "All Off" already setting zero brightness,
  142. // and "All On" already setting non-zero brightness.
  143. #if defined(MONO_BACKLIGHT_WT60_A) || \
  144. defined(MONO_BACKLIGHT_WT65_A) || \
  145. defined(MONO_BACKLIGHT_WT65_B) || \
  146. defined(MONO_BACKLIGHT_WT75_A) || \
  147. defined(MONO_BACKLIGHT_WT75_B) || \
  148. defined(MONO_BACKLIGHT_WT75_C) || \
  149. defined(MONO_BACKLIGHT_WT80_A)
  150. if ( host_keyboard_led_state().caps_lock ) {
  151. // SW3,CS1 = (2*8+0) = 16
  152. IS31FL3736_mono_set_brightness(16, 255);
  153. }
  154. #endif
  155. #if defined(MONO_BACKLIGHT_WT80_A)
  156. if ( host_keyboard_led_state().scroll_lock ) {
  157. // SW7,CS7 = (6*8+6) = 54
  158. IS31FL3736_mono_set_brightness(54, 255);
  159. }
  160. #endif
  161. #if defined(MONO_BACKLIGHT_WT75_C)
  162. if ( host_keyboard_led_state().scroll_lock ) {
  163. // SW7,CS8 = (6*8+7) = 55
  164. IS31FL3736_mono_set_brightness(55, 255);
  165. }
  166. #endif
  167. }
  168. ISR(TIMER3_COMPA_vect)
  169. {
  170. // delay 1 second before driving LEDs or doing anything else
  171. static uint8_t startup_tick = 0;
  172. if ( startup_tick < 20 ) {
  173. startup_tick++;
  174. return;
  175. }
  176. g_tick++;
  177. if ( g_any_key_hit < 0xFFFFFFFF )
  178. {
  179. g_any_key_hit++;
  180. }
  181. // Ideally we would also stop sending zeros to the LED driver PWM buffers
  182. // while suspended and just do a software shutdown. This is a cheap hack for now.
  183. bool suspend_backlight = ((g_suspend_state && g_config.disable_when_usb_suspended) ||
  184. (g_config.disable_after_timeout > 0 && g_any_key_hit > g_config.disable_after_timeout * 60 * 20));
  185. uint8_t effect = suspend_backlight ? 0 : g_config.effect;
  186. // Keep track of the effect used last time,
  187. // detect change in effect, so each effect can
  188. // have an optional initialization.
  189. static uint8_t effect_last = 255;
  190. bool initialize = effect != effect_last;
  191. effect_last = effect;
  192. // this gets ticked at 20 Hz.
  193. // each effect can opt to do calculations
  194. // and/or request PWM buffer updates.
  195. switch ( effect )
  196. {
  197. case 0:
  198. backlight_effect_all_off();
  199. break;
  200. case 1:
  201. backlight_effect_all_on();;
  202. break;
  203. case 2:
  204. backlight_effect_raindrops(initialize);
  205. break;
  206. default:
  207. backlight_effect_all_off();
  208. break;
  209. }
  210. if ( ! suspend_backlight )
  211. {
  212. backlight_effect_indicators();
  213. }
  214. }
  215. // Some helpers for setting/getting HSV
  216. void _set_color( HS *color, uint8_t *data )
  217. {
  218. color->h = data[0];
  219. color->s = data[1];
  220. }
  221. void _get_color( HS *color, uint8_t *data )
  222. {
  223. data[0] = color->h;
  224. data[1] = color->s;
  225. }
  226. void backlight_config_set_value( uint8_t *data )
  227. {
  228. bool reinitialize = false;
  229. uint8_t *value_id = &(data[0]);
  230. uint8_t *value_data = &(data[1]);
  231. switch ( *value_id )
  232. {
  233. case id_disable_when_usb_suspended:
  234. {
  235. g_config.disable_when_usb_suspended = (bool)*value_data;
  236. break;
  237. }
  238. case id_disable_after_timeout:
  239. {
  240. g_config.disable_after_timeout = *value_data;
  241. break;
  242. }
  243. case id_brightness:
  244. {
  245. g_config.brightness = *value_data;
  246. break;
  247. }
  248. case id_effect:
  249. {
  250. g_config.effect = *value_data;
  251. break;
  252. }
  253. case id_effect_speed:
  254. {
  255. g_config.effect_speed = *value_data;
  256. break;
  257. }
  258. case id_color_1:
  259. {
  260. _set_color( &(g_config.color_1), value_data );
  261. break;
  262. }
  263. }
  264. if ( reinitialize )
  265. {
  266. backlight_init_drivers();
  267. }
  268. }
  269. void backlight_config_get_value( uint8_t *data )
  270. {
  271. uint8_t *value_id = &(data[0]);
  272. uint8_t *value_data = &(data[1]);
  273. switch ( *value_id )
  274. {
  275. case id_disable_when_usb_suspended:
  276. {
  277. *value_data = ( g_config.disable_when_usb_suspended ? 1 : 0 );
  278. break;
  279. }
  280. case id_disable_after_timeout:
  281. {
  282. *value_data = g_config.disable_after_timeout;
  283. break;
  284. }
  285. case id_brightness:
  286. {
  287. *value_data = g_config.brightness;
  288. break;
  289. }
  290. case id_effect:
  291. {
  292. *value_data = g_config.effect;
  293. break;
  294. }
  295. case id_effect_speed:
  296. {
  297. *value_data = g_config.effect_speed;
  298. break;
  299. }
  300. case id_color_1:
  301. {
  302. _get_color( &(g_config.color_1), value_data );
  303. break;
  304. }
  305. }
  306. }
  307. void backlight_config_load(void)
  308. {
  309. eeprom_read_block( &g_config, ((void*)MONO_BACKLIGHT_CONFIG_EEPROM_ADDR), sizeof(backlight_config) );
  310. }
  311. void backlight_config_save(void)
  312. {
  313. eeprom_update_block( &g_config, ((void*)MONO_BACKLIGHT_CONFIG_EEPROM_ADDR), sizeof(backlight_config) );
  314. }
  315. void backlight_update_pwm_buffers(void)
  316. {
  317. IS31FL3736_update_pwm_buffers(ISSI_ADDR_DEFAULT,0x00);
  318. }
  319. bool process_record_backlight(uint16_t keycode, keyrecord_t *record)
  320. {
  321. // Record keypresses for backlight effects
  322. if ( record->event.pressed )
  323. {
  324. backlight_set_key_hit( record->event.key.row, record->event.key.col );
  325. }
  326. switch(keycode)
  327. {
  328. case BR_INC:
  329. if (record->event.pressed)
  330. {
  331. backlight_brightness_increase();
  332. }
  333. return false;
  334. break;
  335. case BR_DEC:
  336. if (record->event.pressed)
  337. {
  338. backlight_brightness_decrease();
  339. }
  340. return false;
  341. break;
  342. case EF_INC:
  343. if (record->event.pressed)
  344. {
  345. backlight_effect_increase();
  346. }
  347. return false;
  348. break;
  349. case EF_DEC:
  350. if (record->event.pressed)
  351. {
  352. backlight_effect_decrease();
  353. }
  354. return false;
  355. break;
  356. case ES_INC:
  357. if (record->event.pressed)
  358. {
  359. backlight_effect_speed_increase();
  360. }
  361. return false;
  362. break;
  363. case ES_DEC:
  364. if (record->event.pressed)
  365. {
  366. backlight_effect_speed_decrease();
  367. }
  368. return false;
  369. break;
  370. }
  371. return true;
  372. }
  373. // Deals with the messy details of incrementing an integer
  374. uint8_t increment( uint8_t value, uint8_t step, uint8_t min, uint8_t max )
  375. {
  376. int16_t new_value = value;
  377. new_value += step;
  378. return MIN( MAX( new_value, min ), max );
  379. }
  380. uint8_t decrement( uint8_t value, uint8_t step, uint8_t min, uint8_t max )
  381. {
  382. int16_t new_value = value;
  383. new_value -= step;
  384. return MIN( MAX( new_value, min ), max );
  385. }
  386. void backlight_effect_increase(void)
  387. {
  388. g_config.effect = increment( g_config.effect, 1, 0, BACKLIGHT_EFFECT_MAX );
  389. backlight_config_save();
  390. }
  391. void backlight_effect_decrease(void)
  392. {
  393. g_config.effect = decrement( g_config.effect, 1, 0, BACKLIGHT_EFFECT_MAX );
  394. backlight_config_save();
  395. }
  396. void backlight_effect_speed_increase(void)
  397. {
  398. g_config.effect_speed = increment( g_config.effect_speed, 1, 0, 3 );
  399. backlight_config_save();
  400. }
  401. void backlight_effect_speed_decrease(void)
  402. {
  403. g_config.effect_speed = decrement( g_config.effect_speed, 1, 0, 3 );
  404. backlight_config_save();
  405. }
  406. void backlight_brightness_increase(void)
  407. {
  408. g_config.brightness = increment( g_config.brightness, 8, 0, 255 );
  409. backlight_config_save();
  410. }
  411. void backlight_brightness_decrease(void)
  412. {
  413. g_config.brightness = decrement( g_config.brightness, 8, 0, 255 );
  414. backlight_config_save();
  415. }
  416. void backlight_device_indication(uint8_t value)
  417. {
  418. static uint8_t current_effect = 0;
  419. static uint8_t alternate_effect = 0;
  420. if ( value == 0 ) {
  421. current_effect = g_config.effect;
  422. alternate_effect = g_config.effect > 0 ? 0 : 1;
  423. }
  424. g_config.effect = value % 2 == 0 ? alternate_effect : current_effect;
  425. }