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 void process_action_user(keyrecord_t *record) {
15 // leave this function blank - it can be defined in a keymap file
18 __attribute__ ((weak))
19 void led_set_user(uint8_t usb_led) {
20 // leave this function blank - it can be defined in a keymap file
23 void matrix_init_kb(void) {
24 // put your keyboard start-up code here
25 // runs once when the firmware starts up
30 #ifdef BACKLIGHT_ENABLE
31 backlight_init_ports();
41 void matrix_scan_kb(void) {
42 // put your looping keyboard code here
43 // runs every cycle (a lot)
48 void process_action_kb(keyrecord_t *record) {
49 // put your per-action keyboard code here
50 // runs for every action, just before processing by the firmware
52 process_action_user(record);
55 void led_set_kb(uint8_t usb_led) {
56 // put your keyboard LED indicator (ex: Caps Lock LED) toggling code here
58 led_set_user(usb_led);
61 #ifdef BACKLIGHT_ENABLE
63 #define BREATHING_NO_HALT 0
64 #define BREATHING_HALT_OFF 1
65 #define BREATHING_HALT_ON 2
67 static uint8_t breath_intensity;
68 static uint8_t breath_speed;
69 static uint16_t breathing_index;
70 static uint8_t breathing_halt;
72 void backlight_init_ports()
75 // Setup PB7 as output and output low.
79 // Use full 16-bit resolution.
82 // I could write a wall of text here to explain... but TL;DW
83 // Go read the ATmega32u4 datasheet.
84 // And this: http://blog.saikoled.com/post/43165849837/secret-konami-cheat-code-to-high-resolution-pwm-on
86 // Pin PB7 = OCR1C (Timer 1, Channel C)
87 // Compare Output Mode = Clear on compare match, Channel C = COM1C1=1 COM1C0=0
88 // (i.e. start high, go low when counter matches.)
89 // WGM Mode 14 (Fast PWM) = WGM13=1 WGM12=1 WGM11=1 WGM10=0
90 // Clock Select = clk/1 (no prescaling) = CS12=0 CS11=0 CS10=1
92 TCCR1A = _BV(COM1C1) | _BV(WGM11); // = 0b00001010;
93 TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10); // = 0b00011001;
99 void backlight_set(uint8_t level)
101 // Prevent backlight blink on lowest level
102 PORTB &= ~(_BV(PORTB7));
106 // Turn off PWM control on PB7, revert to output low.
107 TCCR1A &= ~(_BV(COM1C1));
109 // Set the brightness to 0
112 else if ( level >= BACKLIGHT_LEVELS )
114 // Turn on PWM control of PB7
115 TCCR1A |= _BV(COM1C1);
117 // Set the brightness to max
122 // Turn on PWM control of PB7
123 TCCR1A |= _BV(COM1C1);
125 // Set the brightness
126 CHANNEL = 0xFFFF >> ((BACKLIGHT_LEVELS - level) * ((BACKLIGHT_LEVELS + 1) / 2));
128 breathing_intensity_default();
132 void breathing_enable(void)
134 if (get_backlight_level() == 0)
140 // Set breathing_index to be at the midpoint (brightest point)
141 breathing_index = 0x20 << breath_speed;
144 breathing_halt = BREATHING_NO_HALT;
146 // Enable breathing interrupt
147 TIMSK1 |= _BV(OCIE1A);
150 void breathing_pulse(void)
152 if (get_backlight_level() == 0)
158 // Set breathing_index to be at the midpoint + 1 (brightest point)
159 breathing_index = 0x21 << breath_speed;
162 breathing_halt = BREATHING_HALT_ON;
164 // Enable breathing interrupt
165 TIMSK1 |= _BV(OCIE1A);
168 void breathing_disable(void)
170 // Disable breathing interrupt
171 TIMSK1 &= ~_BV(OCIE1A);
172 backlight_set(get_backlight_level());
175 void breathing_self_disable(void)
177 if (get_backlight_level() == 0)
179 breathing_halt = BREATHING_HALT_OFF;
183 breathing_halt = BREATHING_HALT_ON;
186 //backlight_set(get_backlight_level());
189 void breathing_toggle(void)
193 if (get_backlight_level() == 0)
199 // Set breathing_index to be at the midpoint + 1 (brightest point)
200 breathing_index = 0x21 << breath_speed;
203 breathing_halt = BREATHING_NO_HALT;
206 // Toggle breathing interrupt
207 TIMSK1 ^= _BV(OCIE1A);
209 // Restore backlight level
212 backlight_set(get_backlight_level());
216 bool is_breathing(void)
218 return (TIMSK1 && _BV(OCIE1A));
221 void breathing_intensity_default(void)
223 //breath_intensity = (uint8_t)((uint16_t)100 * (uint16_t)get_backlight_level() / (uint16_t)BACKLIGHT_LEVELS);
224 breath_intensity = ((BACKLIGHT_LEVELS - get_backlight_level()) * ((BACKLIGHT_LEVELS + 1) / 2));
227 void breathing_intensity_set(uint8_t value)
229 breath_intensity = value;
232 void breathing_speed_default(void)
237 void breathing_speed_set(uint8_t value)
239 bool is_breathing_now = is_breathing();
240 uint8_t old_breath_speed = breath_speed;
242 if (is_breathing_now)
244 // Disable breathing interrupt
245 TIMSK1 &= ~_BV(OCIE1A);
248 breath_speed = value;
250 if (is_breathing_now)
252 // Adjust index to account for new speed
253 breathing_index = (( (uint8_t)( (breathing_index) >> old_breath_speed ) ) & 0x3F) << breath_speed;
255 // Enable breathing interrupt
256 TIMSK1 |= _BV(OCIE1A);
261 void breathing_speed_inc(uint8_t value)
263 if ((uint16_t)(breath_speed - value) > 10 )
265 breathing_speed_set(0);
269 breathing_speed_set(breath_speed - value);
273 void breathing_speed_dec(uint8_t value)
275 if ((uint16_t)(breath_speed + value) > 10 )
277 breathing_speed_set(10);
281 breathing_speed_set(breath_speed + value);
285 void breathing_defaults(void)
287 breathing_intensity_default();
288 breathing_speed_default();
289 breathing_halt = BREATHING_NO_HALT;
292 /* Breathing Sleep LED brighness(PWM On period) table
293 * (64[steps] * 4[duration]) / 64[PWM periods/s] = 4 second breath cycle
295 * http://www.wolframalpha.com/input/?i=%28sin%28+x%2F64*pi%29**8+*+255%2C+x%3D0+to+63
296 * (0..63).each {|x| p ((sin(x/64.0*PI)**8)*255).to_i }
298 static const uint8_t breathing_table[64] PROGMEM = {
299 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 4, 6, 10,
300 15, 23, 32, 44, 58, 74, 93, 113, 135, 157, 179, 199, 218, 233, 245, 252,
301 255, 252, 245, 233, 218, 199, 179, 157, 135, 113, 93, 74, 58, 44, 32, 23,
302 15, 10, 6, 4, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
305 ISR(TIMER1_COMPA_vect)
307 // CHANNEL = (pgm_read_byte(&breathing_table[ ( (uint8_t)( (breathing_index++) >> breath_speed ) ) & 0x3F ] )) * breath_intensity;
310 uint8_t local_index = ( (uint8_t)( (breathing_index++) >> breath_speed ) ) & 0x3F;
312 if (((breathing_halt == BREATHING_HALT_ON) && (local_index == 0x20)) || ((breathing_halt == BREATHING_HALT_OFF) && (local_index == 0x3F)))
314 // Disable breathing interrupt
315 TIMSK1 &= ~_BV(OCIE1A);
318 CHANNEL = (uint16_t)(((uint16_t)pgm_read_byte(&breathing_table[local_index]) * 257)) >> breath_intensity;