logo

qmk_firmware

custom branch of QMK firmware git clone https://anongit.hacktivis.me/git/qmk_firmware.git

wt_mono_backlight.c (12264B)


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