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.

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