You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

450 lines
11 KiB

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