]> git.donarmstrong.com Git - qmk_firmware.git/blob - keyboard/atomic/atomic.c
adds backlight levels to the satan keyboard (#431)
[qmk_firmware.git] / keyboard / atomic / atomic.c
1 #include "atomic.h"
2
3 __attribute__ ((weak))
4 void matrix_init_user(void) {
5     // leave this function blank - it can be defined in a keymap file
6 };
7
8 __attribute__ ((weak))
9 void matrix_scan_user(void) {
10     // leave this function blank - it can be defined in a keymap file
11 }
12
13 __attribute__ ((weak))
14 bool process_action_user(keyrecord_t *record) {
15     // leave this function blank - it can be defined in a keymap file
16     return true;
17 }
18
19 __attribute__ ((weak))
20 void led_set_user(uint8_t usb_led) {
21     // leave this function blank - it can be defined in a keymap file
22 }
23
24 void matrix_init_kb(void) {
25     // put your keyboard start-up code here
26     // runs once when the firmware starts up
27
28     MCUCR |= (1<<JTD);
29     MCUCR |= (1<<JTD);
30
31 #ifdef BACKLIGHT_ENABLE
32     backlight_init_ports();
33 #endif
34
35     // Turn status LED on
36     DDRE |= (1<<6);
37     PORTE |= (1<<6);
38
39     matrix_init_user();
40 }
41
42 void matrix_scan_kb(void) {
43     // put your looping keyboard code here
44     // runs every cycle (a lot)
45
46     matrix_scan_user();
47 }
48
49 bool process_action_kb(keyrecord_t *record) {
50     // put your per-action keyboard code here
51     // runs for every action, just before processing by the firmware
52
53     return process_action_user(record);
54 }
55
56 void led_set_kb(uint8_t usb_led) {
57     // put your keyboard LED indicator (ex: Caps Lock LED) toggling code here
58
59     led_set_user(usb_led);
60 }
61
62 #ifdef BACKLIGHT_ENABLE
63 #define CHANNEL OCR1C
64 #define BREATHING_NO_HALT  0
65 #define BREATHING_HALT_OFF 1
66 #define BREATHING_HALT_ON  2
67
68 static uint8_t breath_intensity;
69 static uint8_t breath_speed;
70 static uint16_t breathing_index;
71 static uint8_t breathing_halt;
72
73 void backlight_init_ports()
74 {
75
76     // Setup PB7 as output and output low.
77     DDRB |= (1<<7);
78     PORTB &= ~(1<<7);
79
80     // Use full 16-bit resolution.
81     ICR1 = 0xFFFF;
82
83     // I could write a wall of text here to explain... but TL;DW
84     // Go read the ATmega32u4 datasheet.
85     // And this: http://blog.saikoled.com/post/43165849837/secret-konami-cheat-code-to-high-resolution-pwm-on
86
87     // Pin PB7 = OCR1C (Timer 1, Channel C)
88     // Compare Output Mode = Clear on compare match, Channel C = COM1C1=1 COM1C0=0
89     // (i.e. start high, go low when counter matches.)
90     // WGM Mode 14 (Fast PWM) = WGM13=1 WGM12=1 WGM11=1 WGM10=0
91     // Clock Select = clk/1 (no prescaling) = CS12=0 CS11=0 CS10=1
92
93     TCCR1A = _BV(COM1C1) | _BV(WGM11); // = 0b00001010;
94     TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10); // = 0b00011001;
95
96     backlight_init();
97     breathing_defaults();
98 }
99
100 void backlight_set(uint8_t level)
101 {
102     // Prevent backlight blink on lowest level
103     PORTB &= ~(_BV(PORTB7));
104
105     if ( level == 0 )
106     {
107         // Turn off PWM control on PB7, revert to output low.
108         TCCR1A &= ~(_BV(COM1C1));
109
110         // Set the brightness to 0
111         CHANNEL = 0x0;
112     }
113     else if ( level >= BACKLIGHT_LEVELS )
114     {
115         // Turn on PWM control of PB7
116         TCCR1A |= _BV(COM1C1);
117
118         // Set the brightness to max
119         CHANNEL = 0xFFFF;
120     }
121     else
122     {
123         // Turn on PWM control of PB7
124         TCCR1A |= _BV(COM1C1);
125
126         // Set the brightness
127         CHANNEL = 0xFFFF >> ((BACKLIGHT_LEVELS - level) * ((BACKLIGHT_LEVELS + 1) / 2));
128     }
129     breathing_intensity_default();
130 }
131
132
133 void breathing_enable(void)
134 {
135     if (get_backlight_level() == 0)
136     {
137         breathing_index = 0;
138     }
139     else
140     {
141         // Set breathing_index to be at the midpoint (brightest point)
142         breathing_index = 0x20 << breath_speed;
143     }
144
145     breathing_halt = BREATHING_NO_HALT;
146
147     // Enable breathing interrupt
148     TIMSK1 |= _BV(OCIE1A);
149 }
150
151 void breathing_pulse(void)
152 {
153     if (get_backlight_level() == 0)
154     {
155         breathing_index = 0;
156     }
157     else
158     {
159         // Set breathing_index to be at the midpoint + 1 (brightest point)
160         breathing_index = 0x21 << breath_speed;
161     }
162
163     breathing_halt = BREATHING_HALT_ON;
164
165     // Enable breathing interrupt
166     TIMSK1 |= _BV(OCIE1A);
167 }
168
169 void breathing_disable(void)
170 {
171     // Disable breathing interrupt
172     TIMSK1 &= ~_BV(OCIE1A);
173     backlight_set(get_backlight_level());
174 }
175
176 void breathing_self_disable(void)
177 {
178     if (get_backlight_level() == 0)
179     {
180         breathing_halt = BREATHING_HALT_OFF;
181     }
182     else
183     {
184         breathing_halt = BREATHING_HALT_ON;
185     }
186
187     //backlight_set(get_backlight_level());
188 }
189
190 void breathing_toggle(void)
191 {
192     if (!is_breathing())
193     {
194         if (get_backlight_level() == 0)
195         {
196             breathing_index = 0;
197         }
198         else
199         {
200             // Set breathing_index to be at the midpoint + 1 (brightest point)
201             breathing_index = 0x21 << breath_speed;
202         }
203
204         breathing_halt = BREATHING_NO_HALT;
205     }
206
207     // Toggle breathing interrupt
208     TIMSK1 ^= _BV(OCIE1A);
209
210     // Restore backlight level
211     if (!is_breathing())
212     {
213         backlight_set(get_backlight_level());
214     }
215 }
216
217 bool is_breathing(void)
218 {
219     return (TIMSK1 && _BV(OCIE1A));
220 }
221
222 void breathing_intensity_default(void)
223 {
224     //breath_intensity = (uint8_t)((uint16_t)100 * (uint16_t)get_backlight_level() / (uint16_t)BACKLIGHT_LEVELS);
225     breath_intensity = ((BACKLIGHT_LEVELS - get_backlight_level()) * ((BACKLIGHT_LEVELS + 1) / 2));
226 }
227
228 void breathing_intensity_set(uint8_t value)
229 {
230     breath_intensity = value;
231 }
232
233 void breathing_speed_default(void)
234 {
235     breath_speed = 4;
236 }
237
238 void breathing_speed_set(uint8_t value)
239 {
240     bool is_breathing_now = is_breathing();
241     uint8_t old_breath_speed = breath_speed;
242
243     if (is_breathing_now)
244     {
245         // Disable breathing interrupt
246         TIMSK1 &= ~_BV(OCIE1A);
247     }
248
249     breath_speed = value;
250
251     if (is_breathing_now)
252     {
253         // Adjust index to account for new speed
254         breathing_index = (( (uint8_t)( (breathing_index) >> old_breath_speed ) ) & 0x3F) << breath_speed;
255
256         // Enable breathing interrupt
257         TIMSK1 |= _BV(OCIE1A);
258     }
259
260 }
261
262 void breathing_speed_inc(uint8_t value)
263 {
264     if ((uint16_t)(breath_speed - value) > 10 )
265     {
266         breathing_speed_set(0);
267     }
268     else
269     {
270         breathing_speed_set(breath_speed - value);
271     }
272 }
273
274 void breathing_speed_dec(uint8_t value)
275 {
276     if ((uint16_t)(breath_speed + value) > 10 )
277     {
278         breathing_speed_set(10);
279     }
280     else
281     {
282         breathing_speed_set(breath_speed + value);
283     }
284 }
285
286 void breathing_defaults(void)
287 {
288     breathing_intensity_default();
289     breathing_speed_default();
290     breathing_halt = BREATHING_NO_HALT;
291 }
292
293 /* Breathing Sleep LED brighness(PWM On period) table
294  * (64[steps] * 4[duration]) / 64[PWM periods/s] = 4 second breath cycle
295  *
296  * http://www.wolframalpha.com/input/?i=%28sin%28+x%2F64*pi%29**8+*+255%2C+x%3D0+to+63
297  * (0..63).each {|x| p ((sin(x/64.0*PI)**8)*255).to_i }
298  */
299 static const uint8_t breathing_table[64] PROGMEM = {
300   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   1,   2,   4,   6,  10,
301  15,  23,  32,  44,  58,  74,  93, 113, 135, 157, 179, 199, 218, 233, 245, 252,
302 255, 252, 245, 233, 218, 199, 179, 157, 135, 113,  93,  74,  58,  44,  32,  23,
303  15,  10,   6,   4,   2,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
304 };
305
306 ISR(TIMER1_COMPA_vect)
307 {
308     // CHANNEL = (pgm_read_byte(&breathing_table[ ( (uint8_t)( (breathing_index++) >> breath_speed ) ) & 0x3F ] )) * breath_intensity;
309
310
311     uint8_t local_index = ( (uint8_t)( (breathing_index++) >> breath_speed ) ) & 0x3F;
312
313     if (((breathing_halt == BREATHING_HALT_ON) && (local_index == 0x20)) || ((breathing_halt == BREATHING_HALT_OFF) && (local_index == 0x3F)))
314     {
315         // Disable breathing interrupt
316         TIMSK1 &= ~_BV(OCIE1A);
317     }
318
319     CHANNEL = (uint16_t)(((uint16_t)pgm_read_byte(&breathing_table[local_index]) * 257)) >> breath_intensity;
320
321 }
322
323
324
325 #endif