4 void matrix_init_user(void) {}
7 void matrix_scan_user(void) {}
10 bool process_action_user(keyrecord_t *record) {
14 __attribute__ ((weak))
15 void led_set_user(uint8_t usb_led) {}
17 void matrix_init_kb(void) {
18 #ifdef BACKLIGHT_ENABLE
19 backlight_init_ports();
29 void matrix_scan_kb(void) {
33 bool process_action_kb(keyrecord_t *record) {
34 return process_action_user(record);
37 void led_set_kb(uint8_t usb_led) {
38 // put your keyboard LED indicator (ex: Caps Lock LED) toggling code here
40 led_set_user(usb_led);
43 #ifdef BACKLIGHT_ENABLE
45 #define BREATHING_NO_HALT 0
46 #define BREATHING_HALT_OFF 1
47 #define BREATHING_HALT_ON 2
49 static uint8_t breath_intensity;
50 static uint8_t breath_speed;
51 static uint16_t breathing_index;
52 static uint8_t breathing_halt;
54 void backlight_init_ports()
57 // Setup PB7 as output and output low.
61 // Use full 16-bit resolution.
64 // I could write a wall of text here to explain... but TL;DW
65 // Go read the ATmega32u4 datasheet.
66 // And this: http://blog.saikoled.com/post/43165849837/secret-konami-cheat-code-to-high-resolution-pwm-on
68 // Pin PB7 = OCR1C (Timer 1, Channel C)
69 // Compare Output Mode = Clear on compare match, Channel C = COM1C1=1 COM1C0=0
70 // (i.e. start high, go low when counter matches.)
71 // WGM Mode 14 (Fast PWM) = WGM13=1 WGM12=1 WGM11=1 WGM10=0
72 // Clock Select = clk/1 (no prescaling) = CS12=0 CS11=0 CS10=1
74 TCCR1A = _BV(COM1C1) | _BV(WGM11); // = 0b00001010;
75 TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10); // = 0b00011001;
81 void backlight_set(uint8_t level)
83 // Prevent backlight blink on lowest level
84 PORTB &= ~(_BV(PORTB7));
88 // Turn off PWM control on PB7, revert to output low.
89 TCCR1A &= ~(_BV(COM1C1));
92 else if ( level == BACKLIGHT_LEVELS )
94 // Turn on PWM control of PB7
95 TCCR1A |= _BV(COM1C1);
101 // Turn on PWM control of PB7
102 TCCR1A |= _BV(COM1C1);
103 // Set the brightness
104 CHANNEL = 0xFFFF >> ((BACKLIGHT_LEVELS - level) * ((BACKLIGHT_LEVELS + 1) / 2));
106 breathing_intensity_default();
110 void breathing_enable(void)
112 if (get_backlight_level() == 0)
118 // Set breathing_index to be at the midpoint (brightest point)
119 breathing_index = 0x20 << breath_speed;
122 breathing_halt = BREATHING_NO_HALT;
124 // Enable breathing interrupt
125 TIMSK1 |= _BV(OCIE1A);
128 void breathing_pulse(void)
130 if (get_backlight_level() == 0)
136 // Set breathing_index to be at the midpoint + 1 (brightest point)
137 breathing_index = 0x21 << breath_speed;
140 breathing_halt = BREATHING_HALT_ON;
142 // Enable breathing interrupt
143 TIMSK1 |= _BV(OCIE1A);
146 void breathing_disable(void)
148 // Disable breathing interrupt
149 TIMSK1 &= ~_BV(OCIE1A);
150 backlight_set(get_backlight_level());
153 void breathing_self_disable(void)
155 if (get_backlight_level() == 0)
157 breathing_halt = BREATHING_HALT_OFF;
161 breathing_halt = BREATHING_HALT_ON;
164 //backlight_set(get_backlight_level());
167 void breathing_toggle(void)
171 if (get_backlight_level() == 0)
177 // Set breathing_index to be at the midpoint + 1 (brightest point)
178 breathing_index = 0x21 << breath_speed;
181 breathing_halt = BREATHING_NO_HALT;
184 // Toggle breathing interrupt
185 TIMSK1 ^= _BV(OCIE1A);
187 // Restore backlight level
190 backlight_set(get_backlight_level());
194 bool is_breathing(void)
196 return (TIMSK1 && _BV(OCIE1A));
199 void breathing_intensity_default(void)
201 //breath_intensity = (uint8_t)((uint16_t)100 * (uint16_t)get_backlight_level() / (uint16_t)BACKLIGHT_LEVELS);
202 breath_intensity = ((BACKLIGHT_LEVELS - get_backlight_level()) * ((BACKLIGHT_LEVELS + 1) / 2));
205 void breathing_intensity_set(uint8_t value)
207 breath_intensity = value;
210 void breathing_speed_default(void)
215 void breathing_speed_set(uint8_t value)
217 bool is_breathing_now = is_breathing();
218 uint8_t old_breath_speed = breath_speed;
220 if (is_breathing_now)
222 // Disable breathing interrupt
223 TIMSK1 &= ~_BV(OCIE1A);
226 breath_speed = value;
228 if (is_breathing_now)
230 // Adjust index to account for new speed
231 breathing_index = (( (uint8_t)( (breathing_index) >> old_breath_speed ) ) & 0x3F) << breath_speed;
233 // Enable breathing interrupt
234 TIMSK1 |= _BV(OCIE1A);
239 void breathing_speed_inc(uint8_t value)
241 if ((uint16_t)(breath_speed - value) > 10 )
243 breathing_speed_set(0);
247 breathing_speed_set(breath_speed - value);
251 void breathing_speed_dec(uint8_t value)
253 if ((uint16_t)(breath_speed + value) > 10 )
255 breathing_speed_set(10);
259 breathing_speed_set(breath_speed + value);
263 void breathing_defaults(void)
265 breathing_intensity_default();
266 breathing_speed_default();
267 breathing_halt = BREATHING_NO_HALT;
270 /* Breathing Sleep LED brighness(PWM On period) table
271 * (64[steps] * 4[duration]) / 64[PWM periods/s] = 4 second breath cycle
273 * http://www.wolframalpha.com/input/?i=%28sin%28+x%2F64*pi%29**8+*+255%2C+x%3D0+to+63
274 * (0..63).each {|x| p ((sin(x/64.0*PI)**8)*255).to_i }
276 static const uint8_t breathing_table[64] PROGMEM = {
277 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 4, 6, 10,
278 15, 23, 32, 44, 58, 74, 93, 113, 135, 157, 179, 199, 218, 233, 245, 252,
279 255, 252, 245, 233, 218, 199, 179, 157, 135, 113, 93, 74, 58, 44, 32, 23,
280 15, 10, 6, 4, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
283 ISR(TIMER1_COMPA_vect)
285 // CHANNEL = (pgm_read_byte(&breathing_table[ ( (uint8_t)( (breathing_index++) >> breath_speed ) ) & 0x3F ] )) * breath_intensity;
288 uint8_t local_index = ( (uint8_t)( (breathing_index++) >> breath_speed ) ) & 0x3F;
290 if (((breathing_halt == BREATHING_HALT_ON) && (local_index == 0x20)) || ((breathing_halt == BREATHING_HALT_OFF) && (local_index == 0x3F)))
292 // Disable breathing interrupt
293 TIMSK1 &= ~_BV(OCIE1A);
296 CHANNEL = (uint16_t)(((uint16_t)pgm_read_byte(&breathing_table[local_index]) * 257)) >> breath_intensity;