summaryrefslogtreecommitdiffstats
path: root/tmk_core/common
diff options
context:
space:
mode:
Diffstat (limited to 'tmk_core/common')
-rw-r--r--tmk_core/common/action.c698
-rw-r--r--tmk_core/common/action.h90
-rw-r--r--tmk_core/common/action_code.h318
-rw-r--r--tmk_core/common/action_layer.c203
-rw-r--r--tmk_core/common/action_layer.h89
-rw-r--r--tmk_core/common/action_macro.c85
-rw-r--r--tmk_core/common/action_macro.h102
-rw-r--r--tmk_core/common/action_tapping.c377
-rw-r--r--tmk_core/common/action_tapping.h39
-rw-r--r--tmk_core/common/action_util.c378
-rw-r--r--tmk_core/common/action_util.h93
-rw-r--r--tmk_core/common/avr/bootloader.c185
-rw-r--r--tmk_core/common/avr/sleep_led.c95
-rw-r--r--tmk_core/common/avr/suspend.c148
-rw-r--r--tmk_core/common/avr/suspend_avr.h27
-rw-r--r--tmk_core/common/avr/timer.c117
-rw-r--r--tmk_core/common/avr/timer_avr.h42
-rw-r--r--tmk_core/common/avr/xprintf.S500
-rw-r--r--tmk_core/common/avr/xprintf.h111
-rw-r--r--tmk_core/common/backlight.c90
-rw-r--r--tmk_core/common/backlight.h41
-rw-r--r--tmk_core/common/bootloader.h25
-rw-r--r--tmk_core/common/bootmagic.c129
-rw-r--r--tmk_core/common/bootmagic.h100
-rw-r--r--tmk_core/common/chibios/bootloader.c47
-rw-r--r--tmk_core/common/chibios/eeprom.c588
-rw-r--r--tmk_core/common/chibios/printf.c240
-rw-r--r--tmk_core/common/chibios/printf.h111
-rw-r--r--tmk_core/common/chibios/sleep_led.c226
-rw-r--r--tmk_core/common/chibios/suspend.c65
-rw-r--r--tmk_core/common/chibios/timer.c27
-rw-r--r--tmk_core/common/command.c794
-rw-r--r--tmk_core/common/command.h157
-rw-r--r--tmk_core/common/debug.c24
-rw-r--r--tmk_core/common/debug.h117
-rw-r--r--tmk_core/common/eeconfig.c56
-rw-r--r--tmk_core/common/eeconfig.h82
-rw-r--r--tmk_core/common/eeprom.h22
-rw-r--r--tmk_core/common/host.c97
-rw-r--r--tmk_core/common/host.h57
-rw-r--r--tmk_core/common/host_driver.h33
-rw-r--r--tmk_core/common/keyboard.c188
-rw-r--r--tmk_core/common/keyboard.h74
-rw-r--r--tmk_core/common/keycode.h494
-rw-r--r--tmk_core/common/led.h43
-rw-r--r--tmk_core/common/magic.c38
-rw-r--r--tmk_core/common/magic.h6
-rw-r--r--tmk_core/common/matrix.h79
-rw-r--r--tmk_core/common/mbed/bootloader.c4
-rw-r--r--tmk_core/common/mbed/suspend.c6
-rw-r--r--tmk_core/common/mbed/timer.c41
-rw-r--r--tmk_core/common/mbed/xprintf.cpp51
-rw-r--r--tmk_core/common/mbed/xprintf.h17
-rw-r--r--tmk_core/common/mousekey.c196
-rw-r--r--tmk_core/common/mousekey.h77
-rw-r--r--tmk_core/common/nodebug.h29
-rw-r--r--tmk_core/common/print.c52
-rw-r--r--tmk_core/common/print.h145
-rw-r--r--tmk_core/common/progmem.h12
-rw-r--r--tmk_core/common/report.h188
-rw-r--r--tmk_core/common/sendchar.h35
-rw-r--r--tmk_core/common/sendchar_null.c23
-rw-r--r--tmk_core/common/sendchar_uart.c25
-rw-r--r--tmk_core/common/sleep_led.h21
-rw-r--r--tmk_core/common/suspend.h13
-rw-r--r--tmk_core/common/timer.h53
-rw-r--r--tmk_core/common/uart.c129
-rw-r--r--tmk_core/common/uart.h11
-rw-r--r--tmk_core/common/util.c101
-rw-r--r--tmk_core/common/util.h43
-rw-r--r--tmk_core/common/wait.h24
71 files changed, 9043 insertions, 0 deletions
diff --git a/tmk_core/common/action.c b/tmk_core/common/action.c
new file mode 100644
index 000000000..be6dea2b7
--- /dev/null
+++ b/tmk_core/common/action.c
@@ -0,0 +1,698 @@
+/*
+Copyright 2012,2013 Jun Wako <wakojun@gmail.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "host.h"
+#include "keycode.h"
+#include "keyboard.h"
+#include "mousekey.h"
+#include "command.h"
+#include "led.h"
+#include "backlight.h"
+#include "action_layer.h"
+#include "action_tapping.h"
+#include "action_macro.h"
+#include "action_util.h"
+#include "action.h"
+
+#ifdef DEBUG_ACTION
+#include "debug.h"
+#else
+#include "nodebug.h"
+#endif
+
+
+void action_exec(keyevent_t event)
+{
+ if (!IS_NOEVENT(event)) {
+ dprint("\n---- action_exec: start -----\n");
+ dprint("EVENT: "); debug_event(event); dprintln();
+ }
+
+ keyrecord_t record = { .event = event };
+
+#ifndef NO_ACTION_TAPPING
+ action_tapping_process(record);
+#else
+ process_record(&record);
+ if (!IS_NOEVENT(record.event)) {
+ dprint("processed: "); debug_record(record); dprintln();
+ }
+#endif
+}
+
+#if !defined(NO_ACTION_LAYER) && defined(PREVENT_STUCK_MODIFIERS)
+bool disable_action_cache = false;
+
+void process_record_nocache(keyrecord_t *record)
+{
+ disable_action_cache = true;
+ process_record(record);
+ disable_action_cache = false;
+}
+#else
+void process_record_nocache(keyrecord_t *record)
+{
+ process_record(record);
+}
+#endif
+
+__attribute__ ((weak))
+bool process_record_quantum(keyrecord_t *record) {
+ return true;
+}
+
+void process_record(keyrecord_t *record)
+{
+ if (IS_NOEVENT(record->event)) { return; }
+
+ if(!process_record_quantum(record))
+ return;
+
+ action_t action = store_or_get_action(record->event.pressed, record->event.key);
+ dprint("ACTION: "); debug_action(action);
+#ifndef NO_ACTION_LAYER
+ dprint(" layer_state: "); layer_debug();
+ dprint(" default_layer_state: "); default_layer_debug();
+#endif
+ dprintln();
+
+ process_action(record, action);
+}
+
+void process_action(keyrecord_t *record, action_t action)
+{
+ bool do_release_oneshot = false;
+ keyevent_t event = record->event;
+#ifndef NO_ACTION_TAPPING
+ uint8_t tap_count = record->tap.count;
+#endif
+
+#if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0))
+ if (has_oneshot_layer_timed_out()) {
+ dprintf("Oneshot layer: timeout\n");
+ clear_oneshot_layer_state(ONESHOT_OTHER_KEY_PRESSED);
+ }
+#endif
+
+ if (event.pressed) {
+ // clear the potential weak mods left by previously pressed keys
+ clear_weak_mods();
+ }
+
+#ifndef NO_ACTION_ONESHOT
+ // notice we only clear the one shot layer if the pressed key is not a modifier.
+ if (is_oneshot_layer_active() && event.pressed && !IS_MOD(action.key.code)) {
+ clear_oneshot_layer_state(ONESHOT_OTHER_KEY_PRESSED);
+ do_release_oneshot = !is_oneshot_layer_active();
+ }
+#endif
+
+ switch (action.kind.id) {
+ /* Key and Mods */
+ case ACT_LMODS:
+ case ACT_RMODS:
+ {
+ uint8_t mods = (action.kind.id == ACT_LMODS) ? action.key.mods :
+ action.key.mods<<4;
+ if (event.pressed) {
+ if (mods) {
+ if (IS_MOD(action.key.code)) {
+ // e.g. LSFT(KC_LGUI): we don't want the LSFT to be weak as it would make it useless.
+ // this also makes LSFT(KC_LGUI) behave exactly the same as LGUI(KC_LSFT)
+ add_mods(mods);
+ } else {
+ add_weak_mods(mods);
+ }
+ send_keyboard_report();
+ }
+ register_code(action.key.code);
+ } else {
+ unregister_code(action.key.code);
+ if (mods) {
+ if (IS_MOD(action.key.code)) {
+ del_mods(mods);
+ } else {
+ del_weak_mods(mods);
+ }
+ send_keyboard_report();
+ }
+ }
+ }
+ break;
+#ifndef NO_ACTION_TAPPING
+ case ACT_LMODS_TAP:
+ case ACT_RMODS_TAP:
+ {
+ uint8_t mods = (action.kind.id == ACT_LMODS_TAP) ? action.key.mods :
+ action.key.mods<<4;
+ switch (action.layer_tap.code) {
+ #ifndef NO_ACTION_ONESHOT
+ case MODS_ONESHOT:
+ // Oneshot modifier
+ if (event.pressed) {
+ if (tap_count == 0) {
+ dprint("MODS_TAP: Oneshot: 0\n");
+ register_mods(mods);
+ } else if (tap_count == 1) {
+ dprint("MODS_TAP: Oneshot: start\n");
+ set_oneshot_mods(mods);
+ #if defined(ONESHOT_TAP_TOGGLE) && ONESHOT_TAP_TOGGLE > 1
+ } else if (tap_count == ONESHOT_TAP_TOGGLE) {
+ dprint("MODS_TAP: Toggling oneshot");
+ clear_oneshot_mods();
+ set_oneshot_locked_mods(mods);
+ register_mods(mods);
+ #endif
+ } else {
+ register_mods(mods);
+ }
+ } else {
+ if (tap_count == 0) {
+ clear_oneshot_mods();
+ unregister_mods(mods);
+ } else if (tap_count == 1) {
+ // Retain Oneshot mods
+ #if defined(ONESHOT_TAP_TOGGLE) && ONESHOT_TAP_TOGGLE > 1
+ if (mods & get_mods()) {
+ clear_oneshot_locked_mods();
+ clear_oneshot_mods();
+ unregister_mods(mods);
+ }
+ } else if (tap_count == ONESHOT_TAP_TOGGLE) {
+ // Toggle Oneshot Layer
+ #endif
+ } else {
+ clear_oneshot_mods();
+ unregister_mods(mods);
+ }
+ }
+ break;
+ #endif
+ case MODS_TAP_TOGGLE:
+ if (event.pressed) {
+ if (tap_count <= TAPPING_TOGGLE) {
+ register_mods(mods);
+ }
+ } else {
+ if (tap_count < TAPPING_TOGGLE) {
+ unregister_mods(mods);
+ }
+ }
+ break;
+ default:
+ if (event.pressed) {
+ if (tap_count > 0) {
+#ifndef IGNORE_MOD_TAP_INTERRUPT
+ if (record->tap.interrupted) {
+ dprint("mods_tap: tap: cancel: add_mods\n");
+ // ad hoc: set 0 to cancel tap
+ record->tap.count = 0;
+ register_mods(mods);
+ } else
+#endif
+ {
+ dprint("MODS_TAP: Tap: register_code\n");
+ register_code(action.key.code);
+ }
+ } else {
+ dprint("MODS_TAP: No tap: add_mods\n");
+ register_mods(mods);
+ }
+ } else {
+ if (tap_count > 0) {
+ dprint("MODS_TAP: Tap: unregister_code\n");
+ unregister_code(action.key.code);
+ } else {
+ dprint("MODS_TAP: No tap: add_mods\n");
+ unregister_mods(mods);
+ }
+ }
+ break;
+ }
+ }
+ break;
+#endif
+#ifdef EXTRAKEY_ENABLE
+ /* other HID usage */
+ case ACT_USAGE:
+ switch (action.usage.page) {
+ case PAGE_SYSTEM:
+ if (event.pressed) {
+ host_system_send(action.usage.code);
+ } else {
+ host_system_send(0);
+ }
+ break;
+ case PAGE_CONSUMER:
+ if (event.pressed) {
+ host_consumer_send(action.usage.code);
+ } else {
+ host_consumer_send(0);
+ }
+ break;
+ }
+ break;
+#endif
+#ifdef MOUSEKEY_ENABLE
+ /* Mouse key */
+ case ACT_MOUSEKEY:
+ if (event.pressed) {
+ mousekey_on(action.key.code);
+ mousekey_send();
+ } else {
+ mousekey_off(action.key.code);
+ mousekey_send();
+ }
+ break;
+#endif
+#ifndef NO_ACTION_LAYER
+ case ACT_LAYER:
+ if (action.layer_bitop.on == 0) {
+ /* Default Layer Bitwise Operation */
+ if (!event.pressed) {
+ uint8_t shift = action.layer_bitop.part*4;
+ uint32_t bits = ((uint32_t)action.layer_bitop.bits)<<shift;
+ uint32_t mask = (action.layer_bitop.xbit) ? ~(((uint32_t)0xf)<<shift) : 0;
+ switch (action.layer_bitop.op) {
+ case OP_BIT_AND: default_layer_and(bits | mask); break;
+ case OP_BIT_OR: default_layer_or(bits | mask); break;
+ case OP_BIT_XOR: default_layer_xor(bits | mask); break;
+ case OP_BIT_SET: default_layer_and(mask); default_layer_or(bits); break;
+ }
+ }
+ } else {
+ /* Layer Bitwise Operation */
+ if (event.pressed ? (action.layer_bitop.on & ON_PRESS) :
+ (action.layer_bitop.on & ON_RELEASE)) {
+ uint8_t shift = action.layer_bitop.part*4;
+ uint32_t bits = ((uint32_t)action.layer_bitop.bits)<<shift;
+ uint32_t mask = (action.layer_bitop.xbit) ? ~(((uint32_t)0xf)<<shift) : 0;
+ switch (action.layer_bitop.op) {
+ case OP_BIT_AND: layer_and(bits | mask); break;
+ case OP_BIT_OR: layer_or(bits | mask); break;
+ case OP_BIT_XOR: layer_xor(bits | mask); break;
+ case OP_BIT_SET: layer_and(mask); layer_or(bits); break;
+ }
+ }
+ }
+ break;
+ #ifndef NO_ACTION_TAPPING
+ case ACT_LAYER_TAP:
+ case ACT_LAYER_TAP_EXT:
+ switch (action.layer_tap.code) {
+ case 0xe0 ... 0xef:
+ /* layer On/Off with modifiers(left only) */
+ if (event.pressed) {
+ layer_on(action.layer_tap.val);
+ register_mods(action.layer_tap.code & 0x0f);
+ } else {
+ layer_off(action.layer_tap.val);
+ unregister_mods(action.layer_tap.code & 0x0f);
+ }
+ break;
+ case OP_TAP_TOGGLE:
+ /* tap toggle */
+ if (event.pressed) {
+ if (tap_count < TAPPING_TOGGLE) {
+ layer_invert(action.layer_tap.val);
+ }
+ } else {
+ if (tap_count <= TAPPING_TOGGLE) {
+ layer_invert(action.layer_tap.val);
+ }
+ }
+ break;
+ case OP_ON_OFF:
+ event.pressed ? layer_on(action.layer_tap.val) :
+ layer_off(action.layer_tap.val);
+ break;
+ case OP_OFF_ON:
+ event.pressed ? layer_off(action.layer_tap.val) :
+ layer_on(action.layer_tap.val);
+ break;
+ case OP_SET_CLEAR:
+ event.pressed ? layer_move(action.layer_tap.val) :
+ layer_clear();
+ break;
+ #ifndef NO_ACTION_ONESHOT
+ case OP_ONESHOT:
+ // Oneshot modifier
+ #if defined(ONESHOT_TAP_TOGGLE) && ONESHOT_TAP_TOGGLE > 1
+ do_release_oneshot = false;
+ if (event.pressed) {
+ del_mods(get_oneshot_locked_mods());
+ if (get_oneshot_layer_state() == ONESHOT_TOGGLED) {
+ reset_oneshot_layer();
+ layer_off(action.layer_tap.val);
+ break;
+ } else if (tap_count < ONESHOT_TAP_TOGGLE) {
+ layer_on(action.layer_tap.val);
+ set_oneshot_layer(action.layer_tap.val, ONESHOT_START);
+ }
+ } else {
+ add_mods(get_oneshot_locked_mods());
+ if (tap_count >= ONESHOT_TAP_TOGGLE) {
+ reset_oneshot_layer();
+ clear_oneshot_locked_mods();
+ set_oneshot_layer(action.layer_tap.val, ONESHOT_TOGGLED);
+ } else {
+ clear_oneshot_layer_state(ONESHOT_PRESSED);
+ }
+ }
+ #else
+ if (event.pressed) {
+ layer_on(action.layer_tap.val);
+ set_oneshot_layer(action.layer_tap.val, ONESHOT_START);
+ } else {
+ clear_oneshot_layer_state(ONESHOT_PRESSED);
+ if (tap_count > 1) {
+ clear_oneshot_layer_state(ONESHOT_OTHER_KEY_PRESSED);
+ }
+ }
+ #endif
+ break;
+ #endif
+ default:
+ /* tap key */
+ if (event.pressed) {
+ if (tap_count > 0) {
+ dprint("KEYMAP_TAP_KEY: Tap: register_code\n");
+ register_code(action.layer_tap.code);
+ } else {
+ dprint("KEYMAP_TAP_KEY: No tap: On on press\n");
+ layer_on(action.layer_tap.val);
+ }
+ } else {
+ if (tap_count > 0) {
+ dprint("KEYMAP_TAP_KEY: Tap: unregister_code\n");
+ unregister_code(action.layer_tap.code);
+ } else {
+ dprint("KEYMAP_TAP_KEY: No tap: Off on release\n");
+ layer_off(action.layer_tap.val);
+ }
+ }
+ break;
+ }
+ break;
+ #endif
+#endif
+ /* Extentions */
+#ifndef NO_ACTION_MACRO
+ case ACT_MACRO:
+ action_macro_play(action_get_macro(record, action.func.id, action.func.opt));
+ break;
+#endif
+#ifdef BACKLIGHT_ENABLE
+ case ACT_BACKLIGHT:
+ if (!event.pressed) {
+ switch (action.backlight.opt) {
+ case BACKLIGHT_INCREASE:
+ backlight_increase();
+ break;
+ case BACKLIGHT_DECREASE:
+ backlight_decrease();
+ break;
+ case BACKLIGHT_TOGGLE:
+ backlight_toggle();
+ break;
+ case BACKLIGHT_STEP:
+ backlight_step();
+ break;
+ case BACKLIGHT_LEVEL:
+ backlight_level(action.backlight.level);
+ break;
+ }
+ }
+ break;
+#endif
+ case ACT_COMMAND:
+ break;
+#ifndef NO_ACTION_FUNCTION
+ case ACT_FUNCTION:
+ action_function(record, action.func.id, action.func.opt);
+ break;
+#endif
+ default:
+ break;
+ }
+
+#ifndef NO_ACTION_ONESHOT
+ /* Because we switch layers after a oneshot event, we need to release the
+ * key before we leave the layer or no key up event will be generated.
+ */
+ if (do_release_oneshot && !(get_oneshot_layer_state() & ONESHOT_PRESSED ) ) {
+ record->event.pressed = false;
+ layer_on(get_oneshot_layer());
+ process_record(record);
+ layer_off(get_oneshot_layer());
+ }
+#endif
+}
+
+
+
+
+/*
+ * Utilities for actions.
+ */
+void register_code(uint8_t code)
+{
+ if (code == KC_NO) {
+ return;
+ }
+
+#ifdef LOCKING_SUPPORT_ENABLE
+ else if (KC_LOCKING_CAPS == code) {
+#ifdef LOCKING_RESYNC_ENABLE
+ // Resync: ignore if caps lock already is on
+ if (host_keyboard_leds() & (1<<USB_LED_CAPS_LOCK)) return;
+#endif
+ add_key(KC_CAPSLOCK);
+ send_keyboard_report();
+ del_key(KC_CAPSLOCK);
+ send_keyboard_report();
+ }
+
+ else if (KC_LOCKING_NUM == code) {
+#ifdef LOCKING_RESYNC_ENABLE
+ if (host_keyboard_leds() & (1<<USB_LED_NUM_LOCK)) return;
+#endif
+ add_key(KC_NUMLOCK);
+ send_keyboard_report();
+ del_key(KC_NUMLOCK);
+ send_keyboard_report();
+ }
+
+ else if (KC_LOCKING_SCROLL == code) {
+#ifdef LOCKING_RESYNC_ENABLE
+ if (host_keyboard_leds() & (1<<USB_LED_SCROLL_LOCK)) return;
+#endif
+ add_key(KC_SCROLLLOCK);
+ send_keyboard_report();
+ del_key(KC_SCROLLLOCK);
+ send_keyboard_report();
+ }
+#endif
+
+ else if IS_KEY(code) {
+ // TODO: should push command_proc out of this block?
+ if (command_proc(code)) return;
+
+#ifndef NO_ACTION_ONESHOT
+/* TODO: remove
+ if (oneshot_state.mods && !oneshot_state.disabled) {
+ uint8_t tmp_mods = get_mods();
+ add_mods(oneshot_state.mods);
+
+ add_key(code);
+ send_keyboard_report();
+
+ set_mods(tmp_mods);
+ send_keyboard_report();
+ oneshot_cancel();
+ } else
+*/
+#endif
+ {
+ add_key(code);
+ send_keyboard_report();
+ }
+ }
+ else if IS_MOD(code) {
+ add_mods(MOD_BIT(code));
+ send_keyboard_report();
+ }
+ else if IS_SYSTEM(code) {
+ host_system_send(KEYCODE2SYSTEM(code));
+ }
+ else if IS_CONSUMER(code) {
+ host_consumer_send(KEYCODE2CONSUMER(code));
+ }
+}
+
+void unregister_code(uint8_t code)
+{
+ if (code == KC_NO) {
+ return;
+ }
+
+#ifdef LOCKING_SUPPORT_ENABLE
+ else if (KC_LOCKING_CAPS == code) {
+#ifdef LOCKING_RESYNC_ENABLE
+ // Resync: ignore if caps lock already is off
+ if (!(host_keyboard_leds() & (1<<USB_LED_CAPS_LOCK))) return;
+#endif
+ add_key(KC_CAPSLOCK);
+ send_keyboard_report();
+ del_key(KC_CAPSLOCK);
+ send_keyboard_report();
+ }
+
+ else if (KC_LOCKING_NUM == code) {
+#ifdef LOCKING_RESYNC_ENABLE
+ if (!(host_keyboard_leds() & (1<<USB_LED_NUM_LOCK))) return;
+#endif
+ add_key(KC_NUMLOCK);
+ send_keyboard_report();
+ del_key(KC_NUMLOCK);
+ send_keyboard_report();
+ }
+
+ else if (KC_LOCKING_SCROLL == code) {
+#ifdef LOCKING_RESYNC_ENABLE
+ if (!(host_keyboard_leds() & (1<<USB_LED_SCROLL_LOCK))) return;
+#endif
+ add_key(KC_SCROLLLOCK);
+ send_keyboard_report();
+ del_key(KC_SCROLLLOCK);
+ send_keyboard_report();
+ }
+#endif
+
+ else if IS_KEY(code) {
+ del_key(code);
+ send_keyboard_report();
+ }
+ else if IS_MOD(code) {
+ del_mods(MOD_BIT(code));
+ send_keyboard_report();
+ }
+ else if IS_SYSTEM(code) {
+ host_system_send(0);
+ }
+ else if IS_CONSUMER(code) {
+ host_consumer_send(0);
+ }
+}
+
+void register_mods(uint8_t mods)
+{
+ if (mods) {
+ add_mods(mods);
+ send_keyboard_report();
+ }
+}
+
+void unregister_mods(uint8_t mods)
+{
+ if (mods) {
+ del_mods(mods);
+ send_keyboard_report();
+ }
+}
+
+void clear_keyboard(void)
+{
+ clear_mods();
+ clear_keyboard_but_mods();
+}
+
+void clear_keyboard_but_mods(void)
+{
+ clear_weak_mods();
+ clear_macro_mods();
+ clear_keys();
+ send_keyboard_report();
+#ifdef MOUSEKEY_ENABLE
+ mousekey_clear();
+ mousekey_send();
+#endif
+#ifdef EXTRAKEY_ENABLE
+ host_system_send(0);
+ host_consumer_send(0);
+#endif
+}
+
+bool is_tap_key(keypos_t key)
+{
+ action_t action = layer_switch_get_action(key);
+
+ switch (action.kind.id) {
+ case ACT_LMODS_TAP:
+ case ACT_RMODS_TAP:
+ case ACT_LAYER_TAP:
+ case ACT_LAYER_TAP_EXT:
+ switch (action.layer_tap.code) {
+ case 0x00 ... 0xdf:
+ case OP_TAP_TOGGLE:
+ case OP_ONESHOT:
+ return true;
+ }
+ return false;
+ case ACT_MACRO:
+ case ACT_FUNCTION:
+ if (action.func.opt & FUNC_TAP) { return true; }
+ return false;
+ }
+ return false;
+}
+
+
+/*
+ * debug print
+ */
+void debug_event(keyevent_t event)
+{
+ dprintf("%04X%c(%u)", (event.key.row<<8 | event.key.col), (event.pressed ? 'd' : 'u'), event.time);
+}
+
+void debug_record(keyrecord_t record)
+{
+ debug_event(record.event);
+#ifndef NO_ACTION_TAPPING
+ dprintf(":%u%c", record.tap.count, (record.tap.interrupted ? '-' : ' '));
+#endif
+}
+
+void debug_action(action_t action)
+{
+ switch (action.kind.id) {
+ case ACT_LMODS: dprint("ACT_LMODS"); break;
+ case ACT_RMODS: dprint("ACT_RMODS"); break;
+ case ACT_LMODS_TAP: dprint("ACT_LMODS_TAP"); break;
+ case ACT_RMODS_TAP: dprint("ACT_RMODS_TAP"); break;
+ case ACT_USAGE: dprint("ACT_USAGE"); break;
+ case ACT_MOUSEKEY: dprint("ACT_MOUSEKEY"); break;
+ case ACT_LAYER: dprint("ACT_LAYER"); break;
+ case ACT_LAYER_TAP: dprint("ACT_LAYER_TAP"); break;
+ case ACT_LAYER_TAP_EXT: dprint("ACT_LAYER_TAP_EXT"); break;
+ case ACT_MACRO: dprint("ACT_MACRO"); break;
+ case ACT_COMMAND: dprint("ACT_COMMAND"); break;
+ case ACT_FUNCTION: dprint("ACT_FUNCTION"); break;
+ default: dprint("UNKNOWN"); break;
+ }
+ dprintf("[%X:%02X]", action.kind.param>>8, action.kind.param&0xff);
+}
diff --git a/tmk_core/common/action.h b/tmk_core/common/action.h
new file mode 100644
index 000000000..e8aa12a7c
--- /dev/null
+++ b/tmk_core/common/action.h
@@ -0,0 +1,90 @@
+/*
+Copyright 2012,2013 Jun Wako <wakojun@gmail.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef ACTION_H
+#define ACTION_H
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "keyboard.h"
+#include "keycode.h"
+#include "action_code.h"
+#include "action_macro.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* tapping count and state */
+typedef struct {
+ bool interrupted :1;
+ bool reserved2 :1;
+ bool reserved1 :1;
+ bool reserved0 :1;
+ uint8_t count :4;
+} tap_t;
+
+/* Key event container for recording */
+typedef struct {
+ keyevent_t event;
+#ifndef NO_ACTION_TAPPING
+ tap_t tap;
+#endif
+} keyrecord_t;
+
+/* Execute action per keyevent */
+void action_exec(keyevent_t event);
+
+/* action for key */
+action_t action_for_key(uint8_t layer, keypos_t key);
+
+/* macro */
+const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt);
+
+/* user defined special function */
+void action_function(keyrecord_t *record, uint8_t id, uint8_t opt);
+
+/* keyboard-specific key event (pre)processing */
+bool process_record_quantum(keyrecord_t *record);
+
+/* Utilities for actions. */
+#if !defined(NO_ACTION_LAYER) && defined(PREVENT_STUCK_MODIFIERS)
+extern bool disable_action_cache;
+#endif
+void process_record_nocache(keyrecord_t *record);
+void process_record(keyrecord_t *record);
+void process_action(keyrecord_t *record, action_t action);
+void register_code(uint8_t code);
+void unregister_code(uint8_t code);
+void register_mods(uint8_t mods);
+void unregister_mods(uint8_t mods);
+//void set_mods(uint8_t mods);
+void clear_keyboard(void);
+void clear_keyboard_but_mods(void);
+void layer_switch(uint8_t new_layer);
+bool is_tap_key(keypos_t key);
+
+/* debug */
+void debug_event(keyevent_t event);
+void debug_record(keyrecord_t record);
+void debug_action(action_t action);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ACTION_H */
diff --git a/tmk_core/common/action_code.h b/tmk_core/common/action_code.h
new file mode 100644
index 000000000..ca729aaec
--- /dev/null
+++ b/tmk_core/common/action_code.h
@@ -0,0 +1,318 @@
+/*
+Copyright 2013 Jun Wako <wakojun@gmail.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef ACTION_CODE_H
+#define ACTION_CODE_H
+
+/* Action codes
+ * ============
+ * 16bit code: action_kind(4bit) + action_parameter(12bit)
+ *
+ *
+ * Key Actions(00xx)
+ * -----------------
+ * ACT_MODS(000r):
+ * 000r|0000|0000 0000 No action code
+ * 000r|0000|0000 0001 Transparent code
+ * 000r|0000| keycode Key
+ * 000r|mods|0000 0000 Modifiers
+ * 000r|mods| keycode Modifiers+Key(Modified key)
+ * r: Left/Right flag(Left:0, Right:1)
+ *
+ * ACT_MODS_TAP(001r):
+ * 001r|mods|0000 0000 Modifiers with OneShot
+ * 001r|mods|0000 0001 Modifiers with tap toggle
+ * 001r|mods|0000 00xx (reserved)
+ * 001r|mods| keycode Modifiers with Tap Key(Dual role)
+ *
+ *
+ * Other Keys(01xx)
+ * ----------------
+ * ACT_USAGE(0100): TODO: Not needed?
+ * 0100|00| usage(10) System control(0x80) - General Desktop page(0x01)
+ * 0100|01| usage(10) Consumer control(0x01) - Consumer page(0x0C)
+ * 0100|10| usage(10) (reserved)
+ * 0100|11| usage(10) (reserved)
+ *
+ * ACT_MOUSEKEY(0110): TODO: Not needed?
+ * 0101|xxxx| keycode Mouse key
+ *
+ * 011x|xxxx xxxx xxxx (reseved)
+ *
+ *
+ * Layer Actions(10xx)
+ * -------------------
+ * ACT_LAYER(1000):
+ * 1000|oo00|pppE BBBB Default Layer Bitwise operation
+ * oo: operation(00:AND, 01:OR, 10:XOR, 11:SET)
+ * ppp: 4-bit chunk part(0-7)
+ * EBBBB: bits and extra bit
+ * 1000|ooee|pppE BBBB Layer Bitwise Operation
+ * oo: operation(00:AND, 01:OR, 10:XOR, 11:SET)
+ * ppp: 4-bit chunk part(0-7)
+ * EBBBB: bits and extra bit
+ * ee: on event(01:press, 10:release, 11:both)
+ *
+ * 1001|xxxx|xxxx xxxx (reserved)
+ * 1001|oopp|BBBB BBBB 8-bit Bitwise Operation???
+ *
+ * ACT_LAYER_TAP(101x):
+ * 101E|LLLL| keycode On/Off with tap key (0x00-DF)[TAP]
+ * 101E|LLLL|1110 mods On/Off with modifiers (0xE0-EF)[NOT TAP]
+ * 101E|LLLL|1111 0000 Invert with tap toggle (0xF0) [TAP]
+ * 101E|LLLL|1111 0001 On/Off (0xF1) [NOT TAP]
+ * 101E|LLLL|1111 0010 Off/On (0xF2) [NOT TAP]
+ * 101E|LLLL|1111 0011 Set/Clear (0xF3) [NOT TAP]
+ * 101E|LLLL|1111 0100 One Shot Layer (0xF4) [TAP]
+ * 101E|LLLL|1111 xxxx Reserved (0xF5-FF)
+ * ELLLL: layer 0-31(E: extra bit for layer 16-31)
+ *
+ *
+ * Extensions(11xx)
+ * ----------------
+ * ACT_MACRO(1100):
+ * 1100|opt | id(8) Macro play?
+ * 1100|1111| id(8) Macro record?
+ *
+ * ACT_BACKLIGHT(1101):
+ * 1101|opt |level(8) Backlight commands
+ *
+ * ACT_COMMAND(1110):
+ * 1110|opt | id(8) Built-in Command exec
+ *
+ * ACT_FUNCTION(1111):
+ * 1111| address(12) Function?
+ * 1111|opt | id(8) Function?
+ */
+enum action_kind_id {
+ /* Key Actions */
+ ACT_MODS = 0b0000,
+ ACT_LMODS = 0b0000,
+ ACT_RMODS = 0b0001,
+ ACT_MODS_TAP = 0b0010,
+ ACT_LMODS_TAP = 0b0010,
+ ACT_RMODS_TAP = 0b0011,
+ /* Other Keys */
+ ACT_USAGE = 0b0100,
+ ACT_MOUSEKEY = 0b0101,
+ /* Layer Actions */
+ ACT_LAYER = 0b1000,
+ ACT_LAYER_TAP = 0b1010, /* Layer 0-15 */
+ ACT_LAYER_TAP_EXT = 0b1011, /* Layer 16-31 */
+ /* Extensions */
+ ACT_MACRO = 0b1100,
+ ACT_BACKLIGHT = 0b1101,
+ ACT_COMMAND = 0b1110,
+ ACT_FUNCTION = 0b1111
+};
+
+
+/* Action Code Struct
+ *
+ * NOTE:
+ * In avr-gcc bit field seems to be assigned from LSB(bit0) to MSB(bit15).
+ * AVR looks like a little endian in avr-gcc.
+ * Not portable across compiler/endianness?
+ *
+ * Byte order and bit order of 0x1234:
+ * Big endian: Little endian:
+ * -------------------- --------------------
+ * FEDC BA98 7654 3210 0123 4567 89AB CDEF
+ * 0001 0010 0011 0100 0010 1100 0100 1000
+ * 0x12 0x34 0x34 0x12
+ */
+typedef union {
+ uint16_t code;
+ struct action_kind {
+ uint16_t param :12;
+ uint8_t id :4;
+ } kind;
+ struct action_key {
+ uint8_t code :8;
+ uint8_t mods :4;
+ uint8_t kind :4;
+ } key;
+ struct action_layer_bitop {
+ uint8_t bits :4;
+ uint8_t xbit :1;
+ uint8_t part :3;
+ uint8_t on :2;
+ uint8_t op :2;
+ uint8_t kind :4;
+ } layer_bitop;
+ struct action_layer_tap {
+ uint8_t code :8;
+ uint8_t val :5;
+ uint8_t kind :3;
+ } layer_tap;
+ struct action_usage {
+ uint16_t code :10;
+ uint8_t page :2;
+ uint8_t kind :4;
+ } usage;
+ struct action_backlight {
+ uint8_t level :8;
+ uint8_t opt :4;
+ uint8_t kind :4;
+ } backlight;
+ struct action_command {
+ uint8_t id :8;
+ uint8_t opt :4;
+ uint8_t kind :4;
+ } command;
+ struct action_function {
+ uint8_t id :8;
+ uint8_t opt :4;
+ uint8_t kind :4;
+ } func;
+} action_t;
+
+
+/* action utility */
+#define ACTION_NO 0
+#define ACTION_TRANSPARENT 1
+#define ACTION(kind, param) ((kind)<<12 | (param))
+
+
+/*
+ * Key Actions
+ */
+/* Mod bits: 43210
+ * bit 0 ||||+- Control
+ * bit 1 |||+-- Shift
+ * bit 2 ||+--- Alt
+ * bit 3 |+---- Gui
+ * bit 4 +----- LR flag(Left:0, Right:1)
+ */
+enum mods_bit {
+ MOD_LCTL = 0x01,
+ MOD_LSFT = 0x02,
+ MOD_LALT = 0x04,
+ MOD_LGUI = 0x08,
+ MOD_RCTL = 0x11,
+ MOD_RSFT = 0x12,
+ MOD_RALT = 0x14,
+ MOD_RGUI = 0x18,
+};
+enum mods_codes {
+ MODS_ONESHOT = 0x00,
+ MODS_TAP_TOGGLE = 0x01,
+};
+#define ACTION_KEY(key) ACTION(ACT_MODS, (key))
+#define ACTION_MODS(mods) ACTION(ACT_MODS, ((mods)&0x1f)<<8 | 0)
+#define ACTION_MODS_KEY(mods, key) ACTION(ACT_MODS, ((mods)&0x1f)<<8 | (key))
+#define ACTION_MODS_TAP_KEY(mods, key) ACTION(ACT_MODS_TAP, ((mods)&0x1f)<<8 | (key))
+#define ACTION_MODS_ONESHOT(mods) ACTION(ACT_MODS_TAP, ((mods)&0x1f)<<8 | MODS_ONESHOT)
+#define ACTION_MODS_TAP_TOGGLE(mods) ACTION(ACT_MODS_TAP, ((mods)&0x1f)<<8 | MODS_TAP_TOGGLE)
+
+
+/*
+ * Other Keys
+ */
+enum usage_pages {
+ PAGE_SYSTEM,
+ PAGE_CONSUMER
+};
+#define ACTION_USAGE_SYSTEM(id) ACTION(ACT_USAGE, PAGE_SYSTEM<<10 | (id))
+#define ACTION_USAGE_CONSUMER(id) ACTION(ACT_USAGE, PAGE_CONSUMER<<10 | (id))
+#define ACTION_MOUSEKEY(key) ACTION(ACT_MOUSEKEY, key)
+
+
+
+/*
+ * Layer Actions
+ */
+enum layer_param_on {
+ ON_PRESS = 1,
+ ON_RELEASE = 2,
+ ON_BOTH = 3,
+};
+enum layer_param_bit_op {
+ OP_BIT_AND = 0,
+ OP_BIT_OR = 1,
+ OP_BIT_XOR = 2,
+ OP_BIT_SET = 3,
+};
+enum layer_pram_tap_op {
+ OP_TAP_TOGGLE = 0xF0,
+ OP_ON_OFF,
+ OP_OFF_ON,
+ OP_SET_CLEAR,
+ OP_ONESHOT,
+};
+#define ACTION_LAYER_BITOP(op, part, bits, on) (ACT_LAYER<<12 | (op)<<10 | (on)<<8 | (part)<<5 | ((bits)&0x1f))
+#define ACTION_LAYER_TAP(layer, key) (ACT_LAYER_TAP<<12 | (layer)<<8 | (key))
+/* Default Layer */
+#define ACTION_DEFAULT_LAYER_SET(layer) ACTION_DEFAULT_LAYER_BIT_SET((layer)/4, 1<<((layer)%4))
+/* Layer Operation */
+#define ACTION_LAYER_CLEAR(on) ACTION_LAYER_BIT_AND(0, 0, (on))
+#define ACTION_LAYER_MOMENTARY(layer) ACTION_LAYER_ON_OFF(layer)
+#define ACTION_LAYER_TOGGLE(layer) ACTION_LAYER_INVERT(layer, ON_RELEASE)
+#define ACTION_LAYER_INVERT(layer, on) ACTION_LAYER_BIT_XOR((layer)/4, 1<<((layer)%4), (on))
+#define ACTION_LAYER_ON(layer, on) ACTION_LAYER_BIT_OR( (layer)/4, 1<<((layer)%4), (on))
+#define ACTION_LAYER_OFF(layer, on) ACTION_LAYER_BIT_AND((layer)/4, ~(1<<((layer)%4)), (on))
+#define ACTION_LAYER_SET(layer, on) ACTION_LAYER_BIT_SET((layer)/4, 1<<((layer)%4), (on))
+#define ACTION_LAYER_ON_OFF(layer) ACTION_LAYER_TAP((layer), OP_ON_OFF)
+#define ACTION_LAYER_OFF_ON(layer) ACTION_LAYER_TAP((layer), OP_OFF_ON)
+#define ACTION_LAYER_SET_CLEAR(layer) ACTION_LAYER_TAP((layer), OP_SET_CLEAR)
+#define ACTION_LAYER_ONESHOT(layer) ACTION_LAYER_TAP((layer), OP_ONESHOT)
+#define ACTION_LAYER_MODS(layer, mods) ACTION_LAYER_TAP((layer), 0xe0 | ((mods)&0x0f))
+/* With Tapping */
+#define ACTION_LAYER_TAP_KEY(layer, key) ACTION_LAYER_TAP((layer), (key))
+#define ACTION_LAYER_TAP_TOGGLE(layer) ACTION_LAYER_TAP((layer), OP_TAP_TOGGLE)
+/* Bitwise Operation */
+#define ACTION_LAYER_BIT_AND(part, bits, on) ACTION_LAYER_BITOP(OP_BIT_AND, (part), (bits), (on))
+#define ACTION_LAYER_BIT_OR( part, bits, on) ACTION_LAYER_BITOP(OP_BIT_OR, (part), (bits), (on))
+#define ACTION_LAYER_BIT_XOR(part, bits, on) ACTION_LAYER_BITOP(OP_BIT_XOR, (part), (bits), (on))
+#define ACTION_LAYER_BIT_SET(part, bits, on) ACTION_LAYER_BITOP(OP_BIT_SET, (part), (bits), (on))
+/* Default Layer Bitwise Operation */
+#define ACTION_DEFAULT_LAYER_BIT_AND(part, bits) ACTION_LAYER_BITOP(OP_BIT_AND, (part), (bits), 0)
+#define ACTION_DEFAULT_LAYER_BIT_OR( part, bits) ACTION_LAYER_BITOP(OP_BIT_OR, (part), (bits), 0)
+#define ACTION_DEFAULT_LAYER_BIT_XOR(part, bits) ACTION_LAYER_BITOP(OP_BIT_XOR, (part), (bits), 0)
+#define ACTION_DEFAULT_LAYER_BIT_SET(part, bits) ACTION_LAYER_BITOP(OP_BIT_SET, (part), (bits), 0)
+
+
+/*
+ * Extensions
+ */
+enum backlight_opt {
+ BACKLIGHT_INCREASE = 0,
+ BACKLIGHT_DECREASE = 1,
+ BACKLIGHT_TOGGLE = 2,
+ BACKLIGHT_STEP = 3,
+ BACKLIGHT_LEVEL = 4,
+};
+/* Macro */
+#define ACTION_MACRO(id) ACTION(ACT_MACRO, (id))
+#define ACTION_MACRO_TAP(id) ACTION(ACT_MACRO, FUNC_TAP<<8 | (id))
+#define ACTION_MACRO_OPT(id, opt) ACTION(ACT_MACRO, (opt)<<8 | (id))
+/* Backlight */
+#define ACTION_BACKLIGHT_INCREASE() ACTION(ACT_BACKLIGHT, BACKLIGHT_INCREASE << 8)
+#define ACTION_BACKLIGHT_DECREASE() ACTION(ACT_BACKLIGHT, BACKLIGHT_DECREASE << 8)
+#define ACTION_BACKLIGHT_TOGGLE() ACTION(ACT_BACKLIGHT, BACKLIGHT_TOGGLE << 8)
+#define ACTION_BACKLIGHT_STEP() ACTION(ACT_BACKLIGHT, BACKLIGHT_STEP << 8)
+#define ACTION_BACKLIGHT_LEVEL(level) ACTION(ACT_BACKLIGHT, BACKLIGHT_LEVEL << 8 | (level))
+/* Command */
+#define ACTION_COMMAND(id, opt) ACTION(ACT_COMMAND, (opt)<<8 | (addr))
+/* Function */
+enum function_opts {
+ FUNC_TAP = 0x8, /* indciates function is tappable */
+};
+#define ACTION_FUNCTION(id) ACTION(ACT_FUNCTION, (id))
+#define ACTION_FUNCTION_TAP(id) ACTION(ACT_FUNCTION, FUNC_TAP<<8 | (id))
+#define ACTION_FUNCTION_OPT(id, opt) ACTION(ACT_FUNCTION, (opt)<<8 | (id))
+
+#endif /* ACTION_CODE_H */
diff --git a/tmk_core/common/action_layer.c b/tmk_core/common/action_layer.c
new file mode 100644
index 000000000..63fa2b5ae
--- /dev/null
+++ b/tmk_core/common/action_layer.c
@@ -0,0 +1,203 @@
+#include <stdint.h>
+#include "keyboard.h"
+#include "action.h"
+#include "util.h"
+#include "action_layer.h"
+
+#ifdef DEBUG_ACTION
+#include "debug.h"
+#else
+#include "nodebug.h"
+#endif
+
+
+/*
+ * Default Layer State
+ */
+uint32_t default_layer_state = 0;
+
+static void default_layer_state_set(uint32_t state)
+{
+ debug("default_layer_state: ");
+ default_layer_debug(); debug(" to ");
+ default_layer_state = state;
+ default_layer_debug(); debug("\n");
+ clear_keyboard_but_mods(); // To avoid stuck keys
+}
+
+void default_layer_debug(void)
+{
+ dprintf("%08lX(%u)", default_layer_state, biton32(default_layer_state));
+}
+
+void default_layer_set(uint32_t state)
+{
+ default_layer_state_set(state);
+}
+
+#ifndef NO_ACTION_LAYER
+void default_layer_or(uint32_t state)
+{
+ default_layer_state_set(default_layer_state | state);
+}
+void default_layer_and(uint32_t state)
+{
+ default_layer_state_set(default_layer_state & state);
+}
+void default_layer_xor(uint32_t state)
+{
+ default_layer_state_set(default_layer_state ^ state);
+}
+#endif
+
+
+#ifndef NO_ACTION_LAYER
+/*
+ * Keymap Layer State
+ */
+uint32_t layer_state = 0;
+
+static void layer_state_set(uint32_t state)
+{
+ dprint("layer_state: ");
+ layer_debug(); dprint(" to ");
+ layer_state = state;
+ layer_debug(); dprintln();
+ clear_keyboard_but_mods(); // To avoid stuck keys
+}
+
+void layer_clear(void)
+{
+ layer_state_set(0);
+}
+
+void layer_move(uint8_t layer)
+{
+ layer_state_set(1UL<<layer);
+}
+
+void layer_on(uint8_t layer)
+{
+ layer_state_set(layer_state | (1UL<<layer));
+}
+
+void layer_off(uint8_t layer)
+{
+ layer_state_set(layer_state & ~(1UL<<layer));
+}
+
+void layer_invert(uint8_t layer)
+{
+ layer_state_set(layer_state ^ (1UL<<layer));
+}
+
+void layer_or(uint32_t state)
+{
+ layer_state_set(layer_state | state);
+}
+void layer_and(uint32_t state)
+{
+ layer_state_set(layer_state & state);
+}
+void layer_xor(uint32_t state)
+{
+ layer_state_set(layer_state ^ state);
+}
+
+void layer_debug(void)
+{
+ dprintf("%08lX(%u)", layer_state, biton32(layer_state));
+}
+#endif
+
+#if !defined(NO_ACTION_LAYER) && defined(PREVENT_STUCK_MODIFIERS)
+uint8_t source_layers_cache[(MATRIX_ROWS * MATRIX_COLS + 7) / 8][MAX_LAYER_BITS] = {0};
+
+void update_source_layers_cache(keypos_t key, uint8_t layer)
+{
+ const uint8_t key_number = key.col + (key.row * MATRIX_COLS);
+ const uint8_t storage_row = key_number / 8;
+ const uint8_t storage_bit = key_number % 8;
+
+ for (uint8_t bit_number = 0; bit_number < MAX_LAYER_BITS; bit_number++) {
+ source_layers_cache[storage_row][bit_number] ^=
+ (-((layer & (1U << bit_number)) != 0)
+ ^ source_layers_cache[storage_row][bit_number])
+ & (1U << storage_bit);
+ }
+}
+
+uint8_t read_source_layers_cache(keypos_t key)
+{
+ const uint8_t key_number = key.col + (key.row * MATRIX_COLS);
+ const uint8_t storage_row = key_number / 8;
+ const uint8_t storage_bit = key_number % 8;
+ uint8_t layer = 0;
+
+ for (uint8_t bit_number = 0; bit_number < MAX_LAYER_BITS; bit_number++) {
+ layer |=
+ ((source_layers_cache[storage_row][bit_number]
+ & (1U << storage_bit)) != 0)
+ << bit_number;
+ }
+
+ return layer;
+}
+#endif
+
+/*
+ * Make sure the action triggered when the key is released is the same
+ * one as the one triggered on press. It's important for the mod keys
+ * when the layer is switched after the down event but before the up
+ * event as they may get stuck otherwise.
+ */
+action_t store_or_get_action(bool pressed, keypos_t key)
+{
+#if !defined(NO_ACTION_LAYER) && defined(PREVENT_STUCK_MODIFIERS)
+ if (disable_action_cache) {
+ return layer_switch_get_action(key);
+ }
+
+ uint8_t layer;
+
+ if (pressed) {
+ layer = layer_switch_get_layer(key);
+ update_source_layers_cache(key, layer);
+ }
+ else {
+ layer = read_source_layers_cache(key);
+ }
+ return action_for_key(layer, key);
+#else
+ return layer_switch_get_action(key);
+#endif
+}
+
+
+int8_t layer_switch_get_layer(keypos_t key)
+{
+ action_t action;
+ action.code = ACTION_TRANSPARENT;
+
+#ifndef NO_ACTION_LAYER
+ uint32_t layers = layer_state | default_layer_state;
+ /* check top layer first */
+ for (int8_t i = 31; i >= 0; i--) {
+ if (layers & (1UL<<i)) {
+ action = action_for_key(i, key);
+ if (action.code != ACTION_TRANSPARENT) {
+ return i;
+ }
+ }
+ }
+ /* fall back to layer 0 */
+ return 0;
+#else
+ return biton32(default_layer_state);
+#endif
+}
+
+action_t layer_switch_get_action(keypos_t key)
+{
+ return action_for_key(layer_switch_get_layer(key), key);
+}
diff --git a/tmk_core/common/action_layer.h b/tmk_core/common/action_layer.h
new file mode 100644
index 000000000..025cf5420
--- /dev/null
+++ b/tmk_core/common/action_layer.h
@@ -0,0 +1,89 @@
+/*
+Copyright 2013 Jun Wako <wakojun@gmail.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef ACTION_LAYER_H
+#define ACTION_LAYER_H
+
+#include <stdint.h>
+#include "keyboard.h"
+#include "action.h"
+
+
+/*
+ * Default Layer
+ */
+extern uint32_t default_layer_state;
+void default_layer_debug(void);
+void default_layer_set(uint32_t state);
+
+#ifndef NO_ACTION_LAYER
+/* bitwise operation */
+void default_layer_or(uint32_t state);
+void default_layer_and(uint32_t state);
+void default_layer_xor(uint32_t state);
+#else
+#define default_layer_or(state)
+#define default_layer_and(state)
+#define default_layer_xor(state)
+#endif
+
+
+/*
+ * Keymap Layer
+ */
+#ifndef NO_ACTION_LAYER
+extern uint32_t layer_state;
+void layer_debug(void);
+void layer_clear(void);
+void layer_move(uint8_t layer);
+void layer_on(uint8_t layer);
+void layer_off(uint8_t layer);
+void layer_invert(uint8_t layer);
+/* bitwise operation */
+void layer_or(uint32_t state);
+void layer_and(uint32_t state);
+void layer_xor(uint32_t state);
+#else
+#define layer_state 0
+#define layer_clear()
+#define layer_move(layer)
+#define layer_on(layer)
+#define layer_off(layer)
+#define layer_invert(layer)
+
+#define layer_or(state)
+#define layer_and(state)
+#define layer_xor(state)
+#define layer_debug()
+
+#endif
+
+/* pressed actions cache */
+#if !defined(NO_ACTION_LAYER) && defined(PREVENT_STUCK_MODIFIERS)
+/* The number of bits needed to represent the layer number: log2(32). */
+#define MAX_LAYER_BITS 5
+void update_source_layers_cache(keypos_t key, uint8_t layer);
+uint8_t read_source_layers_cache(keypos_t key);
+#endif
+action_t store_or_get_action(bool pressed, keypos_t key);
+
+/* return the topmost non-transparent layer currently associated with key */
+int8_t layer_switch_get_layer(keypos_t key);
+
+/* return action depending on current layer status */
+action_t layer_switch_get_action(keypos_t key);
+
+#endif
diff --git a/tmk_core/common/action_macro.c b/tmk_core/common/action_macro.c
new file mode 100644
index 000000000..7726b1190
--- /dev/null
+++ b/tmk_core/common/action_macro.c
@@ -0,0 +1,85 @@
+/*
+Copyright 2013 Jun Wako <wakojun@gmail.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "action.h"
+#include "action_util.h"
+#include "action_macro.h"
+#include "wait.h"
+
+#ifdef DEBUG_ACTION
+#include "debug.h"
+#else
+#include "nodebug.h"
+#endif
+
+
+#ifndef NO_ACTION_MACRO
+
+#define MACRO_READ() (macro = MACRO_GET(macro_p++))
+void action_macro_play(const macro_t *macro_p)
+{
+ macro_t macro = END;
+ uint8_t interval = 0;
+
+ if (!macro_p) return;
+ while (true) {
+ switch (MACRO_READ()) {
+ case KEY_DOWN:
+ MACRO_READ();
+ dprintf("KEY_DOWN(%02X)\n", macro);
+ if (IS_MOD(macro)) {
+ add_macro_mods(MOD_BIT(macro));
+ send_keyboard_report();
+ } else {
+ register_code(macro);
+ }
+ break;
+ case KEY_UP:
+ MACRO_READ();
+ dprintf("KEY_UP(%02X)\n", macro);
+ if (IS_MOD(macro)) {
+ del_macro_mods(MOD_BIT(macro));
+ send_keyboard_report();
+ } else {
+ unregister_code(macro);
+ }
+ break;
+ case WAIT:
+ MACRO_READ();
+ dprintf("WAIT(%u)\n", macro);
+ { uint8_t ms = macro; while (ms--) wait_ms(1); }
+ break;
+ case INTERVAL:
+ interval = MACRO_READ();
+ dprintf("INTERVAL(%u)\n", interval);
+ break;
+ case 0x04 ... 0x73:
+ dprintf("DOWN(%02X)\n", macro);
+ register_code(macro);
+ break;
+ case 0x84 ... 0xF3:
+ dprintf("UP(%02X)\n", macro);
+ unregister_code(macro&0x7F);
+ break;
+ case END:
+ default:
+ return;
+ }
+ // interval
+ { uint8_t ms = interval; while (ms--) wait_ms(1); }
+ }
+}
+#endif
diff --git a/tmk_core/common/action_macro.h b/tmk_core/common/action_macro.h
new file mode 100644
index 000000000..aedc32ec6
--- /dev/null
+++ b/tmk_core/common/action_macro.h
@@ -0,0 +1,102 @@
+/*
+Copyright 2013 Jun Wako <wakojun@gmail.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef ACTION_MACRO_H
+#define ACTION_MACRO_H
+#include <stdint.h>
+#include "progmem.h"
+
+
+#define MACRO_NONE 0
+#define MACRO(...) ({ static const macro_t __m[] PROGMEM = { __VA_ARGS__ }; &__m[0]; })
+#define MACRO_GET(p) pgm_read_byte(p)
+
+typedef uint8_t macro_t;
+
+
+#ifndef NO_ACTION_MACRO
+void action_macro_play(const macro_t *macro_p);
+#else
+#define action_macro_play(macro)
+#endif
+
+
+
+/* Macro commands
+ * code(0x04-73) // key down(1byte)
+ * code(0x04-73) | 0x80 // key up(1byte)
+ * { KEY_DOWN, code(0x04-0xff) } // key down(2bytes)
+ * { KEY_UP, code(0x04-0xff) } // key up(2bytes)
+ * WAIT // wait milli-seconds
+ * INTERVAL // set interval between macro commands
+ * END // stop macro execution
+ *
+ * Ideas(Not implemented):
+ * modifiers
+ * system usage
+ * consumer usage
+ * unicode usage
+ * function call
+ * conditionals
+ * loop
+ */
+enum macro_command_id{
+ /* 0x00 - 0x03 */
+ END = 0x00,
+ KEY_DOWN,
+ KEY_UP,
+
+ /* 0x04 - 0x73 (reserved for keycode down) */
+
+ /* 0x74 - 0x83 */
+ WAIT = 0x74,
+ INTERVAL,
+
+ /* 0x84 - 0xf3 (reserved for keycode up) */
+
+ /* 0xf4 - 0xff */
+};
+
+
+/* TODO: keycode:0x04-0x73 can be handled by 1byte command else 2bytes are needed
+ * if keycode between 0x04 and 0x73
+ * keycode / (keycode|0x80)
+ * else
+ * {KEY_DOWN, keycode} / {KEY_UP, keycode}
+*/
+#define DOWN(key) KEY_DOWN, (key)
+#define UP(key) KEY_UP, (key)
+#define TYPE(key) DOWN(key), UP(key)
+#define WAIT(ms) WAIT, (ms)
+#define INTERVAL(ms) INTERVAL, (ms)
+
+/* key down */
+#define D(key) DOWN(KC_##key)
+/* key up */
+#define U(key) UP(KC_##key)
+/* key type */
+#define T(key) TYPE(KC_##key)
+/* wait */
+#define W(ms) WAIT(ms)
+/* interval */
+#define I(ms) INTERVAL(ms)
+
+/* for backward comaptibility */
+#define MD(key) DOWN(KC_##key)
+#define MU(key) UP(KC_##key)
+
+
+#endif /* ACTION_MACRO_H */
diff --git a/tmk_core/common/action_tapping.c b/tmk_core/common/action_tapping.c
new file mode 100644
index 000000000..e16e11be7
--- /dev/null
+++ b/tmk_core/common/action_tapping.c
@@ -0,0 +1,377 @@
+#include <stdint.h>
+#include <stdbool.h>
+#include "action.h"
+#include "action_layer.h"
+#include "action_tapping.h"
+#include "keycode.h"
+#include "timer.h"
+
+#ifdef DEBUG_ACTION
+#include "debug.h"
+#else
+#include "nodebug.h"
+#endif
+
+#ifndef NO_ACTION_TAPPING
+
+#define IS_TAPPING() !IS_NOEVENT(tapping_key.event)
+#define IS_TAPPING_PRESSED() (IS_TAPPING() && tapping_key.event.pressed)
+#define IS_TAPPING_RELEASED() (IS_TAPPING() && !tapping_key.event.pressed)
+#define IS_TAPPING_KEY(k) (IS_TAPPING() && KEYEQ(tapping_key.event.key, (k)))
+#define WITHIN_TAPPING_TERM(e) (TIMER_DIFF_16(e.time, tapping_key.event.time) < TAPPING_TERM)
+
+
+static keyrecord_t tapping_key = {};
+static keyrecord_t waiting_buffer[WAITING_BUFFER_SIZE] = {};
+static uint8_t waiting_buffer_head = 0;
+static uint8_t waiting_buffer_tail = 0;
+
+static bool process_tapping(keyrecord_t *record);
+static bool waiting_buffer_enq(keyrecord_t record);
+static void waiting_buffer_clear(void);
+static bool waiting_buffer_typed(keyevent_t event);
+static bool waiting_buffer_has_anykey_pressed(void);
+static void waiting_buffer_scan_tap(void);
+static void debug_tapping_key(void);
+static void debug_waiting_buffer(void);
+
+
+void action_tapping_process(keyrecord_t record)
+{
+ if (process_tapping(&record)) {
+ if (!IS_NOEVENT(record.event)) {
+ debug("processed: "); debug_record(record); debug("\n");
+ }
+ } else {
+ if (!waiting_buffer_enq(record)) {
+ // clear all in case of overflow.
+ debug("OVERFLOW: CLEAR ALL STATES\n");
+ clear_keyboard();
+ waiting_buffer_clear();
+ tapping_key = (keyrecord_t){};
+ }
+ }
+
+ // process waiting_buffer
+ if (!IS_NOEVENT(record.event) && waiting_buffer_head != waiting_buffer_tail) {
+ debug("---- action_exec: process waiting_buffer -----\n");
+ }
+ for (; waiting_buffer_tail != waiting_buffer_head; waiting_buffer_tail = (waiting_buffer_tail + 1) % WAITING_BUFFER_SIZE) {
+ if (process_tapping(&waiting_buffer[waiting_buffer_tail])) {
+ debug("processed: waiting_buffer["); debug_dec(waiting_buffer_tail); debug("] = ");
+ debug_record(waiting_buffer[waiting_buffer_tail]); debug("\n\n");
+ } else {
+ break;
+ }
+ }
+ if (!IS_NOEVENT(record.event)) {
+ debug("\n");
+ }
+}
+
+
+/* Tapping
+ *
+ * Rule: Tap key is typed(pressed and released) within TAPPING_TERM.
+ * (without interfering by typing other key)
+ */
+/* return true when key event is processed or consumed. */
+bool process_tapping(keyrecord_t *keyp)
+{
+ keyevent_t event = keyp->event;
+
+ // if tapping
+ if (IS_TAPPING_PRESSED()) {
+ if (WITHIN_TAPPING_TERM(event)) {
+ if (tapping_key.tap.count == 0) {
+ if (IS_TAPPING_KEY(event.key) && !event.pressed) {
+ // first tap!
+ debug("Tapping: First tap(0->1).\n");
+ tapping_key.tap.count = 1;
+ debug_tapping_key();
+ process_record(&tapping_key);
+
+ // copy tapping state
+ keyp->tap = tapping_key.tap;
+ // enqueue
+ return false;
+ }
+#if TAPPING_TERM >= 500
+ /* Process a key typed within TAPPING_TERM
+ * This can register the key before settlement of tapping,
+ * useful for long TAPPING_TERM but may prevent fast typing.
+ */
+ else if (IS_RELEASED(event) && waiting_buffer_typed(event)) {
+ debug("Tapping: End. No tap. Interfered by typing key\n");
+ process_record(&tapping_key);
+ tapping_key = (keyrecord_t){};
+ debug_tapping_key();
+ // enqueue
+ return false;
+ }
+#endif
+ /* Process release event of a key pressed before tapping starts
+ * Without this unexpected repeating will occur with having fast repeating setting
+ * https://github.com/tmk/tmk_keyboard/issues/60
+ */
+ else if (IS_RELEASED(event) && !waiting_buffer_typed(event)) {
+ // Modifier should be retained till end of this tapping.
+ action_t action = layer_switch_get_action(event.key);
+ switch (action.kind.id) {
+ case ACT_LMODS:
+ case ACT_RMODS:
+ if (action.key.mods && !action.key.code) return false;
+ if (IS_MOD(action.key.code)) return false;
+ break;
+ case ACT_LMODS_TAP:
+ case ACT_RMODS_TAP:
+ if (action.key.mods && keyp->tap.count == 0) return false;
+ if (IS_MOD(action.key.code)) return false;
+ break;
+ }
+ // Release of key should be process immediately.
+ debug("Tapping: release event of a key pressed before tapping\n");
+ process_record(keyp);
+ return true;
+ }
+ else {
+ // set interrupted flag when other key preesed during tapping
+ if (event.pressed) {
+ tapping_key.tap.interrupted = true;
+ }
+ // enqueue
+ return false;
+ }
+ }
+ // tap_count > 0
+ else {
+ if (IS_TAPPING_KEY(event.key) && !event.pressed) {
+ debug("Tapping: Tap release("); debug_dec(tapping_key.tap.count); debug(")\n");
+ keyp->tap = tapping_key.tap;
+ process_record(keyp);
+ tapping_key = *keyp;
+ debug_tapping_key();
+ return true;
+ }
+ else if (is_tap_key(event.key) && event.pressed) {
+ if (tapping_key.tap.count > 1) {
+ debug("Tapping: Start new tap with releasing last tap(>1).\n");
+ // unregister key
+ process_record(&(keyrecord_t){
+ .tap = tapping_key.tap,
+ .event.key = tapping_key.event.key,
+ .event.time = event.time,
+ .event.pressed = false
+ });
+ } else {
+ debug("Tapping: Start while last tap(1).\n");
+ }
+ tapping_key = *keyp;
+ waiting_buffer_scan_tap();
+ debug_tapping_key();
+ return true;
+ }
+ else {
+ if (!IS_NOEVENT(event)) {
+ debug("Tapping: key event while last tap(>0).\n");
+ }
+ process_record(keyp);
+ return true;
+ }
+ }
+ }
+ // after TAPPING_TERM
+ else {
+ if (tapping_key.tap.count == 0) {
+ debug("Tapping: End. Timeout. Not tap(0): ");
+ debug_event(event); debug("\n");
+ process_record(&tapping_key);
+ tapping_key = (keyrecord_t){};
+ debug_tapping_key();
+ return false;
+ } else {
+ if (IS_TAPPING_KEY(event.key) && !event.pressed) {
+ debug("Tapping: End. last timeout tap release(>0).");
+ keyp->tap = tapping_key.tap;
+ process_record(keyp);
+ tapping_key = (keyrecord_t){};
+ return true;
+ }
+ else if (is_tap_key(event.key) && event.pressed) {
+ if (tapping_key.tap.count > 1) {
+ debug("Tapping: Start new tap with releasing last timeout tap(>1).\n");
+ // unregister key
+ process_record(&(keyrecord_t){
+ .tap = tapping_key.tap,
+ .event.key = tapping_key.event.key,
+ .event.time = event.time,
+ .event.pressed = false
+ });
+ } else {
+ debug("Tapping: Start while last timeout tap(1).\n");
+ }
+ tapping_key = *keyp;
+ waiting_buffer_scan_tap();
+ debug_tapping_key();
+ return true;
+ }
+ else {
+ if (!IS_NOEVENT(event)) {
+ debug("Tapping: key event while last timeout tap(>0).\n");
+ }
+ process_record(keyp);
+ return true;
+ }
+ }
+ }
+ } else if (IS_TAPPING_RELEASED()) {
+ if (WITHIN_TAPPING_TERM(event)) {
+ if (event.pressed) {
+ if (IS_TAPPING_KEY(event.key)) {
+ if (!tapping_key.tap.interrupted && tapping_key.tap.count > 0) {
+ // sequential tap.
+ keyp->tap = tapping_key.tap;
+ if (keyp->tap.count < 15) keyp->tap.count += 1;
+ debug("Tapping: Tap press("); debug_dec(keyp->tap.count); debug(")\n");
+ process_record(keyp);
+ tapping_key = *keyp;
+ debug_tapping_key();
+ return true;
+ } else {
+ // FIX: start new tap again
+ tapping_key = *keyp;
+ return true;
+ }
+ } else if (is_tap_key(event.key)) {
+ // Sequential tap can be interfered with other tap key.
+ debug("Tapping: Start with interfering other tap.\n");
+ tapping_key = *keyp;
+ waiting_buffer_scan_tap();
+ debug_tapping_key();
+ return true;
+ } else {
+ // should none in buffer
+ // FIX: interrupted when other key is pressed
+ tapping_key.tap.interrupted = true;
+ process_record(keyp);
+ return true;
+ }
+ } else {
+ if (!IS_NOEVENT(event)) debug("Tapping: other key just after tap.\n") {};
+ process_record(keyp);
+ return true;
+ }
+ } else {
+ // FIX: process_aciton here?
+ // timeout. no sequential tap.
+ debug("Tapping: End(Timeout after releasing last tap): ");
+ debug_event(event); debug("\n");
+ tapping_key = (keyrecord_t){};
+ debug_tapping_key();
+ return false;
+ }
+ }
+ // not tapping state
+ else {
+ if (event.pressed && is_tap_key(event.key)) {
+ debug("Tapping: Start(Press tap key).\n");
+ tapping_key = *keyp;
+ waiting_buffer_scan_tap();
+ debug_tapping_key();
+ return true;
+ } else {
+ process_record(keyp);
+ return true;
+ }
+ }
+}
+
+
+/*
+ * Waiting buffer
+ */
+bool waiting_buffer_enq(keyrecord_t record)
+{
+ if (IS_NOEVENT(record.event)) {
+ return true;
+ }
+
+ if ((waiting_buffer_head + 1) % WAITING_BUFFER_SIZE == waiting_buffer_tail) {
+ debug("waiting_buffer_enq: Over flow.\n");
+ return false;
+ }
+
+ waiting_buffer[waiting_buffer_head] = record;
+ waiting_buffer_head = (waiting_buffer_head + 1) % WAITING_BUFFER_SIZE;
+
+ debug("waiting_buffer_enq: "); debug_waiting_buffer();
+ return true;
+}
+
+void waiting_buffer_clear(void)
+{
+ waiting_buffer_head = 0;
+ waiting_buffer_tail = 0;
+}
+
+bool waiting_buffer_typed(keyevent_t event)
+{
+ for (uint8_t i = waiting_buffer_tail; i != waiting_buffer_head; i = (i + 1) % WAITING_BUFFER_SIZE) {
+ if (KEYEQ(event.key, waiting_buffer[i].event.key) && event.pressed != waiting_buffer[i].event.pressed) {
+ return true;
+ }
+ }
+ return false;
+}
+
+__attribute__((unused))
+bool waiting_buffer_has_anykey_pressed(void)
+{
+ for (uint8_t i = waiting_buffer_tail; i != waiting_buffer_head; i = (i + 1) % WAITING_BUFFER_SIZE) {
+ if (waiting_buffer[i].event.pressed) return true;
+ }
+ return false;
+}
+
+/* scan buffer for tapping */
+void waiting_buffer_scan_tap(void)
+{
+ // tapping already is settled
+ if (tapping_key.tap.count > 0) return;
+ // invalid state: tapping_key released && tap.count == 0
+ if (!tapping_key.event.pressed) return;
+
+ for (uint8_t i = waiting_buffer_tail; i != waiting_buffer_head; i = (i + 1) % WAITING_BUFFER_SIZE) {
+ if (IS_TAPPING_KEY(waiting_buffer[i].event.key) &&
+ !waiting_buffer[i].event.pressed &&
+ WITHIN_TAPPING_TERM(waiting_buffer[i].event)) {
+ tapping_key.tap.count = 1;
+ waiting_buffer[i].tap.count = 1;
+ process_record(&tapping_key);
+
+ debug("waiting_buffer_scan_tap: found at ["); debug_dec(i); debug("]\n");
+ debug_waiting_buffer();
+ return;
+ }
+ }
+}
+
+
+/*
+ * debug print
+ */
+static void debug_tapping_key(void)
+{
+ debug("TAPPING_KEY="); debug_record(tapping_key); debug("\n");
+}
+
+static void debug_waiting_buffer(void)
+{
+ debug("{ ");
+ for (uint8_t i = waiting_buffer_tail; i != waiting_buffer_head; i = (i + 1) % WAITING_BUFFER_SIZE) {
+ debug("["); debug_dec(i); debug("]="); debug_record(waiting_buffer[i]); debug(" ");
+ }
+ debug("}\n");
+}
+
+#endif
diff --git a/tmk_core/common/action_tapping.h b/tmk_core/common/action_tapping.h
new file mode 100644
index 000000000..9b42d50dc
--- /dev/null
+++ b/tmk_core/common/action_tapping.h
@@ -0,0 +1,39 @@
+/*
+Copyright 2013 Jun Wako <wakojun@gmail.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef ACTION_TAPPING_H
+#define ACTION_TAPPING_H
+
+
+
+/* period of tapping(ms) */
+#ifndef TAPPING_TERM
+#define TAPPING_TERM 200
+#endif
+
+/* tap count needed for toggling a feature */
+#ifndef TAPPING_TOGGLE
+#define TAPPING_TOGGLE 5
+#endif
+
+#define WAITING_BUFFER_SIZE 8
+
+
+#ifndef NO_ACTION_TAPPING
+void action_tapping_process(keyrecord_t record);
+#endif
+
+#endif
diff --git a/tmk_core/common/action_util.c b/tmk_core/common/action_util.c
new file mode 100644
index 000000000..61ff202be
--- /dev/null
+++ b/tmk_core/common/action_util.c
@@ -0,0 +1,378 @@
+/*
+Copyright 2013 Jun Wako <wakojun@gmail.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "host.h"
+#include "report.h"
+#include "debug.h"
+#include "action_util.h"
+#include "action_layer.h"
+#include "timer.h"
+
+static inline void add_key_byte(uint8_t code);
+static inline void del_key_byte(uint8_t code);
+#ifdef NKRO_ENABLE
+static inline void add_key_bit(uint8_t code);
+static inline void del_key_bit(uint8_t code);
+#endif
+
+static uint8_t real_mods = 0;
+static uint8_t weak_mods = 0;
+static uint8_t macro_mods = 0;
+
+#ifdef USB_6KRO_ENABLE
+#define RO_ADD(a, b) ((a + b) % KEYBOARD_REPORT_KEYS)
+#define RO_SUB(a, b) ((a - b + KEYBOARD_REPORT_KEYS) % KEYBOARD_REPORT_KEYS)
+#define RO_INC(a) RO_ADD(a, 1)
+#define RO_DEC(a) RO_SUB(a, 1)
+static int8_t cb_head = 0;
+static int8_t cb_tail = 0;
+static int8_t cb_count = 0;
+#endif
+
+// TODO: pointer variable is not needed
+//report_keyboard_t keyboard_report = {};
+report_keyboard_t *keyboard_report = &(report_keyboard_t){};
+
+#ifndef NO_ACTION_ONESHOT
+static int8_t oneshot_mods = 0;
+static int8_t oneshot_locked_mods = 0;
+int8_t get_oneshot_locked_mods(void) { return oneshot_locked_mods; }
+void set_oneshot_locked_mods(int8_t mods) { oneshot_locked_mods = mods; }
+void clear_oneshot_locked_mods(void) { oneshot_locked_mods = 0; }
+#if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0))
+static int16_t oneshot_time = 0;
+inline bool has_oneshot_mods_timed_out() {
+ return TIMER_DIFF_16(timer_read(), oneshot_time) >= ONESHOT_TIMEOUT;
+}
+#endif
+#endif
+
+/* oneshot layer */
+#ifndef NO_ACTION_ONESHOT
+/* oneshot_layer_data bits
+* LLLL LSSS
+* where:
+* L => are layer bits
+* S => oneshot state bits
+*/
+static int8_t oneshot_layer_data = 0;
+
+inline uint8_t get_oneshot_layer(void) { return oneshot_layer_data >> 3; }
+inline uint8_t get_oneshot_layer_state(void) { return oneshot_layer_data & 0b111; }
+
+#if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0))
+static int16_t oneshot_layer_time = 0;
+inline bool has_oneshot_layer_timed_out() {
+ return TIMER_DIFF_16(timer_read(), oneshot_layer_time) >= ONESHOT_TIMEOUT &&
+ !(get_oneshot_layer_state() & ONESHOT_TOGGLED);
+}
+#endif
+
+/* Oneshot layer */
+void set_oneshot_layer(uint8_t layer, uint8_t state)
+{
+ oneshot_layer_data = layer << 3 | state;
+ layer_on(layer);
+#if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0))
+ oneshot_layer_time = timer_read();
+#endif
+}
+void reset_oneshot_layer(void) {
+ oneshot_layer_data = 0;
+#if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0))
+ oneshot_layer_time = 0;
+#endif
+}
+void clear_oneshot_layer_state(oneshot_fullfillment_t state)
+{
+ uint8_t start_state = oneshot_layer_data;
+ oneshot_layer_data &= ~state;
+ if (!get_oneshot_layer_state() && start_state != oneshot_layer_data) {
+ layer_off(get_oneshot_layer());
+#if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0))
+ oneshot_layer_time = 0;
+#endif
+ }
+}
+bool is_oneshot_layer_active(void)
+{
+ return get_oneshot_layer_state();
+}
+#endif
+
+void send_keyboard_report(void) {
+ keyboard_report->mods = real_mods;
+ keyboard_report->mods |= weak_mods;
+ keyboard_report->mods |= macro_mods;
+#ifndef NO_ACTION_ONESHOT
+ if (oneshot_mods) {
+#if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0))
+ if (has_oneshot_mods_timed_out()) {
+ dprintf("Oneshot: timeout\n");
+ clear_oneshot_mods();
+ }
+#endif
+ keyboard_report->mods |= oneshot_mods;
+ if (has_anykey()) {
+ clear_oneshot_mods();
+ }
+ }
+
+#endif
+ host_keyboard_send(keyboard_report);
+}
+
+/* key */
+void add_key(uint8_t key)
+{
+#ifdef NKRO_ENABLE
+ if (keyboard_protocol && keyboard_nkro) {
+ add_key_bit(key);
+ return;
+ }
+#endif
+ add_key_byte(key);
+}
+
+void del_key(uint8_t key)
+{
+#ifdef NKRO_ENABLE
+ if (keyboard_protocol && keyboard_nkro) {
+ del_key_bit(key);
+ return;
+ }
+#endif
+ del_key_byte(key);
+}
+
+void clear_keys(void)
+{
+ // not clear mods
+ for (int8_t i = 1; i < KEYBOARD_REPORT_SIZE; i++) {
+ keyboard_report->raw[i] = 0;
+ }
+}
+
+
+/* modifier */
+uint8_t get_mods(void) { return real_mods; }
+void add_mods(uint8_t mods) { real_mods |= mods; }
+void del_mods(uint8_t mods) { real_mods &= ~mods; }
+void set_mods(uint8_t mods) { real_mods = mods; }
+void clear_mods(void) { real_mods = 0; }
+
+/* weak modifier */
+uint8_t get_weak_mods(void) { return weak_mods; }
+void add_weak_mods(uint8_t mods) { weak_mods |= mods; }
+void del_weak_mods(uint8_t mods) { weak_mods &= ~mods; }
+void set_weak_mods(uint8_t mods) { weak_mods = mods; }
+void clear_weak_mods(void) { weak_mods = 0; }
+
+/* macro modifier */
+uint8_t get_macro_mods(void) { return macro_mods; }
+void add_macro_mods(uint8_t mods) { macro_mods |= mods; }
+void del_macro_mods(uint8_t mods) { macro_mods &= ~mods; }
+void set_macro_mods(uint8_t mods) { macro_mods = mods; }
+void clear_macro_mods(void) { macro_mods = 0; }
+
+/* Oneshot modifier */
+#ifndef NO_ACTION_ONESHOT
+void set_oneshot_mods(uint8_t mods)
+{
+ oneshot_mods = mods;
+#if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0))
+ oneshot_time = timer_read();
+#endif
+}
+void clear_oneshot_mods(void)
+{
+ oneshot_mods = 0;
+#if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0))
+ oneshot_time = 0;
+#endif
+}
+uint8_t get_oneshot_mods(void)
+{
+ return oneshot_mods;
+}
+#endif
+
+/*
+ * inspect keyboard state
+ */
+uint8_t has_anykey(void)
+{
+ uint8_t cnt = 0;
+ for (uint8_t i = 1; i < KEYBOARD_REPORT_SIZE; i++) {
+ if (keyboard_report->raw[i])
+ cnt++;
+ }
+ return cnt;
+}
+
+uint8_t has_anymod(void)
+{
+ return bitpop(real_mods);
+}
+
+uint8_t get_first_key(void)
+{
+#ifdef NKRO_ENABLE
+ if (keyboard_protocol && keyboard_nkro) {
+ uint8_t i = 0;
+ for (; i < KEYBOARD_REPORT_BITS && !keyboard_report->nkro.bits[i]; i++)
+ ;
+ return i<<3 | biton(keyboard_report->nkro.bits[i]);
+ }
+#endif
+#ifdef USB_6KRO_ENABLE
+ uint8_t i = cb_head;
+ do {
+ if (keyboard_report->keys[i] != 0) {
+ break;
+ }
+ i = RO_INC(i);
+ } while (i != cb_tail);
+ return keyboard_report->keys[i];
+#else
+ return keyboard_report->keys[0];
+#endif
+}
+
+
+
+/* local functions */
+static inline void add_key_byte(uint8_t code)
+{
+#ifdef USB_6KRO_ENABLE
+ int8_t i = cb_head;
+ int8_t empty = -1;
+ if (cb_count) {
+ do {
+ if (keyboard_report->keys[i] == code) {
+ return;
+ }
+ if (empty == -1 && keyboard_report->keys[i] == 0) {
+ empty = i;
+ }
+ i = RO_INC(i);
+ } while (i != cb_tail);
+ if (i == cb_tail) {
+ if (cb_tail == cb_head) {
+ // buffer is full
+ if (empty == -1) {
+ // pop head when has no empty space
+ cb_head = RO_INC(cb_head);
+ cb_count--;
+ }
+ else {
+ // left shift when has empty space
+ uint8_t offset = 1;
+ i = RO_INC(empty);
+ do {
+ if (keyboard_report->keys[i] != 0) {
+ keyboard_report->keys[empty] = keyboard_report->keys[i];
+ keyboard_report->keys[i] = 0;
+ empty = RO_INC(empty);
+ }
+ else {
+ offset++;
+ }
+ i = RO_INC(i);
+ } while (i != cb_tail);
+ cb_tail = RO_SUB(cb_tail, offset);
+ }
+ }
+ }
+ }
+ // add to tail
+ keyboard_report->keys[cb_tail] = code;
+ cb_tail = RO_INC(cb_tail);
+ cb_count++;
+#else
+ int8_t i = 0;
+ int8_t empty = -1;
+ for (; i < KEYBOARD_REPORT_KEYS; i++) {
+ if (keyboard_report->keys[i] == code) {
+ break;
+ }
+ if (empty == -1 && keyboard_report->keys[i] == 0) {
+ empty = i;
+ }
+ }
+ if (i == KEYBOARD_REPORT_KEYS) {
+ if (empty != -1) {
+ keyboard_report->keys[empty] = code;
+ }
+ }
+#endif
+}
+
+static inline void del_key_byte(uint8_t code)
+{
+#ifdef USB_6KRO_ENABLE
+ uint8_t i = cb_head;
+ if (cb_count) {
+ do {
+ if (keyboard_report->keys[i] == code) {
+ keyboard_report->keys[i] = 0;
+ cb_count--;
+ if (cb_count == 0) {
+ // reset head and tail
+ cb_tail = cb_head = 0;
+ }
+ if (i == RO_DEC(cb_tail)) {
+ // left shift when next to tail
+ do {
+ cb_tail = RO_DEC(cb_tail);
+ if (keyboard_report->keys[RO_DEC(cb_tail)] != 0) {
+ break;
+ }
+ } while (cb_tail != cb_head);
+ }
+ break;
+ }
+ i = RO_INC(i);
+ } while (i != cb_tail);
+ }
+#else
+ for (uint8_t i = 0; i < KEYBOARD_REPORT_KEYS; i++) {
+ if (keyboard_report->keys[i] == code) {
+ keyboard_report->keys[i] = 0;
+ }
+ }
+#endif
+}
+
+#ifdef NKRO_ENABLE
+static inline void add_key_bit(uint8_t code)
+{
+ if ((code>>3) < KEYBOARD_REPORT_BITS) {
+ keyboard_report->nkro.bits[code>>3] |= 1<<(code&7);
+ } else {
+ dprintf("add_key_bit: can't add: %02X\n", code);
+ }
+}
+
+static inline void del_key_bit(uint8_t code)
+{
+ if ((code>>3) < KEYBOARD_REPORT_BITS) {
+ keyboard_report->nkro.bits[code>>3] &= ~(1<<(code&7));
+ } else {
+ dprintf("del_key_bit: can't del: %02X\n", code);
+ }
+}
+#endif
diff --git a/tmk_core/common/action_util.h b/tmk_core/common/action_util.h
new file mode 100644
index 000000000..dd0c4c2bf
--- /dev/null
+++ b/tmk_core/common/action_util.h
@@ -0,0 +1,93 @@
+/*
+Copyright 2013 Jun Wako <wakojun@gmail.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef ACTION_UTIL_H
+#define ACTION_UTIL_H
+
+#include <stdint.h>
+#include "report.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern report_keyboard_t *keyboard_report;
+
+void send_keyboard_report(void);
+
+/* key */
+void add_key(uint8_t key);
+void del_key(uint8_t key);
+void clear_keys(void);
+
+/* modifier */
+uint8_t get_mods(void);
+void add_mods(uint8_t mods);
+void del_mods(uint8_t mods);
+void set_mods(uint8_t mods);
+void clear_mods(void);
+
+/* weak modifier */
+uint8_t get_weak_mods(void);
+void add_weak_mods(uint8_t mods);
+void del_weak_mods(uint8_t mods);
+void set_weak_mods(uint8_t mods);
+void clear_weak_mods(void);
+
+/* macro modifier */
+uint8_t get_macro_mods(void);
+void add_macro_mods(uint8_t mods);
+void del_macro_mods(uint8_t mods);
+void set_macro_mods(uint8_t mods);
+void clear_macro_mods(void);
+
+/* oneshot modifier */
+void set_oneshot_mods(uint8_t mods);
+uint8_t get_oneshot_mods(void);
+void clear_oneshot_mods(void);
+void oneshot_toggle(void);
+void oneshot_enable(void);
+void oneshot_disable(void);
+bool has_oneshot_mods_timed_out(void);
+
+int8_t get_oneshot_locked_mods(void);
+void set_oneshot_locked_mods(int8_t mods);
+void clear_oneshot_locked_mods(void);
+
+typedef enum {
+ ONESHOT_PRESSED = 0b01,
+ ONESHOT_OTHER_KEY_PRESSED = 0b10,
+ ONESHOT_START = 0b11,
+ ONESHOT_TOGGLED = 0b100
+} oneshot_fullfillment_t;
+void set_oneshot_layer(uint8_t layer, uint8_t state);
+uint8_t get_oneshot_layer(void);
+void clear_oneshot_layer_state(oneshot_fullfillment_t state);
+void reset_oneshot_layer(void);
+bool is_oneshot_layer_active(void);
+uint8_t get_oneshot_layer_state(void);
+bool has_oneshot_layer_timed_out(void);
+
+/* inspect */
+uint8_t has_anykey(void);
+uint8_t has_anymod(void);
+uint8_t get_first_key(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/tmk_core/common/avr/bootloader.c b/tmk_core/common/avr/bootloader.c
new file mode 100644
index 000000000..7c744e8c7
--- /dev/null
+++ b/tmk_core/common/avr/bootloader.c
@@ -0,0 +1,185 @@
+#include <stdint.h>
+#include <stdbool.h>
+#include <avr/io.h>
+#include <avr/interrupt.h>
+#include <avr/wdt.h>
+#include <util/delay.h>
+#include "bootloader.h"
+
+#ifdef PROTOCOL_LUFA
+#include <LUFA/Drivers/USB/USB.h>
+#endif
+
+
+/* Bootloader Size in *bytes*
+ *
+ * AVR Boot section size are defined by setting BOOTSZ fuse in fact. Consult with your MCU datasheet.
+ * Note that 'Word'(2 bytes) size and address are used in datasheet while TMK uses 'Byte'.
+ *
+ *
+ * Size of Bootloaders in bytes:
+ * Atmel DFU loader(ATmega32U4) 4096
+ * Atmel DFU loader(AT90USB128) 8192
+ * LUFA bootloader(ATmega32U4) 4096
+ * Arduino Caterina(ATmega32U4) 4096
+ * USBaspLoader(ATmega***) 2048
+ * Teensy halfKay(ATmega32U4) 512
+ * Teensy++ halfKay(AT90USB128) 1024
+ *
+ *
+ * AVR Boot section is located at the end of Flash memory like the followings.
+ *
+ *
+ * byte Atmel/LUFA(ATMega32u4) byte Atmel(AT90SUB128)
+ * 0x0000 +---------------+ 0x00000 +---------------+
+ * | | | |
+ * | | | |
+ * | Application | | Application |
+ * | | | |
+ * = = = =
+ * | | 32KB-4KB | | 128KB-8KB
+ * 0x6000 +---------------+ 0x1FC00 +---------------+
+ * | Bootloader | 4KB | Bootloader | 8KB
+ * 0x7FFF +---------------+ 0x1FFFF +---------------+
+ *
+ *
+ * byte Teensy(ATMega32u4) byte Teensy++(AT90SUB128)
+ * 0x0000 +---------------+ 0x00000 +---------------+
+ * | | | |
+ * | | | |
+ * | Application | | Application |
+ * | | | |
+ * = = = =
+ * | | 32KB-512B | | 128KB-1KB
+ * 0x7E00 +---------------+ 0x1FC00 +---------------+
+ * | Bootloader | 512B | Bootloader | 1KB
+ * 0x7FFF +---------------+ 0x1FFFF +---------------+
+ */
+#ifndef BOOTLOADER_SIZE
+#warning To use bootloader_jump() you need to define BOOTLOADER_SIZE in config.h.
+#define BOOTLOADER_SIZE 4096
+#endif
+
+#define FLASH_SIZE (FLASHEND + 1L)
+#define BOOTLOADER_START (FLASH_SIZE - BOOTLOADER_SIZE)
+
+
+/*
+ * Entering the Bootloader via Software
+ * http://www.fourwalledcubicle.com/files/LUFA/Doc/120730/html/_page__software_bootloader_start.html
+ */
+#define BOOTLOADER_RESET_KEY 0xB007B007
+uint32_t reset_key __attribute__ ((section (".noinit")));
+
+/* initialize MCU status by watchdog reset */
+void bootloader_jump(void) {
+#ifdef PROTOCOL_LUFA
+ USB_Disable();
+ cli();
+ _delay_ms(2000);
+#endif
+
+#ifdef PROTOCOL_PJRC
+ cli();
+ UDCON = 1;
+ USBCON = (1<<FRZCLK);
+ UCSR1B = 0;
+ _delay_ms(5);
+#endif
+
+ // watchdog reset
+ reset_key = BOOTLOADER_RESET_KEY;
+ wdt_enable(WDTO_250MS);
+ for (;;);
+}
+
+
+/* this runs before main() */
+void bootloader_jump_after_watchdog_reset(void) __attribute__ ((used, naked, section (".init3")));
+void bootloader_jump_after_watchdog_reset(void)
+{
+ if ((MCUSR & (1<<WDRF)) && reset_key == BOOTLOADER_RESET_KEY) {
+ reset_key = 0;
+
+ // My custom USBasploader requires this to come up.
+ MCUSR = 0;
+
+ // Seems like Teensy halfkay loader requires clearing WDRF and disabling watchdog.
+ MCUSR &= ~(1<<WDRF);
+ wdt_disable();
+
+ // This is compled into 'icall', address should be in word unit, not byte.
+ ((void (*)(void))(BOOTLOADER_START/2))();
+ }
+}
+
+
+#if 0
+/* Jumping To The Bootloader
+ * http://www.pjrc.com/teensy/jump_to_bootloader.html
+ *
+ * This method doen't work when using LUFA. idk why.
+ * - needs to initialize more regisers or interrupt setting?
+ */
+void bootloader_jump(void) {
+#ifdef PROTOCOL_LUFA
+ USB_Disable();
+ cli();
+ _delay_ms(2000);
+#endif
+
+#ifdef PROTOCOL_PJRC
+ cli();
+ UDCON = 1;
+ USBCON = (1<<FRZCLK);
+ UCSR1B = 0;
+ _delay_ms(5);
+#endif
+
+ /*
+ * Initialize
+ */
+#if defined(__AVR_AT90USB162__)
+ EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0;
+ TIMSK0 = 0; TIMSK1 = 0; UCSR1B = 0;
+ DDRB = 0; DDRC = 0; DDRD = 0;
+ PORTB = 0; PORTC = 0; PORTD = 0;
+#elif defined(__AVR_ATmega32U4__)
+ EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0; ADCSRA = 0;
+ TIMSK0 = 0; TIMSK1 = 0; TIMSK3 = 0; TIMSK4 = 0; UCSR1B = 0; TWCR = 0;
+ DDRB = 0; DDRC = 0; DDRD = 0; DDRE = 0; DDRF = 0; TWCR = 0;
+ PORTB = 0; PORTC = 0; PORTD = 0; PORTE = 0; PORTF = 0;
+#elif defined(__AVR_AT90USB646__)
+ EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0; ADCSRA = 0;
+ TIMSK0 = 0; TIMSK1 = 0; TIMSK2 = 0; TIMSK3 = 0; UCSR1B = 0; TWCR = 0;
+ DDRA = 0; DDRB = 0; DDRC = 0; DDRD = 0; DDRE = 0; DDRF = 0;
+ PORTA = 0; PORTB = 0; PORTC = 0; PORTD = 0; PORTE = 0; PORTF = 0;
+#elif defined(__AVR_AT90USB1286__)
+ EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0; ADCSRA = 0;
+ TIMSK0 = 0; TIMSK1 = 0; TIMSK2 = 0; TIMSK3 = 0; UCSR1B = 0; TWCR = 0;
+ DDRA = 0; DDRB = 0; DDRC = 0; DDRD = 0; DDRE = 0; DDRF = 0;
+ PORTA = 0; PORTB = 0; PORTC = 0; PORTD = 0; PORTE = 0; PORTF = 0;
+#endif
+
+ /*
+ * USBaspLoader
+ */
+#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega328P__)
+ // This makes custom USBasploader come up.
+ MCUSR = 0;
+
+ // initialize ports
+ PORTB = 0; PORTC= 0; PORTD = 0;
+ DDRB = 0; DDRC= 0; DDRD = 0;
+
+ // disable interrupts
+ EIMSK = 0; EECR = 0; SPCR = 0;
+ ACSR = 0; SPMCSR = 0; WDTCSR = 0; PCICR = 0;
+ TIMSK0 = 0; TIMSK1 = 0; TIMSK2 = 0;
+ ADCSRA = 0; TWCR = 0; UCSR0B = 0;
+#endif
+
+ // This is compled into 'icall', address should be in word unit, not byte.
+ ((void (*)(void))(BOOTLOADER_START/2))();
+}
+#endif
diff --git a/tmk_core/common/avr/sleep_led.c b/tmk_core/common/avr/sleep_led.c
new file mode 100644
index 000000000..dab3eb0f3
--- /dev/null
+++ b/tmk_core/common/avr/sleep_led.c
@@ -0,0 +1,95 @@
+#include <stdint.h>
+#include <avr/io.h>
+#include <avr/interrupt.h>
+#include <avr/pgmspace.h>
+#include "led.h"
+#include "sleep_led.h"
+
+/* Software PWM
+ * ______ ______ __
+ * | ON |___OFF___| ON |___OFF___| ....
+ * |<-------------->|<-------------->|<- ....
+ * PWM period PWM period
+ *
+ * 256 interrupts/period[resolution]
+ * 64 periods/second[frequency]
+ * 256*64 interrupts/second
+ * F_CPU/(256*64) clocks/interrupt
+ */
+#define SLEEP_LED_TIMER_TOP F_CPU/(256*64)
+
+void sleep_led_init(void)
+{
+ /* Timer1 setup */
+ /* CTC mode */
+ TCCR1B |= _BV(WGM12);
+ /* Clock selelct: clk/1 */
+ TCCR1B |= _BV(CS10);
+ /* Set TOP value */
+ uint8_t sreg = SREG;
+ cli();
+ OCR1AH = (SLEEP_LED_TIMER_TOP>>8)&0xff;
+ OCR1AL = SLEEP_LED_TIMER_TOP&0xff;
+ SREG = sreg;
+}
+
+void sleep_led_enable(void)
+{
+ /* Enable Compare Match Interrupt */
+ TIMSK1 |= _BV(OCIE1A);
+}
+
+void sleep_led_disable(void)
+{
+ /* Disable Compare Match Interrupt */
+ TIMSK1 &= ~_BV(OCIE1A);
+}
+
+void sleep_led_toggle(void)
+{
+ /* Disable Compare Match Interrupt */
+ TIMSK1 ^= _BV(OCIE1A);
+}
+
+
+/* Breathing Sleep LED brighness(PWM On period) table
+ * (64[steps] * 4[duration]) / 64[PWM periods/s] = 4 second breath cycle
+ *
+ * http://www.wolframalpha.com/input/?i=%28sin%28+x%2F64*pi%29**8+*+255%2C+x%3D0+to+63
+ * (0..63).each {|x| p ((sin(x/64.0*PI)**8)*255).to_i }
+ */
+static const uint8_t breathing_table[64] PROGMEM = {
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 4, 6, 10,
+15, 23, 32, 44, 58, 74, 93, 113, 135, 157, 179, 199, 218, 233, 245, 252,
+255, 252, 245, 233, 218, 199, 179, 157, 135, 113, 93, 74, 58, 44, 32, 23,
+15, 10, 6, 4, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+ISR(TIMER1_COMPA_vect)
+{
+ /* Software PWM
+ * timer:1111 1111 1111 1111
+ * \_____/\/ \_______/____ count(0-255)
+ * \ \______________ duration of step(4)
+ * \__________________ index of step table(0-63)
+ */
+ static union {
+ uint16_t row;
+ struct {
+ uint8_t count:8;
+ uint8_t duration:2;
+ uint8_t index:6;
+ } pwm;
+ } timer = { .row = 0 };
+
+ timer.row++;
+
+ // LED on
+ if (timer.pwm.count == 0) {
+ led_set(1<<USB_LED_CAPS_LOCK);
+ }
+ // LED off
+ if (timer.pwm.count == pgm_read_byte(&breathing_table[timer.pwm.index])) {
+ led_set(0);
+ }
+}
diff --git a/tmk_core/common/avr/suspend.c b/tmk_core/common/avr/suspend.c
new file mode 100644
index 000000000..8a7272bbc
--- /dev/null
+++ b/tmk_core/common/avr/suspend.c
@@ -0,0 +1,148 @@
+#include <stdbool.h>
+#include <avr/sleep.h>
+#include <avr/wdt.h>
+#include <avr/interrupt.h>
+#include "matrix.h"
+#include "action.h"
+#include "backlight.h"
+#include "suspend_avr.h"
+#include "suspend.h"
+#include "timer.h"
+#include "led.h"
+
+#ifdef PROTOCOL_LUFA
+ #include "lufa.h"
+#endif
+
+#ifdef AUDIO_ENABLE
+ #include "audio.h"
+#endif /* AUDIO_ENABLE */
+
+
+
+#define wdt_intr_enable(value) \
+__asm__ __volatile__ ( \
+ "in __tmp_reg__,__SREG__" "\n\t" \
+ "cli" "\n\t" \
+ "wdr" "\n\t" \
+ "sts %0,%1" "\n\t" \
+ "out __SREG__,__tmp_reg__" "\n\t" \
+ "sts %0,%2" "\n\t" \
+ : /* no outputs */ \
+ : "M" (_SFR_MEM_ADDR(_WD_CONTROL_REG)), \
+ "r" (_BV(_WD_CHANGE_BIT) | _BV(WDE)), \
+ "r" ((uint8_t) ((value & 0x08 ? _WD_PS3_MASK : 0x00) | \
+ _BV(WDIE) | (value & 0x07)) ) \
+ : "r0" \
+)
+
+
+void suspend_idle(uint8_t time)
+{
+ cli();
+ set_sleep_mode(SLEEP_MODE_IDLE);
+ sleep_enable();
+ sei();
+ sleep_cpu();
+ sleep_disable();
+}
+
+/* Power down MCU with watchdog timer
+ * wdto: watchdog timer timeout defined in <avr/wdt.h>
+ * WDTO_15MS
+ * WDTO_30MS
+ * WDTO_60MS
+ * WDTO_120MS
+ * WDTO_250MS
+ * WDTO_500MS
+ * WDTO_1S
+ * WDTO_2S
+ * WDTO_4S
+ * WDTO_8S
+ */
+static uint8_t wdt_timeout = 0;
+static void power_down(uint8_t wdto)
+{
+#ifdef PROTOCOL_LUFA
+ if (USB_DeviceState == DEVICE_STATE_Configured) return;
+#endif
+ wdt_timeout = wdto;
+
+ // Watchdog Interrupt Mode
+ wdt_intr_enable(wdto);
+
+#ifdef BACKLIGHT_ENABLE
+ backlight_set(0);
+#endif
+
+ // Turn off LED indicators
+ led_set(0);
+
+ #ifdef AUDIO_ENABLE
+ // This sometimes disables the start-up noise, so it's been disabled
+ // stop_all_notes();
+ #endif /* AUDIO_ENABLE */
+
+ // TODO: more power saving
+ // See PicoPower application note
+ // - I/O port input with pullup
+ // - prescale clock
+ // - BOD disable
+ // - Power Reduction Register PRR
+ set_sleep_mode(SLEEP_MODE_PWR_DOWN);
+ sleep_enable();
+ sei();
+ sleep_cpu();
+ sleep_disable();
+
+ // Disable watchdog after sleep
+ wdt_disable();
+}
+
+void suspend_power_down(void)
+{
+ power_down(WDTO_15MS);
+}
+
+__attribute__ ((weak)) void matrix_power_up(void) {}
+__attribute__ ((weak)) void matrix_power_down(void) {}
+bool suspend_wakeup_condition(void)
+{
+#ifdef BACKLIGHT_ENABLE
+ backlight_set(0);
+#endif
+ matrix_power_up();
+ matrix_scan();
+ matrix_power_down();
+ for (uint8_t r = 0; r < MATRIX_ROWS; r++) {
+ if (matrix_get_row(r)) return true;
+ }
+ return false;
+}
+
+// run immediately after wakeup
+void suspend_wakeup_init(void)
+{
+ // clear keyboard state
+ clear_keyboard();
+#ifdef BACKLIGHT_ENABLE
+ backlight_set(0);
+ backlight_init();
+#endif
+led_set(host_keyboard_leds());
+}
+
+#ifndef NO_SUSPEND_POWER_DOWN
+/* watchdog timeout */
+ISR(WDT_vect)
+{
+ // compensate timer for sleep
+ switch (wdt_timeout) {
+ case WDTO_15MS:
+ timer_count += 15 + 2; // WDTO_15MS + 2(from observation)
+ break;
+ default:
+ ;
+ }
+}
+#endif
diff --git a/tmk_core/common/avr/suspend_avr.h b/tmk_core/common/avr/suspend_avr.h
new file mode 100644
index 000000000..357102da4
--- /dev/null
+++ b/tmk_core/common/avr/suspend_avr.h
@@ -0,0 +1,27 @@
+#ifndef SUSPEND_AVR_H
+#define SUSPEND_AVR_H
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <avr/sleep.h>
+#include <avr/wdt.h>
+#include <avr/interrupt.h>
+
+
+#define wdt_intr_enable(value) \
+__asm__ __volatile__ ( \
+ "in __tmp_reg__,__SREG__" "\n\t" \
+ "cli" "\n\t" \
+ "wdr" "\n\t" \
+ "sts %0,%1" "\n\t" \
+ "out __SREG__,__tmp_reg__" "\n\t" \
+ "sts %0,%2" "\n\t" \
+ : /* no outputs */ \
+ : "M" (_SFR_MEM_ADDR(_WD_CONTROL_REG)), \
+ "r" (_BV(_WD_CHANGE_BIT) | _BV(WDE)), \
+ "r" ((uint8_t) ((value & 0x08 ? _WD_PS3_MASK : 0x00) | \
+ _BV(WDIE) | (value & 0x07)) ) \
+ : "r0" \
+)
+
+#endif
diff --git a/tmk_core/common/avr/timer.c b/tmk_core/common/avr/timer.c
new file mode 100644
index 000000000..292b41c3a
--- /dev/null
+++ b/tmk_core/common/avr/timer.c
@@ -0,0 +1,117 @@
+/*
+Copyright 2011 Jun Wako <wakojun@gmail.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <avr/io.h>
+#include <avr/interrupt.h>
+#include <stdint.h>
+#include "timer_avr.h"
+#include "timer.h"
+
+
+// counter resolution 1ms
+// NOTE: union { uint32_t timer32; struct { uint16_t dummy; uint16_t timer16; }}
+volatile uint32_t timer_count = 0;
+
+void timer_init(void)
+{
+ // Timer0 CTC mode
+ TCCR0A = 0x02;
+
+#if TIMER_PRESCALER == 1
+ TCCR0B = 0x01;
+#elif TIMER_PRESCALER == 8
+ TCCR0B = 0x02;
+#elif TIMER_PRESCALER == 64
+ TCCR0B = 0x03;
+#elif TIMER_PRESCALER == 256
+ TCCR0B = 0x04;
+#elif TIMER_PRESCALER == 1024
+ TCCR0B = 0x05;
+#else
+# error "Timer prescaler value is NOT vaild."
+#endif
+
+ OCR0A = TIMER_RAW_TOP;
+ TIMSK0 = (1<<OCIE0A);
+}
+
+inline
+void timer_clear(void)
+{
+ uint8_t sreg = SREG;
+ cli();
+ timer_count = 0;
+ SREG = sreg;
+}
+
+inline
+uint16_t timer_read(void)
+{
+ uint32_t t;
+
+ uint8_t sreg = SREG;
+ cli();
+ t = timer_count;
+ SREG = sreg;
+
+ return (t & 0xFFFF);
+}
+
+inline
+uint32_t timer_read32(void)
+{
+ uint32_t t;
+
+ uint8_t sreg = SREG;
+ cli();
+ t = timer_count;
+ SREG = sreg;
+
+ return t;
+}
+
+inline
+uint16_t timer_elapsed(uint16_t last)
+{
+ uint32_t t;
+
+ uint8_t sreg = SREG;
+ cli();
+ t = timer_count;
+ SREG = sreg;
+
+ return TIMER_DIFF_16((t & 0xFFFF), last);
+}
+
+inline
+uint32_t timer_elapsed32(uint32_t last)
+{
+ uint32_t t;
+
+ uint8_t sreg = SREG;
+ cli();
+ t = timer_count;
+ SREG = sreg;
+
+ return TIMER_DIFF_32(t, last);
+}
+
+// excecuted once per 1ms.(excess for just timer count?)
+ISR(TIMER0_COMPA_vect)
+{
+ timer_count++;
+}
diff --git a/tmk_core/common/avr/timer_avr.h b/tmk_core/common/avr/timer_avr.h
new file mode 100644
index 000000000..0e85eb101
--- /dev/null
+++ b/tmk_core/common/avr/timer_avr.h
@@ -0,0 +1,42 @@
+/*
+Copyright 2011 Jun Wako <wakojun@gmail.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef TIMER_AVR_H
+#define TIMER_AVR_H 1
+
+#include <stdint.h>
+
+#ifndef TIMER_PRESCALER
+# if F_CPU > 16000000
+# define TIMER_PRESCALER 256
+# elif F_CPU > 2000000
+# define TIMER_PRESCALER 64
+# elif F_CPU > 250000
+# define TIMER_PRESCALER 8
+# else
+# define TIMER_PRESCALER 1
+# endif
+#endif
+#define TIMER_RAW_FREQ (F_CPU/TIMER_PRESCALER)
+#define TIMER_RAW TCNT0
+#define TIMER_RAW_TOP (TIMER_RAW_FREQ/1000)
+
+#if (TIMER_RAW_TOP > 255)
+# error "Timer0 can't count 1ms at this clock freq. Use larger prescaler."
+#endif
+
+#endif
diff --git a/tmk_core/common/avr/xprintf.S b/tmk_core/common/avr/xprintf.S
new file mode 100644
index 000000000..0cec70ce2
--- /dev/null
+++ b/tmk_core/common/avr/xprintf.S
@@ -0,0 +1,500 @@
+;---------------------------------------------------------------------------;
+; Extended itoa, puts, printf and atoi (C)ChaN, 2011
+;---------------------------------------------------------------------------;
+
+ // Base size is 152 bytes
+#define CR_CRLF 0 // Convert \n to \r\n (+10 bytes)
+#define USE_XPRINTF 1 // Enable xprintf function (+194 bytes)
+#define USE_XSPRINTF 0 // Add xsprintf function (+78 bytes)
+#define USE_XFPRINTF 0 // Add xfprintf function (+54 bytes)
+#define USE_XATOI 0 // Enable xatoi function (+182 bytes)
+
+
+#if FLASHEND > 0x1FFFF
+#error xitoa module does not support 256K devices
+#endif
+
+.nolist
+#include <avr/io.h> // Include device specific definitions.
+.list
+
+#ifdef SPM_PAGESIZE // Recent devices have "lpm Rd,Z+" and "movw".
+.macro _LPMI reg
+ lpm \reg, Z+
+.endm
+.macro _MOVW dh,dl, sh,sl
+ movw \dl, \sl
+.endm
+#else // Earlier devices do not have "lpm Rd,Z+" nor "movw".
+.macro _LPMI reg
+ lpm
+ mov \reg, r0
+ adiw ZL, 1
+.endm
+.macro _MOVW dh,dl, sh,sl
+ mov \dl, \sl
+ mov \dh, \sh
+.endm
+#endif
+
+
+
+;---------------------------------------------------------------------------
+; Stub function to forward to user output function
+;
+;Prototype: void xputc (char chr // a character to be output
+; );
+;Size: 12/12 words
+
+.section .bss
+.global xfunc_out ; xfunc_out must be initialized before using this module.
+xfunc_out: .ds.w 1
+.section .text
+
+
+.func xputc
+.global xputc
+xputc:
+#if CR_CRLF
+ cpi r24, 10 ;LF --> CRLF
+ brne 1f ;
+ ldi r24, 13 ;
+ rcall 1f ;
+ ldi r24, 10 ;/
+1:
+#endif
+ push ZH
+ push ZL
+ lds ZL, xfunc_out+0 ;Pointer to the registered output function.
+ lds ZH, xfunc_out+1 ;/
+ sbiw ZL, 0 ;Skip if null
+ breq 2f ;/
+ icall
+2: pop ZL
+ pop ZH
+ ret
+.endfunc
+
+
+
+;---------------------------------------------------------------------------
+; Direct ROM string output
+;
+;Prototype: void xputs (const char *str_p // rom string to be output
+; );
+
+.func xputs
+.global xputs
+xputs:
+ _MOVW ZH,ZL, r25,r24 ; Z = pointer to rom string
+1: _LPMI r24
+ cpi r24, 0
+ breq 2f
+ rcall xputc
+ rjmp 1b
+2: ret
+.endfunc
+
+
+;---------------------------------------------------------------------------
+; Extended direct numeral string output (32bit version)
+;
+;Prototype: void xitoa (long value, // value to be output
+; char radix, // radix
+; char width); // minimum width
+;
+
+.func xitoa
+.global xitoa
+xitoa:
+ ;r25:r22 = value, r20 = base, r18 = digits
+ clr r31 ;r31 = stack level
+ ldi r30, ' ' ;r30 = sign
+ ldi r19, ' ' ;r19 = filler
+ sbrs r20, 7 ;When base indicates signd format and the value
+ rjmp 0f ;is minus, add a '-'.
+ neg r20 ;
+ sbrs r25, 7 ;
+ rjmp 0f ;
+ ldi r30, '-' ;
+ com r22 ;
+ com r23 ;
+ com r24 ;
+ com r25 ;
+ adc r22, r1 ;
+ adc r23, r1 ;
+ adc r24, r1 ;
+ adc r25, r1 ;/
+0: sbrs r18, 7 ;When digits indicates zero filled,
+ rjmp 1f ;filler is '0'.
+ neg r18 ;
+ ldi r19, '0' ;/
+ ;----- string conversion loop
+1: ldi r21, 32 ;r26 = r25:r22 % r20
+ clr r26 ;r25:r22 /= r20
+2: lsl r22 ;
+ rol r23 ;
+ rol r24 ;
+ rol r25 ;
+ rol r26 ;
+ cp r26, r20 ;
+ brcs 3f ;
+ sub r26, r20 ;
+ inc r22 ;
+3: dec r21 ;
+ brne 2b ;/
+ cpi r26, 10 ;r26 is a numeral digit '0'-'F'
+ brcs 4f ;
+ subi r26, -7 ;
+4: subi r26, -'0' ;/
+ push r26 ;Stack it
+ inc r31 ;/
+ cp r22, r1 ;Repeat until r25:r22 gets zero
+ cpc r23, r1 ;
+ cpc r24, r1 ;
+ cpc r25, r1 ;
+ brne 1b ;/
+
+ cpi r30, '-' ;Minus sign if needed
+ brne 5f ;
+ push r30 ;
+ inc r31 ;/
+5: cp r31, r18 ;Filler
+ brcc 6f ;
+ push r19 ;
+ inc r31 ;
+ rjmp 5b ;/
+
+6: pop r24 ;Flush stacked digits and exit
+ rcall xputc ;
+ dec r31 ;
+ brne 6b ;/
+
+ ret
+.endfunc
+
+
+
+;---------------------------------------------------------------------------;
+; Formatted string output (16/32bit version)
+;
+;Prototype:
+; void __xprintf (const char *format_p, ...);
+; void __xsprintf(char*, const char *format_p, ...);
+; void __xfprintf(void(*func)(char), const char *format_p, ...);
+;
+
+#if USE_XPRINTF
+
+.func xvprintf
+xvprintf:
+ ld ZL, Y+ ;Z = pointer to format string
+ ld ZH, Y+ ;/
+
+0: _LPMI r24 ;Get a format char
+ cpi r24, 0 ;End of format string?
+ breq 90f ;/
+ cpi r24, '%' ;Is format?
+ breq 20f ;/
+1: rcall xputc ;Put a normal character
+ rjmp 0b ;/
+90: ret
+
+20: ldi r18, 0 ;r18: digits
+ clt ;T: filler
+ _LPMI r21 ;Get flags
+ cpi r21, '%' ;Is a %?
+ breq 1b ;/
+ cpi r21, '0' ;Zero filled?
+ brne 23f ;
+ set ;/
+22: _LPMI r21 ;Get width
+23: cpi r21, '9'+1 ;
+ brcc 24f ;
+ subi r21, '0' ;
+ brcs 90b ;
+ lsl r18 ;
+ mov r0, r18 ;
+ lsl r18 ;
+ lsl r18 ;
+ add r18, r0 ;
+ add r18, r21 ;
+ rjmp 22b ;/
+
+24: brtc 25f ;get value (low word)
+ neg r18 ;
+25: ld r24, Y+ ;
+ ld r25, Y+ ;/
+ cpi r21, 'c' ;Is type character?
+ breq 1b ;/
+ cpi r21, 's' ;Is type RAM string?
+ breq 50f ;/
+ cpi r21, 'S' ;Is type ROM string?
+ breq 60f ;/
+ _MOVW r23,r22,r25,r24 ;r25:r22 = value
+ clr r24 ;
+ clr r25 ;
+ clt ;/
+ cpi r21, 'l' ;Is long int?
+ brne 26f ;
+ ld r24, Y+ ;get value (high word)
+ ld r25, Y+ ;
+ set ;
+ _LPMI r21 ;/
+26: cpi r21, 'd' ;Is type signed decimal?
+ brne 27f ;/
+ ldi r20, -10 ;
+ brts 40f ;
+ sbrs r23, 7 ;
+ rjmp 40f ;
+ ldi r24, -1 ;
+ ldi r25, -1 ;
+ rjmp 40f ;/
+27: cpi r21, 'u' ;Is type unsigned decimal?
+ ldi r20, 10 ;
+ breq 40f ;/
+ cpi r21, 'X' ;Is type hexdecimal?
+ ldi r20, 16 ;
+ breq 40f ;/
+ cpi r21, 'b' ;Is type binary?
+ ldi r20, 2 ;
+ breq 40f ;/
+ ret ;abort
+40: push ZH ;Output the value
+ push ZL ;
+ rcall xitoa ;
+42: pop ZL ;
+ pop ZH ;
+ rjmp 0b ;/
+
+50: push ZH ;Put a string on the RAM
+ push ZL
+ _MOVW ZH,ZL, r25,r24
+51: ld r24, Z+
+ cpi r24, 0
+ breq 42b
+ rcall xputc
+ rjmp 51b
+
+60: push ZH ;Put a string on the ROM
+ push ZL
+ rcall xputs
+ rjmp 42b
+.endfunc
+
+
+.func __xprintf
+.global __xprintf
+__xprintf:
+ push YH
+ push YL
+ in YL, _SFR_IO_ADDR(SPL)
+#ifdef SPH
+ in YH, _SFR_IO_ADDR(SPH)
+#else
+ clr YH
+#endif
+ adiw YL, 5 ;Y = pointer to arguments
+ rcall xvprintf
+ pop YL
+ pop YH
+ ret
+.endfunc
+
+
+#if USE_XSPRINTF
+
+.func __xsprintf
+putram:
+ _MOVW ZH,ZL, r15,r14
+ st Z+, r24
+ _MOVW r15,r14, ZH,ZL
+ ret
+.global __xsprintf
+__xsprintf:
+ push YH
+ push YL
+ in YL, _SFR_IO_ADDR(SPL)
+#ifdef SPH
+ in YH, _SFR_IO_ADDR(SPH)
+#else
+ clr YH
+#endif
+ adiw YL, 5 ;Y = pointer to arguments
+ lds ZL, xfunc_out+0 ;Save registered output function
+ lds ZH, xfunc_out+1 ;
+ push ZL ;
+ push ZH ;/
+ ldi ZL, lo8(pm(putram));Set local output function
+ ldi ZH, hi8(pm(putram));
+ sts xfunc_out+0, ZL ;
+ sts xfunc_out+1, ZH ;/
+ push r15 ;Initialize pointer to string buffer
+ push r14 ;
+ ld r14, Y+ ;
+ ld r15, Y+ ;/
+ rcall xvprintf
+ _MOVW ZH,ZL, r15,r14 ;Terminate string
+ st Z, r1 ;
+ pop r14 ;
+ pop r15 ;/
+ pop ZH ;Restore registered output function
+ pop ZL ;
+ sts xfunc_out+0, ZL ;
+ sts xfunc_out+1, ZH ;/
+ pop YL
+ pop YH
+ ret
+.endfunc
+#endif
+
+
+#if USE_XFPRINTF
+.func __xfprintf
+.global __xfprintf
+__xfprintf:
+ push YH
+ push YL
+ in YL, _SFR_IO_ADDR(SPL)
+#ifdef SPH
+ in YH, _SFR_IO_ADDR(SPH)
+#else
+ clr YH
+#endif
+ adiw YL, 5 ;Y = pointer to arguments
+ lds ZL, xfunc_out+0 ;Save registered output function
+ lds ZH, xfunc_out+1 ;
+ push ZL ;
+ push ZH ;/
+ ld ZL, Y+ ;Set output function
+ ld ZH, Y+ ;
+ sts xfunc_out+0, ZL ;
+ sts xfunc_out+1, ZH ;/
+ rcall xvprintf
+ pop ZH ;Restore registered output function
+ pop ZL ;
+ sts xfunc_out+0, ZL ;
+ sts xfunc_out+1, ZH ;/
+ pop YL
+ pop YH
+ ret
+.endfunc
+#endif
+
+#endif
+
+
+
+;---------------------------------------------------------------------------
+; Extended numeral string input
+;
+;Prototype:
+; char xatoi ( /* 1: Successful, 0: Failed */
+; const char **str, /* pointer to pointer to source string */
+; long *res /* result */
+; );
+;
+
+
+#if USE_XATOI
+.func xatoi
+.global xatoi
+xatoi:
+ _MOVW r1, r0, r23, r22
+ _MOVW XH, XL, r25, r24
+ ld ZL, X+
+ ld ZH, X+
+ clr r18 ;r21:r18 = 0;
+ clr r19 ;
+ clr r20 ;
+ clr r21 ;/
+ clt ;T = 0;
+
+ ldi r25, 10 ;r25 = 10;
+ rjmp 41f ;/
+40: adiw ZL, 1 ;Z++;
+41: ld r22, Z ;r22 = *Z;
+ cpi r22, ' ' ;if(r22 == ' ') continue
+ breq 40b ;/
+ brcs 70f ;if(r22 < ' ') error;
+ cpi r22, '-' ;if(r22 == '-') {
+ brne 42f ; T = 1;
+ set ; continue;
+ rjmp 40b ;}
+42: cpi r22, '9'+1 ;if(r22 > '9') error;
+ brcc 70f ;/
+ cpi r22, '0' ;if(r22 < '0') error;
+ brcs 70f ;/
+ brne 51f ;if(r22 > '0') cv_start;
+ ldi r25, 8 ;r25 = 8;
+ adiw ZL, 1 ;r22 = *(++Z);
+ ld r22, Z ;/
+ cpi r22, ' '+1 ;if(r22 <= ' ') exit;
+ brcs 80f ;/
+ cpi r22, 'b' ;if(r22 == 'b') {
+ brne 43f ; r25 = 2;
+ ldi r25, 2 ; cv_start;
+ rjmp 50f ;}
+43: cpi r22, 'x' ;if(r22 != 'x') error;
+ brne 51f ;/
+ ldi r25, 16 ;r25 = 16;
+
+50: adiw ZL, 1 ;Z++;
+ ld r22, Z ;r22 = *Z;
+51: cpi r22, ' '+1 ;if(r22 <= ' ') break;
+ brcs 80f ;/
+ cpi r22, 'a' ;if(r22 >= 'a') r22 =- 0x20;
+ brcs 52f ;
+ subi r22, 0x20 ;/
+52: subi r22, '0' ;if((r22 -= '0') < 0) error;
+ brcs 70f ;/
+ cpi r22, 10 ;if(r22 >= 10) {
+ brcs 53f ; r22 -= 7;
+ subi r22, 7 ; if(r22 < 10)
+ cpi r22, 10 ;
+ brcs 70f ;}
+53: cp r22, r25 ;if(r22 >= r25) error;
+ brcc 70f ;/
+60: ldi r24, 33 ;r21:r18 *= r25;
+ sub r23, r23 ;
+61: brcc 62f ;
+ add r23, r25 ;
+62: lsr r23 ;
+ ror r21 ;
+ ror r20 ;
+ ror r19 ;
+ ror r18 ;
+ dec r24 ;
+ brne 61b ;/
+ add r18, r22 ;r21:r18 += r22;
+ adc r19, r24 ;
+ adc r20, r24 ;
+ adc r21, r24 ;/
+ rjmp 50b ;repeat
+
+70: ldi r24, 0
+ rjmp 81f
+80: ldi r24, 1
+81: brtc 82f
+ clr r22
+ com r18
+ com r19
+ com r20
+ com r21
+ adc r18, r22
+ adc r19, r22
+ adc r20, r22
+ adc r21, r22
+82: st -X, ZH
+ st -X, ZL
+ _MOVW XH, XL, r1, r0
+ st X+, r18
+ st X+, r19
+ st X+, r20
+ st X+, r21
+ clr r1
+ ret
+.endfunc
+#endif
+
+
diff --git a/tmk_core/common/avr/xprintf.h b/tmk_core/common/avr/xprintf.h
new file mode 100644
index 000000000..59c6f2531
--- /dev/null
+++ b/tmk_core/common/avr/xprintf.h
@@ -0,0 +1,111 @@
+/*---------------------------------------------------------------------------
+ Extended itoa, puts and printf (C)ChaN, 2011
+-----------------------------------------------------------------------------*/
+
+#ifndef XPRINTF_H
+#define XPRINTF_H
+
+#include <inttypes.h>
+#include <avr/pgmspace.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void (*xfunc_out)(uint8_t);
+#define xdev_out(func) xfunc_out = (void(*)(uint8_t))(func)
+
+/* This is a pointer to user defined output function. It must be initialized
+ before using this modle.
+*/
+
+void xputc(char chr);
+
+/* This is a stub function to forward outputs to user defined output function.
+ All outputs from this module are output via this function.
+*/
+
+
+/*-----------------------------------------------------------------------------*/
+void xputs(const char *string_p);
+
+/* The string placed in the ROM is forwarded to xputc() directly.
+*/
+
+
+/*-----------------------------------------------------------------------------*/
+void xitoa(long value, char radix, char width);
+
+/* Extended itoa().
+
+ value radix width output
+ 100 10 6 " 100"
+ 100 10 -6 "000100"
+ 100 10 0 "100"
+ 4294967295 10 0 "4294967295"
+ 4294967295 -10 0 "-1"
+ 655360 16 -8 "000A0000"
+ 1024 16 0 "400"
+ 0x55 2 -8 "01010101"
+*/
+
+
+/*-----------------------------------------------------------------------------*/
+#define xprintf(format, ...) __xprintf(PSTR(format), ##__VA_ARGS__)
+#define xsprintf(str, format, ...) __xsprintf(str, PSTR(format), ##__VA_ARGS__)
+#define xfprintf(func, format, ...) __xfprintf(func, PSTR(format), ##__VA_ARGS__)
+
+void __xprintf(const char *format_p, ...); /* Send formatted string to the registered device */
+void __xsprintf(char*, const char *format_p, ...); /* Put formatted string to the memory */
+void __xfprintf(void(*func)(uint8_t), const char *format_p, ...); /* Send formatted string to the specified device */
+
+/* Format string is placed in the ROM. The format flags is similar to printf().
+
+ %[flag][width][size]type
+
+ flag
+ A '0' means filled with '0' when output is shorter than width.
+ ' ' is used in default. This is effective only numeral type.
+ width
+ Minimum width in decimal number. This is effective only numeral type.
+ Default width is zero.
+ size
+ A 'l' means the argument is long(32bit). Default is short(16bit).
+ This is effective only numeral type.
+ type
+ 'c' : Character, argument is the value
+ 's' : String placed on the RAM, argument is the pointer
+ 'S' : String placed on the ROM, argument is the pointer
+ 'd' : Signed decimal, argument is the value
+ 'u' : Unsigned decimal, argument is the value
+ 'X' : Hexdecimal, argument is the value
+ 'b' : Binary, argument is the value
+ '%' : '%'
+
+*/
+
+
+/*-----------------------------------------------------------------------------*/
+char xatoi(char **str, long *ret);
+
+/* Get value of the numeral string.
+
+ str
+ Pointer to pointer to source string
+
+ "0b11001010" binary
+ "0377" octal
+ "0xff800" hexdecimal
+ "1250000" decimal
+ "-25000" decimal
+
+ ret
+ Pointer to return value
+*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/tmk_core/common/backlight.c b/tmk_core/common/backlight.c
new file mode 100644
index 000000000..c9e8fd3fd
--- /dev/null
+++ b/tmk_core/common/backlight.c
@@ -0,0 +1,90 @@
+/*
+Copyright 2013 Mathias Andersson <wraul@dbox.se>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "backlight.h"
+#include "eeconfig.h"
+#include "debug.h"
+
+backlight_config_t backlight_config;
+
+void backlight_init(void)
+{
+ /* check signature */
+ if (!eeconfig_is_enabled()) {
+ eeconfig_init();
+ }
+ backlight_config.raw = eeconfig_read_backlight();
+ backlight_set(backlight_config.enable ? backlight_config.level : 0);
+}
+
+void backlight_increase(void)
+{
+ if(backlight_config.level < BACKLIGHT_LEVELS)
+ {
+ backlight_config.level++;
+ backlight_config.enable = 1;
+ eeconfig_update_backlight(backlight_config.raw);
+ }
+ dprintf("backlight increase: %u\n", backlight_config.level);
+ backlight_set(backlight_config.level);
+}
+
+void backlight_decrease(void)
+{
+ if(backlight_config.level > 0)
+ {
+ backlight_config.level--;
+ backlight_config.enable = !!backlight_config.level;
+ eeconfig_update_backlight(backlight_config.raw);
+ }
+ dprintf("backlight decrease: %u\n", backlight_config.level);
+ backlight_set(backlight_config.level);
+}
+
+void backlight_toggle(void)
+{
+ backlight_config.enable ^= 1;
+ eeconfig_update_backlight(backlight_config.raw);
+ dprintf("backlight toggle: %u\n", backlight_config.enable);
+ backlight_set(backlight_config.enable ? backlight_config.level : 0);
+}
+
+void backlight_step(void)
+{
+ backlight_config.level++;
+ if(backlight_config.level > BACKLIGHT_LEVELS)
+ {
+ backlight_config.level = 0;
+ }
+ backlight_config.enable = !!backlight_config.level;
+ eeconfig_update_backlight(backlight_config.raw);
+ dprintf("backlight step: %u\n", backlight_config.level);
+ backlight_set(backlight_config.level);
+}
+
+void backlight_level(uint8_t level)
+{
+ backlight_config.level ^= level;
+ backlight_config.enable = !!backlight_config.level;
+ eeconfig_update_backlight(backlight_config.raw);
+ backlight_set(backlight_config.level);
+}
+
+uint8_t get_backlight_level(void)
+{
+ return backlight_config.level;
+} \ No newline at end of file
diff --git a/tmk_core/common/backlight.h b/tmk_core/common/backlight.h
new file mode 100644
index 000000000..f57309267
--- /dev/null
+++ b/tmk_core/common/backlight.h
@@ -0,0 +1,41 @@
+/*
+Copyright 2013 Mathias Andersson <wraul@dbox.se>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef BACKLIGHT_H
+#define BACKLIGHT_H
+
+#include <stdint.h>
+#include <stdbool.h>
+
+typedef union {
+ uint8_t raw;
+ struct {
+ bool enable :1;
+ uint8_t level :7;
+ };
+} backlight_config_t;
+
+void backlight_init(void);
+void backlight_increase(void);
+void backlight_decrease(void);
+void backlight_toggle(void);
+void backlight_step(void);
+void backlight_set(uint8_t level);
+void backlight_level(uint8_t level);
+uint8_t get_backlight_level(void);
+
+#endif
diff --git a/tmk_core/common/bootloader.h b/tmk_core/common/bootloader.h
new file mode 100644
index 000000000..44775039d
--- /dev/null
+++ b/tmk_core/common/bootloader.h
@@ -0,0 +1,25 @@
+/*
+Copyright 2011 Jun Wako <wakojun@gmail.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef BOOTLOADER_H
+#define BOOTLOADER_H
+
+
+/* give code for your bootloader to come up if needed */
+void bootloader_jump(void);
+
+#endif
diff --git a/tmk_core/common/bootmagic.c b/tmk_core/common/bootmagic.c
new file mode 100644
index 000000000..6730a2a4a
--- /dev/null
+++ b/tmk_core/common/bootmagic.c
@@ -0,0 +1,129 @@
+#include <stdint.h>
+#include <stdbool.h>
+#include "wait.h"
+#include "matrix.h"
+#include "bootloader.h"
+#include "debug.h"
+#include "keymap.h"
+#include "host.h"
+#include "action_layer.h"
+#include "eeconfig.h"
+#include "bootmagic.h"
+
+keymap_config_t keymap_config;
+
+void bootmagic(void)
+{
+ /* check signature */
+ if (!eeconfig_is_enabled()) {
+ eeconfig_init();
+ }
+
+ /* do scans in case of bounce */
+ print("bootmagic scan: ... ");
+ uint8_t scan = 100;
+ while (scan--) { matrix_scan(); wait_ms(10); }
+ print("done.\n");
+
+ /* bootmagic skip */
+ if (bootmagic_scan_keycode(BOOTMAGIC_KEY_SKIP)) {
+ return;
+ }
+
+ /* eeconfig clear */
+ if (bootmagic_scan_keycode(BOOTMAGIC_KEY_EEPROM_CLEAR)) {
+ eeconfig_init();
+ }
+
+ /* bootloader */
+ if (bootmagic_scan_keycode(BOOTMAGIC_KEY_BOOTLOADER)) {
+ bootloader_jump();
+ }
+
+ /* debug enable */
+ debug_config.raw = eeconfig_read_debug();
+ if (bootmagic_scan_keycode(BOOTMAGIC_KEY_DEBUG_ENABLE)) {
+ if (bootmagic_scan_keycode(BOOTMAGIC_KEY_DEBUG_MATRIX)) {
+ debug_config.matrix = !debug_config.matrix;
+ } else if (bootmagic_scan_keycode(BOOTMAGIC_KEY_DEBUG_KEYBOARD)) {
+ debug_config.keyboard = !debug_config.keyboard;
+ } else if (bootmagic_scan_keycode(BOOTMAGIC_KEY_DEBUG_MOUSE)) {
+ debug_config.mouse = !debug_config.mouse;
+ } else {
+ debug_config.enable = !debug_config.enable;
+ }
+ }
+ eeconfig_update_debug(debug_config.raw);
+
+ /* keymap config */
+ keymap_config.raw = eeconfig_read_keymap();
+ if (bootmagic_scan_keycode(BOOTMAGIC_KEY_SWAP_CONTROL_CAPSLOCK)) {
+ keymap_config.swap_control_capslock = !keymap_config.swap_control_capslock;
+ }
+ if (bootmagic_scan_keycode(BOOTMAGIC_KEY_CAPSLOCK_TO_CONTROL)) {
+ keymap_config.capslock_to_control = !keymap_config.capslock_to_control;
+ }
+ if (bootmagic_scan_keycode(BOOTMAGIC_KEY_SWAP_LALT_LGUI)) {
+ keymap_config.swap_lalt_lgui = !keymap_config.swap_lalt_lgui;
+ }
+ if (bootmagic_scan_keycode(BOOTMAGIC_KEY_SWAP_RALT_RGUI)) {
+ keymap_config.swap_ralt_rgui = !keymap_config.swap_ralt_rgui;
+ }
+ if (bootmagic_scan_keycode(BOOTMAGIC_KEY_NO_GUI)) {
+ keymap_config.no_gui = !keymap_config.no_gui;
+ }
+ if (bootmagic_scan_keycode(BOOTMAGIC_KEY_SWAP_GRAVE_ESC)) {
+ keymap_config.swap_grave_esc = !keymap_config.swap_grave_esc;
+ }
+ if (bootmagic_scan_keycode(BOOTMAGIC_KEY_SWAP_BACKSLASH_BACKSPACE)) {
+ keymap_config.swap_backslash_backspace = !keymap_config.swap_backslash_backspace;
+ }
+ if (bootmagic_scan_keycode(BOOTMAGIC_HOST_NKRO)) {
+ keymap_config.nkro = !keymap_config.nkro;
+ }
+ eeconfig_update_keymap(keymap_config.raw);
+
+#ifdef NKRO_ENABLE
+ keyboard_nkro = keymap_config.nkro;
+#endif
+
+ /* default layer */
+ uint8_t default_layer = 0;
+ if (bootmagic_scan_keycode(BOOTMAGIC_KEY_DEFAULT_LAYER_0)) { default_layer |= (1<<0); }
+ if (bootmagic_scan_keycode(BOOTMAGIC_KEY_DEFAULT_LAYER_1)) { default_layer |= (1<<1); }
+ if (bootmagic_scan_keycode(BOOTMAGIC_KEY_DEFAULT_LAYER_2)) { default_layer |= (1<<2); }
+ if (bootmagic_scan_keycode(BOOTMAGIC_KEY_DEFAULT_LAYER_3)) { default_layer |= (1<<3); }
+ if (bootmagic_scan_keycode(BOOTMAGIC_KEY_DEFAULT_LAYER_4)) { default_layer |= (1<<4); }
+ if (bootmagic_scan_keycode(BOOTMAGIC_KEY_DEFAULT_LAYER_5)) { default_layer |= (1<<5); }
+ if (bootmagic_scan_keycode(BOOTMAGIC_KEY_DEFAULT_LAYER_6)) { default_layer |= (1<<6); }
+ if (bootmagic_scan_keycode(BOOTMAGIC_KEY_DEFAULT_LAYER_7)) { default_layer |= (1<<7); }
+ if (default_layer) {
+ eeconfig_update_default_layer(default_layer);
+ default_layer_set((uint32_t)default_layer);
+ } else {
+ default_layer = eeconfig_read_default_layer();
+ default_layer_set((uint32_t)default_layer);
+ }
+}
+
+static bool scan_keycode(uint8_t keycode)
+{
+ for (uint8_t r = 0; r < MATRIX_ROWS; r++) {
+ matrix_row_t matrix_row = matrix_get_row(r);
+ for (uint8_t c = 0; c < MATRIX_COLS; c++) {
+ if (matrix_row & ((matrix_row_t)1<<c)) {
+ if (keycode == keymap_key_to_keycode(0, (keypos_t){ .row = r, .col = c })) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+bool bootmagic_scan_keycode(uint8_t keycode)
+{
+ if (!scan_keycode(BOOTMAGIC_KEY_SALT)) return false;
+
+ return scan_keycode(keycode);
+} \ No newline at end of file
diff --git a/tmk_core/common/bootmagic.h b/tmk_core/common/bootmagic.h
new file mode 100644
index 000000000..8f6618f4b
--- /dev/null
+++ b/tmk_core/common/bootmagic.h
@@ -0,0 +1,100 @@
+#ifndef BOOTMAGIC_H
+#define BOOTMAGIC_H
+
+
+/* bootmagic salt key */
+#ifndef BOOTMAGIC_KEY_SALT
+#define BOOTMAGIC_KEY_SALT KC_SPACE
+#endif
+
+/* skip bootmagic and eeconfig */
+#ifndef BOOTMAGIC_KEY_SKIP
+#define BOOTMAGIC_KEY_SKIP KC_ESC
+#endif
+
+/* eeprom clear */
+#ifndef BOOTMAGIC_KEY_EEPROM_CLEAR
+#define BOOTMAGIC_KEY_EEPROM_CLEAR KC_BSPACE
+#endif
+
+/* kick up bootloader */
+#ifndef BOOTMAGIC_KEY_BOOTLOADER
+#define BOOTMAGIC_KEY_BOOTLOADER KC_B
+#endif
+
+/* debug enable */
+#ifndef BOOTMAGIC_KEY_DEBUG_ENABLE
+#define BOOTMAGIC_KEY_DEBUG_ENABLE KC_D
+#endif
+#ifndef BOOTMAGIC_KEY_DEBUG_MATRIX
+#define BOOTMAGIC_KEY_DEBUG_MATRIX KC_X
+#endif
+#ifndef BOOTMAGIC_KEY_DEBUG_KEYBOARD
+#define BOOTMAGIC_KEY_DEBUG_KEYBOARD KC_K
+#endif
+#ifndef BOOTMAGIC_KEY_DEBUG_MOUSE
+#define BOOTMAGIC_KEY_DEBUG_MOUSE KC_M
+#endif
+
+/*
+ * keymap config
+ */
+#ifndef BOOTMAGIC_KEY_SWAP_CONTROL_CAPSLOCK
+#define BOOTMAGIC_KEY_SWAP_CONTROL_CAPSLOCK KC_LCTRL
+#endif
+#ifndef BOOTMAGIC_KEY_CAPSLOCK_TO_CONTROL
+#define BOOTMAGIC_KEY_CAPSLOCK_TO_CONTROL KC_CAPSLOCK
+#endif
+#ifndef BOOTMAGIC_KEY_SWAP_LALT_LGUI
+#define BOOTMAGIC_KEY_SWAP_LALT_LGUI KC_LALT
+#endif
+#ifndef BOOTMAGIC_KEY_SWAP_RALT_RGUI
+#define BOOTMAGIC_KEY_SWAP_RALT_RGUI KC_RALT
+#endif
+#ifndef BOOTMAGIC_KEY_NO_GUI
+#define BOOTMAGIC_KEY_NO_GUI KC_LGUI
+#endif
+#ifndef BOOTMAGIC_KEY_SWAP_GRAVE_ESC
+#define BOOTMAGIC_KEY_SWAP_GRAVE_ESC KC_GRAVE
+#endif
+#ifndef BOOTMAGIC_KEY_SWAP_BACKSLASH_BACKSPACE
+#define BOOTMAGIC_KEY_SWAP_BACKSLASH_BACKSPACE KC_BSLASH
+#endif
+#ifndef BOOTMAGIC_HOST_NKRO
+#define BOOTMAGIC_HOST_NKRO KC_N
+#endif
+
+
+/*
+ * change default layer
+ */
+#ifndef BOOTMAGIC_KEY_DEFAULT_LAYER_0
+#define BOOTMAGIC_KEY_DEFAULT_LAYER_0 KC_0
+#endif
+#ifndef BOOTMAGIC_KEY_DEFAULT_LAYER_1
+#define BOOTMAGIC_KEY_DEFAULT_LAYER_1 KC_1
+#endif
+#ifndef BOOTMAGIC_KEY_DEFAULT_LAYER_2
+#define BOOTMAGIC_KEY_DEFAULT_LAYER_2 KC_2
+#endif
+#ifndef BOOTMAGIC_KEY_DEFAULT_LAYER_3
+#define BOOTMAGIC_KEY_DEFAULT_LAYER_3 KC_3
+#endif
+#ifndef BOOTMAGIC_KEY_DEFAULT_LAYER_4
+#define BOOTMAGIC_KEY_DEFAULT_LAYER_4 KC_4
+#endif
+#ifndef BOOTMAGIC_KEY_DEFAULT_LAYER_5
+#define BOOTMAGIC_KEY_DEFAULT_LAYER_5 KC_5
+#endif
+#ifndef BOOTMAGIC_KEY_DEFAULT_LAYER_6
+#define BOOTMAGIC_KEY_DEFAULT_LAYER_6 KC_6
+#endif
+#ifndef BOOTMAGIC_KEY_DEFAULT_LAYER_7
+#define BOOTMAGIC_KEY_DEFAULT_LAYER_7 KC_7
+#endif
+
+
+void bootmagic(void);
+bool bootmagic_scan_keycode(uint8_t keycode);
+
+#endif
diff --git a/tmk_core/common/chibios/bootloader.c b/tmk_core/common/chibios/bootloader.c
new file mode 100644
index 000000000..8a533ab6f
--- /dev/null
+++ b/tmk_core/common/chibios/bootloader.c
@@ -0,0 +1,47 @@
+#include "bootloader.h"
+
+#include "ch.h"
+#include "hal.h"
+
+#ifdef STM32_BOOTLOADER_ADDRESS
+/* STM32 */
+
+#if defined(STM32F0XX)
+/* This code should be checked whether it runs correctly on platforms */
+#define SYMVAL(sym) (uint32_t)(((uint8_t *)&(sym)) - ((uint8_t *)0))
+extern uint32_t __ram0_end__;
+
+void bootloader_jump(void) {
+ *((unsigned long *)(SYMVAL(__ram0_end__) - 4)) = 0xDEADBEEF; // set magic flag => reset handler will jump into boot loader
+ NVIC_SystemReset();
+}
+
+#else /* defined(STM32F0XX) */
+#error Check that the bootloader code works on your platform and add it to bootloader.c!
+#endif /* defined(STM32F0XX) */
+
+#elif defined(KL2x) || defined(K20x) /* STM32_BOOTLOADER_ADDRESS */
+/* Kinetis */
+
+#if defined(KIIBOHD_BOOTLOADER)
+/* Kiibohd Bootloader (MCHCK and Infinity KB) */
+#define SCB_AIRCR_VECTKEY_WRITEMAGIC 0x05FA0000
+const uint8_t sys_reset_to_loader_magic[] = "\xff\x00\x7fRESET TO LOADER\x7f\x00\xff";
+void bootloader_jump(void) {
+ __builtin_memcpy((void *)VBAT, (const void *)sys_reset_to_loader_magic, sizeof(sys_reset_to_loader_magic));
+ // request reset
+ SCB->AIRCR = SCB_AIRCR_VECTKEY_WRITEMAGIC | SCB_AIRCR_SYSRESETREQ_Msk;
+}
+
+#else /* defined(KIIBOHD_BOOTLOADER) */
+/* Default for Kinetis - expecting an ARM Teensy */
+void bootloader_jump(void) {
+ chThdSleepMilliseconds(100);
+ __BKPT(0);
+}
+#endif /* defined(KIIBOHD_BOOTLOADER) */
+
+#else /* neither STM32 nor KINETIS */
+__attribute__((weak))
+void bootloader_jump(void) {}
+#endif \ No newline at end of file
diff --git a/tmk_core/common/chibios/eeprom.c b/tmk_core/common/chibios/eeprom.c
new file mode 100644
index 000000000..5ff8ee86f
--- /dev/null
+++ b/tmk_core/common/chibios/eeprom.c
@@ -0,0 +1,588 @@
+#include "ch.h"
+#include "hal.h"
+
+#include "eeconfig.h"
+
+/*************************************/
+/* Hardware backend */
+/* */
+/* Code from PJRC/Teensyduino */
+/*************************************/
+
+/* Teensyduino Core Library
+ * http://www.pjrc.com/teensy/
+ * Copyright (c) 2013 PJRC.COM, LLC.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * 1. The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * 2. If the Software is incorporated into a build system that allows
+ * selection among a list of target devices, then similar target
+ * devices manufactured by PJRC.COM must be included in the list of
+ * target devices and selectable in the same manner.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+
+#if defined(K20x) /* chip selection */
+/* Teensy 3.0, 3.1, 3.2; mchck; infinity keyboard */
+
+// The EEPROM is really RAM with a hardware-based backup system to
+// flash memory. Selecting a smaller size EEPROM allows more wear
+// leveling, for higher write endurance. If you edit this file,
+// set this to the smallest size your application can use. Also,
+// due to Freescale's implementation, writing 16 or 32 bit words
+// (aligned to 2 or 4 byte boundaries) has twice the endurance
+// compared to writing 8 bit bytes.
+//
+#define EEPROM_SIZE 32
+
+// Writing unaligned 16 or 32 bit data is handled automatically when
+// this is defined, but at a cost of extra code size. Without this,
+// any unaligned write will cause a hard fault exception! If you're
+// absolutely sure all 16 and 32 bit writes will be aligned, you can
+// remove the extra unnecessary code.
+//
+#define HANDLE_UNALIGNED_WRITES
+
+// Minimum EEPROM Endurance
+// ------------------------
+#if (EEPROM_SIZE == 2048) // 35000 writes/byte or 70000 writes/word
+ #define EEESIZE 0x33
+#elif (EEPROM_SIZE == 1024) // 75000 writes/byte or 150000 writes/word
+ #define EEESIZE 0x34
+#elif (EEPROM_SIZE == 512) // 155000 writes/byte or 310000 writes/word
+ #define EEESIZE 0x35
+#elif (EEPROM_SIZE == 256) // 315000 writes/byte or 630000 writes/word
+ #define EEESIZE 0x36
+#elif (EEPROM_SIZE == 128) // 635000 writes/byte or 1270000 writes/word
+ #define EEESIZE 0x37
+#elif (EEPROM_SIZE == 64) // 1275000 writes/byte or 2550000 writes/word
+ #define EEESIZE 0x38
+#elif (EEPROM_SIZE == 32) // 2555000 writes/byte or 5110000 writes/word
+ #define EEESIZE 0x39
+#endif
+
+void eeprom_initialize(void)
+{
+ uint32_t count=0;
+ uint16_t do_flash_cmd[] = {
+ 0xf06f, 0x037f, 0x7003, 0x7803,
+ 0xf013, 0x0f80, 0xd0fb, 0x4770};
+ uint8_t status;
+
+ if (FTFL->FCNFG & FTFL_FCNFG_RAMRDY) {
+ // FlexRAM is configured as traditional RAM
+ // We need to reconfigure for EEPROM usage
+ FTFL->FCCOB0 = 0x80; // PGMPART = Program Partition Command
+ FTFL->FCCOB4 = EEESIZE; // EEPROM Size
+ FTFL->FCCOB5 = 0x03; // 0K for Dataflash, 32K for EEPROM backup
+ __disable_irq();
+ // do_flash_cmd() must execute from RAM. Luckily the C syntax is simple...
+ (*((void (*)(volatile uint8_t *))((uint32_t)do_flash_cmd | 1)))(&(FTFL->FSTAT));
+ __enable_irq();
+ status = FTFL->FSTAT;
+ if (status & (FTFL_FSTAT_RDCOLERR|FTFL_FSTAT_ACCERR|FTFL_FSTAT_FPVIOL)) {
+ FTFL->FSTAT = (status & (FTFL_FSTAT_RDCOLERR|FTFL_FSTAT_ACCERR|FTFL_FSTAT_FPVIOL));
+ return; // error
+ }
+ }
+ // wait for eeprom to become ready (is this really necessary?)
+ while (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) {
+ if (++count > 20000) break;
+ }
+}
+
+#define FlexRAM ((uint8_t *)0x14000000)
+
+uint8_t eeprom_read_byte(const uint8_t *addr)
+{
+ uint32_t offset = (uint32_t)addr;
+ if (offset >= EEPROM_SIZE) return 0;
+ if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
+ return FlexRAM[offset];
+}
+
+uint16_t eeprom_read_word(const uint16_t *addr)
+{
+ uint32_t offset = (uint32_t)addr;
+ if (offset >= EEPROM_SIZE-1) return 0;
+ if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
+ return *(uint16_t *)(&FlexRAM[offset]);
+}
+
+uint32_t eeprom_read_dword(const uint32_t *addr)
+{
+ uint32_t offset = (uint32_t)addr;
+ if (offset >= EEPROM_SIZE-3) return 0;
+ if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
+ return *(uint32_t *)(&FlexRAM[offset]);
+}
+
+void eeprom_read_block(void *buf, const void *addr, uint32_t len)
+{
+ uint32_t offset = (uint32_t)addr;
+ uint8_t *dest = (uint8_t *)buf;
+ uint32_t end = offset + len;
+
+ if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
+ if (end > EEPROM_SIZE) end = EEPROM_SIZE;
+ while (offset < end) {
+ *dest++ = FlexRAM[offset++];
+ }
+}
+
+int eeprom_is_ready(void)
+{
+ return (FTFL->FCNFG & FTFL_FCNFG_EEERDY) ? 1 : 0;
+}
+
+static void flexram_wait(void)
+{
+ while (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) {
+ // TODO: timeout
+ }
+}
+
+void eeprom_write_byte(uint8_t *addr, uint8_t value)
+{
+ uint32_t offset = (uint32_t)addr;
+
+ if (offset >= EEPROM_SIZE) return;
+ if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
+ if (FlexRAM[offset] != value) {
+ FlexRAM[offset] = value;
+ flexram_wait();
+ }
+}
+
+void eeprom_write_word(uint16_t *addr, uint16_t value)
+{
+ uint32_t offset = (uint32_t)addr;
+
+ if (offset >= EEPROM_SIZE-1) return;
+ if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
+#ifdef HANDLE_UNALIGNED_WRITES
+ if ((offset & 1) == 0) {
+#endif
+ if (*(uint16_t *)(&FlexRAM[offset]) != value) {
+ *(uint16_t *)(&FlexRAM[offset]) = value;
+ flexram_wait();
+ }
+#ifdef HANDLE_UNALIGNED_WRITES
+ } else {
+ if (FlexRAM[offset] != value) {
+ FlexRAM[offset] = value;
+ flexram_wait();
+ }
+ if (FlexRAM[offset + 1] != (value >> 8)) {
+ FlexRAM[offset + 1] = value >> 8;
+ flexram_wait();
+ }
+ }
+#endif
+}
+
+void eeprom_write_dword(uint32_t *addr, uint32_t value)
+{
+ uint32_t offset = (uint32_t)addr;
+
+ if (offset >= EEPROM_SIZE-3) return;
+ if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
+#ifdef HANDLE_UNALIGNED_WRITES
+ switch (offset & 3) {
+ case 0:
+#endif
+ if (*(uint32_t *)(&FlexRAM[offset]) != value) {
+ *(uint32_t *)(&FlexRAM[offset]) = value;
+ flexram_wait();
+ }
+ return;
+#ifdef HANDLE_UNALIGNED_WRITES
+ case 2:
+ if (*(uint16_t *)(&FlexRAM[offset]) != value) {
+ *(uint16_t *)(&FlexRAM[offset]) = value;
+ flexram_wait();
+ }
+ if (*(uint16_t *)(&FlexRAM[offset + 2]) != (value >> 16)) {
+ *(uint16_t *)(&FlexRAM[offset + 2]) = value >> 16;
+ flexram_wait();
+ }
+ return;
+ default:
+ if (FlexRAM[offset] != value) {
+ FlexRAM[offset] = value;
+ flexram_wait();
+ }
+ if (*(uint16_t *)(&FlexRAM[offset + 1]) != (value >> 8)) {
+ *(uint16_t *)(&FlexRAM[offset + 1]) = value >> 8;
+ flexram_wait();
+ }
+ if (FlexRAM[offset + 3] != (value >> 24)) {
+ FlexRAM[offset + 3] = value >> 24;
+ flexram_wait();
+ }
+ }
+#endif
+}
+
+void eeprom_write_block(const void *buf, void *addr, uint32_t len)
+{
+ uint32_t offset = (uint32_t)addr;
+ const uint8_t *src = (const uint8_t *)buf;
+
+ if (offset >= EEPROM_SIZE) return;
+ if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
+ if (len >= EEPROM_SIZE) len = EEPROM_SIZE;
+ if (offset + len >= EEPROM_SIZE) len = EEPROM_SIZE - offset;
+ while (len > 0) {
+ uint32_t lsb = offset & 3;
+ if (lsb == 0 && len >= 4) {
+ // write aligned 32 bits
+ uint32_t val32;
+ val32 = *src++;
+ val32 |= (*src++ << 8);
+ val32 |= (*src++ << 16);
+ val32 |= (*src++ << 24);
+ if (*(uint32_t *)(&FlexRAM[offset]) != val32) {
+ *(uint32_t *)(&FlexRAM[offset]) = val32;
+ flexram_wait();
+ }
+ offset += 4;
+ len -= 4;
+ } else if ((lsb == 0 || lsb == 2) && len >= 2) {
+ // write aligned 16 bits
+ uint16_t val16;
+ val16 = *src++;
+ val16 |= (*src++ << 8);
+ if (*(uint16_t *)(&FlexRAM[offset]) != val16) {
+ *(uint16_t *)(&FlexRAM[offset]) = val16;
+ flexram_wait();
+ }
+ offset += 2;
+ len -= 2;
+ } else {
+ // write 8 bits
+ uint8_t val8 = *src++;
+ if (FlexRAM[offset] != val8) {
+ FlexRAM[offset] = val8;
+ flexram_wait();
+ }
+ offset++;
+ len--;
+ }
+ }
+}
+
+/*
+void do_flash_cmd(volatile uint8_t *fstat)
+{
+ *fstat = 0x80;
+ while ((*fstat & 0x80) == 0) ; // wait
+}
+00000000 <do_flash_cmd>:
+ 0: f06f 037f mvn.w r3, #127 ; 0x7f
+ 4: 7003 strb r3, [r0, #0]
+ 6: 7803 ldrb r3, [r0, #0]
+ 8: f013 0f80 tst.w r3, #128 ; 0x80
+ c: d0fb beq.n 6 <do_flash_cmd+0x6>
+ e: 4770 bx lr
+*/
+
+#elif defined(KL2x) /* chip selection */
+/* Teensy LC (emulated) */
+
+#define SYMVAL(sym) (uint32_t)(((uint8_t *)&(sym)) - ((uint8_t *)0))
+
+extern uint32_t __eeprom_workarea_start__;
+extern uint32_t __eeprom_workarea_end__;
+
+#define EEPROM_SIZE 128
+
+static uint32_t flashend = 0;
+
+void eeprom_initialize(void)
+{
+ const uint16_t *p = (uint16_t *)SYMVAL(__eeprom_workarea_start__);
+
+ do {
+ if (*p++ == 0xFFFF) {
+ flashend = (uint32_t)(p - 2);
+ return;
+ }
+ } while (p < (uint16_t *)SYMVAL(__eeprom_workarea_end__));
+ flashend = (uint32_t)((uint16_t *)SYMVAL(__eeprom_workarea_end__) - 1);
+}
+
+uint8_t eeprom_read_byte(const uint8_t *addr)
+{
+ uint32_t offset = (uint32_t)addr;
+ const uint16_t *p = (uint16_t *)SYMVAL(__eeprom_workarea_start__);
+ const uint16_t *end = (const uint16_t *)((uint32_t)flashend);
+ uint16_t val;
+ uint8_t data=0xFF;
+
+ if (!end) {
+ eeprom_initialize();
+ end = (const uint16_t *)((uint32_t)flashend);
+ }
+ if (offset < EEPROM_SIZE) {
+ while (p <= end) {
+ val = *p++;
+ if ((val & 255) == offset) data = val >> 8;
+ }
+ }
+ return data;
+}
+
+static void flash_write(const uint16_t *code, uint32_t addr, uint32_t data)
+{
+ // with great power comes great responsibility....
+ uint32_t stat;
+ *(uint32_t *)&(FTFA->FCCOB3) = 0x06000000 | (addr & 0x00FFFFFC);
+ *(uint32_t *)&(FTFA->FCCOB7) = data;
+ __disable_irq();
+ (*((void (*)(volatile uint8_t *))((uint32_t)code | 1)))(&(FTFA->FSTAT));
+ __enable_irq();
+ stat = FTFA->FSTAT & (FTFA_FSTAT_RDCOLERR|FTFA_FSTAT_ACCERR|FTFA_FSTAT_FPVIOL);
+ if (stat) {
+ FTFA->FSTAT = stat;
+ }
+ MCM->PLACR |= MCM_PLACR_CFCC;
+}
+
+void eeprom_write_byte(uint8_t *addr, uint8_t data)
+{
+ uint32_t offset = (uint32_t)addr;
+ const uint16_t *p, *end = (const uint16_t *)((uint32_t)flashend);
+ uint32_t i, val, flashaddr;
+ uint16_t do_flash_cmd[] = {
+ 0x2380, 0x7003, 0x7803, 0xb25b, 0x2b00, 0xdafb, 0x4770};
+ uint8_t buf[EEPROM_SIZE];
+
+ if (offset >= EEPROM_SIZE) return;
+ if (!end) {
+ eeprom_initialize();
+ end = (const uint16_t *)((uint32_t)flashend);
+ }
+ if (++end < (uint16_t *)SYMVAL(__eeprom_workarea_end__)) {
+ val = (data << 8) | offset;
+ flashaddr = (uint32_t)end;
+ flashend = flashaddr;
+ if ((flashaddr & 2) == 0) {
+ val |= 0xFFFF0000;
+ } else {
+ val <<= 16;
+ val |= 0x0000FFFF;
+ }
+ flash_write(do_flash_cmd, flashaddr, val);
+ } else {
+ for (i=0; i < EEPROM_SIZE; i++) {
+ buf[i] = 0xFF;
+ }
+ val = 0;
+ for (p = (uint16_t *)SYMVAL(__eeprom_workarea_start__); p < (uint16_t *)SYMVAL(__eeprom_workarea_end__); p++) {
+ val = *p;
+ if ((val & 255) < EEPROM_SIZE) {
+ buf[val & 255] = val >> 8;
+ }
+ }
+ buf[offset] = data;
+ for (flashaddr=(uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_start__); flashaddr < (uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_end__); flashaddr += 1024) {
+ *(uint32_t *)&(FTFA->FCCOB3) = 0x09000000 | flashaddr;
+ __disable_irq();
+ (*((void (*)(volatile uint8_t *))((uint32_t)do_flash_cmd | 1)))(&(FTFA->FSTAT));
+ __enable_irq();
+ val = FTFA->FSTAT & (FTFA_FSTAT_RDCOLERR|FTFA_FSTAT_ACCERR|FTFA_FSTAT_FPVIOL);;
+ if (val) FTFA->FSTAT = val;
+ MCM->PLACR |= MCM_PLACR_CFCC;
+ }
+ flashaddr=(uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_start__);
+ for (i=0; i < EEPROM_SIZE; i++) {
+ if (buf[i] == 0xFF) continue;
+ if ((flashaddr & 2) == 0) {
+ val = (buf[i] << 8) | i;
+ } else {
+ val = val | (buf[i] << 24) | (i << 16);
+ flash_write(do_flash_cmd, flashaddr, val);
+ }
+ flashaddr += 2;
+ }
+ flashend = flashaddr;
+ if ((flashaddr & 2)) {
+ val |= 0xFFFF0000;
+ flash_write(do_flash_cmd, flashaddr, val);
+ }
+ }
+}
+
+/*
+void do_flash_cmd(volatile uint8_t *fstat)
+{
+ *fstat = 0x80;
+ while ((*fstat & 0x80) == 0) ; // wait
+}
+00000000 <do_flash_cmd>:
+ 0: 2380 movs r3, #128 ; 0x80
+ 2: 7003 strb r3, [r0, #0]
+ 4: 7803 ldrb r3, [r0, #0]
+ 6: b25b sxtb r3, r3
+ 8: 2b00 cmp r3, #0
+ a: dafb bge.n 4 <do_flash_cmd+0x4>
+ c: 4770 bx lr
+*/
+
+
+uint16_t eeprom_read_word(const uint16_t *addr)
+{
+ const uint8_t *p = (const uint8_t *)addr;
+ return eeprom_read_byte(p) | (eeprom_read_byte(p+1) << 8);
+}
+
+uint32_t eeprom_read_dword(const uint32_t *addr)
+{
+ const uint8_t *p = (const uint8_t *)addr;
+ return eeprom_read_byte(p) | (eeprom_read_byte(p+1) << 8)
+ | (eeprom_read_byte(p+2) << 16) | (eeprom_read_byte(p+3) << 24);
+}
+
+void eeprom_read_block(void *buf, const void *addr, uint32_t len)
+{
+ const uint8_t *p = (const uint8_t *)addr;
+ uint8_t *dest = (uint8_t *)buf;
+ while (len--) {
+ *dest++ = eeprom_read_byte(p++);
+ }
+}
+
+int eeprom_is_ready(void)
+{
+ return 1;
+}
+
+void eeprom_write_word(uint16_t *addr, uint16_t value)
+{
+ uint8_t *p = (uint8_t *)addr;
+ eeprom_write_byte(p++, value);
+ eeprom_write_byte(p, value >> 8);
+}
+
+void eeprom_write_dword(uint32_t *addr, uint32_t value)
+{
+ uint8_t *p = (uint8_t *)addr;
+ eeprom_write_byte(p++, value);
+ eeprom_write_byte(p++, value >> 8);
+ eeprom_write_byte(p++, value >> 16);
+ eeprom_write_byte(p, value >> 24);
+}
+
+void eeprom_write_block(const void *buf, void *addr, uint32_t len)
+{
+ uint8_t *p = (uint8_t *)addr;
+ const uint8_t *src = (const uint8_t *)buf;
+ while (len--) {
+ eeprom_write_byte(p++, *src++);
+ }
+}
+
+#else
+// No EEPROM supported, so emulate it
+
+#define EEPROM_SIZE 32
+static uint8_t buffer[EEPROM_SIZE];
+
+uint8_t eeprom_read_byte(const uint8_t *addr) {
+ uint32_t offset = (uint32_t)addr;
+ return buffer[offset];
+}
+
+void eeprom_write_byte(uint8_t *addr, uint8_t value) {
+ uint32_t offset = (uint32_t)addr;
+ buffer[offset] = value;
+}
+
+uint16_t eeprom_read_word(const uint16_t *addr) {
+ const uint8_t *p = (const uint8_t *)addr;
+ return eeprom_read_byte(p) | (eeprom_read_byte(p+1) << 8);
+}
+
+uint32_t eeprom_read_dword(const uint32_t *addr) {
+ const uint8_t *p = (const uint8_t *)addr;
+ return eeprom_read_byte(p) | (eeprom_read_byte(p+1) << 8)
+ | (eeprom_read_byte(p+2) << 16) | (eeprom_read_byte(p+3) << 24);
+}
+
+void eeprom_read_block(void *buf, const void *addr, uint32_t len) {
+ const uint8_t *p = (const uint8_t *)addr;
+ uint8_t *dest = (uint8_t *)buf;
+ while (len--) {
+ *dest++ = eeprom_read_byte(p++);
+ }
+}
+
+void eeprom_write_word(uint16_t *addr, uint16_t value) {
+ uint8_t *p = (uint8_t *)addr;
+ eeprom_write_byte(p++, value);
+ eeprom_write_byte(p, value >> 8);
+}
+
+void eeprom_write_dword(uint32_t *addr, uint32_t value) {
+ uint8_t *p = (uint8_t *)addr;
+ eeprom_write_byte(p++, value);
+ eeprom_write_byte(p++, value >> 8);
+ eeprom_write_byte(p++, value >> 16);
+ eeprom_write_byte(p, value >> 24);
+}
+
+void eeprom_write_block(const void *buf, void *addr, uint32_t len) {
+ uint8_t *p = (uint8_t *)addr;
+ const uint8_t *src = (const uint8_t *)buf;
+ while (len--) {
+ eeprom_write_byte(p++, *src++);
+ }
+}
+
+#endif /* chip selection */
+// The update functions just calls write for now, but could probably be optimized
+
+void eeprom_update_byte(uint8_t *addr, uint8_t value) {
+ eeprom_write_byte(addr, value);
+}
+
+void eeprom_update_word(uint16_t *addr, uint16_t value) {
+ uint8_t *p = (uint8_t *)addr;
+ eeprom_write_byte(p++, value);
+ eeprom_write_byte(p, value >> 8);
+}
+
+void eeprom_update_dword(uint32_t *addr, uint32_t value) {
+ uint8_t *p = (uint8_t *)addr;
+ eeprom_write_byte(p++, value);
+ eeprom_write_byte(p++, value >> 8);
+ eeprom_write_byte(p++, value >> 16);
+ eeprom_write_byte(p, value >> 24);
+}
+
+void eeprom_update_block(const void *buf, void *addr, uint32_t len) {
+ uint8_t *p = (uint8_t *)addr;
+ const uint8_t *src = (const uint8_t *)buf;
+ while (len--) {
+ eeprom_write_byte(p++, *src++);
+ }
+}
diff --git a/tmk_core/common/chibios/printf.c b/tmk_core/common/chibios/printf.c
new file mode 100644
index 000000000..72e3d4f8c
--- /dev/null
+++ b/tmk_core/common/chibios/printf.c
@@ -0,0 +1,240 @@
+/*
+ * found at: http://www.sparetimelabs.com/tinyprintf/tinyprintf.php
+ * and: http://www.sparetimelabs.com/printfrevisited/printfrevisited.php
+ */
+
+/*
+File: printf.c
+
+Copyright (C) 2004 Kustaa Nyholm
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*/
+
+#include "printf.h"
+
+typedef void (*putcf) (void*,char);
+static putcf stdout_putf;
+static void* stdout_putp;
+
+// this adds cca 400 bytes
+#define PRINTF_LONG_SUPPORT
+
+#ifdef PRINTF_LONG_SUPPORT
+
+static void uli2a(unsigned long int num, unsigned int base, int uc,char * bf)
+ {
+ int n=0;
+ unsigned int d=1;
+ while (num/d >= base)
+ d*=base;
+ while (d!=0) {
+ int dgt = num / d;
+ num%=d;
+ d/=base;
+ if (n || dgt>0|| d==0) {
+ *bf++ = dgt+(dgt<10 ? '0' : (uc ? 'A' : 'a')-10);
+ ++n;
+ }
+ }
+ *bf=0;
+ }
+
+static void li2a (long num, char * bf)
+ {
+ if (num<0) {
+ num=-num;
+ *bf++ = '-';
+ }
+ uli2a(num,10,0,bf);
+ }
+
+#endif
+
+static void ui2a(unsigned int num, unsigned int base, int uc,char * bf)
+ {
+ int n=0;
+ unsigned int d=1;
+ while (num/d >= base)
+ d*=base;
+ while (d!=0) {
+ int dgt = num / d;
+ num%= d;
+ d/=base;
+ if (n || dgt>0 || d==0) {
+ *bf++ = dgt+(dgt<10 ? '0' : (uc ? 'A' : 'a')-10);
+ ++n;
+ }
+ }
+ *bf=0;
+ }
+
+static void i2a (int num, char * bf)
+ {
+ if (num<0) {
+ num=-num;
+ *bf++ = '-';
+ }
+ ui2a(num,10,0,bf);
+ }
+
+static int a2d(char ch)
+ {
+ if (ch>='0' && ch<='9')
+ return ch-'0';
+ else if (ch>='a' && ch<='f')
+ return ch-'a'+10;
+ else if (ch>='A' && ch<='F')
+ return ch-'A'+10;
+ else return -1;
+ }
+
+static char a2i(char ch, char** src,int base,int* nump)
+ {
+ char* p= *src;
+ int num=0;
+ int digit;
+ while ((digit=a2d(ch))>=0) {
+ if (digit>base) break;
+ num=num*base+digit;
+ ch=*p++;
+ }
+ *src=p;
+ *nump=num;
+ return ch;
+ }
+
+static void putchw(void* putp,putcf putf,int n, char z, char* bf)
+ {
+ char fc=z? '0' : ' ';
+ char ch;
+ char* p=bf;
+ while (*p++ && n > 0)
+ n--;
+ while (n-- > 0)
+ putf(putp,fc);
+ while ((ch= *bf++))
+ putf(putp,ch);
+ }
+
+void tfp_format(void* putp,putcf putf,char *fmt, va_list va)
+ {
+ char bf[12];
+
+ char ch;
+
+
+ while ((ch=*(fmt++))) {
+ if (ch!='%')
+ putf(putp,ch);
+ else {
+ char lz=0;
+#ifdef PRINTF_LONG_SUPPORT
+ char lng=0;
+#endif
+ int w=0;
+ ch=*(fmt++);
+ if (ch=='0') {
+ ch=*(fmt++);
+ lz=1;
+ }
+ if (ch>='0' && ch<='9') {
+ ch=a2i(ch,&fmt,10,&w);
+ }
+#ifdef PRINTF_LONG_SUPPORT
+ if (ch=='l') {
+ ch=*(fmt++);
+ lng=1;
+ }
+#endif
+ switch (ch) {
+ case 0:
+ goto abort;
+ case 'u' : {
+#ifdef PRINTF_LONG_SUPPORT
+ if (lng)
+ uli2a(va_arg(va, unsigned long int),10,0,bf);
+ else
+#endif
+ ui2a(va_arg(va, unsigned int),10,0,bf);
+ putchw(putp,putf,w,lz,bf);
+ break;
+ }
+ case 'd' : {
+#ifdef PRINTF_LONG_SUPPORT
+ if (lng)
+ li2a(va_arg(va, unsigned long int),bf);
+ else
+#endif
+ i2a(va_arg(va, int),bf);
+ putchw(putp,putf,w,lz,bf);
+ break;
+ }
+ case 'x': case 'X' :
+#ifdef PRINTF_LONG_SUPPORT
+ if (lng)
+ uli2a(va_arg(va, unsigned long int),16,(ch=='X'),bf);
+ else
+#endif
+ ui2a(va_arg(va, unsigned int),16,(ch=='X'),bf);
+ putchw(putp,putf,w,lz,bf);
+ break;
+ case 'c' :
+ putf(putp,(char)(va_arg(va, int)));
+ break;
+ case 's' :
+ putchw(putp,putf,w,0,va_arg(va, char*));
+ break;
+ case '%' :
+ putf(putp,ch);
+ default:
+ break;
+ }
+ }
+ }
+ abort:;
+ }
+
+
+void init_printf(void* putp,void (*putf) (void*,char))
+ {
+ stdout_putf=putf;
+ stdout_putp=putp;
+ }
+
+void tfp_printf(char *fmt, ...)
+ {
+ va_list va;
+ va_start(va,fmt);
+ tfp_format(stdout_putp,stdout_putf,fmt,va);
+ va_end(va);
+ }
+
+static void putcp(void* p,char c)
+ {
+ *(*((char**)p))++ = c;
+ }
+
+
+
+void tfp_sprintf(char* s,char *fmt, ...)
+ {
+ va_list va;
+ va_start(va,fmt);
+ tfp_format(&s,putcp,fmt,va);
+ putcp(&s,0);
+ va_end(va);
+ }
diff --git a/tmk_core/common/chibios/printf.h b/tmk_core/common/chibios/printf.h
new file mode 100644
index 000000000..678a100c6
--- /dev/null
+++ b/tmk_core/common/chibios/printf.h
@@ -0,0 +1,111 @@
+/*
+ * found at: http://www.sparetimelabs.com/tinyprintf/tinyprintf.php
+ * and: http://www.sparetimelabs.com/printfrevisited/printfrevisited.php
+ */
+
+/*
+File: printf.h
+
+Copyright (C) 2004 Kustaa Nyholm
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+This library is realy just two files: 'printf.h' and 'printf.c'.
+
+They provide a simple and small (+200 loc) printf functionality to
+be used in embedded systems.
+
+I've found them so usefull in debugging that I do not bother with a
+debugger at all.
+
+They are distributed in source form, so to use them, just compile them
+into your project.
+
+Two printf variants are provided: printf and sprintf.
+
+The formats supported by this implementation are: 'd' 'u' 'c' 's' 'x' 'X'.
+
+Zero padding and field width are also supported.
+
+If the library is compiled with 'PRINTF_SUPPORT_LONG' defined then the
+long specifier is also
+supported. Note that this will pull in some long math routines (pun intended!)
+and thus make your executable noticably longer.
+
+The memory foot print of course depends on the target cpu, compiler and
+compiler options, but a rough guestimate (based on a H8S target) is about
+1.4 kB for code and some twenty 'int's and 'char's, say 60 bytes of stack space.
+Not too bad. Your milage may vary. By hacking the source code you can
+get rid of some hunred bytes, I'm sure, but personally I feel the balance of
+functionality and flexibility versus code size is close to optimal for
+many embedded systems.
+
+To use the printf you need to supply your own character output function,
+something like :
+
+ void putc ( void* p, char c)
+ {
+ while (!SERIAL_PORT_EMPTY) ;
+ SERIAL_PORT_TX_REGISTER = c;
+ }
+
+Before you can call printf you need to initialize it to use your
+character output function with something like:
+
+ init_printf(NULL,putc);
+
+Notice the 'NULL' in 'init_printf' and the parameter 'void* p' in 'putc',
+the NULL (or any pointer) you pass into the 'init_printf' will eventually be
+passed to your 'putc' routine. This allows you to pass some storage space (or
+anything realy) to the character output function, if necessary.
+This is not often needed but it was implemented like that because it made
+implementing the sprintf function so neat (look at the source code).
+
+The code is re-entrant, except for the 'init_printf' function, so it
+is safe to call it from interupts too, although this may result in mixed output.
+If you rely on re-entrancy, take care that your 'putc' function is re-entrant!
+
+The printf and sprintf functions are actually macros that translate to
+'tfp_printf' and 'tfp_sprintf'. This makes it possible
+to use them along with 'stdio.h' printf's in a single source file.
+You just need to undef the names before you include the 'stdio.h'.
+Note that these are not function like macros, so if you have variables
+or struct members with these names, things will explode in your face.
+Without variadic macros this is the best we can do to wrap these
+fucnction. If it is a problem just give up the macros and use the
+functions directly or rename them.
+
+For further details see source code.
+
+regs Kusti, 23.10.2004
+*/
+
+
+#ifndef __TFP_PRINTF__
+#define __TFP_PRINTF__
+
+#include <stdarg.h>
+
+void init_printf(void* putp,void (*putf) (void*,char));
+
+void tfp_printf(char *fmt, ...);
+void tfp_sprintf(char* s,char *fmt, ...);
+
+void tfp_format(void* putp,void (*putf) (void*,char),char *fmt, va_list va);
+
+#define printf tfp_printf
+#define sprintf tfp_sprintf
+
+#endif
diff --git a/tmk_core/common/chibios/sleep_led.c b/tmk_core/common/chibios/sleep_led.c
new file mode 100644
index 000000000..4c35cfcba
--- /dev/null
+++ b/tmk_core/common/chibios/sleep_led.c
@@ -0,0 +1,226 @@
+#include "ch.h"
+#include "hal.h"
+
+#include "led.h"
+#include "sleep_led.h"
+
+/* All right, we go the "software" way: timer, toggle LED in interrupt.
+ * Based on hasu's code for AVRs.
+ * Use LP timer on Kinetises, TIM14 on STM32F0.
+ */
+
+#if defined(KL2x) || defined(K20x)
+
+/* Use Low Power Timer (LPTMR) */
+#define TIMER_INTERRUPT_VECTOR KINETIS_LPTMR0_IRQ_VECTOR
+#define RESET_COUNTER LPTMR0->CSR |= LPTMRx_CSR_TCF
+
+#elif defined(STM32F0XX)
+
+/* Use TIM14 manually */
+#define TIMER_INTERRUPT_VECTOR STM32_TIM14_HANDLER
+#define RESET_COUNTER STM32_TIM14->SR &= ~STM32_TIM_SR_UIF
+
+#endif
+
+#if defined(KL2x) || defined(K20x) || defined(STM32F0XX) /* common parts for timers/interrupts */
+
+/* Breathing Sleep LED brighness(PWM On period) table
+ * (64[steps] * 4[duration]) / 64[PWM periods/s] = 4 second breath cycle
+ *
+ * http://www.wolframalpha.com/input/?i=%28sin%28+x%2F64*pi%29**8+*+255%2C+x%3D0+to+63
+ * (0..63).each {|x| p ((sin(x/64.0*PI)**8)*255).to_i }
+ */
+static const uint8_t breathing_table[64] = {
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 4, 6, 10,
+15, 23, 32, 44, 58, 74, 93, 113, 135, 157, 179, 199, 218, 233, 245, 252,
+255, 252, 245, 233, 218, 199, 179, 157, 135, 113, 93, 74, 58, 44, 32, 23,
+15, 10, 6, 4, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* interrupt handler */
+OSAL_IRQ_HANDLER(TIMER_INTERRUPT_VECTOR) {
+ OSAL_IRQ_PROLOGUE();
+
+ /* Software PWM
+ * timer:1111 1111 1111 1111
+ * \_____/\/ \_______/____ count(0-255)
+ * \ \______________ duration of step(4)
+ * \__________________ index of step table(0-63)
+ */
+
+ // this works for cca 65536 irqs/sec
+ static union {
+ uint16_t row;
+ struct {
+ uint8_t count:8;
+ uint8_t duration:2;
+ uint8_t index:6;
+ } pwm;
+ } timer = { .row = 0 };
+
+ timer.row++;
+
+ // LED on
+ if (timer.pwm.count == 0) {
+ led_set(1<<USB_LED_CAPS_LOCK);
+ }
+ // LED off
+ if (timer.pwm.count == breathing_table[timer.pwm.index]) {
+ led_set(0);
+ }
+
+ /* Reset the counter */
+ RESET_COUNTER;
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+#endif /* common parts for known platforms */
+
+
+#if defined(KL2x) || defined(K20x) /* platform selection: familiar Kinetis chips */
+
+/* LPTMR clock options */
+#define LPTMR_CLOCK_MCGIRCLK 0 /* 4MHz clock */
+#define LPTMR_CLOCK_LPO 1 /* 1kHz clock */
+#define LPTMR_CLOCK_ERCLK32K 2 /* external 32kHz crystal */
+#define LPTMR_CLOCK_OSCERCLK 3 /* output from OSC */
+
+/* Work around inconsistencies in Freescale naming */
+#if !defined(SIM_SCGC5_LPTMR)
+#define SIM_SCGC5_LPTMR SIM_SCGC5_LPTIMER
+#endif
+
+/* Initialise the timer */
+void sleep_led_init(void) {
+ /* Make sure the clock to the LPTMR is enabled */
+ SIM->SCGC5 |= SIM_SCGC5_LPTMR;
+ /* Reset LPTMR settings */
+ LPTMR0->CSR = 0;
+ /* Set the compare value */
+ LPTMR0->CMR = 0; // trigger on counter value (i.e. every time)
+
+ /* Set up clock source and prescaler */
+ /* Software PWM
+ * ______ ______ __
+ * | ON |___OFF___| ON |___OFF___| ....
+ * |<-------------->|<-------------->|<- ....
+ * PWM period PWM period
+ *
+ * R interrupts/period[resolution]
+ * F periods/second[frequency]
+ * R * F interrupts/second
+ */
+
+ /* === OPTION 1 === */
+ #if 0
+ // 1kHz LPO
+ // No prescaler => 1024 irqs/sec
+ // Note: this is too slow for a smooth breathe
+ LPTMR0->PSR = LPTMRx_PSR_PCS(LPTMR_CLOCK_LPO)|LPTMRx_PSR_PBYP;
+ #endif /* OPTION 1 */
+
+ /* === OPTION 2 === */
+ #if 1
+ // nMHz IRC (n=4 on KL25Z, KL26Z and K20x; n=2 or 8 on KL27Z)
+ MCG->C2 |= MCG_C2_IRCS; // fast (4MHz) internal ref clock
+ #if defined(KL27) // divide the 8MHz IRC by 2, to have the same MCGIRCLK speed as others
+ MCG->MC |= MCG_MC_LIRC_DIV2_DIV2;
+ #endif /* KL27 */
+ MCG->C1 |= MCG_C1_IRCLKEN; // enable internal ref clock
+ // to work in stop mode, also MCG_C1_IREFSTEN
+ // Divide 4MHz by 2^N (N=6) => 62500 irqs/sec =>
+ // => approx F=61, R=256, duration = 4
+ LPTMR0->PSR = LPTMRx_PSR_PCS(LPTMR_CLOCK_MCGIRCLK)|LPTMRx_PSR_PRESCALE(6);
+ #endif /* OPTION 2 */
+
+ /* === OPTION 3 === */
+ #if 0
+ // OSC output (external crystal), usually 8MHz or 16MHz
+ OSC0->CR |= OSC_CR_ERCLKEN; // enable ext ref clock
+ // to work in stop mode, also OSC_CR_EREFSTEN
+ // Divide by 2^N
+ LPTMR0->PSR = LPTMRx_PSR_PCS(LPTMR_CLOCK_OSCERCLK)|LPTMRx_PSR_PRESCALE(7);
+ #endif /* OPTION 3 */
+ /* === END OPTIONS === */
+
+ /* Interrupt on TCF set (compare flag) */
+ nvicEnableVector(LPTMR0_IRQn, 2); // vector, priority
+ LPTMR0->CSR |= LPTMRx_CSR_TIE;
+}
+
+void sleep_led_enable(void) {
+ /* Enable the timer */
+ LPTMR0->CSR |= LPTMRx_CSR_TEN;
+}
+
+void sleep_led_disable(void) {
+ /* Disable the timer */
+ LPTMR0->CSR &= ~LPTMRx_CSR_TEN;
+}
+
+void sleep_led_toggle(void) {
+ /* Toggle the timer */
+ LPTMR0->CSR ^= LPTMRx_CSR_TEN;
+}
+
+#elif defined(STM32F0XX) /* platform selection: STM32F0XX */
+
+/* Initialise the timer */
+void sleep_led_init(void) {
+ /* enable clock */
+ rccEnableTIM14(FALSE); /* low power enable = FALSE */
+ rccResetTIM14();
+
+ /* prescale */
+ /* Assuming 48MHz internal clock */
+ /* getting cca 65484 irqs/sec */
+ STM32_TIM14->PSC = 733;
+
+ /* auto-reload */
+ /* 0 => interrupt every time */
+ STM32_TIM14->ARR = 3;
+
+ /* enable counter update event interrupt */
+ STM32_TIM14->DIER |= STM32_TIM_DIER_UIE;
+
+ /* register interrupt vector */
+ nvicEnableVector(STM32_TIM14_NUMBER, 2); /* vector, priority */
+}
+
+void sleep_led_enable(void) {
+ /* Enable the timer */
+ STM32_TIM14->CR1 = STM32_TIM_CR1_CEN | STM32_TIM_CR1_URS;
+ /* URS => update event only on overflow; setting UG bit disabled */
+}
+
+void sleep_led_disable(void) {
+ /* Disable the timer */
+ STM32_TIM14->CR1 = 0;
+}
+
+void sleep_led_toggle(void) {
+ /* Toggle the timer */
+ STM32_TIM14->CR1 ^= STM32_TIM_CR1_CEN;
+}
+
+
+#else /* platform selection: not on familiar chips */
+
+void sleep_led_init(void) {
+}
+
+void sleep_led_enable(void) {
+ led_set(1<<USB_LED_CAPS_LOCK);
+}
+
+void sleep_led_disable(void) {
+ led_set(0);
+}
+
+void sleep_led_toggle(void) {
+ // not implemented
+}
+
+#endif /* platform selection */ \ No newline at end of file
diff --git a/tmk_core/common/chibios/suspend.c b/tmk_core/common/chibios/suspend.c
new file mode 100644
index 000000000..6ca16034f
--- /dev/null
+++ b/tmk_core/common/chibios/suspend.c
@@ -0,0 +1,65 @@
+/* TODO */
+
+#include "ch.h"
+#include "hal.h"
+
+#include "matrix.h"
+#include "action.h"
+#include "action_util.h"
+#include "mousekey.h"
+#include "host.h"
+#include "backlight.h"
+#include "suspend.h"
+
+void suspend_idle(uint8_t time) {
+ // TODO: this is not used anywhere - what units is 'time' in?
+ chThdSleepMilliseconds(time);
+}
+
+void suspend_power_down(void) {
+ // TODO: figure out what to power down and how
+ // shouldn't power down TPM/FTM if we want a breathing LED
+ // also shouldn't power down USB
+
+ // on AVR, this enables the watchdog for 15ms (max), and goes to
+ // SLEEP_MODE_PWR_DOWN
+
+ chThdSleepMilliseconds(17);
+}
+
+__attribute__ ((weak)) void matrix_power_up(void) {}
+__attribute__ ((weak)) void matrix_power_down(void) {}
+bool suspend_wakeup_condition(void)
+{
+ matrix_power_up();
+ matrix_scan();
+ matrix_power_down();
+ for (uint8_t r = 0; r < MATRIX_ROWS; r++) {
+ if (matrix_get_row(r)) return true;
+ }
+ return false;
+}
+
+// run immediately after wakeup
+void suspend_wakeup_init(void)
+{
+ // clear keyboard state
+ // need to do it manually, because we're running from ISR
+ // and clear_keyboard() calls print
+ // so only clear the variables in memory
+ // the reports will be sent from main.c afterwards
+ // or if the PC asks for GET_REPORT
+ clear_mods();
+ clear_weak_mods();
+ clear_keys();
+#ifdef MOUSEKEY_ENABLE
+ mousekey_clear();
+#endif /* MOUSEKEY_ENABLE */
+#ifdef EXTRAKEY_ENABLE
+ host_system_send(0);
+ host_consumer_send(0);
+#endif /* EXTRAKEY_ENABLE */
+#ifdef BACKLIGHT_ENABLE
+ backlight_init();
+#endif /* BACKLIGHT_ENABLE */
+}
diff --git a/tmk_core/common/chibios/timer.c b/tmk_core/common/chibios/timer.c
new file mode 100644
index 000000000..3de4cc368
--- /dev/null
+++ b/tmk_core/common/chibios/timer.c
@@ -0,0 +1,27 @@
+#include "ch.h"
+
+#include "timer.h"
+
+void timer_init(void) {}
+
+void timer_clear(void) {}
+
+uint16_t timer_read(void)
+{
+ return (uint16_t)ST2MS(chVTGetSystemTime());
+}
+
+uint32_t timer_read32(void)
+{
+ return ST2MS(chVTGetSystemTime());
+}
+
+uint16_t timer_elapsed(uint16_t last)
+{
+ return (uint16_t)(ST2MS(chVTTimeElapsedSinceX(MS2ST(last))));
+}
+
+uint32_t timer_elapsed32(uint32_t last)
+{
+ return ST2MS(chVTTimeElapsedSinceX(MS2ST(last)));
+}
diff --git a/tmk_core/common/command.c b/tmk_core/common/command.c
new file mode 100644
index 000000000..084c9fe15
--- /dev/null
+++ b/tmk_core/common/command.c
@@ -0,0 +1,794 @@
+/*
+Copyright 2011 Jun Wako <wakojun@gmail.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include <stdint.h>
+#include <stdbool.h>
+#include "wait.h"
+#include "keycode.h"
+#include "host.h"
+#include "keymap.h"
+#include "print.h"
+#include "debug.h"
+#include "util.h"
+#include "timer.h"
+#include "keyboard.h"
+#include "bootloader.h"
+#include "action_layer.h"
+#include "action_util.h"
+#include "eeconfig.h"
+#include "sleep_led.h"
+#include "led.h"
+#include "command.h"
+#include "backlight.h"
+#include "quantum.h"
+
+#ifdef MOUSEKEY_ENABLE
+#include "mousekey.h"
+#endif
+
+#ifdef PROTOCOL_PJRC
+ #include "usb_keyboard.h"
+ #ifdef EXTRAKEY_ENABLE
+ #include "usb_extra.h"
+ #endif
+#endif
+
+#ifdef PROTOCOL_VUSB
+ #include "usbdrv.h"
+#endif
+
+#ifdef AUDIO_ENABLE
+ #include "audio.h"
+#endif /* AUDIO_ENABLE */
+
+
+static bool command_common(uint8_t code);
+static void command_common_help(void);
+static void print_version(void);
+static void print_status(void);
+static bool command_console(uint8_t code);
+static void command_console_help(void);
+#ifdef MOUSEKEY_ENABLE
+static bool mousekey_console(uint8_t code);
+static void mousekey_console_help(void);
+#endif
+
+static void switch_default_layer(uint8_t layer);
+
+
+command_state_t command_state = ONESHOT;
+
+
+bool command_proc(uint8_t code)
+{
+ switch (command_state) {
+ case ONESHOT:
+ if (!IS_COMMAND())
+ return false;
+ return (command_extra(code) || command_common(code));
+ break;
+ case CONSOLE:
+ if (IS_COMMAND())
+ return (command_extra(code) || command_common(code));
+ else
+ return (command_console_extra(code) || command_console(code));
+ break;
+#ifdef MOUSEKEY_ENABLE
+ case MOUSEKEY:
+ mousekey_console(code);
+ break;
+#endif
+ default:
+ command_state = ONESHOT;
+ return false;
+ }
+ return true;
+}
+
+/* TODO: Refactoring is needed. */
+/* This allows to define extra commands. return false when not processed. */
+bool command_extra(uint8_t code) __attribute__ ((weak));
+bool command_extra(uint8_t code)
+{
+ (void)code;
+ return false;
+}
+
+bool command_console_extra(uint8_t code) __attribute__ ((weak));
+bool command_console_extra(uint8_t code)
+{
+ (void)code;
+ return false;
+}
+
+
+/***********************************************************
+ * Command common
+ ***********************************************************/
+static void command_common_help(void)
+{
+ print( "\n\t- Magic -\n"
+ STR(MAGIC_KEY_DEBUG ) ": Debug Message Toggle\n"
+ STR(MAGIC_KEY_DEBUG_MATRIX) ": Matrix Debug Mode Toggle - Show keypresses in matrix grid\n"
+ STR(MAGIC_KEY_DEBUG_KBD ) ": Keyboard Debug Toggle - Show keypress report\n"
+ STR(MAGIC_KEY_DEBUG_MOUSE ) ": Debug Mouse Toggle\n"
+ STR(MAGIC_KEY_VERSION ) ": Version\n"
+ STR(MAGIC_KEY_STATUS ) ": Status\n"
+ STR(MAGIC_KEY_CONSOLE ) ": Activate Console Mode\n"
+
+#if MAGIC_KEY_SWITCH_LAYER_WITH_CUSTOM
+ STR(MAGIC_KEY_LAYER0 ) ": Switch to Layer 0\n"
+ STR(MAGIC_KEY_LAYER1 ) ": Switch to Layer 1\n"
+ STR(MAGIC_KEY_LAYER2 ) ": Switch to Layer 2\n"
+ STR(MAGIC_KEY_LAYER3 ) ": Switch to Layer 3\n"
+ STR(MAGIC_KEY_LAYER4 ) ": Switch to Layer 4\n"
+ STR(MAGIC_KEY_LAYER5 ) ": Switch to Layer 5\n"
+ STR(MAGIC_KEY_LAYER6 ) ": Switch to Layer 6\n"
+ STR(MAGIC_KEY_LAYER7 ) ": Switch to Layer 7\n"
+ STR(MAGIC_KEY_LAYER8 ) ": Switch to Layer 8\n"
+ STR(MAGIC_KEY_LAYER9 ) ": Switch to Layer 9\n"
+#endif
+
+#if MAGIC_KEY_SWITCH_LAYER_WITH_FKEYS
+ "F1-F10: Switch to Layer 0-9 (F10 = L0)\n"
+#endif
+
+#if MAGIC_KEY_SWITCH_LAYER_WITH_NKEYS
+ "0-9: Switch to Layer 0-9\n"
+#endif
+
+ STR(MAGIC_KEY_LAYER0_ALT1 ) ": Switch to Layer 0 (alternate key 1)\n"
+ STR(MAGIC_KEY_LAYER0_ALT2 ) ": Switch to Layer 0 (alternate key 2)\n"
+ STR(MAGIC_KEY_BOOTLOADER ) ": Jump to Bootloader (Reset)\n"
+
+#ifdef KEYBOARD_LOCK_ENABLE
+ STR(MAGIC_KEY_LOCK ) ": Lock\n"
+#endif
+
+#ifdef BOOTMAGIC_ENABLE
+ STR(MAGIC_KEY_EEPROM ) ": Print EEPROM Settings\n"
+#endif
+
+#ifdef NKRO_ENABLE
+ STR(MAGIC_KEY_NKRO ) ": NKRO Toggle\n"
+#endif
+
+#ifdef SLEEP_LED_ENABLE
+ STR(MAGIC_KEY_SLEEP_LED ) ": Sleep LED Test\n"
+#endif
+ );
+}
+
+static void print_version(void)
+{
+ // print version & information
+ print("\n\t- Version -\n");
+ print("DESC: " STR(DESCRIPTION) "\n");
+ print("VID: " STR(VENDOR_ID) "(" STR(MANUFACTURER) ") "
+ "PID: " STR(PRODUCT_ID) "(" STR(PRODUCT) ") "
+ "VER: " STR(DEVICE_VER) "\n");
+ print("BUILD: " STR(VERSION) " (" __TIME__ " " __DATE__ ")\n");
+
+ /* build options */
+ print("OPTIONS:"
+
+#ifdef PROTOCOL_PJRC
+ " PJRC"
+#endif
+#ifdef PROTOCOL_LUFA
+ " LUFA"
+#endif
+#ifdef PROTOCOL_VUSB
+ " VUSB"
+#endif
+#ifdef BOOTMAGIC_ENABLE
+ " BOOTMAGIC"
+#endif
+#ifdef MOUSEKEY_ENABLE
+ " MOUSEKEY"
+#endif
+#ifdef EXTRAKEY_ENABLE
+ " EXTRAKEY"
+#endif
+#ifdef CONSOLE_ENABLE
+ " CONSOLE"
+#endif
+#ifdef COMMAND_ENABLE
+ " COMMAND"
+#endif
+#ifdef NKRO_ENABLE
+ " NKRO"
+#endif
+#ifdef KEYMAP_SECTION_ENABLE
+ " KEYMAP_SECTION"
+#endif
+
+ " " STR(BOOTLOADER_SIZE) "\n");
+
+ print("GCC: " STR(__GNUC__) "." STR(__GNUC_MINOR__) "." STR(__GNUC_PATCHLEVEL__)
+#if defined(__AVR__)
+ " AVR-LIBC: " __AVR_LIBC_VERSION_STRING__
+ " AVR_ARCH: avr" STR(__AVR_ARCH__)
+#endif
+ "\n");
+
+ return;
+}
+
+static void print_status(void)
+{
+
+ print("\n\t- Status -\n");
+
+ print_val_hex8(host_keyboard_leds());
+ print_val_hex8(keyboard_protocol);
+ print_val_hex8(keyboard_idle);
+#ifdef NKRO_ENABLE
+ print_val_hex8(keyboard_nkro);
+#endif
+ print_val_hex32(timer_read32());
+
+#ifdef PROTOCOL_PJRC
+ print_val_hex8(UDCON);
+ print_val_hex8(UDIEN);
+ print_val_hex8(UDINT);
+ print_val_hex8(usb_keyboard_leds);
+ print_val_hex8(usb_keyboard_idle_count);
+#endif
+
+#ifdef PROTOCOL_PJRC
+# if USB_COUNT_SOF
+ print_val_hex8(usbSofCount);
+# endif
+#endif
+ return;
+}
+
+#ifdef BOOTMAGIC_ENABLE
+static void print_eeconfig(void)
+{
+#ifndef NO_PRINT
+ print("default_layer: "); print_dec(eeconfig_read_default_layer()); print("\n");
+
+ debug_config_t dc;
+ dc.raw = eeconfig_read_debug();
+ print("debug_config.raw: "); print_hex8(dc.raw); print("\n");
+ print(".enable: "); print_dec(dc.enable); print("\n");
+ print(".matrix: "); print_dec(dc.matrix); print("\n");
+ print(".keyboard: "); print_dec(dc.keyboard); print("\n");
+ print(".mouse: "); print_dec(dc.mouse); print("\n");
+
+ keymap_config_t kc;
+ kc.raw = eeconfig_read_keymap();
+ print("keymap_config.raw: "); print_hex8(kc.raw); print("\n");
+ print(".swap_control_capslock: "); print_dec(kc.swap_control_capslock); print("\n");
+ print(".capslock_to_control: "); print_dec(kc.capslock_to_control); print("\n");
+ print(".swap_lalt_lgui: "); print_dec(kc.swap_lalt_lgui); print("\n");
+ print(".swap_ralt_rgui: "); print_dec(kc.swap_ralt_rgui); print("\n");
+ print(".no_gui: "); print_dec(kc.no_gui); print("\n");
+ print(".swap_grave_esc: "); print_dec(kc.swap_grave_esc); print("\n");
+ print(".swap_backslash_backspace: "); print_dec(kc.swap_backslash_backspace); print("\n");
+ print(".nkro: "); print_dec(kc.nkro); print("\n");
+
+#ifdef BACKLIGHT_ENABLE
+ backlight_config_t bc;
+ bc.raw = eeconfig_read_backlight();
+ print("backlight_config.raw: "); print_hex8(bc.raw); print("\n");
+ print(".enable: "); print_dec(bc.enable); print("\n");
+ print(".level: "); print_dec(bc.level); print("\n");
+#endif /* BACKLIGHT_ENABLE */
+
+#endif /* !NO_PRINT */
+
+}
+#endif /* BOOTMAGIC_ENABLE */
+
+static bool command_common(uint8_t code)
+{
+
+#ifdef KEYBOARD_LOCK_ENABLE
+ static host_driver_t *host_driver = 0;
+#endif
+
+ switch (code) {
+
+#ifdef SLEEP_LED_ENABLE
+
+ // test breathing sleep LED
+ case MAGIC_KC(MAGIC_KEY_SLEEP_LED):
+ print("Sleep LED Test\n");
+ sleep_led_toggle();
+ led_set(host_keyboard_leds());
+ break;
+#endif
+
+#ifdef BOOTMAGIC_ENABLE
+
+ // print stored eeprom config
+ case MAGIC_KC(MAGIC_KEY_EEPROM):
+ print("eeconfig:\n");
+ print_eeconfig();
+ break;
+#endif
+
+#ifdef KEYBOARD_LOCK_ENABLE
+
+ // lock/unlock keyboard
+ case MAGIC_KC(MAGIC_KEY_LOCK):
+ if (host_get_driver()) {
+ host_driver = host_get_driver();
+ clear_keyboard();
+ host_set_driver(0);
+ print("Locked.\n");
+ } else {
+ host_set_driver(host_driver);
+ print("Unlocked.\n");
+ }
+ break;
+#endif
+
+ // print help
+ case MAGIC_KC(MAGIC_KEY_HELP1):
+ case MAGIC_KC(MAGIC_KEY_HELP2):
+ command_common_help();
+ break;
+
+ // activate console
+ case MAGIC_KC(MAGIC_KEY_CONSOLE):
+ debug_matrix = false;
+ debug_keyboard = false;
+ debug_mouse = false;
+ debug_enable = false;
+ command_console_help();
+ print("C> ");
+ command_state = CONSOLE;
+ break;
+
+ // jump to bootloader
+ case MAGIC_KC(MAGIC_KEY_BOOTLOADER):
+ clear_keyboard(); // clear to prevent stuck keys
+ print("\n\nJumping to bootloader... ");
+ #ifdef AUDIO_ENABLE
+ stop_all_notes();
+ shutdown_user();
+ #else
+ wait_ms(1000);
+ #endif
+ bootloader_jump(); // not return
+ break;
+
+ // debug toggle
+ case MAGIC_KC(MAGIC_KEY_DEBUG):
+ debug_enable = !debug_enable;
+ if (debug_enable) {
+ print("\ndebug: on\n");
+ debug_matrix = true;
+ debug_keyboard = true;
+ debug_mouse = true;
+ } else {
+ print("\ndebug: off\n");
+ debug_matrix = false;
+ debug_keyboard = false;
+ debug_mouse = false;
+ }
+ break;
+
+ // debug matrix toggle
+ case MAGIC_KC(MAGIC_KEY_DEBUG_MATRIX):
+ debug_matrix = !debug_matrix;
+ if (debug_matrix) {
+ print("\nmatrix: on\n");
+ debug_enable = true;
+ } else {
+ print("\nmatrix: off\n");
+ }
+ break;
+
+ // debug keyboard toggle
+ case MAGIC_KC(MAGIC_KEY_DEBUG_KBD):
+ debug_keyboard = !debug_keyboard;
+ if (debug_keyboard) {
+ print("\nkeyboard: on\n");
+ debug_enable = true;
+ } else {
+ print("\nkeyboard: off\n");
+ }
+ break;
+
+ // debug mouse toggle
+ case MAGIC_KC(MAGIC_KEY_DEBUG_MOUSE):
+ debug_mouse = !debug_mouse;
+ if (debug_mouse) {
+ print("\nmouse: on\n");
+ debug_enable = true;
+ } else {
+ print("\nmouse: off\n");
+ }
+ break;
+
+ // print version
+ case MAGIC_KC(MAGIC_KEY_VERSION):
+ print_version();
+ break;
+
+ // print status
+ case MAGIC_KC(MAGIC_KEY_STATUS):
+ print_status();
+ break;
+
+#ifdef NKRO_ENABLE
+
+ // NKRO toggle
+ case MAGIC_KC(MAGIC_KEY_NKRO):
+ clear_keyboard(); // clear to prevent stuck keys
+ keyboard_nkro = !keyboard_nkro;
+ if (keyboard_nkro) {
+ print("NKRO: on\n");
+ } else {
+ print("NKRO: off\n");
+ }
+ break;
+#endif
+
+ // switch layers
+
+ case MAGIC_KC(MAGIC_KEY_LAYER0_ALT1):
+ case MAGIC_KC(MAGIC_KEY_LAYER0_ALT2):
+ switch_default_layer(0);
+ break;
+
+#if MAGIC_KEY_SWITCH_LAYER_WITH_CUSTOM
+
+ case MAGIC_KC(MAGIC_KEY_LAYER0):
+ switch_default_layer(0);
+ break;
+
+ case MAGIC_KC(MAGIC_KEY_LAYER1):
+ switch_default_layer(1);
+ break;
+
+ case MAGIC_KC(MAGIC_KEY_LAYER2):
+ switch_default_layer(2);
+ break;
+
+ case MAGIC_KC(MAGIC_KEY_LAYER3):
+ switch_default_layer(3);
+ break;
+
+ case MAGIC_KC(MAGIC_KEY_LAYER4):
+ switch_default_layer(4);
+ break;
+
+ case MAGIC_KC(MAGIC_KEY_LAYER5):
+ switch_default_layer(5);
+ break;
+
+ case MAGIC_KC(MAGIC_KEY_LAYER6):
+ switch_default_layer(6);
+ break;
+
+ case MAGIC_KC(MAGIC_KEY_LAYER7):
+ switch_default_layer(7);
+ break;
+
+ case MAGIC_KC(MAGIC_KEY_LAYER8):
+ switch_default_layer(8);
+ break;
+
+ case MAGIC_KC(MAGIC_KEY_LAYER9):
+ switch_default_layer(9);
+ break;
+#endif
+
+
+#if MAGIC_KEY_SWITCH_LAYER_WITH_FKEYS
+
+ case KC_F1 ... KC_F9:
+ switch_default_layer((code - KC_F1) + 1);
+ break;
+ case KC_F10:
+ switch_default_layer(0);
+ break;
+#endif
+
+#if MAGIC_KEY_SWITCH_LAYER_WITH_NKEYS
+
+ case KC_1 ... KC_9:
+ switch_default_layer((code - KC_1) + 1);
+ break;
+ case KC_0:
+ switch_default_layer(0);
+ break;
+#endif
+
+ default:
+ print("?");
+ return false;
+ }
+ return true;
+}
+
+
+/***********************************************************
+ * Command console
+ ***********************************************************/
+static void command_console_help(void)
+{
+ print("\n\t- Console -\n"
+ "ESC/q: quit\n"
+#ifdef MOUSEKEY_ENABLE
+ "m: mousekey\n"
+#endif
+ );
+}
+
+static bool command_console(uint8_t code)
+{
+ switch (code) {
+ case KC_H:
+ case KC_SLASH: /* ? */
+ command_console_help();
+ break;
+ case KC_Q:
+ case KC_ESC:
+ command_state = ONESHOT;
+ return false;
+#ifdef MOUSEKEY_ENABLE
+ case KC_M:
+ mousekey_console_help();
+ print("M> ");
+ command_state = MOUSEKEY;
+ return true;
+#endif
+ default:
+ print("?");
+ return false;
+ }
+ print("C> ");
+ return true;
+}
+
+
+#ifdef MOUSEKEY_ENABLE
+/***********************************************************
+ * Mousekey console
+ ***********************************************************/
+static uint8_t mousekey_param = 0;
+
+static void mousekey_param_print(void)
+{
+#ifndef NO_PRINT
+ print("\n\t- Values -\n");
+ print("1: delay(*10ms): "); pdec(mk_delay); print("\n");
+ print("2: interval(ms): "); pdec(mk_interval); print("\n");
+ print("3: max_speed: "); pdec(mk_max_speed); print("\n");
+ print("4: time_to_max: "); pdec(mk_time_to_max); print("\n");
+ print("5: wheel_max_speed: "); pdec(mk_wheel_max_speed); print("\n");
+ print("6: wheel_time_to_max: "); pdec(mk_wheel_time_to_max); print("\n");
+#endif /* !NO_PRINT */
+
+}
+
+//#define PRINT_SET_VAL(v) print(#v " = "); print_dec(v); print("\n");
+#define PRINT_SET_VAL(v) xprintf(#v " = %d\n", (v))
+static void mousekey_param_inc(uint8_t param, uint8_t inc)
+{
+ switch (param) {
+ case 1:
+ if (mk_delay + inc < UINT8_MAX)
+ mk_delay += inc;
+ else
+ mk_delay = UINT8_MAX;
+ PRINT_SET_VAL(mk_delay);
+ break;
+ case 2:
+ if (mk_interval + inc < UINT8_MAX)
+ mk_interval += inc;
+ else
+ mk_interval = UINT8_MAX;
+ PRINT_SET_VAL(mk_interval);
+ break;
+ case 3:
+ if (mk_max_speed + inc < UINT8_MAX)
+ mk_max_speed += inc;
+ else
+ mk_max_speed = UINT8_MAX;
+ PRINT_SET_VAL(mk_max_speed);
+ break;
+ case 4:
+ if (mk_time_to_max + inc < UINT8_MAX)
+ mk_time_to_max += inc;
+ else
+ mk_time_to_max = UINT8_MAX;
+ PRINT_SET_VAL(mk_time_to_max);
+ break;
+ case 5:
+ if (mk_wheel_max_speed + inc < UINT8_MAX)
+ mk_wheel_max_speed += inc;
+ else
+ mk_wheel_max_speed = UINT8_MAX;
+ PRINT_SET_VAL(mk_wheel_max_speed);
+ break;
+ case 6:
+ if (mk_wheel_time_to_max + inc < UINT8_MAX)
+ mk_wheel_time_to_max += inc;
+ else
+ mk_wheel_time_to_max = UINT8_MAX;
+ PRINT_SET_VAL(mk_wheel_time_to_max);
+ break;
+ }
+}
+
+static void mousekey_param_dec(uint8_t param, uint8_t dec)
+{
+ switch (param) {
+ case 1:
+ if (mk_delay > dec)
+ mk_delay -= dec;
+ else
+ mk_delay = 0;
+ PRINT_SET_VAL(mk_delay);
+ break;
+ case 2:
+ if (mk_interval > dec)
+ mk_interval -= dec;
+ else
+ mk_interval = 0;
+ PRINT_SET_VAL(mk_interval);
+ break;
+ case 3:
+ if (mk_max_speed > dec)
+ mk_max_speed -= dec;
+ else
+ mk_max_speed = 0;
+ PRINT_SET_VAL(mk_max_speed);
+ break;
+ case 4:
+ if (mk_time_to_max > dec)
+ mk_time_to_max -= dec;
+ else
+ mk_time_to_max = 0;
+ PRINT_SET_VAL(mk_time_to_max);
+ break;
+ case 5:
+ if (mk_wheel_max_speed > dec)
+ mk_wheel_max_speed -= dec;
+ else
+ mk_wheel_max_speed = 0;
+ PRINT_SET_VAL(mk_wheel_max_speed);
+ break;
+ case 6:
+ if (mk_wheel_time_to_max > dec)
+ mk_wheel_time_to_max -= dec;
+ else
+ mk_wheel_time_to_max = 0;
+ PRINT_SET_VAL(mk_wheel_time_to_max);
+ break;
+ }
+}
+
+static void mousekey_console_help(void)
+{
+ print("\n\t- Mousekey -\n"
+ "ESC/q: quit\n"
+ "1: delay(*10ms)\n"
+ "2: interval(ms)\n"
+ "3: max_speed\n"
+ "4: time_to_max\n"
+ "5: wheel_max_speed\n"
+ "6: wheel_time_to_max\n"
+ "\n"
+ "p: print values\n"
+ "d: set defaults\n"
+ "up: +1\n"
+ "down: -1\n"
+ "pgup: +10\n"
+ "pgdown: -10\n"
+ "\n"
+ "speed = delta * max_speed * (repeat / time_to_max)\n");
+ xprintf("where delta: cursor=%d, wheel=%d\n"
+ "See http://en.wikipedia.org/wiki/Mouse_keys\n", MOUSEKEY_MOVE_DELTA, MOUSEKEY_WHEEL_DELTA);
+}
+
+static bool mousekey_console(uint8_t code)
+{
+ switch (code) {
+ case KC_H:
+ case KC_SLASH: /* ? */
+ mousekey_console_help();
+ break;
+ case KC_Q:
+ case KC_ESC:
+ if (mousekey_param) {
+ mousekey_param = 0;
+ } else {
+ print("C> ");
+ command_state = CONSOLE;
+ return false;
+ }
+ break;
+ case KC_P:
+ mousekey_param_print();
+ break;
+ case KC_1:
+ case KC_2:
+ case KC_3:
+ case KC_4:
+ case KC_5:
+ case KC_6:
+ mousekey_param = numkey2num(code);
+ break;
+ case KC_UP:
+ mousekey_param_inc(mousekey_param, 1);
+ break;
+ case KC_DOWN:
+ mousekey_param_dec(mousekey_param, 1);
+ break;
+ case KC_PGUP:
+ mousekey_param_inc(mousekey_param, 10);
+ break;
+ case KC_PGDN:
+ mousekey_param_dec(mousekey_param, 10);
+ break;
+ case KC_D:
+ mk_delay = MOUSEKEY_DELAY/10;
+ mk_interval = MOUSEKEY_INTERVAL;
+ mk_max_speed = MOUSEKEY_MAX_SPEED;
+ mk_time_to_max = MOUSEKEY_TIME_TO_MAX;
+ mk_wheel_max_speed = MOUSEKEY_WHEEL_MAX_SPEED;
+ mk_wheel_time_to_max = MOUSEKEY_WHEEL_TIME_TO_MAX;
+ print("set default\n");
+ break;
+ default:
+ print("?");
+ return false;
+ }
+ if (mousekey_param) {
+ xprintf("M%d> ", mousekey_param);
+ } else {
+ print("M>" );
+ }
+ return true;
+}
+#endif
+
+
+/***********************************************************
+ * Utilities
+ ***********************************************************/
+uint8_t numkey2num(uint8_t code)
+{
+ switch (code) {
+ case KC_1: return 1;
+ case KC_2: return 2;
+ case KC_3: return 3;
+ case KC_4: return 4;
+ case KC_5: return 5;
+ case KC_6: return 6;
+ case KC_7: return 7;
+ case KC_8: return 8;
+ case KC_9: return 9;
+ case KC_0: return 0;
+ }
+ return 0;
+}
+
+static void switch_default_layer(uint8_t layer)
+{
+ xprintf("L%d\n", layer);
+ default_layer_set(1UL<<layer);
+ clear_keyboard();
+}
diff --git a/tmk_core/common/command.h b/tmk_core/common/command.h
new file mode 100644
index 000000000..a729e4b1e
--- /dev/null
+++ b/tmk_core/common/command.h
@@ -0,0 +1,157 @@
+/*
+Copyright 2011 Jun Wako <wakojun@gmail.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef COMMAND_H
+#define COMMAND
+
+/* TODO: Refactoring */
+typedef enum { ONESHOT, CONSOLE, MOUSEKEY } command_state_t;
+extern command_state_t command_state;
+
+/* This allows to extend commands. Return false when command is not processed. */
+bool command_extra(uint8_t code);
+bool command_console_extra(uint8_t code);
+
+#ifdef COMMAND_ENABLE
+uint8_t numkey2num(uint8_t code);
+bool command_proc(uint8_t code);
+#else
+#define command_proc(code) false
+#endif
+
+
+#ifndef MAGIC_KEY_SWITCH_LAYER_WITH_FKEYS
+#define MAGIC_KEY_SWITCH_LAYER_WITH_FKEYS true
+#endif
+
+#ifndef MAGIC_KEY_SWITCH_LAYER_WITH_NKEYS
+#define MAGIC_KEY_SWITCH_LAYER_WITH_NKEYS true
+#endif
+
+#ifndef MAGIC_KEY_SWITCH_LAYER_WITH_CUSTOM
+#define MAGIC_KEY_SWITCH_LAYER_WITH_CUSTOM false
+#endif
+
+#ifndef MAGIC_KEY_HELP1
+#define MAGIC_KEY_HELP1 H
+#endif
+
+#ifndef MAGIC_KEY_HELP2
+#define MAGIC_KEY_HELP2 SLASH
+#endif
+
+#ifndef MAGIC_KEY_DEBUG
+#define MAGIC_KEY_DEBUG D
+#endif
+
+#ifndef MAGIC_KEY_DEBUG_MATRIX
+#define MAGIC_KEY_DEBUG_MATRIX X
+#endif
+
+#ifndef MAGIC_KEY_DEBUG_KBD
+#define MAGIC_KEY_DEBUG_KBD K
+#endif
+
+#ifndef MAGIC_KEY_DEBUG_MOUSE
+#define MAGIC_KEY_DEBUG_MOUSE M
+#endif
+
+#ifndef MAGIC_KEY_VERSION
+#define MAGIC_KEY_VERSION V
+#endif
+
+#ifndef MAGIC_KEY_STATUS
+#define MAGIC_KEY_STATUS S
+#endif
+
+#ifndef MAGIC_KEY_CONSOLE
+#define MAGIC_KEY_CONSOLE C
+#endif
+
+#ifndef MAGIC_KEY_LAYER0_ALT1
+#define MAGIC_KEY_LAYER0_ALT1 ESC
+#endif
+
+#ifndef MAGIC_KEY_LAYER0_ALT2
+#define MAGIC_KEY_LAYER0_ALT2 GRAVE
+#endif
+
+#ifndef MAGIC_KEY_LAYER0
+#define MAGIC_KEY_LAYER0 0
+#endif
+
+#ifndef MAGIC_KEY_LAYER1
+#define MAGIC_KEY_LAYER1 1
+#endif
+
+#ifndef MAGIC_KEY_LAYER2
+#define MAGIC_KEY_LAYER2 2
+#endif
+
+#ifndef MAGIC_KEY_LAYER3
+#define MAGIC_KEY_LAYER3 3
+#endif
+
+#ifndef MAGIC_KEY_LAYER4
+#define MAGIC_KEY_LAYER4 4
+#endif
+
+#ifndef MAGIC_KEY_LAYER5
+#define MAGIC_KEY_LAYER5 5
+#endif
+
+#ifndef MAGIC_KEY_LAYER6
+#define MAGIC_KEY_LAYER6 6
+#endif
+
+#ifndef MAGIC_KEY_LAYER7
+#define MAGIC_KEY_LAYER7 7
+#endif
+
+#ifndef MAGIC_KEY_LAYER8
+#define MAGIC_KEY_LAYER8 8
+#endif
+
+#ifndef MAGIC_KEY_LAYER9
+#define MAGIC_KEY_LAYER9 9
+#endif
+
+#ifndef MAGIC_KEY_BOOTLOADER
+#define MAGIC_KEY_BOOTLOADER PAUSE
+#endif
+
+#ifndef MAGIC_KEY_LOCK
+#define MAGIC_KEY_LOCK CAPS
+#endif
+
+#ifndef MAGIC_KEY_EEPROM
+#define MAGIC_KEY_EEPROM E
+#endif
+
+#ifndef MAGIC_KEY_NKRO
+#define MAGIC_KEY_NKRO N
+#endif
+
+#ifndef MAGIC_KEY_SLEEP_LED
+#define MAGIC_KEY_SLEEP_LED Z
+
+#endif
+
+#define XMAGIC_KC(key) KC_##key
+#define MAGIC_KC(key) XMAGIC_KC(key)
+
+#endif \ No newline at end of file
diff --git a/tmk_core/common/debug.c b/tmk_core/common/debug.c
new file mode 100644
index 000000000..18613fc28
--- /dev/null
+++ b/tmk_core/common/debug.c
@@ -0,0 +1,24 @@
+#include <stdbool.h>
+#include "debug.h"
+
+#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
+
+debug_config_t debug_config = {
+/* GCC Bug 10676 - Using unnamed fields in initializers
+ * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=10676 */
+#if GCC_VERSION >= 40600
+ .enable = false,
+ .matrix = false,
+ .keyboard = false,
+ .mouse = false,
+ .reserved = 0
+#else
+ {
+ false, // .enable
+ false, // .matrix
+ false, // .keyboard
+ false, // .mouse
+ 0 // .reserved
+ }
+#endif
+};
diff --git a/tmk_core/common/debug.h b/tmk_core/common/debug.h
new file mode 100644
index 000000000..3cbe2092d
--- /dev/null
+++ b/tmk_core/common/debug.h
@@ -0,0 +1,117 @@
+/*
+Copyright 2011 Jun Wako <wakojun@gmail.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef DEBUG_H
+#define DEBUG_H 1
+
+#include <stdbool.h>
+#include "print.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Debug output control
+ */
+typedef union {
+ struct {
+ bool enable:1;
+ bool matrix:1;
+ bool keyboard:1;
+ bool mouse:1;
+ uint8_t reserved:4;
+ };
+ uint8_t raw;
+} debug_config_t;
+
+extern debug_config_t debug_config;
+
+#ifdef __cplusplus
+}
+#endif
+
+/* for backward compatibility */
+#define debug_enable (debug_config.enable)
+#define debug_matrix (debug_config.matrix)
+#define debug_keyboard (debug_config.keyboard)
+#define debug_mouse (debug_config.mouse)
+
+
+/*
+ * Debug print utils
+ */
+#ifndef NO_DEBUG
+
+#define dprint(s) do { if (debug_enable) print(s); } while (0)
+#define dprintln(s) do { if (debug_enable) println(s); } while (0)
+#define dprintf(fmt, ...) do { if (debug_enable) xprintf(fmt, ##__VA_ARGS__); } while (0)
+#define dmsg(s) dprintf("%s at %s: %S\n", __FILE__, __LINE__, PSTR(s))
+
+/* Deprecated. DO NOT USE these anymore, use dprintf instead. */
+#define debug(s) do { if (debug_enable) print(s); } while (0)
+#define debugln(s) do { if (debug_enable) println(s); } while (0)
+#define debug_msg(s) do { \
+ if (debug_enable) { \
+ print(__FILE__); print(" at "); print_dec(__LINE__); print(" in "); print(": "); print(s); \
+ } \
+} while (0)
+#define debug_dec(data) do { if (debug_enable) print_dec(data); } while (0)
+#define debug_decs(data) do { if (debug_enable) print_decs(data); } while (0)
+#define debug_hex4(data) do { if (debug_enable) print_hex4(data); } while (0)
+#define debug_hex8(data) do { if (debug_enable) print_hex8(data); } while (0)
+#define debug_hex16(data) do { if (debug_enable) print_hex16(data); } while (0)
+#define debug_hex32(data) do { if (debug_enable) print_hex32(data); } while (0)
+#define debug_bin8(data) do { if (debug_enable) print_bin8(data); } while (0)
+#define debug_bin16(data) do { if (debug_enable) print_bin16(data); } while (0)
+#define debug_bin32(data) do { if (debug_enable) print_bin32(data); } while (0)
+#define debug_bin_reverse8(data) do { if (debug_enable) print_bin_reverse8(data); } while (0)
+#define debug_bin_reverse16(data) do { if (debug_enable) print_bin_reverse16(data); } while (0)
+#define debug_bin_reverse32(data) do { if (debug_enable) print_bin_reverse32(data); } while (0)
+#define debug_hex(data) debug_hex8(data)
+#define debug_bin(data) debug_bin8(data)
+#define debug_bin_reverse(data) debug_bin8(data)
+
+#else /* NO_DEBUG */
+
+#define dprint(s)
+#define dprintln(s)
+#define dprintf(fmt, ...)
+#define dmsg(s)
+#define debug(s)
+#define debugln(s)
+#define debug_msg(s)
+#define debug_dec(data)
+#define debug_decs(data)
+#define debug_hex4(data)
+#define debug_hex8(data)
+#define debug_hex16(data)
+#define debug_hex32(data)
+#define debug_bin8(data)
+#define debug_bin16(data)
+#define debug_bin32(data)
+#define debug_bin_reverse8(data)
+#define debug_bin_reverse16(data)
+#define debug_bin_reverse32(data)
+#define debug_hex(data)
+#define debug_bin(data)
+#define debug_bin_reverse(data)
+
+#endif /* NO_DEBUG */
+
+#endif
diff --git a/tmk_core/common/eeconfig.c b/tmk_core/common/eeconfig.c
new file mode 100644
index 000000000..140d2b85b
--- /dev/null
+++ b/tmk_core/common/eeconfig.c
@@ -0,0 +1,56 @@
+#include <stdint.h>
+#include <stdbool.h>
+#include "eeprom.h"
+#include "eeconfig.h"
+
+void eeconfig_init(void)
+{
+ eeprom_update_word(EECONFIG_MAGIC, EECONFIG_MAGIC_NUMBER);
+ eeprom_update_byte(EECONFIG_DEBUG, 0);
+ eeprom_update_byte(EECONFIG_DEFAULT_LAYER, 0);
+ eeprom_update_byte(EECONFIG_KEYMAP, 0);
+ eeprom_update_byte(EECONFIG_MOUSEKEY_ACCEL, 0);
+#ifdef BACKLIGHT_ENABLE
+ eeprom_update_byte(EECONFIG_BACKLIGHT, 0);
+#endif
+#ifdef AUDIO_ENABLE
+ eeprom_update_byte(EECONFIG_AUDIO, 0xFF); // On by default
+#endif
+#ifdef RGBLIGHT_ENABLE
+ eeprom_update_dword(EECONFIG_RGBLIGHT, 0);
+#endif
+}
+
+void eeconfig_enable(void)
+{
+ eeprom_update_word(EECONFIG_MAGIC, EECONFIG_MAGIC_NUMBER);
+}
+
+void eeconfig_disable(void)
+{
+ eeprom_update_word(EECONFIG_MAGIC, 0xFFFF);
+}
+
+bool eeconfig_is_enabled(void)
+{
+ return (eeprom_read_word(EECONFIG_MAGIC) == EECONFIG_MAGIC_NUMBER);
+}
+
+uint8_t eeconfig_read_debug(void) { return eeprom_read_byte(EECONFIG_DEBUG); }
+void eeconfig_update_debug(uint8_t val) { eeprom_update_byte(EECONFIG_DEBUG, val); }
+
+uint8_t eeconfig_read_default_layer(void) { return eeprom_read_byte(EECONFIG_DEFAULT_LAYER); }
+void eeconfig_update_default_layer(uint8_t val) { eeprom_update_byte(EECONFIG_DEFAULT_LAYER, val); }
+
+uint8_t eeconfig_read_keymap(void) { return eeprom_read_byte(EECONFIG_KEYMAP); }
+void eeconfig_update_keymap(uint8_t val) { eeprom_update_byte(EECONFIG_KEYMAP, val); }
+
+#ifdef BACKLIGHT_ENABLE
+uint8_t eeconfig_read_backlight(void) { return eeprom_read_byte(EECONFIG_BACKLIGHT); }
+void eeconfig_update_backlight(uint8_t val) { eeprom_update_byte(EECONFIG_BACKLIGHT, val); }
+#endif
+
+#ifdef AUDIO_ENABLE
+uint8_t eeconfig_read_audio(void) { return eeprom_read_byte(EECONFIG_AUDIO); }
+void eeconfig_update_audio(uint8_t val) { eeprom_update_byte(EECONFIG_AUDIO, val); }
+#endif
diff --git a/tmk_core/common/eeconfig.h b/tmk_core/common/eeconfig.h
new file mode 100644
index 000000000..d8caa346f
--- /dev/null
+++ b/tmk_core/common/eeconfig.h
@@ -0,0 +1,82 @@
+/*
+Copyright 2013 Jun Wako <wakojun@gmail.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef EECONFIG_H
+#define EECONFIG_H
+
+#include <stdint.h>
+#include <stdbool.h>
+
+
+#define EECONFIG_MAGIC_NUMBER (uint16_t)0xFEED
+
+/* eeprom parameteter address */
+#define EECONFIG_MAGIC (uint16_t *)0
+#define EECONFIG_DEBUG (uint8_t *)2
+#define EECONFIG_DEFAULT_LAYER (uint8_t *)3
+#define EECONFIG_KEYMAP (uint8_t *)4
+#define EECONFIG_MOUSEKEY_ACCEL (uint8_t *)5
+#define EECONFIG_BACKLIGHT (uint8_t *)6
+#define EECONFIG_AUDIO (uint8_t *)7
+#define EECONFIG_RGBLIGHT (uint32_t *)8
+
+
+/* debug bit */
+#define EECONFIG_DEBUG_ENABLE (1<<0)
+#define EECONFIG_DEBUG_MATRIX (1<<1)
+#define EECONFIG_DEBUG_KEYBOARD (1<<2)
+#define EECONFIG_DEBUG_MOUSE (1<<3)
+
+/* keyconf bit */
+#define EECONFIG_KEYMAP_SWAP_CONTROL_CAPSLOCK (1<<0)
+#define EECONFIG_KEYMAP_CAPSLOCK_TO_CONTROL (1<<1)
+#define EECONFIG_KEYMAP_SWAP_LALT_LGUI (1<<2)
+#define EECONFIG_KEYMAP_SWAP_RALT_RGUI (1<<3)
+#define EECONFIG_KEYMAP_NO_GUI (1<<4)
+#define EECONFIG_KEYMAP_SWAP_GRAVE_ESC (1<<5)
+#define EECONFIG_KEYMAP_SWAP_BACKSLASH_BACKSPACE (1<<6)
+#define EECONFIG_KEYMAP_NKRO (1<<7)
+
+
+bool eeconfig_is_enabled(void);
+
+void eeconfig_init(void);
+
+void eeconfig_enable(void);
+
+void eeconfig_disable(void);
+
+uint8_t eeconfig_read_debug(void);
+void eeconfig_update_debug(uint8_t val);
+
+uint8_t eeconfig_read_default_layer(void);
+void eeconfig_update_default_layer(uint8_t val);
+
+uint8_t eeconfig_read_keymap(void);
+void eeconfig_update_keymap(uint8_t val);
+
+#ifdef BACKLIGHT_ENABLE
+uint8_t eeconfig_read_backlight(void);
+void eeconfig_update_backlight(uint8_t val);
+#endif
+
+#ifdef AUDIO_ENABLE
+uint8_t eeconfig_read_audio(void);
+void eeconfig_update_audio(uint8_t val);
+#endif
+
+#endif
diff --git a/tmk_core/common/eeprom.h b/tmk_core/common/eeprom.h
new file mode 100644
index 000000000..2cc2ccee3
--- /dev/null
+++ b/tmk_core/common/eeprom.h
@@ -0,0 +1,22 @@
+#ifndef TMK_CORE_COMMON_EEPROM_H_
+#define TMK_CORE_COMMON_EEPROM_H_
+
+#if defined(__AVR__)
+#include <avr/eeprom.h>
+#else
+uint8_t eeprom_read_byte (const uint8_t *__p);
+uint16_t eeprom_read_word (const uint16_t *__p);
+uint32_t eeprom_read_dword (const uint32_t *__p);
+void eeprom_read_block (void *__dst, const void *__src, uint32_t __n);
+void eeprom_write_byte (uint8_t *__p, uint8_t __value);
+void eeprom_write_word (uint16_t *__p, uint16_t __value);
+void eeprom_write_dword (uint32_t *__p, uint32_t __value);
+void eeprom_write_block (const void *__src, void *__dst, uint32_t __n);
+void eeprom_update_byte (uint8_t *__p, uint8_t __value);
+void eeprom_update_word (uint16_t *__p, uint16_t __value);
+void eeprom_update_dword (uint32_t *__p, uint32_t __value);
+void eeprom_update_block (const void *__src, void *__dst, uint32_t __n);
+#endif
+
+
+#endif /* TMK_CORE_COMMON_EEPROM_H_ */
diff --git a/tmk_core/common/host.c b/tmk_core/common/host.c
new file mode 100644
index 000000000..11a05c2dd
--- /dev/null
+++ b/tmk_core/common/host.c
@@ -0,0 +1,97 @@
+/*
+Copyright 2011,2012 Jun Wako <wakojun@gmail.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdint.h>
+//#include <avr/interrupt.h>
+#include "keycode.h"
+#include "host.h"
+#include "util.h"
+#include "debug.h"
+
+
+#ifdef NKRO_ENABLE
+bool keyboard_nkro = true;
+#endif
+
+static host_driver_t *driver;
+static uint16_t last_system_report = 0;
+static uint16_t last_consumer_report = 0;
+
+
+void host_set_driver(host_driver_t *d)
+{
+ driver = d;
+}
+
+host_driver_t *host_get_driver(void)
+{
+ return driver;
+}
+
+uint8_t host_keyboard_leds(void)
+{
+ if (!driver) return 0;
+ return (*driver->keyboard_leds)();
+}
+/* send report */
+void host_keyboard_send(report_keyboard_t *report)
+{
+ if (!driver) return;
+ (*driver->send_keyboard)(report);
+
+ if (debug_keyboard) {
+ dprint("keyboard_report: ");
+ for (uint8_t i = 0; i < KEYBOARD_REPORT_SIZE; i++) {
+ dprintf("%02X ", report->raw[i]);
+ }
+ dprint("\n");
+ }
+}
+
+void host_mouse_send(report_mouse_t *report)
+{
+ if (!driver) return;
+ (*driver->send_mouse)(report);
+}
+
+void host_system_send(uint16_t report)
+{
+ if (report == last_system_report) return;
+ last_system_report = report;
+
+ if (!driver) return;
+ (*driver->send_system)(report);
+}
+
+void host_consumer_send(uint16_t report)
+{
+ if (report == last_consumer_report) return;
+ last_consumer_report = report;
+
+ if (!driver) return;
+ (*driver->send_consumer)(report);
+}
+
+uint16_t host_last_system_report(void)
+{
+ return last_system_report;
+}
+
+uint16_t host_last_consumer_report(void)
+{
+ return last_consumer_report;
+}
diff --git a/tmk_core/common/host.h b/tmk_core/common/host.h
new file mode 100644
index 000000000..9814b10d2
--- /dev/null
+++ b/tmk_core/common/host.h
@@ -0,0 +1,57 @@
+/*
+Copyright 2011 Jun Wako <wakojun@gmail.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef HOST_H
+#define HOST_H
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "report.h"
+#include "host_driver.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef NKRO_ENABLE
+extern bool keyboard_nkro;
+#endif
+
+extern uint8_t keyboard_idle;
+extern uint8_t keyboard_protocol;
+
+
+/* host driver */
+void host_set_driver(host_driver_t *driver);
+host_driver_t *host_get_driver(void);
+
+/* host driver interface */
+uint8_t host_keyboard_leds(void);
+void host_keyboard_send(report_keyboard_t *report);
+void host_mouse_send(report_mouse_t *report);
+void host_system_send(uint16_t data);
+void host_consumer_send(uint16_t data);
+
+uint16_t host_last_system_report(void);
+uint16_t host_last_consumer_report(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/tmk_core/common/host_driver.h b/tmk_core/common/host_driver.h
new file mode 100644
index 000000000..edb9e5dd9
--- /dev/null
+++ b/tmk_core/common/host_driver.h
@@ -0,0 +1,33 @@
+/*
+Copyright 2011 Jun Wako <wakojun@gmail.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef HOST_DRIVER_H
+#define HOST_DRIVER_H
+
+#include <stdint.h>
+#include "report.h"
+
+
+typedef struct {
+ uint8_t (*keyboard_leds)(void);
+ void (*send_keyboard)(report_keyboard_t *);
+ void (*send_mouse)(report_mouse_t *);
+ void (*send_system)(uint16_t);
+ void (*send_consumer)(uint16_t);
+} host_driver_t;
+
+#endif
diff --git a/tmk_core/common/keyboard.c b/tmk_core/common/keyboard.c
new file mode 100644
index 000000000..81df8eb73
--- /dev/null
+++ b/tmk_core/common/keyboard.c
@@ -0,0 +1,188 @@
+/*
+Copyright 2011, 2012, 2013 Jun Wako <wakojun@gmail.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include <stdint.h>
+#include "keyboard.h"
+#include "matrix.h"
+#include "keymap.h"
+#include "host.h"
+#include "led.h"
+#include "keycode.h"
+#include "timer.h"
+#include "print.h"
+#include "debug.h"
+#include "command.h"
+#include "util.h"
+#include "sendchar.h"
+#include "eeconfig.h"
+#include "backlight.h"
+#ifdef BOOTMAGIC_ENABLE
+# include "bootmagic.h"
+#else
+# include "magic.h"
+#endif
+#ifdef MOUSEKEY_ENABLE
+# include "mousekey.h"
+#endif
+#ifdef PS2_MOUSE_ENABLE
+# include "ps2_mouse.h"
+#endif
+#ifdef SERIAL_MOUSE_ENABLE
+# include "serial_mouse.h"
+#endif
+#ifdef ADB_MOUSE_ENABLE
+# include "adb.h"
+#endif
+#ifdef RGBLIGHT_ENABLE
+# include "rgblight.h"
+#endif
+
+#ifdef MATRIX_HAS_GHOST
+static bool has_ghost_in_row(uint8_t row)
+{
+ matrix_row_t matrix_row = matrix_get_row(row);
+ // No ghost exists when less than 2 keys are down on the row
+ if (((matrix_row - 1) & matrix_row) == 0)
+ return false;
+
+ // Ghost occurs when the row shares column line with other row
+ for (uint8_t i=0; i < MATRIX_ROWS; i++) {
+ if (i != row && (matrix_get_row(i) & matrix_row))
+ return true;
+ }
+ return false;
+}
+#endif
+
+__attribute__ ((weak))
+void matrix_setup(void) {
+}
+
+void keyboard_setup(void) {
+ matrix_setup();
+}
+
+void keyboard_init(void) {
+ timer_init();
+ matrix_init();
+#ifdef PS2_MOUSE_ENABLE
+ ps2_mouse_init();
+#endif
+#ifdef SERIAL_MOUSE_ENABLE
+ serial_mouse_init();
+#endif
+#ifdef ADB_MOUSE_ENABLE
+ adb_mouse_init();
+#endif
+#ifdef BOOTMAGIC_ENABLE
+ bootmagic();
+#else
+ magic();
+#endif
+#ifdef BACKLIGHT_ENABLE
+ backlight_init();
+#endif
+#ifdef RGBLIGHT_ENABLE
+ rgblight_init();
+#endif
+#if defined(NKRO_ENABLE) && defined(FORCE_NKRO)
+ keyboard_nkro = true;
+#endif
+}
+
+/*
+ * Do keyboard routine jobs: scan mantrix, light LEDs, ...
+ * This is repeatedly called as fast as possible.
+ */
+void keyboard_task(void)
+{
+ static matrix_row_t matrix_prev[MATRIX_ROWS];
+#ifdef MATRIX_HAS_GHOST
+ static matrix_row_t matrix_ghost[MATRIX_ROWS];
+#endif
+ static uint8_t led_status = 0;
+ matrix_row_t matrix_row = 0;
+ matrix_row_t matrix_change = 0;
+
+ matrix_scan();
+ for (uint8_t r = 0; r < MATRIX_ROWS; r++) {
+ matrix_row = matrix_get_row(r);
+ matrix_change = matrix_row ^ matrix_prev[r];
+ if (matrix_change) {
+#ifdef MATRIX_HAS_GHOST
+ if (has_ghost_in_row(r)) {
+ /* Keep track of whether ghosted status has changed for
+ * debugging. But don't update matrix_prev until un-ghosted, or
+ * the last key would be lost.
+ */
+ if (debug_matrix && matrix_ghost[r] != matrix_row) {
+ matrix_print();
+ }
+ matrix_ghost[r] = matrix_row;
+ continue;
+ }
+ matrix_ghost[r] = matrix_row;
+#endif
+ if (debug_matrix) matrix_print();
+ for (uint8_t c = 0; c < MATRIX_COLS; c++) {
+ if (matrix_change & ((matrix_row_t)1<<c)) {
+ action_exec((keyevent_t){
+ .key = (keypos_t){ .row = r, .col = c },
+ .pressed = (matrix_row & ((matrix_row_t)1<<c)),
+ .time = (timer_read() | 1) /* time should not be 0 */
+ });
+ // record a processed key
+ matrix_prev[r] ^= ((matrix_row_t)1<<c);
+ // process a key per task call
+ goto MATRIX_LOOP_END;
+ }
+ }
+ }
+ }
+ // call with pseudo tick event when no real key event.
+ action_exec(TICK);
+
+MATRIX_LOOP_END:
+
+#ifdef MOUSEKEY_ENABLE
+ // mousekey repeat & acceleration
+ mousekey_task();
+#endif
+
+#ifdef PS2_MOUSE_ENABLE
+ ps2_mouse_task();
+#endif
+
+#ifdef SERIAL_MOUSE_ENABLE
+ serial_mouse_task();
+#endif
+
+#ifdef ADB_MOUSE_ENABLE
+ adb_mouse_task();
+#endif
+
+ // update LED
+ if (led_status != host_keyboard_leds()) {
+ led_status = host_keyboard_leds();
+ keyboard_set_leds(led_status);
+ }
+}
+
+void keyboard_set_leds(uint8_t leds)
+{
+ if (debug_keyboard) { debug("keyboard_set_led: "); debug_hex8(leds); debug("\n"); }
+ led_set(leds);
+}
diff --git a/tmk_core/common/keyboard.h b/tmk_core/common/keyboard.h
new file mode 100644
index 000000000..7738251b6
--- /dev/null
+++ b/tmk_core/common/keyboard.h
@@ -0,0 +1,74 @@
+/*
+Copyright 2011,2012,2013 Jun Wako <wakojun@gmail.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef KEYBOARD_H
+#define KEYBOARD_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* key matrix position */
+typedef struct {
+ uint8_t col;
+ uint8_t row;
+} keypos_t;
+
+/* key event */
+typedef struct {
+ keypos_t key;
+ bool pressed;
+ uint16_t time;
+} keyevent_t;
+
+/* equivalent test of keypos_t */
+#define KEYEQ(keya, keyb) ((keya).row == (keyb).row && (keya).col == (keyb).col)
+
+/* Rules for No Event:
+ * 1) (time == 0) to handle (keyevent_t){} as empty event
+ * 2) Matrix(255, 255) to make TICK event available
+ */
+static inline bool IS_NOEVENT(keyevent_t event) { return event.time == 0 || (event.key.row == 255 && event.key.col == 255); }
+static inline bool IS_PRESSED(keyevent_t event) { return (!IS_NOEVENT(event) && event.pressed); }
+static inline bool IS_RELEASED(keyevent_t event) { return (!IS_NOEVENT(event) && !event.pressed); }
+
+/* Tick event */
+#define TICK (keyevent_t){ \
+ .key = (keypos_t){ .row = 255, .col = 255 }, \
+ .pressed = false, \
+ .time = (timer_read() | 1) \
+}
+
+
+/* it runs once at early stage of startup before keyboard_init. */
+void keyboard_setup(void);
+/* it runs once after initializing host side protocol, debug and MCU peripherals. */
+void keyboard_init(void);
+/* it runs repeatedly in main loop */
+void keyboard_task(void);
+/* it runs when host LED status is updated */
+void keyboard_set_leds(uint8_t leds);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/tmk_core/common/keycode.h b/tmk_core/common/keycode.h
new file mode 100644
index 000000000..448195306
--- /dev/null
+++ b/tmk_core/common/keycode.h
@@ -0,0 +1,494 @@
+/*
+Copyright 2011,2012 Jun Wako <wakojun@gmail.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ * Keycodes based on HID Usage Keyboard/Keypad Page(0x07) plus special codes
+ * http://www.usb.org/developers/devclass_docs/Hut1_12.pdf
+ */
+#ifndef KEYCODE_H
+#define KEYCODE_H
+
+
+#define IS_ERROR(code) (KC_ROLL_OVER <= (code) && (code) <= KC_UNDEFINED)
+#define IS_ANY(code) (KC_A <= (code) && (code) <= 0xFF)
+#define IS_KEY(code) (KC_A <= (code) && (code) <= KC_EXSEL)
+#define IS_MOD(code) (KC_LCTRL <= (code) && (code) <= KC_RGUI)
+
+
+#define IS_SPECIAL(code) ((0xA5 <= (code) && (code) <= 0xDF) || (0xE8 <= (code) && (code) <= 0xFF))
+#define IS_SYSTEM(code) (KC_PWR <= (code) && (code) <= KC_WAKE)
+#define IS_CONSUMER(code) (KC_MUTE <= (code) && (code) <= KC_WFAV)
+#define IS_FN(code) (KC_FN0 <= (code) && (code) <= KC_FN31)
+#define IS_MOUSEKEY(code) (KC_MS_UP <= (code) && (code) <= KC_MS_ACCEL2)
+#define IS_MOUSEKEY_MOVE(code) (KC_MS_UP <= (code) && (code) <= KC_MS_RIGHT)
+#define IS_MOUSEKEY_BUTTON(code) (KC_MS_BTN1 <= (code) && (code) <= KC_MS_BTN5)
+#define IS_MOUSEKEY_WHEEL(code) (KC_MS_WH_UP <= (code) && (code) <= KC_MS_WH_RIGHT)
+#define IS_MOUSEKEY_ACCEL(code) (KC_MS_ACCEL0 <= (code) && (code) <= KC_MS_ACCEL2)
+
+#define MOD_BIT(code) (1<<MOD_INDEX(code))
+#define MOD_INDEX(code) ((code) & 0x07)
+#define FN_BIT(code) (1<<FN_INDEX(code))
+#define FN_INDEX(code) ((code) - KC_FN0)
+#define FN_MIN KC_FN0
+#define FN_MAX KC_FN31
+
+
+/*
+ * Short names for ease of definition of keymap
+ */
+#define KC_LCTL KC_LCTRL
+#define KC_RCTL KC_RCTRL
+#define KC_LSFT KC_LSHIFT
+#define KC_RSFT KC_RSHIFT
+#define KC_ESC KC_ESCAPE
+#define KC_BSPC KC_BSPACE
+#define KC_ENT KC_ENTER
+#define KC_DEL KC_DELETE
+#define KC_INS KC_INSERT
+#define KC_CAPS KC_CAPSLOCK
+#define KC_CLCK KC_CAPSLOCK
+#define KC_RGHT KC_RIGHT
+#define KC_PGDN KC_PGDOWN
+#define KC_PSCR KC_PSCREEN
+#define KC_SLCK KC_SCROLLLOCK
+#define KC_PAUS KC_PAUSE
+#define KC_BRK KC_PAUSE
+#define KC_NLCK KC_NUMLOCK
+#define KC_SPC KC_SPACE
+#define KC_MINS KC_MINUS
+#define KC_EQL KC_EQUAL
+#define KC_GRV KC_GRAVE
+#define KC_RBRC KC_RBRACKET
+#define KC_LBRC KC_LBRACKET
+#define KC_COMM KC_COMMA
+#define KC_BSLS KC_BSLASH
+#define KC_SLSH KC_SLASH
+#define KC_SCLN KC_SCOLON
+#define KC_QUOT KC_QUOTE
+#define KC_APP KC_APPLICATION
+#define KC_NUHS KC_NONUS_HASH
+#define KC_NUBS KC_NONUS_BSLASH
+#define KC_LCAP KC_LOCKING_CAPS
+#define KC_LNUM KC_LOCKING_NUM
+#define KC_LSCR KC_LOCKING_SCROLL
+#define KC_ERAS KC_ALT_ERASE,
+#define KC_CLR KC_CLEAR
+/* Japanese specific */
+#define KC_ZKHK KC_GRAVE
+#define KC_RO KC_INT1
+#define KC_KANA KC_INT2
+#define KC_JYEN KC_INT3
+#define KC_HENK KC_INT4
+#define KC_MHEN KC_INT5
+/* Keypad */
+#define KC_P1 KC_KP_1
+#define KC_P2 KC_KP_2
+#define KC_P3 KC_KP_3
+#define KC_P4 KC_KP_4
+#define KC_P5 KC_KP_5
+#define KC_P6 KC_KP_6
+#define KC_P7 KC_KP_7
+#define KC_P8 KC_KP_8
+#define KC_P9 KC_KP_9
+#define KC_P0 KC_KP_0
+#define KC_PDOT KC_KP_DOT
+#define KC_PCMM KC_KP_COMMA
+#define KC_PSLS KC_KP_SLASH
+#define KC_PAST KC_KP_ASTERISK
+#define KC_PMNS KC_KP_MINUS
+#define KC_PPLS KC_KP_PLUS
+#define KC_PEQL KC_KP_EQUAL
+#define KC_PENT KC_KP_ENTER
+/* Mousekey */
+#define KC_MS_U KC_MS_UP
+#define KC_MS_D KC_MS_DOWN
+#define KC_MS_L KC_MS_LEFT
+#define KC_MS_R KC_MS_RIGHT
+#define KC_BTN1 KC_MS_BTN1
+#define KC_BTN2 KC_MS_BTN2
+#define KC_BTN3 KC_MS_BTN3
+#define KC_BTN4 KC_MS_BTN4
+#define KC_BTN5 KC_MS_BTN5
+#define KC_WH_U KC_MS_WH_UP
+#define KC_WH_D KC_MS_WH_DOWN
+#define KC_WH_L KC_MS_WH_LEFT
+#define KC_WH_R KC_MS_WH_RIGHT
+#define KC_ACL0 KC_MS_ACCEL0
+#define KC_ACL1 KC_MS_ACCEL1
+#define KC_ACL2 KC_MS_ACCEL2
+/* Sytem Control */
+#define KC_PWR KC_SYSTEM_POWER
+#define KC_SLEP KC_SYSTEM_SLEEP
+#define KC_WAKE KC_SYSTEM_WAKE
+/* Consumer Page */
+#define KC_MUTE KC_AUDIO_MUTE
+#define KC_VOLU KC_AUDIO_VOL_UP
+#define KC_VOLD KC_AUDIO_VOL_DOWN
+#define KC_MNXT KC_MEDIA_NEXT_TRACK
+#define KC_MPRV KC_MEDIA_PREV_TRACK
+#define KC_MFFD KC_MEDIA_FAST_FORWARD
+#define KC_MRWD KC_MEDIA_REWIND
+#define KC_MSTP KC_MEDIA_STOP
+#define KC_MPLY KC_MEDIA_PLAY_PAUSE
+#define KC_MSEL KC_MEDIA_SELECT
+#define KC_EJCT KC_MEDIA_EJECT
+#define KC_MAIL KC_MAIL
+#define KC_CALC KC_CALCULATOR
+#define KC_MYCM KC_MY_COMPUTER
+#define KC_WSCH KC_WWW_SEARCH
+#define KC_WHOM KC_WWW_HOME
+#define KC_WBAK KC_WWW_BACK
+#define KC_WFWD KC_WWW_FORWARD
+#define KC_WSTP KC_WWW_STOP
+#define KC_WREF KC_WWW_REFRESH
+#define KC_WFAV KC_WWW_FAVORITES
+/* Jump to bootloader */
+#define KC_BTLD KC_BOOTLOADER
+/* Transparent */
+#define KC_TRANSPARENT 1
+#define KC_TRNS KC_TRANSPARENT
+
+
+
+/* USB HID Keyboard/Keypad Usage(0x07) */
+enum hid_keyboard_keypad_usage {
+ KC_NO = 0x00,
+ KC_ROLL_OVER,
+ KC_POST_FAIL,
+ KC_UNDEFINED,
+ KC_A,
+ KC_B,
+ KC_C,
+ KC_D,
+ KC_E,
+ KC_F,
+ KC_G,
+ KC_H,
+ KC_I,
+ KC_J,
+ KC_K,
+ KC_L,
+ KC_M, /* 0x10 */
+ KC_N,
+ KC_O,
+ KC_P,
+ KC_Q,
+ KC_R,
+ KC_S,
+ KC_T,
+ KC_U,
+ KC_V,
+ KC_W,
+ KC_X,
+ KC_Y,
+ KC_Z,
+ KC_1,
+ KC_2,
+ KC_3, /* 0x20 */
+ KC_4,
+ KC_5,
+ KC_6,
+ KC_7,
+ KC_8,
+ KC_9,
+ KC_0,
+ KC_ENTER,
+ KC_ESCAPE,
+ KC_BSPACE,
+ KC_TAB,
+ KC_SPACE,
+ KC_MINUS,
+ KC_EQUAL,
+ KC_LBRACKET,
+ KC_RBRACKET, /* 0x30 */
+ KC_BSLASH, /* \ (and |) */
+ KC_NONUS_HASH, /* Non-US # and ~ (Typically near the Enter key) */
+ KC_SCOLON, /* ; (and :) */
+ KC_QUOTE, /* ' and " */
+ KC_GRAVE, /* Grave accent and tilde */
+ KC_COMMA, /* , and < */
+ KC_DOT, /* . and > */
+ KC_SLASH, /* / and ? */
+ KC_CAPSLOCK,
+ KC_F1,
+ KC_F2,
+ KC_F3,
+ KC_F4,
+ KC_F5,
+ KC_F6,
+ KC_F7, /* 0x40 */
+ KC_F8,
+ KC_F9,
+ KC_F10,
+ KC_F11,
+ KC_F12,
+ KC_PSCREEN,
+ KC_SCROLLLOCK,
+ KC_PAUSE,
+ KC_INSERT,
+ KC_HOME,
+ KC_PGUP,
+ KC_DELETE,
+ KC_END,
+ KC_PGDOWN,
+ KC_RIGHT,
+ KC_LEFT, /* 0x50 */
+ KC_DOWN,
+ KC_UP,
+ KC_NUMLOCK,
+ KC_KP_SLASH,
+ KC_KP_ASTERISK,
+ KC_KP_MINUS,
+ KC_KP_PLUS,
+ KC_KP_ENTER,
+ KC_KP_1,
+ KC_KP_2,
+ KC_KP_3,
+ KC_KP_4,
+ KC_KP_5,
+ KC_KP_6,
+ KC_KP_7,
+ KC_KP_8, /* 0x60 */
+ KC_KP_9,
+ KC_KP_0,
+ KC_KP_DOT,
+ KC_NONUS_BSLASH, /* Non-US \ and | (Typically near the Left-Shift key) */
+ KC_APPLICATION,
+ KC_POWER,
+ KC_KP_EQUAL,
+ KC_F13,
+ KC_F14,
+ KC_F15,
+ KC_F16,
+ KC_F17,
+ KC_F18,
+ KC_F19,
+ KC_F20,
+ KC_F21, /* 0x70 */
+ KC_F22,
+ KC_F23,
+ KC_F24,
+ KC_EXECUTE,
+ KC_HELP,
+ KC_MENU,
+ KC_SELECT,
+ KC_STOP,
+ KC_AGAIN,
+ KC_UNDO,
+ KC_CUT,
+ KC_COPY,
+ KC_PASTE,
+ KC_FIND,
+ KC__MUTE,
+ KC__VOLUP, /* 0x80 */
+ KC__VOLDOWN,
+ KC_LOCKING_CAPS, /* locking Caps Lock */
+ KC_LOCKING_NUM, /* locking Num Lock */
+ KC_LOCKING_SCROLL, /* locking Scroll Lock */
+ KC_KP_COMMA,
+ KC_KP_EQUAL_AS400, /* equal sign on AS/400 */
+ KC_INT1,
+ KC_INT2,
+ KC_INT3,
+ KC_INT4,
+ KC_INT5,
+ KC_INT6,
+ KC_INT7,
+ KC_INT8,
+ KC_INT9,
+ KC_LANG1, /* 0x90 */
+ KC_LANG2,
+ KC_LANG3,
+ KC_LANG4,
+ KC_LANG5,
+ KC_LANG6,
+ KC_LANG7,
+ KC_LANG8,
+ KC_LANG9,
+ KC_ALT_ERASE,
+ KC_SYSREQ,
+ KC_CANCEL,
+ KC_CLEAR,
+ KC_PRIOR,
+ KC_RETURN,
+ KC_SEPARATOR,
+ KC_OUT, /* 0xA0 */
+ KC_OPER,
+ KC_CLEAR_AGAIN,
+ KC_CRSEL,
+ KC_EXSEL, /* 0xA4 */
+
+ /* NOTE: 0xA5-DF are used for internal special purpose */
+
+#if 0
+ /* NOTE: Following codes(0xB0-DD) are not used. Leave them for reference. */
+ KC_KP_00 = 0xB0,
+ KC_KP_000,
+ KC_THOUSANDS_SEPARATOR,
+ KC_DECIMAL_SEPARATOR,
+ KC_CURRENCY_UNIT,
+ KC_CURRENCY_SUB_UNIT,
+ KC_KP_LPAREN,
+ KC_KP_RPAREN,
+ KC_KP_LCBRACKET, /* { */
+ KC_KP_RCBRACKET, /* } */
+ KC_KP_TAB,
+ KC_KP_BSPACE,
+ KC_KP_A,
+ KC_KP_B,
+ KC_KP_C,
+ KC_KP_D,
+ KC_KP_E, /* 0xC0 */
+ KC_KP_F,
+ KC_KP_XOR,
+ KC_KP_HAT,
+ KC_KP_PERC,
+ KC_KP_LT,
+ KC_KP_GT,
+ KC_KP_AND,
+ KC_KP_LAZYAND,
+ KC_KP_OR,
+ KC_KP_LAZYOR,
+ KC_KP_COLON,
+ KC_KP_HASH,
+ KC_KP_SPACE,
+ KC_KP_ATMARK,
+ KC_KP_EXCLAMATION,
+ KC_KP_MEM_STORE, /* 0xD0 */
+ KC_KP_MEM_RECALL,
+ KC_KP_MEM_CLEAR,
+ KC_KP_MEM_ADD,
+ KC_KP_MEM_SUB,
+ KC_KP_MEM_MUL,
+ KC_KP_MEM_DIV,
+ KC_KP_PLUS_MINUS,
+ KC_KP_CLEAR,
+ KC_KP_CLEAR_ENTRY,
+ KC_KP_BINARY,
+ KC_KP_OCTAL,
+ KC_KP_DECIMAL,
+ KC_KP_HEXADECIMAL, /* 0xDD */
+#endif
+
+ /* Modifiers */
+ KC_LCTRL = 0xE0,
+ KC_LSHIFT,
+ KC_LALT,
+ KC_LGUI,
+ KC_RCTRL,
+ KC_RSHIFT,
+ KC_RALT,
+ KC_RGUI,
+
+ /* NOTE: 0xE8-FF are used for internal special purpose */
+};
+
+/* Special keycodes */
+/* NOTE: 0xA5-DF and 0xE8-FF are used for internal special purpose */
+enum internal_special_keycodes {
+ /* System Control */
+ KC_SYSTEM_POWER = 0xA5,
+ KC_SYSTEM_SLEEP,
+ KC_SYSTEM_WAKE,
+
+ /* Media Control */
+ KC_AUDIO_MUTE,
+ KC_AUDIO_VOL_UP,
+ KC_AUDIO_VOL_DOWN,
+ KC_MEDIA_NEXT_TRACK,
+ KC_MEDIA_PREV_TRACK,
+ KC_MEDIA_STOP,
+ KC_MEDIA_PLAY_PAUSE,
+ KC_MEDIA_SELECT,
+ KC_MEDIA_EJECT,
+ KC_MAIL,
+ KC_CALCULATOR,
+ KC_MY_COMPUTER,
+ KC_WWW_SEARCH,
+ KC_WWW_HOME,
+ KC_WWW_BACK,
+ KC_WWW_FORWARD,
+ KC_WWW_STOP,
+ KC_WWW_REFRESH,
+ KC_WWW_FAVORITES,
+ KC_MEDIA_FAST_FORWARD,
+ KC_MEDIA_REWIND, /* 0xBC */
+
+ /* Jump to bootloader */
+ KC_BOOTLOADER = 0xBF,
+
+ /* Fn key */
+ KC_FN0 = 0xC0,
+ KC_FN1,
+ KC_FN2,
+ KC_FN3,
+ KC_FN4,
+ KC_FN5,
+ KC_FN6,
+ KC_FN7,
+ KC_FN8,
+ KC_FN9,
+ KC_FN10,
+ KC_FN11,
+ KC_FN12,
+ KC_FN13,
+ KC_FN14,
+ KC_FN15,
+
+ KC_FN16 = 0xD0,
+ KC_FN17,
+ KC_FN18,
+ KC_FN19,
+ KC_FN20,
+ KC_FN21,
+ KC_FN22,
+ KC_FN23,
+ KC_FN24,
+ KC_FN25,
+ KC_FN26,
+ KC_FN27,
+ KC_FN28,
+ KC_FN29,
+ KC_FN30,
+ KC_FN31, /* 0xDF */
+
+ /**************************************/
+ /* 0xE0-E7 for Modifiers. DO NOT USE. */
+ /**************************************/
+
+ /* Mousekey */
+ KC_MS_UP = 0xF0,
+ KC_MS_DOWN,
+ KC_MS_LEFT,
+ KC_MS_RIGHT,
+ KC_MS_BTN1,
+ KC_MS_BTN2,
+ KC_MS_BTN3,
+ KC_MS_BTN4,
+ KC_MS_BTN5, /* 0xF8 */
+ /* Mousekey wheel */
+ KC_MS_WH_UP,
+ KC_MS_WH_DOWN,
+ KC_MS_WH_LEFT,
+ KC_MS_WH_RIGHT, /* 0xFC */
+ /* Mousekey accel */
+ KC_MS_ACCEL0,
+ KC_MS_ACCEL1,
+ KC_MS_ACCEL2 /* 0xFF */
+};
+
+#endif /* KEYCODE_H */
diff --git a/tmk_core/common/led.h b/tmk_core/common/led.h
new file mode 100644
index 000000000..61c971c10
--- /dev/null
+++ b/tmk_core/common/led.h
@@ -0,0 +1,43 @@
+/*
+Copyright 2011 Jun Wako <wakojun@gmail.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef LED_H
+#define LED_H
+#include "stdint.h"
+
+
+/* keyboard LEDs */
+#define USB_LED_NUM_LOCK 0
+#define USB_LED_CAPS_LOCK 1
+#define USB_LED_SCROLL_LOCK 2
+#define USB_LED_COMPOSE 3
+#define USB_LED_KANA 4
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void led_set(uint8_t usb_led);
+
+void led_init_ports(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif \ No newline at end of file
diff --git a/tmk_core/common/magic.c b/tmk_core/common/magic.c
new file mode 100644
index 000000000..194e4cc02
--- /dev/null
+++ b/tmk_core/common/magic.c
@@ -0,0 +1,38 @@
+#include <stdint.h>
+#include <stdbool.h>
+#if defined(__AVR__)
+#include <util/delay.h>
+#endif
+#include "matrix.h"
+#include "bootloader.h"
+#include "debug.h"
+#include "keymap.h"
+#include "host.h"
+#include "action_layer.h"
+#include "eeconfig.h"
+#include "magic.h"
+
+keymap_config_t keymap_config;
+
+void magic(void)
+{
+ /* check signature */
+ if (!eeconfig_is_enabled()) {
+ eeconfig_init();
+ }
+
+ /* debug enable */
+ debug_config.raw = eeconfig_read_debug();
+
+ /* keymap config */
+ keymap_config.raw = eeconfig_read_keymap();
+
+#ifdef NKRO_ENABLE
+ keyboard_nkro = keymap_config.nkro;
+#endif
+
+ uint8_t default_layer = 0;
+ default_layer = eeconfig_read_default_layer();
+ default_layer_set((uint32_t)default_layer);
+
+}
diff --git a/tmk_core/common/magic.h b/tmk_core/common/magic.h
new file mode 100644
index 000000000..3fa2d8b81
--- /dev/null
+++ b/tmk_core/common/magic.h
@@ -0,0 +1,6 @@
+#ifndef MAGIC_H
+#define MAGIC_H
+
+void magic(void);
+
+#endif
diff --git a/tmk_core/common/matrix.h b/tmk_core/common/matrix.h
new file mode 100644
index 000000000..71153a5f5
--- /dev/null
+++ b/tmk_core/common/matrix.h
@@ -0,0 +1,79 @@
+/*
+Copyright 2011 Jun Wako <wakojun@gmail.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef MATRIX_H
+#define MATRIX_H
+
+#include <stdint.h>
+#include <stdbool.h>
+
+
+#if (MATRIX_COLS <= 8)
+typedef uint8_t matrix_row_t;
+#elif (MATRIX_COLS <= 16)
+typedef uint16_t matrix_row_t;
+#elif (MATRIX_COLS <= 32)
+typedef uint32_t matrix_row_t;
+#else
+#error "MATRIX_COLS: invalid value"
+#endif
+
+#define MATRIX_IS_ON(row, col) (matrix_get_row(row) && (1<<col))
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* number of matrix rows */
+uint8_t matrix_rows(void);
+/* number of matrix columns */
+uint8_t matrix_cols(void);
+/* should be called at early stage of startup before matrix_init.(optional) */
+void matrix_setup(void);
+/* intialize matrix for scaning. */
+void matrix_init(void);
+/* scan all key states on matrix */
+uint8_t matrix_scan(void);
+/* whether modified from previous scan. used after matrix_scan. */
+bool matrix_is_modified(void) __attribute__ ((deprecated));
+/* whether a swtich is on */
+bool matrix_is_on(uint8_t row, uint8_t col);
+/* matrix state on row */
+matrix_row_t matrix_get_row(uint8_t row);
+/* print matrix for debug */
+void matrix_print(void);
+
+
+/* power control */
+void matrix_power_up(void);
+void matrix_power_down(void);
+
+/* executes code for Quantum */
+void matrix_init_quantum(void);
+void matrix_scan_quantum(void);
+
+void matrix_init_kb(void);
+void matrix_scan_kb(void);
+
+void matrix_init_user(void);
+void matrix_scan_user(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/tmk_core/common/mbed/bootloader.c b/tmk_core/common/mbed/bootloader.c
new file mode 100644
index 000000000..b51e83943
--- /dev/null
+++ b/tmk_core/common/mbed/bootloader.c
@@ -0,0 +1,4 @@
+#include "bootloader.h"
+
+
+void bootloader_jump(void) {}
diff --git a/tmk_core/common/mbed/suspend.c b/tmk_core/common/mbed/suspend.c
new file mode 100644
index 000000000..32651574f
--- /dev/null
+++ b/tmk_core/common/mbed/suspend.c
@@ -0,0 +1,6 @@
+#include <stdbool.h>
+
+
+void suspend_power_down(void) {}
+bool suspend_wakeup_condition(void) { return true; }
+void suspend_wakeup_init(void) {}
diff --git a/tmk_core/common/mbed/timer.c b/tmk_core/common/mbed/timer.c
new file mode 100644
index 000000000..c357ceb78
--- /dev/null
+++ b/tmk_core/common/mbed/timer.c
@@ -0,0 +1,41 @@
+#include "cmsis.h"
+#include "timer.h"
+
+/* Mill second tick count */
+volatile uint32_t timer_count = 0;
+
+/* Timer interrupt handler */
+void SysTick_Handler(void) {
+ timer_count++;
+}
+
+void timer_init(void)
+{
+ timer_count = 0;
+ SysTick_Config(SystemCoreClock / 1000); /* 1ms tick */
+}
+
+void timer_clear(void)
+{
+ timer_count = 0;
+}
+
+uint16_t timer_read(void)
+{
+ return (uint16_t)(timer_count & 0xFFFF);
+}
+
+uint32_t timer_read32(void)
+{
+ return timer_count;
+}
+
+uint16_t timer_elapsed(uint16_t last)
+{
+ return TIMER_DIFF_16(timer_read(), last);
+}
+
+uint32_t timer_elapsed32(uint32_t last)
+{
+ return TIMER_DIFF_32(timer_read32(), last);
+}
diff --git a/tmk_core/common/mbed/xprintf.cpp b/tmk_core/common/mbed/xprintf.cpp
new file mode 100644
index 000000000..3647ece75
--- /dev/null
+++ b/tmk_core/common/mbed/xprintf.cpp
@@ -0,0 +1,51 @@
+#include <cstdarg>
+//#include <stdarg.h>
+#include "mbed.h"
+#include "mbed/xprintf.h"
+
+
+#define STRING_STACK_LIMIT 120
+
+//TODO
+int xprintf(const char* format, ...) { return 0; }
+
+#if 0
+/* mbed Serial */
+Serial ser(UART_TX, UART_RX);
+
+/* TODO: Need small implementation for embedded */
+int xprintf(const char* format, ...)
+{
+ /* copy from mbed/common/RawSerial.cpp */
+ std::va_list arg;
+ va_start(arg, format);
+ int len = vsnprintf(NULL, 0, format, arg);
+ if (len < STRING_STACK_LIMIT) {
+ char temp[STRING_STACK_LIMIT];
+ vsprintf(temp, format, arg);
+ ser.puts(temp);
+ } else {
+ char *temp = new char[len + 1];
+ vsprintf(temp, format, arg);
+ ser.puts(temp);
+ delete[] temp;
+ }
+ va_end(arg);
+ return len;
+
+/* Fail: __builtin_va_arg_pack?
+ * https://gcc.gnu.org/onlinedocs/gcc-4.3.5/gcc/Constructing-Calls.html#Constructing-Calls
+ void *arg = __builtin_apply_args();
+ void *ret = __builtin_apply((void*)(&(ser.printf)), arg, 100);
+ __builtin_return(ret)
+*/
+/* Fail: varargs can not be passed to printf
+ //int r = ser.printf("test %i\r\n", 123);
+ va_list arg;
+ va_start(arg, format);
+ int r = ser.printf(format, arg);
+ va_end(arg);
+ return r;
+*/
+}
+#endif
diff --git a/tmk_core/common/mbed/xprintf.h b/tmk_core/common/mbed/xprintf.h
new file mode 100644
index 000000000..26bc529e5
--- /dev/null
+++ b/tmk_core/common/mbed/xprintf.h
@@ -0,0 +1,17 @@
+#ifndef XPRINTF_H
+#define XPRINTF_H
+
+//#define xprintf(format, ...) __xprintf(format, ##__VA_ARGS__)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int xprintf(const char *format, ...);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
diff --git a/tmk_core/common/mousekey.c b/tmk_core/common/mousekey.c
new file mode 100644
index 000000000..23469476e
--- /dev/null
+++ b/tmk_core/common/mousekey.c
@@ -0,0 +1,196 @@
+/*
+Copyright 2011 Jun Wako <wakojun@gmail.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdint.h>
+#include "keycode.h"
+#include "host.h"
+#include "timer.h"
+#include "print.h"
+#include "debug.h"
+#include "mousekey.h"
+
+
+
+static report_mouse_t mouse_report = {};
+static uint8_t mousekey_repeat = 0;
+static uint8_t mousekey_accel = 0;
+
+static void mousekey_debug(void);
+
+
+/*
+ * Mouse keys acceleration algorithm
+ * http://en.wikipedia.org/wiki/Mouse_keys
+ *
+ * speed = delta * max_speed * (repeat / time_to_max)**((1000+curve)/1000)
+ */
+/* milliseconds between the initial key press and first repeated motion event (0-2550) */
+uint8_t mk_delay = MOUSEKEY_DELAY/10;
+/* milliseconds between repeated motion events (0-255) */
+uint8_t mk_interval = MOUSEKEY_INTERVAL;
+/* steady speed (in action_delta units) applied each event (0-255) */
+uint8_t mk_max_speed = MOUSEKEY_MAX_SPEED;
+/* number of events (count) accelerating to steady speed (0-255) */
+uint8_t mk_time_to_max = MOUSEKEY_TIME_TO_MAX;
+/* ramp used to reach maximum pointer speed (NOT SUPPORTED) */
+//int8_t mk_curve = 0;
+/* wheel params */
+uint8_t mk_wheel_max_speed = MOUSEKEY_WHEEL_MAX_SPEED;
+uint8_t mk_wheel_time_to_max = MOUSEKEY_WHEEL_TIME_TO_MAX;
+
+
+static uint16_t last_timer = 0;
+
+
+static uint8_t move_unit(void)
+{
+ uint16_t unit;
+ if (mousekey_accel & (1<<0)) {
+ unit = (MOUSEKEY_MOVE_DELTA * mk_max_speed)/4;
+ } else if (mousekey_accel & (1<<1)) {
+ unit = (MOUSEKEY_MOVE_DELTA * mk_max_speed)/2;
+ } else if (mousekey_accel & (1<<2)) {
+ unit = (MOUSEKEY_MOVE_DELTA * mk_max_speed);
+ } else if (mousekey_repeat == 0) {
+ unit = MOUSEKEY_MOVE_DELTA;
+ } else if (mousekey_repeat >= mk_time_to_max) {
+ unit = MOUSEKEY_MOVE_DELTA * mk_max_speed;
+ } else {
+ unit = (MOUSEKEY_MOVE_DELTA * mk_max_speed * mousekey_repeat) / mk_time_to_max;
+ }
+ return (unit > MOUSEKEY_MOVE_MAX ? MOUSEKEY_MOVE_MAX : (unit == 0 ? 1 : unit));
+}
+
+static uint8_t wheel_unit(void)
+{
+ uint16_t unit;
+ if (mousekey_accel & (1<<0)) {
+ unit = (MOUSEKEY_WHEEL_DELTA * mk_wheel_max_speed)/4;
+ } else if (mousekey_accel & (1<<1)) {
+ unit = (MOUSEKEY_WHEEL_DELTA * mk_wheel_max_speed)/2;
+ } else if (mousekey_accel & (1<<2)) {
+ unit = (MOUSEKEY_WHEEL_DELTA * mk_wheel_max_speed);
+ } else if (mousekey_repeat == 0) {
+ unit = MOUSEKEY_WHEEL_DELTA;
+ } else if (mousekey_repeat >= mk_wheel_time_to_max) {
+ unit = MOUSEKEY_WHEEL_DELTA * mk_wheel_max_speed;
+ } else {
+ unit = (MOUSEKEY_WHEEL_DELTA * mk_wheel_max_speed * mousekey_repeat) / mk_wheel_time_to_max;
+ }
+ return (unit > MOUSEKEY_WHEEL_MAX ? MOUSEKEY_WHEEL_MAX : (unit == 0 ? 1 : unit));
+}
+
+void mousekey_task(void)
+{
+ if (timer_elapsed(last_timer) < (mousekey_repeat ? mk_interval : mk_delay*10))
+ return;
+
+ if (mouse_report.x == 0 && mouse_report.y == 0 && mouse_report.v == 0 && mouse_report.h == 0)
+ return;
+
+ if (mousekey_repeat != UINT8_MAX)
+ mousekey_repeat++;
+
+
+ if (mouse_report.x > 0) mouse_report.x = move_unit();
+ if (mouse_report.x < 0) mouse_report.x = move_unit() * -1;
+ if (mouse_report.y > 0) mouse_report.y = move_unit();
+ if (mouse_report.y < 0) mouse_report.y = move_unit() * -1;
+
+ /* diagonal move [1/sqrt(2) = 0.7] */
+ if (mouse_report.x && mouse_report.y) {
+ mouse_report.x *= 0.7;
+ mouse_report.y *= 0.7;
+ }
+
+ if (mouse_report.v > 0) mouse_report.v = wheel_unit();
+ if (mouse_report.v < 0) mouse_report.v = wheel_unit() * -1;
+ if (mouse_report.h > 0) mouse_report.h = wheel_unit();
+ if (mouse_report.h < 0) mouse_report.h = wheel_unit() * -1;
+
+ mousekey_send();
+}
+
+void mousekey_on(uint8_t code)
+{
+ if (code == KC_MS_UP) mouse_report.y = move_unit() * -1;
+ else if (code == KC_MS_DOWN) mouse_report.y = move_unit();
+ else if (code == KC_MS_LEFT) mouse_report.x = move_unit() * -1;
+ else if (code == KC_MS_RIGHT) mouse_report.x = move_unit();
+ else if (code == KC_MS_WH_UP) mouse_report.v = wheel_unit();
+ else if (code == KC_MS_WH_DOWN) mouse_report.v = wheel_unit() * -1;
+ else if (code == KC_MS_WH_LEFT) mouse_report.h = wheel_unit() * -1;
+ else if (code == KC_MS_WH_RIGHT) mouse_report.h = wheel_unit();
+ else if (code == KC_MS_BTN1) mouse_report.buttons |= MOUSE_BTN1;
+ else if (code == KC_MS_BTN2) mouse_report.buttons |= MOUSE_BTN2;
+ else if (code == KC_MS_BTN3) mouse_report.buttons |= MOUSE_BTN3;
+ else if (code == KC_MS_BTN4) mouse_report.buttons |= MOUSE_BTN4;
+ else if (code == KC_MS_BTN5) mouse_report.buttons |= MOUSE_BTN5;
+ else if (code == KC_MS_ACCEL0) mousekey_accel |= (1<<0);
+ else if (code == KC_MS_ACCEL1) mousekey_accel |= (1<<1);
+ else if (code == KC_MS_ACCEL2) mousekey_accel |= (1<<2);
+}
+
+void mousekey_off(uint8_t code)
+{
+ if (code == KC_MS_UP && mouse_report.y < 0) mouse_report.y = 0;
+ else if (code == KC_MS_DOWN && mouse_report.y > 0) mouse_report.y = 0;
+ else if (code == KC_MS_LEFT && mouse_report.x < 0) mouse_report.x = 0;
+ else if (code == KC_MS_RIGHT && mouse_report.x > 0) mouse_report.x = 0;
+ else if (code == KC_MS_WH_UP && mouse_report.v > 0) mouse_report.v = 0;
+ else if (code == KC_MS_WH_DOWN && mouse_report.v < 0) mouse_report.v = 0;
+ else if (code == KC_MS_WH_LEFT && mouse_report.h < 0) mouse_report.h = 0;
+ else if (code == KC_MS_WH_RIGHT && mouse_report.h > 0) mouse_report.h = 0;
+ else if (code == KC_MS_BTN1) mouse_report.buttons &= ~MOUSE_BTN1;
+ else if (code == KC_MS_BTN2) mouse_report.buttons &= ~MOUSE_BTN2;
+ else if (code == KC_MS_BTN3) mouse_report.buttons &= ~MOUSE_BTN3;
+ else if (code == KC_MS_BTN4) mouse_report.buttons &= ~MOUSE_BTN4;
+ else if (code == KC_MS_BTN5) mouse_report.buttons &= ~MOUSE_BTN5;
+ else if (code == KC_MS_ACCEL0) mousekey_accel &= ~(1<<0);
+ else if (code == KC_MS_ACCEL1) mousekey_accel &= ~(1<<1);
+ else if (code == KC_MS_ACCEL2) mousekey_accel &= ~(1<<2);
+
+ if (mouse_report.x == 0 && mouse_report.y == 0 && mouse_report.v == 0 && mouse_report.h == 0)
+ mousekey_repeat = 0;
+}
+
+void mousekey_send(void)
+{
+ mousekey_debug();
+ host_mouse_send(&mouse_report);
+ last_timer = timer_read();
+}
+
+void mousekey_clear(void)
+{
+ mouse_report = (report_mouse_t){};
+ mousekey_repeat = 0;
+ mousekey_accel = 0;
+}
+
+static void mousekey_debug(void)
+{
+ if (!debug_mouse) return;
+ print("mousekey [btn|x y v h](rep/acl): [");
+ phex(mouse_report.buttons); print("|");
+ print_decs(mouse_report.x); print(" ");
+ print_decs(mouse_report.y); print(" ");
+ print_decs(mouse_report.v); print(" ");
+ print_decs(mouse_report.h); print("](");
+ print_dec(mousekey_repeat); print("/");
+ print_dec(mousekey_accel); print(")\n");
+}
diff --git a/tmk_core/common/mousekey.h b/tmk_core/common/mousekey.h
new file mode 100644
index 000000000..6eede06b4
--- /dev/null
+++ b/tmk_core/common/mousekey.h
@@ -0,0 +1,77 @@
+/*
+Copyright 2011 Jun Wako <wakojun@gmail.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef MOUSEKEY_H
+#define MOUSEKEY_H
+
+#include <stdbool.h>
+#include "host.h"
+
+
+/* max value on report descriptor */
+#define MOUSEKEY_MOVE_MAX 127
+#define MOUSEKEY_WHEEL_MAX 127
+
+#ifndef MOUSEKEY_MOVE_DELTA
+#define MOUSEKEY_MOVE_DELTA 5
+#endif
+#ifndef MOUSEKEY_WHEEL_DELTA
+#define MOUSEKEY_WHEEL_DELTA 1
+#endif
+#ifndef MOUSEKEY_DELAY
+#define MOUSEKEY_DELAY 300
+#endif
+#ifndef MOUSEKEY_INTERVAL
+#define MOUSEKEY_INTERVAL 50
+#endif
+#ifndef MOUSEKEY_MAX_SPEED
+#define MOUSEKEY_MAX_SPEED 10
+#endif
+#ifndef MOUSEKEY_TIME_TO_MAX
+#define MOUSEKEY_TIME_TO_MAX 20
+#endif
+#ifndef MOUSEKEY_WHEEL_MAX_SPEED
+#define MOUSEKEY_WHEEL_MAX_SPEED 8
+#endif
+#ifndef MOUSEKEY_WHEEL_TIME_TO_MAX
+#define MOUSEKEY_WHEEL_TIME_TO_MAX 40
+#endif
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern uint8_t mk_delay;
+extern uint8_t mk_interval;
+extern uint8_t mk_max_speed;
+extern uint8_t mk_time_to_max;
+extern uint8_t mk_wheel_max_speed;
+extern uint8_t mk_wheel_time_to_max;
+
+
+void mousekey_task(void);
+void mousekey_on(uint8_t code);
+void mousekey_off(uint8_t code);
+void mousekey_clear(void);
+void mousekey_send(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/tmk_core/common/nodebug.h b/tmk_core/common/nodebug.h
new file mode 100644
index 000000000..5e18656e5
--- /dev/null
+++ b/tmk_core/common/nodebug.h
@@ -0,0 +1,29 @@
+/*
+Copyright 2013 Jun Wako <wakojun@gmail.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef NODEBUG_H
+#define NODEBUG_H
+
+#ifndef NO_DEBUG
+ #define NO_DEBUG
+ #include "debug.h"
+ #undef NO_DEBUG
+#else
+ #include "debug.h"
+#endif
+
+#endif
diff --git a/tmk_core/common/print.c b/tmk_core/common/print.c
new file mode 100644
index 000000000..00489557f
--- /dev/null
+++ b/tmk_core/common/print.c
@@ -0,0 +1,52 @@
+/* Copyright 2012,2013 Jun Wako <wakojun@gmail.com> */
+/* Very basic print functions, intended to be used with usb_debug_only.c
+ * http://www.pjrc.com/teensy/
+ * Copyright (c) 2008 PJRC.COM, LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+#include "print.h"
+
+
+#ifndef NO_PRINT
+
+#if defined(__AVR__)
+
+#define sendchar(c) xputc(c)
+
+
+void print_set_sendchar(int8_t (*sendchar_func)(uint8_t))
+{
+ xdev_out(sendchar_func);
+}
+
+#elif defined(PROTOCOL_CHIBIOS) /* __AVR__ */
+
+// don't need anything extra
+
+#elif defined(__arm__) /* __AVR__ */
+
+// TODO
+//void print_set_sendchar(int8_t (*sendchar_func)(uint8_t)) { }
+
+#endif /* __AVR__ */
+
+#endif
diff --git a/tmk_core/common/print.h b/tmk_core/common/print.h
new file mode 100644
index 000000000..0368bcd4a
--- /dev/null
+++ b/tmk_core/common/print.h
@@ -0,0 +1,145 @@
+/* Copyright 2012 Jun Wako <wakojun@gmail.com> */
+/* Very basic print functions, intended to be used with usb_debug_only.c
+ * http://www.pjrc.com/teensy/
+ * Copyright (c) 2008 PJRC.COM, LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef PRINT_H__
+#define PRINT_H__ 1
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "util.h"
+
+
+
+
+#ifndef NO_PRINT
+
+
+#if defined(__AVR__)
+
+#include "avr/xprintf.h"
+#define print(s) xputs(PSTR(s))
+#define println(s) xputs(PSTR(s "\r\n"))
+
+#ifdef __cplusplus
+extern "C"
+#endif
+/* function pointer of sendchar to be used by print utility */
+void print_set_sendchar(int8_t (*print_sendchar_func)(uint8_t));
+
+#elif defined(PROTOCOL_CHIBIOS) /* __AVR__ */
+
+#include "chibios/printf.h"
+
+#define print(s) printf(s)
+#define println(s) printf(s "\r\n")
+#define xprintf printf
+
+#elif defined(__arm__) /* __AVR__ */
+
+#include "mbed/xprintf.h"
+
+#define print(s) xprintf(s)
+#define println(s) xprintf(s "\r\n")
+
+/* TODO: to select output destinations: UART/USBSerial */
+#define print_set_sendchar(func)
+
+#endif /* __AVR__ */
+
+
+/* decimal */
+#define print_dec(i) xprintf("%u", i)
+#define print_decs(i) xprintf("%d", i)
+/* hex */
+#define print_hex4(i) xprintf("%X", i)
+#define print_hex8(i) xprintf("%02X", i)
+#define print_hex16(i) xprintf("%04X", i)
+#define print_hex32(i) xprintf("%08lX", i)
+/* binary */
+#define print_bin4(i) xprintf("%04b", i)
+#define print_bin8(i) xprintf("%08b", i)
+#define print_bin16(i) xprintf("%016b", i)
+#define print_bin32(i) xprintf("%032lb", i)
+#define print_bin_reverse8(i) xprintf("%08b", bitrev(i))
+#define print_bin_reverse16(i) xprintf("%016b", bitrev16(i))
+#define print_bin_reverse32(i) xprintf("%032lb", bitrev32(i))
+/* print value utility */
+#define print_val_dec(v) xprintf(#v ": %u\n", v)
+#define print_val_decs(v) xprintf(#v ": %d\n", v)
+#define print_val_hex8(v) xprintf(#v ": %X\n", v)
+#define print_val_hex16(v) xprintf(#v ": %02X\n", v)
+#define print_val_hex32(v) xprintf(#v ": %04lX\n", v)
+#define print_val_bin8(v) xprintf(#v ": %08b\n", v)
+#define print_val_bin16(v) xprintf(#v ": %016b\n", v)
+#define print_val_bin32(v) xprintf(#v ": %032lb\n", v)
+#define print_val_bin_reverse8(v) xprintf(#v ": %08b\n", bitrev(v))
+#define print_val_bin_reverse16(v) xprintf(#v ": %016b\n", bitrev16(v))
+#define print_val_bin_reverse32(v) xprintf(#v ": %032lb\n", bitrev32(v))
+
+#else /* NO_PRINT */
+
+#define xprintf(fmt, ...)
+#define print(s)
+#define println(s)
+#define print_set_sendchar(func)
+#define print_dec(data)
+#define print_decs(data)
+#define print_hex4(data)
+#define print_hex8(data)
+#define print_hex16(data)
+#define print_hex32(data)
+#define print_bin4(data)
+#define print_bin8(data)
+#define print_bin16(data)
+#define print_bin32(data)
+#define print_bin_reverse8(data)
+#define print_bin_reverse16(data)
+#define print_bin_reverse32(data)
+#define print_val_dec(v)
+#define print_val_decs(v)
+#define print_val_hex8(v)
+#define print_val_hex16(v)
+#define print_val_hex32(v)
+#define print_val_bin8(v)
+#define print_val_bin16(v)
+#define print_val_bin32(v)
+#define print_val_bin_reverse8(v)
+#define print_val_bin_reverse16(v)
+#define print_val_bin_reverse32(v)
+
+#endif /* NO_PRINT */
+
+
+/* Backward compatiblitly for old name */
+#define pdec(data) print_dec(data)
+#define pdec16(data) print_dec(data)
+#define phex(data) print_hex8(data)
+#define phex16(data) print_hex16(data)
+#define pbin(data) print_bin8(data)
+#define pbin16(data) print_bin16(data)
+#define pbin_reverse(data) print_bin_reverse8(data)
+#define pbin_reverse16(data) print_bin_reverse16(data)
+
+
+#endif
diff --git a/tmk_core/common/progmem.h b/tmk_core/common/progmem.h
new file mode 100644
index 000000000..5b2765625
--- /dev/null
+++ b/tmk_core/common/progmem.h
@@ -0,0 +1,12 @@
+#ifndef PROGMEM_H
+#define PROGMEM_H 1
+
+#if defined(__AVR__)
+# include <avr/pgmspace.h>
+#elif defined(__arm__)
+# define PROGMEM
+# define pgm_read_byte(p) *((unsigned char*)p)
+# define pgm_read_word(p) *((uint16_t*)p)
+#endif
+
+#endif
diff --git a/tmk_core/common/report.h b/tmk_core/common/report.h
new file mode 100644
index 000000000..0c799eca3
--- /dev/null
+++ b/tmk_core/common/report.h
@@ -0,0 +1,188 @@
+/*
+Copyright 2011,2012 Jun Wako <wakojun@gmail.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef REPORT_H
+#define REPORT_H
+
+#include <stdint.h>
+#include "keycode.h"
+
+
+/* report id */
+#define REPORT_ID_MOUSE 1
+#define REPORT_ID_SYSTEM 2
+#define REPORT_ID_CONSUMER 3
+
+/* mouse buttons */
+#define MOUSE_BTN1 (1<<0)
+#define MOUSE_BTN2 (1<<1)
+#define MOUSE_BTN3 (1<<2)
+#define MOUSE_BTN4 (1<<3)
+#define MOUSE_BTN5 (1<<4)
+
+/* Consumer Page(0x0C)
+ * following are supported by Windows: http://msdn.microsoft.com/en-us/windows/hardware/gg463372.aspx
+ */
+#define AUDIO_MUTE 0x00E2
+#define AUDIO_VOL_UP 0x00E9
+#define AUDIO_VOL_DOWN 0x00EA
+#define TRANSPORT_NEXT_TRACK 0x00B5
+#define TRANSPORT_PREV_TRACK 0x00B6
+#define TRANSPORT_STOP 0x00B7
+#define TRANSPORT_STOP_EJECT 0x00CC
+#define TRANSPORT_PLAY_PAUSE 0x00CD
+/* application launch */
+#define AL_CC_CONFIG 0x0183
+#define AL_EMAIL 0x018A
+#define AL_CALCULATOR 0x0192
+#define AL_LOCAL_BROWSER 0x0194
+/* application control */
+#define AC_SEARCH 0x0221
+#define AC_HOME 0x0223
+#define AC_BACK 0x0224
+#define AC_FORWARD 0x0225
+#define AC_STOP 0x0226
+#define AC_REFRESH 0x0227
+#define AC_BOOKMARKS 0x022A
+/* supplement for Bluegiga iWRAP HID(not supported by Windows?) */
+#define AL_LOCK 0x019E
+#define TRANSPORT_RECORD 0x00B2
+#define TRANSPORT_FAST_FORWARD 0x00B3
+#define TRANSPORT_REWIND 0x00B4
+#define TRANSPORT_EJECT 0x00B8
+#define AC_MINIMIZE 0x0206
+
+/* Generic Desktop Page(0x01) - system power control */
+#define SYSTEM_POWER_DOWN 0x0081
+#define SYSTEM_SLEEP 0x0082
+#define SYSTEM_WAKE_UP 0x0083
+
+
+/* key report size(NKRO or boot mode) */
+#if defined(PROTOCOL_PJRC) && defined(NKRO_ENABLE)
+# include "usb.h"
+# define KEYBOARD_REPORT_SIZE KBD2_SIZE
+# define KEYBOARD_REPORT_KEYS (KBD2_SIZE - 2)
+# define KEYBOARD_REPORT_BITS (KBD2_SIZE - 1)
+
+#elif defined(PROTOCOL_LUFA) && defined(NKRO_ENABLE)
+# include "protocol/lufa/descriptor.h"
+# define KEYBOARD_REPORT_SIZE NKRO_EPSIZE
+# define KEYBOARD_REPORT_KEYS (NKRO_EPSIZE - 2)
+# define KEYBOARD_REPORT_BITS (NKRO_EPSIZE - 1)
+#elif defined(PROTOCOL_CHIBIOS) && defined(NKRO_ENABLE)
+# include "protocol/chibios/usb_main.h"
+# define KEYBOARD_REPORT_SIZE NKRO_EPSIZE
+# define KEYBOARD_REPORT_KEYS (NKRO_EPSIZE - 2)
+# define KEYBOARD_REPORT_BITS (NKRO_EPSIZE - 1)
+
+#else
+# define KEYBOARD_REPORT_SIZE 8
+# define KEYBOARD_REPORT_KEYS 6
+#endif
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * keyboard report is 8-byte array retains state of 8 modifiers and 6 keys.
+ *
+ * byte |0 |1 |2 |3 |4 |5 |6 |7
+ * -----+--------+--------+--------+--------+--------+--------+--------+--------
+ * desc |mods |reserved|keys[0] |keys[1] |keys[2] |keys[3] |keys[4] |keys[5]
+ *
+ * It is exended to 16 bytes to retain 120keys+8mods when NKRO mode.
+ *
+ * byte |0 |1 |2 |3 |4 |5 |6 |7 ... |15
+ * -----+--------+--------+--------+--------+--------+--------+--------+-------- +--------
+ * desc |mods |bits[0] |bits[1] |bits[2] |bits[3] |bits[4] |bits[5] |bits[6] ... |bit[14]
+ *
+ * mods retains state of 8 modifiers.
+ *
+ * bit |0 |1 |2 |3 |4 |5 |6 |7
+ * -----+--------+--------+--------+--------+--------+--------+--------+--------
+ * desc |Lcontrol|Lshift |Lalt |Lgui |Rcontrol|Rshift |Ralt |Rgui
+ *
+ */
+typedef union {
+ uint8_t raw[KEYBOARD_REPORT_SIZE];
+ struct {
+ uint8_t mods;
+ uint8_t reserved;
+ uint8_t keys[KEYBOARD_REPORT_KEYS];
+ };
+#ifdef NKRO_ENABLE
+ struct {
+ uint8_t mods;
+ uint8_t bits[KEYBOARD_REPORT_BITS];
+ } nkro;
+#endif
+} __attribute__ ((packed)) report_keyboard_t;
+/*
+typedef struct {
+ uint8_t mods;
+ uint8_t reserved;
+ uint8_t keys[REPORT_KEYS];
+} __attribute__ ((packed)) report_keyboard_t;
+*/
+
+typedef struct {
+ uint8_t buttons;
+ int8_t x;
+ int8_t y;
+ int8_t v;
+ int8_t h;
+} __attribute__ ((packed)) report_mouse_t;
+
+
+/* keycode to system usage */
+#define KEYCODE2SYSTEM(key) \
+ (key == KC_SYSTEM_POWER ? SYSTEM_POWER_DOWN : \
+ (key == KC_SYSTEM_SLEEP ? SYSTEM_SLEEP : \
+ (key == KC_SYSTEM_WAKE ? SYSTEM_WAKE_UP : 0)))
+
+/* keycode to consumer usage */
+#define KEYCODE2CONSUMER(key) \
+ (key == KC_AUDIO_MUTE ? AUDIO_MUTE : \
+ (key == KC_AUDIO_VOL_UP ? AUDIO_VOL_UP : \
+ (key == KC_AUDIO_VOL_DOWN ? AUDIO_VOL_DOWN : \
+ (key == KC_MEDIA_NEXT_TRACK ? TRANSPORT_NEXT_TRACK : \
+ (key == KC_MEDIA_PREV_TRACK ? TRANSPORT_PREV_TRACK : \
+ (key == KC_MEDIA_FAST_FORWARD ? TRANSPORT_FAST_FORWARD : \
+ (key == KC_MEDIA_REWIND ? TRANSPORT_REWIND : \
+ (key == KC_MEDIA_STOP ? TRANSPORT_STOP : \
+ (key == KC_MEDIA_EJECT ? TRANSPORT_STOP_EJECT : \
+ (key == KC_MEDIA_PLAY_PAUSE ? TRANSPORT_PLAY_PAUSE : \
+ (key == KC_MEDIA_SELECT ? AL_CC_CONFIG : \
+ (key == KC_MAIL ? AL_EMAIL : \
+ (key == KC_CALCULATOR ? AL_CALCULATOR : \
+ (key == KC_MY_COMPUTER ? AL_LOCAL_BROWSER : \
+ (key == KC_WWW_SEARCH ? AC_SEARCH : \
+ (key == KC_WWW_HOME ? AC_HOME : \
+ (key == KC_WWW_BACK ? AC_BACK : \
+ (key == KC_WWW_FORWARD ? AC_FORWARD : \
+ (key == KC_WWW_STOP ? AC_STOP : \
+ (key == KC_WWW_REFRESH ? AC_REFRESH : \
+ (key == KC_WWW_FAVORITES ? AC_BOOKMARKS : 0)))))))))))))))))))))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/tmk_core/common/sendchar.h b/tmk_core/common/sendchar.h
new file mode 100644
index 000000000..7a64d00c7
--- /dev/null
+++ b/tmk_core/common/sendchar.h
@@ -0,0 +1,35 @@
+/*
+Copyright 2011 Jun Wako <wakojun@gmail.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef SENDCHAR_H
+#define SENDCHAR_H
+
+#include <stdint.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* transmit a character. return 0 on success, -1 on error. */
+int8_t sendchar(uint8_t c);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/tmk_core/common/sendchar_null.c b/tmk_core/common/sendchar_null.c
new file mode 100644
index 000000000..293330622
--- /dev/null
+++ b/tmk_core/common/sendchar_null.c
@@ -0,0 +1,23 @@
+/*
+Copyright 2011 Jun Wako <wakojun@gmail.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "sendchar.h"
+
+
+int8_t sendchar(uint8_t c)
+{
+ return 0;
+}
diff --git a/tmk_core/common/sendchar_uart.c b/tmk_core/common/sendchar_uart.c
new file mode 100644
index 000000000..0241859eb
--- /dev/null
+++ b/tmk_core/common/sendchar_uart.c
@@ -0,0 +1,25 @@
+/*
+Copyright 2011 Jun Wako <wakojun@gmail.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "uart.h"
+#include "sendchar.h"
+
+
+int8_t sendchar(uint8_t c)
+{
+ uart_putchar(c);
+ return 0;
+}
diff --git a/tmk_core/common/sleep_led.h b/tmk_core/common/sleep_led.h
new file mode 100644
index 000000000..6bdcf558a
--- /dev/null
+++ b/tmk_core/common/sleep_led.h
@@ -0,0 +1,21 @@
+#ifndef SLEEP_LED_H
+#define SLEEP_LED_H
+
+
+#ifdef SLEEP_LED_ENABLE
+
+void sleep_led_init(void);
+void sleep_led_enable(void);
+void sleep_led_disable(void);
+void sleep_led_toggle(void);
+
+#else
+
+#define sleep_led_init()
+#define sleep_led_enable()
+#define sleep_led_disable()
+#define sleep_led_toggle()
+
+#endif
+
+#endif
diff --git a/tmk_core/common/suspend.h b/tmk_core/common/suspend.h
new file mode 100644
index 000000000..80617a824
--- /dev/null
+++ b/tmk_core/common/suspend.h
@@ -0,0 +1,13 @@
+#ifndef SUSPEND_H
+#define SUSPEND_H
+
+#include <stdint.h>
+#include <stdbool.h>
+
+
+void suspend_idle(uint8_t timeout);
+void suspend_power_down(void);
+bool suspend_wakeup_condition(void);
+void suspend_wakeup_init(void);
+
+#endif
diff --git a/tmk_core/common/timer.h b/tmk_core/common/timer.h
new file mode 100644
index 000000000..fe23f87ae
--- /dev/null
+++ b/tmk_core/common/timer.h
@@ -0,0 +1,53 @@
+/*
+Copyright 2011 Jun Wako <wakojun@gmail.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef TIMER_H
+#define TIMER_H 1
+
+#include <stdint.h>
+
+#if defined(__AVR__)
+#include "avr/timer_avr.h"
+#endif
+
+
+#define TIMER_DIFF(a, b, max) ((a) >= (b) ? (a) - (b) : (max) - (b) + (a))
+#define TIMER_DIFF_8(a, b) TIMER_DIFF(a, b, UINT8_MAX)
+#define TIMER_DIFF_16(a, b) TIMER_DIFF(a, b, UINT16_MAX)
+#define TIMER_DIFF_32(a, b) TIMER_DIFF(a, b, UINT32_MAX)
+#define TIMER_DIFF_RAW(a, b) TIMER_DIFF_8(a, b)
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern volatile uint32_t timer_count;
+
+
+void timer_init(void);
+void timer_clear(void);
+uint16_t timer_read(void);
+uint32_t timer_read32(void);
+uint16_t timer_elapsed(uint16_t last);
+uint32_t timer_elapsed32(uint32_t last);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/tmk_core/common/uart.c b/tmk_core/common/uart.c
new file mode 100644
index 000000000..c17649b08
--- /dev/null
+++ b/tmk_core/common/uart.c
@@ -0,0 +1,129 @@
+// TODO: Teensy support(ATMega32u4/AT90USB128)
+// Fixed for Arduino Duemilanove ATmega168p by Jun Wako
+/* UART Example for Teensy USB Development Board
+ * http://www.pjrc.com/teensy/
+ * Copyright (c) 2009 PJRC.COM, LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+// Version 1.0: Initial Release
+// Version 1.1: Add support for Teensy 2.0, minor optimizations
+
+
+#include <avr/io.h>
+#include <avr/interrupt.h>
+
+#include "uart.h"
+
+// These buffers may be any size from 2 to 256 bytes.
+#define RX_BUFFER_SIZE 64
+#define TX_BUFFER_SIZE 40
+
+static volatile uint8_t tx_buffer[TX_BUFFER_SIZE];
+static volatile uint8_t tx_buffer_head;
+static volatile uint8_t tx_buffer_tail;
+static volatile uint8_t rx_buffer[RX_BUFFER_SIZE];
+static volatile uint8_t rx_buffer_head;
+static volatile uint8_t rx_buffer_tail;
+
+// Initialize the UART
+void uart_init(uint32_t baud)
+{
+ cli();
+ UBRR0 = (F_CPU / 4 / baud - 1) / 2;
+ UCSR0A = (1<<U2X0);
+ UCSR0B = (1<<RXEN0) | (1<<TXEN0) | (1<<RXCIE0);
+ UCSR0C = (1<<UCSZ01) | (1<<UCSZ00);
+ tx_buffer_head = tx_buffer_tail = 0;
+ rx_buffer_head = rx_buffer_tail = 0;
+ sei();
+}
+
+// Transmit a byte
+void uart_putchar(uint8_t c)
+{
+ uint8_t i;
+
+ i = tx_buffer_head + 1;
+ if (i >= TX_BUFFER_SIZE) i = 0;
+ while (tx_buffer_tail == i) ; // wait until space in buffer
+ //cli();
+ tx_buffer[i] = c;
+ tx_buffer_head = i;
+ UCSR0B = (1<<RXEN0) | (1<<TXEN0) | (1<<RXCIE0) | (1<<UDRIE0);
+ //sei();
+}
+
+// Receive a byte
+uint8_t uart_getchar(void)
+{
+ uint8_t c, i;
+
+ while (rx_buffer_head == rx_buffer_tail) ; // wait for character
+ i = rx_buffer_tail + 1;
+ if (i >= RX_BUFFER_SIZE) i = 0;
+ c = rx_buffer[i];
+ rx_buffer_tail = i;
+ return c;
+}
+
+// Return the number of bytes waiting in the receive buffer.
+// Call this before uart_getchar() to check if it will need
+// to wait for a byte to arrive.
+uint8_t uart_available(void)
+{
+ uint8_t head, tail;
+
+ head = rx_buffer_head;
+ tail = rx_buffer_tail;
+ if (head >= tail) return head - tail;
+ return RX_BUFFER_SIZE + head - tail;
+}
+
+// Transmit Interrupt
+ISR(USART_UDRE_vect)
+{
+ uint8_t i;
+
+ if (tx_buffer_head == tx_buffer_tail) {
+ // buffer is empty, disable transmit interrupt
+ UCSR0B = (1<<RXEN0) | (1<<TXEN0) | (1<<RXCIE0);
+ } else {
+ i = tx_buffer_tail + 1;
+ if (i >= TX_BUFFER_SIZE) i = 0;
+ UDR0 = tx_buffer[i];
+ tx_buffer_tail = i;
+ }
+}
+
+// Receive Interrupt
+ISR(USART_RX_vect)
+{
+ uint8_t c, i;
+
+ c = UDR0;
+ i = rx_buffer_head + 1;
+ if (i >= RX_BUFFER_SIZE) i = 0;
+ if (i != rx_buffer_tail) {
+ rx_buffer[i] = c;
+ rx_buffer_head = i;
+ }
+}
+
diff --git a/tmk_core/common/uart.h b/tmk_core/common/uart.h
new file mode 100644
index 000000000..41136a396
--- /dev/null
+++ b/tmk_core/common/uart.h
@@ -0,0 +1,11 @@
+#ifndef _uart_included_h_
+#define _uart_included_h_
+
+#include <stdint.h>
+
+void uart_init(uint32_t baud);
+void uart_putchar(uint8_t c);
+uint8_t uart_getchar(void);
+uint8_t uart_available(void);
+
+#endif
diff --git a/tmk_core/common/util.c b/tmk_core/common/util.c
new file mode 100644
index 000000000..7e0d54299
--- /dev/null
+++ b/tmk_core/common/util.c
@@ -0,0 +1,101 @@
+/*
+Copyright 2011 Jun Wako <wakojun@gmail.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "util.h"
+
+// bit population - return number of on-bit
+uint8_t bitpop(uint8_t bits)
+{
+ uint8_t c;
+ for (c = 0; bits; c++)
+ bits &= bits - 1;
+ return c;
+/*
+ const uint8_t bit_count[] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 };
+ return bit_count[bits>>4] + bit_count[bits&0x0F]
+*/
+}
+
+uint8_t bitpop16(uint16_t bits)
+{
+ uint8_t c;
+ for (c = 0; bits; c++)
+ bits &= bits - 1;
+ return c;
+}
+
+uint8_t bitpop32(uint32_t bits)
+{
+ uint8_t c;
+ for (c = 0; bits; c++)
+ bits &= bits - 1;
+ return c;
+}
+
+// most significant on-bit - return highest location of on-bit
+// NOTE: return 0 when bit0 is on or all bits are off
+uint8_t biton(uint8_t bits)
+{
+ uint8_t n = 0;
+ if (bits >> 4) { bits >>= 4; n += 4;}
+ if (bits >> 2) { bits >>= 2; n += 2;}
+ if (bits >> 1) { bits >>= 1; n += 1;}
+ return n;
+}
+
+uint8_t biton16(uint16_t bits)
+{
+ uint8_t n = 0;
+ if (bits >> 8) { bits >>= 8; n += 8;}
+ if (bits >> 4) { bits >>= 4; n += 4;}
+ if (bits >> 2) { bits >>= 2; n += 2;}
+ if (bits >> 1) { bits >>= 1; n += 1;}
+ return n;
+}
+
+uint8_t biton32(uint32_t bits)
+{
+ uint8_t n = 0;
+ if (bits >>16) { bits >>=16; n +=16;}
+ if (bits >> 8) { bits >>= 8; n += 8;}
+ if (bits >> 4) { bits >>= 4; n += 4;}
+ if (bits >> 2) { bits >>= 2; n += 2;}
+ if (bits >> 1) { bits >>= 1; n += 1;}
+ return n;
+}
+
+
+
+uint8_t bitrev(uint8_t bits)
+{
+ bits = (bits & 0x0f)<<4 | (bits & 0xf0)>>4;
+ bits = (bits & 0b00110011)<<2 | (bits & 0b11001100)>>2;
+ bits = (bits & 0b01010101)<<1 | (bits & 0b10101010)>>1;
+ return bits;
+}
+
+uint16_t bitrev16(uint16_t bits)
+{
+ bits = bitrev(bits & 0x00ff)<<8 | bitrev((bits & 0xff00)>>8);
+ return bits;
+}
+
+uint32_t bitrev32(uint32_t bits)
+{
+ bits = (uint32_t)bitrev16(bits & 0x0000ffff)<<16 | bitrev16((bits & 0xffff0000)>>16);
+ return bits;
+}
diff --git a/tmk_core/common/util.h b/tmk_core/common/util.h
new file mode 100644
index 000000000..7451cc084
--- /dev/null
+++ b/tmk_core/common/util.h
@@ -0,0 +1,43 @@
+/*
+Copyright 2011 Jun Wako <wakojun@gmail.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef UTIL_H
+#define UTIL_H
+
+#include <stdint.h>
+
+// convert to L string
+#define LSTR(s) XLSTR(s)
+#define XLSTR(s) L ## #s
+// convert to string
+#define STR(s) XSTR(s)
+#define XSTR(s) #s
+
+
+uint8_t bitpop(uint8_t bits);
+uint8_t bitpop16(uint16_t bits);
+uint8_t bitpop32(uint32_t bits);
+
+uint8_t biton(uint8_t bits);
+uint8_t biton16(uint16_t bits);
+uint8_t biton32(uint32_t bits);
+
+uint8_t bitrev(uint8_t bits);
+uint16_t bitrev16(uint16_t bits);
+uint32_t bitrev32(uint32_t bits);
+
+#endif
diff --git a/tmk_core/common/wait.h b/tmk_core/common/wait.h
new file mode 100644
index 000000000..82727be01
--- /dev/null
+++ b/tmk_core/common/wait.h
@@ -0,0 +1,24 @@
+#ifndef WAIT_H
+#define WAIT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(__AVR__)
+# include <util/delay.h>
+# define wait_ms(ms) _delay_ms(ms)
+# define wait_us(us) _delay_us(us)
+#elif defined(PROTOCOL_CHIBIOS) /* __AVR__ */
+# include "ch.h"
+# define wait_ms(ms) chThdSleepMilliseconds(ms)
+# define wait_us(us) chThdSleepMicroseconds(us)
+#elif defined(__arm__) /* __AVR__ */
+# include "wait_api.h"
+#endif /* __AVR__ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif