]> git.donarmstrong.com Git - qmk_firmware.git/blob - quantum/quantum.c
Moves features to their own files (process_*), adds tap dance feature (#460)
[qmk_firmware.git] / quantum / quantum.c
1 #include "quantum.h"
2
3 __attribute__ ((weak))
4 bool process_action_kb(keyrecord_t *record) {
5   return true;
6 }
7
8 __attribute__ ((weak))
9 bool process_record_kb(uint16_t keycode, keyrecord_t *record) {
10   return process_record_user(keycode, record);
11 }
12
13 __attribute__ ((weak))
14 bool process_record_user(uint16_t keycode, keyrecord_t *record) {
15   return true;
16 }
17
18 // Shift / paren setup
19
20 #ifndef LSPO_KEY
21   #define LSPO_KEY KC_9
22 #endif
23 #ifndef RSPC_KEY
24   #define RSPC_KEY KC_0
25 #endif
26
27 static bool shift_interrupted[2] = {0, 0};
28
29 bool process_record_quantum(keyrecord_t *record) {
30
31   /* This gets the keycode from the key pressed */
32   keypos_t key = record->event.key;
33   uint16_t keycode;
34
35   #if !defined(NO_ACTION_LAYER) && defined(PREVENT_STUCK_MODIFIERS)
36     uint8_t layer;
37
38     if (record->event.pressed) {
39       layer = layer_switch_get_layer(key);
40       update_source_layers_cache(key, layer);
41     } else {
42       layer = read_source_layers_cache(key);
43     }
44     keycode = keymap_key_to_keycode(layer, key);
45   #else
46     keycode = keymap_key_to_keycode(layer_switch_get_layer(key), key);
47   #endif
48
49     // This is how you use actions here
50     // if (keycode == KC_LEAD) {
51     //   action_t action;
52     //   action.code = ACTION_DEFAULT_LAYER_SET(0);
53     //   process_action(record, action);
54     //   return false;
55     // }
56
57   if (!(
58     process_record_kb(keycode, record) &&
59   #ifdef MIDI_ENABLE
60     process_midi(keycode, record) &&
61   #endif
62   #ifdef AUDIO_ENABLE
63     process_music(keycode, record) &&
64   #endif
65   #ifdef TAP_DANCE_ENABLE
66     process_tap_dance(keycode, record) &&
67   #endif
68   #ifndef DISABLE_LEADER
69     process_leader(keycode, record) &&
70   #endif
71   #ifndef DISABLE_CHORDING
72     process_chording(keycode, record) &&
73   #endif
74   #ifdef UNICODE_ENABLE
75     process_unicode(keycode, record) &&
76   #endif
77       true)) {
78     return false;
79   }
80
81   // Shift / paren setup
82
83   switch(keycode) {
84     case RESET:
85       if (record->event.pressed) {
86         clear_keyboard();
87         #ifdef AUDIO_ENABLE
88           stop_all_notes();
89           shutdown_user();
90         #endif
91         _delay_ms(250);
92         #ifdef ATREUS_ASTAR
93             *(uint16_t *)0x0800 = 0x7777; // these two are a-star-specific
94         #endif
95         bootloader_jump();
96         return false;
97       }
98       break;
99     case DEBUG:
100       if (record->event.pressed) {
101           print("\nDEBUG: enabled.\n");
102           debug_enable = true;
103           return false;
104       }
105       break;
106     case MAGIC_SWAP_CONTROL_CAPSLOCK ... MAGIC_UNSWAP_ALT_GUI:
107       if (record->event.pressed) {
108         // MAGIC actions (BOOTMAGIC without the boot)
109         if (!eeconfig_is_enabled()) {
110             eeconfig_init();
111         }
112         /* keymap config */
113         keymap_config.raw = eeconfig_read_keymap();
114         if (keycode == MAGIC_SWAP_CONTROL_CAPSLOCK) {
115             keymap_config.swap_control_capslock = 1;
116         } else if (keycode == MAGIC_CAPSLOCK_TO_CONTROL) {
117             keymap_config.capslock_to_control = 1;
118         } else if (keycode == MAGIC_SWAP_LALT_LGUI) {
119             keymap_config.swap_lalt_lgui = 1;
120         } else if (keycode == MAGIC_SWAP_RALT_RGUI) {
121             keymap_config.swap_ralt_rgui = 1;
122         } else if (keycode == MAGIC_NO_GUI) {
123             keymap_config.no_gui = 1;
124         } else if (keycode == MAGIC_SWAP_GRAVE_ESC) {
125             keymap_config.swap_grave_esc = 1;
126         } else if (keycode == MAGIC_SWAP_BACKSLASH_BACKSPACE) {
127             keymap_config.swap_backslash_backspace = 1;
128         } else if (keycode == MAGIC_HOST_NKRO) {
129             keymap_config.nkro = 1;
130         } else if (keycode == MAGIC_SWAP_ALT_GUI) {
131             keymap_config.swap_lalt_lgui = 1;
132             keymap_config.swap_ralt_rgui = 1;
133         }
134         /* UNs */
135         else if (keycode == MAGIC_UNSWAP_CONTROL_CAPSLOCK) {
136             keymap_config.swap_control_capslock = 0;
137         } else if (keycode == MAGIC_UNCAPSLOCK_TO_CONTROL) {
138             keymap_config.capslock_to_control = 0;
139         } else if (keycode == MAGIC_UNSWAP_LALT_LGUI) {
140             keymap_config.swap_lalt_lgui = 0;
141         } else if (keycode == MAGIC_UNSWAP_RALT_RGUI) {
142             keymap_config.swap_ralt_rgui = 0;
143         } else if (keycode == MAGIC_UNNO_GUI) {
144             keymap_config.no_gui = 0;
145         } else if (keycode == MAGIC_UNSWAP_GRAVE_ESC) {
146             keymap_config.swap_grave_esc = 0;
147         } else if (keycode == MAGIC_UNSWAP_BACKSLASH_BACKSPACE) {
148             keymap_config.swap_backslash_backspace = 0;
149         } else if (keycode == MAGIC_UNHOST_NKRO) {
150             keymap_config.nkro = 0;
151         } else if (keycode == MAGIC_UNSWAP_ALT_GUI) {
152             keymap_config.swap_lalt_lgui = 0;
153             keymap_config.swap_ralt_rgui = 0;
154         }
155         eeconfig_update_keymap(keymap_config.raw);
156         return false;
157       }
158       break;
159     case KC_LSPO: {
160       if (record->event.pressed) {
161         shift_interrupted[0] = false;
162         register_mods(MOD_BIT(KC_LSFT));
163       }
164       else {
165         if (!shift_interrupted[0]) {
166           register_code(LSPO_KEY);
167           unregister_code(LSPO_KEY);
168         }
169         unregister_mods(MOD_BIT(KC_LSFT));
170       }
171       return false;
172       break;
173     }
174
175     case KC_RSPC: {
176       if (record->event.pressed) {
177         shift_interrupted[1] = false;
178         register_mods(MOD_BIT(KC_RSFT));
179       }
180       else {
181         if (!shift_interrupted[1]) {
182           register_code(RSPC_KEY);
183           unregister_code(RSPC_KEY);
184         }
185         unregister_mods(MOD_BIT(KC_RSFT));
186       }
187       return false;
188       break;
189     }
190     default: {
191       shift_interrupted[0] = true;
192       shift_interrupted[1] = true;
193       break;
194     }
195   }
196
197   return process_action_kb(record);
198 }
199
200 const bool ascii_to_qwerty_shift_lut[0x80] PROGMEM = {
201     0, 0, 0, 0, 0, 0, 0, 0,
202     0, 0, 0, 0, 0, 0, 0, 0,
203     0, 0, 0, 0, 0, 0, 0, 0,
204     0, 0, 0, 0, 0, 0, 0, 0,
205     0, 1, 1, 1, 1, 1, 1, 0,
206     1, 1, 1, 1, 0, 0, 0, 0,
207     0, 0, 0, 0, 0, 0, 0, 0,
208     0, 0, 1, 0, 1, 0, 1, 1,
209     1, 1, 1, 1, 1, 1, 1, 1,
210     1, 1, 1, 1, 1, 1, 1, 1,
211     1, 1, 1, 1, 1, 1, 1, 1,
212     1, 1, 1, 0, 0, 0, 1, 1,
213     0, 0, 0, 0, 0, 0, 0, 0,
214     0, 0, 0, 0, 0, 0, 0, 0,
215     0, 0, 0, 0, 0, 0, 0, 0,
216     0, 0, 0, 1, 1, 1, 1, 0
217 };
218
219 const uint8_t ascii_to_qwerty_keycode_lut[0x80] PROGMEM = {
220     0, 0, 0, 0, 0, 0, 0, 0,
221     KC_BSPC, KC_TAB, KC_ENT, 0, 0, 0, 0, 0,
222     0, 0, 0, 0, 0, 0, 0, 0,
223     0, 0, 0, KC_ESC, 0, 0, 0, 0,
224     KC_SPC, KC_1, KC_QUOT, KC_3, KC_4, KC_5, KC_7, KC_QUOT,
225     KC_9, KC_0, KC_8, KC_EQL, KC_COMM, KC_MINS, KC_DOT, KC_SLSH,
226     KC_0, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7,
227     KC_8, KC_9, KC_SCLN, KC_SCLN, KC_COMM, KC_EQL, KC_DOT, KC_SLSH,
228     KC_2, KC_A, KC_B, KC_C, KC_D, KC_E, KC_F, KC_G,
229     KC_H, KC_I, KC_J, KC_K, KC_L, KC_M, KC_N, KC_O,
230     KC_P, KC_Q, KC_R, KC_S, KC_T, KC_U, KC_V, KC_W,
231     KC_X, KC_Y, KC_Z, KC_LBRC, KC_BSLS, KC_RBRC, KC_6, KC_MINS,
232     KC_GRV, KC_A, KC_B, KC_C, KC_D, KC_E, KC_F, KC_G,
233     KC_H, KC_I, KC_J, KC_K, KC_L, KC_M, KC_N, KC_O,
234     KC_P, KC_Q, KC_R, KC_S, KC_T, KC_U, KC_V, KC_W,
235     KC_X, KC_Y, KC_Z, KC_LBRC, KC_BSLS, KC_RBRC, KC_GRV, KC_DEL
236 };
237
238 /* for users whose OSes are set to Colemak */
239 #if 0
240 #include "keymap_colemak.h"
241
242 const bool ascii_to_colemak_shift_lut[0x80] PROGMEM = {
243     0, 0, 0, 0, 0, 0, 0, 0,
244     0, 0, 0, 0, 0, 0, 0, 0,
245     0, 0, 0, 0, 0, 0, 0, 0,
246     0, 0, 0, 0, 0, 0, 0, 0,
247     0, 1, 1, 1, 1, 1, 1, 0,
248     1, 1, 1, 1, 0, 0, 0, 0,
249     0, 0, 0, 0, 0, 0, 0, 0,
250     0, 0, 1, 0, 1, 0, 1, 1,
251     1, 1, 1, 1, 1, 1, 1, 1,
252     1, 1, 1, 1, 1, 1, 1, 1,
253     1, 1, 1, 1, 1, 1, 1, 1,
254     1, 1, 1, 0, 0, 0, 1, 1,
255     0, 0, 0, 0, 0, 0, 0, 0,
256     0, 0, 0, 0, 0, 0, 0, 0,
257     0, 0, 0, 0, 0, 0, 0, 0,
258     0, 0, 0, 1, 1, 1, 1, 0
259 };
260
261 const uint8_t ascii_to_colemak_keycode_lut[0x80] PROGMEM = {
262     0, 0, 0, 0, 0, 0, 0, 0,
263     KC_BSPC, KC_TAB, KC_ENT, 0, 0, 0, 0, 0,
264     0, 0, 0, 0, 0, 0, 0, 0,
265     0, 0, 0, KC_ESC, 0, 0, 0, 0,
266     KC_SPC, KC_1, KC_QUOT, KC_3, KC_4, KC_5, KC_7, KC_QUOT,
267     KC_9, KC_0, KC_8, KC_EQL, KC_COMM, KC_MINS, KC_DOT, KC_SLSH,
268     KC_0, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7,
269     KC_8, KC_9, CM_SCLN, CM_SCLN, KC_COMM, KC_EQL, KC_DOT, KC_SLSH,
270     KC_2, CM_A, CM_B, CM_C, CM_D, CM_E, CM_F, CM_G,
271     CM_H, CM_I, CM_J, CM_K, CM_L, CM_M, CM_N, CM_O,
272     CM_P, CM_Q, CM_R, CM_S, CM_T, CM_U, CM_V, CM_W,
273     CM_X, CM_Y, CM_Z, KC_LBRC, KC_BSLS, KC_RBRC, KC_6, KC_MINS,
274     KC_GRV, CM_A, CM_B, CM_C, CM_D, CM_E, CM_F, CM_G,
275     CM_H, CM_I, CM_J, CM_K, CM_L, CM_M, CM_N, CM_O,
276     CM_P, CM_Q, CM_R, CM_S, CM_T, CM_U, CM_V, CM_W,
277     CM_X, CM_Y, CM_Z, KC_LBRC, KC_BSLS, KC_RBRC, KC_GRV, KC_DEL
278 };
279
280 #endif
281
282 void send_string(const char *str) {
283     while (1) {
284         uint8_t keycode;
285         uint8_t ascii_code = pgm_read_byte(str);
286         if (!ascii_code) break;
287         keycode = pgm_read_byte(&ascii_to_qwerty_keycode_lut[ascii_code]);
288         if (pgm_read_byte(&ascii_to_qwerty_shift_lut[ascii_code])) {
289             register_code(KC_LSFT);
290             register_code(keycode);
291             unregister_code(keycode);
292             unregister_code(KC_LSFT);
293         }
294         else {
295             register_code(keycode);
296             unregister_code(keycode);
297         }
298         ++str;
299     }
300 }
301
302 void update_tri_layer(uint8_t layer1, uint8_t layer2, uint8_t layer3) {
303   if (IS_LAYER_ON(layer1) && IS_LAYER_ON(layer2)) {
304     layer_on(layer3);
305   } else {
306     layer_off(layer3);
307   }
308 }
309
310 void matrix_init_quantum() {
311   #ifdef BACKLIGHT_ENABLE
312     backlight_init_ports();
313   #endif
314   matrix_init_kb();
315 }
316
317 void matrix_scan_quantum() {
318   #ifdef AUDIO_ENABLE
319     matrix_scan_music();
320   #endif
321
322   #ifdef TAP_DANCE_ENABLE
323     matrix_scan_tap_dance();
324   #endif
325   matrix_scan_kb();
326 }
327
328 #if defined(BACKLIGHT_ENABLE) && defined(BACKLIGHT_PIN)
329
330 static const uint8_t backlight_pin = BACKLIGHT_PIN;
331
332 #if BACKLIGHT_PIN == B7
333 #  define COM1x1 COM1C1
334 #  define OCR1x  OCR1C
335 #elif BACKLIGHT_PIN == B6
336 #  define COM1x1 COM1B1
337 #  define OCR1x  OCR1B
338 #elif BACKLIGHT_PIN == B5
339 #  define COM1x1 COM1A1
340 #  define OCR1x  OCR1A
341 #else
342 #  error "Backlight pin not supported - use B5, B6, or B7"
343 #endif
344
345 __attribute__ ((weak))
346 void backlight_init_ports(void)
347 {
348
349   // Setup backlight pin as output and output low.
350   // DDRx |= n
351   _SFR_IO8((backlight_pin >> 4) + 1) |= _BV(backlight_pin & 0xF);
352   // PORTx &= ~n
353   _SFR_IO8((backlight_pin >> 4) + 2) &= ~_BV(backlight_pin & 0xF);
354
355   // Use full 16-bit resolution.
356   ICR1 = 0xFFFF;
357
358   // I could write a wall of text here to explain... but TL;DW
359   // Go read the ATmega32u4 datasheet.
360   // And this: http://blog.saikoled.com/post/43165849837/secret-konami-cheat-code-to-high-resolution-pwm-on
361
362   // Pin PB7 = OCR1C (Timer 1, Channel C)
363   // Compare Output Mode = Clear on compare match, Channel C = COM1C1=1 COM1C0=0
364   // (i.e. start high, go low when counter matches.)
365   // WGM Mode 14 (Fast PWM) = WGM13=1 WGM12=1 WGM11=1 WGM10=0
366   // Clock Select = clk/1 (no prescaling) = CS12=0 CS11=0 CS10=1
367
368   TCCR1A = _BV(COM1x1) | _BV(WGM11); // = 0b00001010;
369   TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10); // = 0b00011001;
370
371   backlight_init();
372   #ifdef BACKLIGHT_BREATHING
373     breathing_defaults();
374   #endif
375 }
376
377 __attribute__ ((weak))
378 void backlight_set(uint8_t level)
379 {
380   // Prevent backlight blink on lowest level
381   // PORTx &= ~n
382   _SFR_IO8((backlight_pin >> 4) + 2) &= ~_BV(backlight_pin & 0xF);
383
384   if ( level == 0 ) {
385     // Turn off PWM control on backlight pin, revert to output low.
386     TCCR1A &= ~(_BV(COM1x1));
387     OCR1x = 0x0;
388   } else if ( level == BACKLIGHT_LEVELS ) {
389     // Turn on PWM control of backlight pin
390     TCCR1A |= _BV(COM1x1);
391     // Set the brightness
392     OCR1x = 0xFFFF;
393   } else {
394     // Turn on PWM control of backlight pin
395     TCCR1A |= _BV(COM1x1);
396     // Set the brightness
397     OCR1x = 0xFFFF >> ((BACKLIGHT_LEVELS - level) * ((BACKLIGHT_LEVELS + 1) / 2));
398   }
399
400   #ifdef BACKLIGHT_BREATHING
401     breathing_intensity_default();
402   #endif
403 }
404
405
406 #ifdef BACKLIGHT_BREATHING
407
408 #define BREATHING_NO_HALT  0
409 #define BREATHING_HALT_OFF 1
410 #define BREATHING_HALT_ON  2
411
412 static uint8_t breath_intensity;
413 static uint8_t breath_speed;
414 static uint16_t breathing_index;
415 static uint8_t breathing_halt;
416
417 void breathing_enable(void)
418 {
419     if (get_backlight_level() == 0)
420     {
421         breathing_index = 0;
422     }
423     else
424     {
425         // Set breathing_index to be at the midpoint (brightest point)
426         breathing_index = 0x20 << breath_speed;
427     }
428
429     breathing_halt = BREATHING_NO_HALT;
430
431     // Enable breathing interrupt
432     TIMSK1 |= _BV(OCIE1A);
433 }
434
435 void breathing_pulse(void)
436 {
437     if (get_backlight_level() == 0)
438     {
439         breathing_index = 0;
440     }
441     else
442     {
443         // Set breathing_index to be at the midpoint + 1 (brightest point)
444         breathing_index = 0x21 << breath_speed;
445     }
446
447     breathing_halt = BREATHING_HALT_ON;
448
449     // Enable breathing interrupt
450     TIMSK1 |= _BV(OCIE1A);
451 }
452
453 void breathing_disable(void)
454 {
455     // Disable breathing interrupt
456     TIMSK1 &= ~_BV(OCIE1A);
457     backlight_set(get_backlight_level());
458 }
459
460 void breathing_self_disable(void)
461 {
462     if (get_backlight_level() == 0)
463     {
464         breathing_halt = BREATHING_HALT_OFF;
465     }
466     else
467     {
468         breathing_halt = BREATHING_HALT_ON;
469     }
470
471     //backlight_set(get_backlight_level());
472 }
473
474 void breathing_toggle(void)
475 {
476     if (!is_breathing())
477     {
478         if (get_backlight_level() == 0)
479         {
480             breathing_index = 0;
481         }
482         else
483         {
484             // Set breathing_index to be at the midpoint + 1 (brightest point)
485             breathing_index = 0x21 << breath_speed;
486         }
487
488         breathing_halt = BREATHING_NO_HALT;
489     }
490
491     // Toggle breathing interrupt
492     TIMSK1 ^= _BV(OCIE1A);
493
494     // Restore backlight level
495     if (!is_breathing())
496     {
497         backlight_set(get_backlight_level());
498     }
499 }
500
501 bool is_breathing(void)
502 {
503     return (TIMSK1 && _BV(OCIE1A));
504 }
505
506 void breathing_intensity_default(void)
507 {
508     //breath_intensity = (uint8_t)((uint16_t)100 * (uint16_t)get_backlight_level() / (uint16_t)BACKLIGHT_LEVELS);
509     breath_intensity = ((BACKLIGHT_LEVELS - get_backlight_level()) * ((BACKLIGHT_LEVELS + 1) / 2));
510 }
511
512 void breathing_intensity_set(uint8_t value)
513 {
514     breath_intensity = value;
515 }
516
517 void breathing_speed_default(void)
518 {
519     breath_speed = 4;
520 }
521
522 void breathing_speed_set(uint8_t value)
523 {
524     bool is_breathing_now = is_breathing();
525     uint8_t old_breath_speed = breath_speed;
526
527     if (is_breathing_now)
528     {
529         // Disable breathing interrupt
530         TIMSK1 &= ~_BV(OCIE1A);
531     }
532
533     breath_speed = value;
534
535     if (is_breathing_now)
536     {
537         // Adjust index to account for new speed
538         breathing_index = (( (uint8_t)( (breathing_index) >> old_breath_speed ) ) & 0x3F) << breath_speed;
539
540         // Enable breathing interrupt
541         TIMSK1 |= _BV(OCIE1A);
542     }
543
544 }
545
546 void breathing_speed_inc(uint8_t value)
547 {
548     if ((uint16_t)(breath_speed - value) > 10 )
549     {
550         breathing_speed_set(0);
551     }
552     else
553     {
554         breathing_speed_set(breath_speed - value);
555     }
556 }
557
558 void breathing_speed_dec(uint8_t value)
559 {
560     if ((uint16_t)(breath_speed + value) > 10 )
561     {
562         breathing_speed_set(10);
563     }
564     else
565     {
566         breathing_speed_set(breath_speed + value);
567     }
568 }
569
570 void breathing_defaults(void)
571 {
572     breathing_intensity_default();
573     breathing_speed_default();
574     breathing_halt = BREATHING_NO_HALT;
575 }
576
577 /* Breathing Sleep LED brighness(PWM On period) table
578  * (64[steps] * 4[duration]) / 64[PWM periods/s] = 4 second breath cycle
579  *
580  * http://www.wolframalpha.com/input/?i=%28sin%28+x%2F64*pi%29**8+*+255%2C+x%3D0+to+63
581  * (0..63).each {|x| p ((sin(x/64.0*PI)**8)*255).to_i }
582  */
583 static const uint8_t breathing_table[64] PROGMEM = {
584   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   1,   2,   4,   6,  10,
585  15,  23,  32,  44,  58,  74,  93, 113, 135, 157, 179, 199, 218, 233, 245, 252,
586 255, 252, 245, 233, 218, 199, 179, 157, 135, 113,  93,  74,  58,  44,  32,  23,
587  15,  10,   6,   4,   2,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
588 };
589
590 ISR(TIMER1_COMPA_vect)
591 {
592     // OCR1x = (pgm_read_byte(&breathing_table[ ( (uint8_t)( (breathing_index++) >> breath_speed ) ) & 0x3F ] )) * breath_intensity;
593
594
595     uint8_t local_index = ( (uint8_t)( (breathing_index++) >> breath_speed ) ) & 0x3F;
596
597     if (((breathing_halt == BREATHING_HALT_ON) && (local_index == 0x20)) || ((breathing_halt == BREATHING_HALT_OFF) && (local_index == 0x3F)))
598     {
599         // Disable breathing interrupt
600         TIMSK1 &= ~_BV(OCIE1A);
601     }
602
603     OCR1x = (uint16_t)(((uint16_t)pgm_read_byte(&breathing_table[local_index]) * 257)) >> breath_intensity;
604
605 }
606
607
608
609 #endif // breathing
610
611 #else // backlight
612
613 __attribute__ ((weak))
614 void backlight_init_ports(void)
615 {
616
617 }
618
619 __attribute__ ((weak))
620 void backlight_set(uint8_t level)
621 {
622
623 }
624
625 #endif // backlight
626
627
628
629 __attribute__ ((weak))
630 void led_set_user(uint8_t usb_led) {
631
632 }
633
634 __attribute__ ((weak))
635 void led_set_kb(uint8_t usb_led) {
636     led_set_user(usb_led);
637 }
638
639 __attribute__ ((weak))
640 void led_init_ports(void)
641 {
642
643 }
644
645 __attribute__ ((weak))
646 void led_set(uint8_t usb_led)
647 {
648
649   // Example LED Code
650   //
651     // // Using PE6 Caps Lock LED
652     // if (usb_led & (1<<USB_LED_CAPS_LOCK))
653     // {
654     //     // Output high.
655     //     DDRE |= (1<<6);
656     //     PORTE |= (1<<6);
657     // }
658     // else
659     // {
660     //     // Output low.
661     //     DDRE &= ~(1<<6);
662     //     PORTE &= ~(1<<6);
663     // }
664
665   led_set_kb(usb_led);
666 }
667
668
669 //------------------------------------------------------------------------------
670 // Override these functions in your keymap file to play different tunes on
671 // different events such as startup and bootloader jump
672
673 __attribute__ ((weak))
674 void startup_user() {}
675
676 __attribute__ ((weak))
677 void shutdown_user() {}
678
679 //------------------------------------------------------------------------------