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