wt_mono_backlight.c 11 KB

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