4 void matrix_init_user(void) {
5 // leave this function blank - it can be defined in a keymap file
9 void matrix_scan_user(void) {
10 // leave this function blank - it can be defined in a keymap file
13 __attribute__ ((weak))
14 bool process_action_user(keyrecord_t *record) {
15 // leave this function blank - it can be defined in a keymap file
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
24 void matrix_init_kb(void) {
25 // put your keyboard start-up code here
26 // runs once when the firmware starts up
31 #ifdef BACKLIGHT_ENABLE
32 backlight_init_ports();
42 void matrix_scan_kb(void) {
43 // put your looping keyboard code here
44 // runs every cycle (a lot)
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
53 return process_action_user(record);
56 void led_set_kb(uint8_t usb_led) {
57 // put your keyboard LED indicator (ex: Caps Lock LED) toggling code here
59 led_set_user(usb_led);
62 #ifdef BACKLIGHT_ENABLE
64 #define BREATHING_NO_HALT 0
65 #define BREATHING_HALT_OFF 1
66 #define BREATHING_HALT_ON 2
68 static uint8_t breath_intensity;
69 static uint8_t breath_speed;
70 static uint16_t breathing_index;
71 static uint8_t breathing_halt;
73 void backlight_init_ports()
76 // Setup PB7 as output and output low.
80 // Use full 16-bit resolution.
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
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
93 TCCR1A = _BV(COM1C1) | _BV(WGM11); // = 0b00001010;
94 TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10); // = 0b00011001;
100 void backlight_set(uint8_t level)
102 // Prevent backlight blink on lowest level
103 PORTB &= ~(_BV(PORTB7));
107 // Turn off PWM control on PB7, revert to output low.
108 TCCR1A &= ~(_BV(COM1C1));
110 // Set the brightness to 0
113 else if ( level >= BACKLIGHT_LEVELS )
115 // Turn on PWM control of PB7
116 TCCR1A |= _BV(COM1C1);
118 // Set the brightness to max
123 // Turn on PWM control of PB7
124 TCCR1A |= _BV(COM1C1);
126 // Set the brightness
127 CHANNEL = 0xFFFF >> ((BACKLIGHT_LEVELS - level) * ((BACKLIGHT_LEVELS + 1) / 2));
129 breathing_intensity_default();
133 void breathing_enable(void)
135 if (get_backlight_level() == 0)
141 // Set breathing_index to be at the midpoint (brightest point)
142 breathing_index = 0x20 << breath_speed;
145 breathing_halt = BREATHING_NO_HALT;
147 // Enable breathing interrupt
148 TIMSK1 |= _BV(OCIE1A);
151 void breathing_pulse(void)
153 if (get_backlight_level() == 0)
159 // Set breathing_index to be at the midpoint + 1 (brightest point)
160 breathing_index = 0x21 << breath_speed;
163 breathing_halt = BREATHING_HALT_ON;
165 // Enable breathing interrupt
166 TIMSK1 |= _BV(OCIE1A);
169 void breathing_disable(void)
171 // Disable breathing interrupt
172 TIMSK1 &= ~_BV(OCIE1A);
173 backlight_set(get_backlight_level());
176 void breathing_self_disable(void)
178 if (get_backlight_level() == 0)
180 breathing_halt = BREATHING_HALT_OFF;
184 breathing_halt = BREATHING_HALT_ON;
187 //backlight_set(get_backlight_level());
190 void breathing_toggle(void)
194 if (get_backlight_level() == 0)
200 // Set breathing_index to be at the midpoint + 1 (brightest point)
201 breathing_index = 0x21 << breath_speed;
204 breathing_halt = BREATHING_NO_HALT;
207 // Toggle breathing interrupt
208 TIMSK1 ^= _BV(OCIE1A);
210 // Restore backlight level
213 backlight_set(get_backlight_level());
217 bool is_breathing(void)
219 return (TIMSK1 && _BV(OCIE1A));
222 void breathing_intensity_default(void)
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));
228 void breathing_intensity_set(uint8_t value)
230 breath_intensity = value;
233 void breathing_speed_default(void)
238 void breathing_speed_set(uint8_t value)
240 bool is_breathing_now = is_breathing();
241 uint8_t old_breath_speed = breath_speed;
243 if (is_breathing_now)
245 // Disable breathing interrupt
246 TIMSK1 &= ~_BV(OCIE1A);
249 breath_speed = value;
251 if (is_breathing_now)
253 // Adjust index to account for new speed
254 breathing_index = (( (uint8_t)( (breathing_index) >> old_breath_speed ) ) & 0x3F) << breath_speed;
256 // Enable breathing interrupt
257 TIMSK1 |= _BV(OCIE1A);
262 void breathing_speed_inc(uint8_t value)
264 if ((uint16_t)(breath_speed - value) > 10 )
266 breathing_speed_set(0);
270 breathing_speed_set(breath_speed - value);
274 void breathing_speed_dec(uint8_t value)
276 if ((uint16_t)(breath_speed + value) > 10 )
278 breathing_speed_set(10);
282 breathing_speed_set(breath_speed + value);
286 void breathing_defaults(void)
288 breathing_intensity_default();
289 breathing_speed_default();
290 breathing_halt = BREATHING_NO_HALT;
293 /* Breathing Sleep LED brighness(PWM On period) table
294 * (64[steps] * 4[duration]) / 64[PWM periods/s] = 4 second breath cycle
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 }
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,
306 ISR(TIMER1_COMPA_vect)
308 // CHANNEL = (pgm_read_byte(&breathing_table[ ( (uint8_t)( (breathing_index++) >> breath_speed ) ) & 0x3F ] )) * breath_intensity;
311 uint8_t local_index = ( (uint8_t)( (breathing_index++) >> breath_speed ) ) & 0x3F;
313 if (((breathing_halt == BREATHING_HALT_ON) && (local_index == 0x20)) || ((breathing_halt == BREATHING_HALT_OFF) && (local_index == 0x3F)))
315 // Disable breathing interrupt
316 TIMSK1 &= ~_BV(OCIE1A);
319 CHANNEL = (uint16_t)(((uint16_t)pgm_read_byte(&breathing_table[local_index]) * 257)) >> breath_intensity;