summaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
authortmk <hasu@tmk-kbd.com>2015-04-10 01:32:04 +0900
committertmk <hasu@tmk-kbd.com>2015-04-10 01:32:04 +0900
commita074364c3731d66b56d988c8a6c960a83ea0e0a1 (patch)
tree5a4ecf854c41b510b4378bacb7c7228297f8bc58 /common
Squashed 'tmk_core/' content from commit 05caacc
git-subtree-dir: tmk_core git-subtree-split: 05caaccec92694bb24c8c3c3a9940b96efd4605c
Diffstat (limited to 'common')
-rw-r--r--common/action.c565
-rw-r--r--common/action.h82
-rw-r--r--common/action_code.h315
-rw-r--r--common/action_layer.c138
-rw-r--r--common/action_layer.h77
-rw-r--r--common/action_macro.c83
-rw-r--r--common/action_macro.h102
-rw-r--r--common/action_tapping.c376
-rw-r--r--common/action_tapping.h39
-rw-r--r--common/action_util.c307
-rw-r--r--common/action_util.h66
-rw-r--r--common/avr/bootloader.c148
-rw-r--r--common/avr/eeconfig.c45
-rw-r--r--common/avr/suspend.c122
-rw-r--r--common/avr/suspend_avr.h27
-rw-r--r--common/avr/timer.c117
-rw-r--r--common/avr/timer_avr.h42
-rw-r--r--common/avr/xprintf.S500
-rw-r--r--common/avr/xprintf.h111
-rw-r--r--common/backlight.c85
-rw-r--r--common/backlight.h40
-rw-r--r--common/bootloader.h25
-rw-r--r--common/bootmagic.c128
-rw-r--r--common/bootmagic.h100
-rw-r--r--common/command.c644
-rw-r--r--common/command.h35
-rw-r--r--common/debug.c24
-rw-r--r--common/debug.h117
-rw-r--r--common/eeconfig.h75
-rw-r--r--common/host.c97
-rw-r--r--common/host.h57
-rw-r--r--common/host_driver.h33
-rw-r--r--common/keyboard.c150
-rw-r--r--common/keyboard.h72
-rw-r--r--common/keycode.h489
-rw-r--r--common/keymap.c185
-rw-r--r--common/keymap.h71
-rw-r--r--common/led.h33
-rw-r--r--common/matrix.h68
-rw-r--r--common/mbed/bootloader.c4
-rw-r--r--common/mbed/suspend.c6
-rw-r--r--common/mbed/timer.c41
-rw-r--r--common/mbed/xprintf.cpp51
-rw-r--r--common/mbed/xprintf.h17
-rw-r--r--common/mousekey.c196
-rw-r--r--common/mousekey.h77
-rw-r--r--common/nodebug.h25
-rw-r--r--common/print.c48
-rw-r--r--common/print.h137
-rw-r--r--common/progmem.h12
-rw-r--r--common/report.h183
-rw-r--r--common/sendchar.h35
-rw-r--r--common/sendchar_null.c23
-rw-r--r--common/sendchar_uart.c25
-rw-r--r--common/sleep_led.c95
-rw-r--r--common/sleep_led.h21
-rw-r--r--common/suspend.h13
-rw-r--r--common/timer.h53
-rw-r--r--common/uart.c129
-rw-r--r--common/uart.h11
-rw-r--r--common/util.c101
-rw-r--r--common/util.h43
-rw-r--r--common/wait.h20
63 files changed, 7156 insertions, 0 deletions
diff --git a/common/action.c b/common/action.c
new file mode 100644
index 0000000000..ec8eeae7bc
--- /dev/null
+++ b/common/action.c
@@ -0,0 +1,565 @@
+/*
+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_action(&record);
+ if (!IS_NOEVENT(record.event)) {
+ dprint("processed: "); debug_record(record); dprintln();
+ }
+#endif
+}
+
+void process_action(keyrecord_t *record)
+{
+ keyevent_t event = record->event;
+#ifndef NO_ACTION_TAPPING
+ uint8_t tap_count = record->tap.count;
+#endif
+
+ if (IS_NOEVENT(event)) { return; }
+
+ action_t action = layer_switch_get_action(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();
+
+ 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) {
+ add_weak_mods(mods);
+ send_keyboard_report();
+ }
+ register_code(action.key.code);
+ } else {
+ unregister_code(action.key.code);
+ if (mods) {
+ 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) {
+ register_mods(mods);
+ }
+ else if (tap_count == 1) {
+ dprint("MODS_TAP: Oneshot: start\n");
+ set_oneshot_mods(mods);
+ }
+ else {
+ register_mods(mods);
+ }
+ } else {
+ if (tap_count == 0) {
+ clear_oneshot_mods();
+ unregister_mods(mods);
+ }
+ else if (tap_count == 1) {
+ // Retain Oneshot mods
+ }
+ 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) {
+ 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 {
+ 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;
+ 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;
+ }
+}
+
+
+
+
+/*
+ * 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_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:
+ return true;
+ 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/common/action.h b/common/action.h
new file mode 100644
index 0000000000..8a4736d7bc
--- /dev/null
+++ b/common/action.h
@@ -0,0 +1,82 @@
+/*
+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);
+
+/* Utilities for actions. */
+void process_action(keyrecord_t *record);
+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/common/action_code.h b/common/action_code.h
new file mode 100644
index 0000000000..bc40e2c6fb
--- /dev/null
+++ b/common/action_code.h
@@ -0,0 +1,315 @@
+/*
+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
+ * 101E|LLLL|1110 mods On/Off with modifiers(0xE0-EF)
+ * 101E|LLLL|1111 0000 Invert with tap toggle(0xF0)
+ * 101E|LLLL|1111 0001 On/Off
+ * 101E|LLLL|1111 0010 Off/On
+ * 101E|LLLL|1111 0011 Set/Clear
+ * 101E|LLLL|1111 xxxx Reserved(0xF4-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,
+};
+#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_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/common/action_layer.c b/common/action_layer.c
new file mode 100644
index 0000000000..c535615f44
--- /dev/null
+++ b/common/action_layer.c
@@ -0,0 +1,138 @@
+#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
+
+
+
+action_t layer_switch_get_action(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 action;
+ }
+ }
+ }
+ /* fall back to layer 0 */
+ action = action_for_key(0, key);
+ return action;
+#else
+ action = action_for_key(biton32(default_layer_state), key);
+ return action;
+#endif
+}
diff --git a/common/action_layer.h b/common/action_layer.h
new file mode 100644
index 0000000000..b6da353cfd
--- /dev/null
+++ b/common/action_layer.h
@@ -0,0 +1,77 @@
+/*
+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
+
+
+/* return action depending on current layer status */
+action_t layer_switch_get_action(keypos_t key);
+
+#endif
diff --git a/common/action_macro.c b/common/action_macro.c
new file mode 100644
index 0000000000..ba93fc8b23
--- /dev/null
+++ b/common/action_macro.c
@@ -0,0 +1,83 @@
+/*
+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_weak_mods(MOD_BIT(macro));
+ } else {
+ register_code(macro);
+ }
+ break;
+ case KEY_UP:
+ MACRO_READ();
+ dprintf("KEY_UP(%02X)\n", macro);
+ if (IS_MOD(macro)) {
+ del_weak_mods(MOD_BIT(macro));
+ } 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/common/action_macro.h b/common/action_macro.h
new file mode 100644
index 0000000000..aedc32ec6b
--- /dev/null
+++ b/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/common/action_tapping.c b/common/action_tapping.c
new file mode 100644
index 0000000000..826c233096
--- /dev/null
+++ b/common/action_tapping.c
@@ -0,0 +1,376 @@
+#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_action(&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_action(&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_action(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_action(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_action(&(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_action(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_action(&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_action(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_action(&(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_action(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_action(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_action(keyp);
+ return true;
+ }
+ } else {
+ if (!IS_NOEVENT(event)) debug("Tapping: other key just after tap.\n");
+ process_action(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_action(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;
+}
+
+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_action(&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/common/action_tapping.h b/common/action_tapping.h
new file mode 100644
index 0000000000..9b42d50dc3
--- /dev/null
+++ b/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/common/action_util.c b/common/action_util.c
new file mode 100644
index 0000000000..dbee630d18
--- /dev/null
+++ b/common/action_util.c
@@ -0,0 +1,307 @@
+/*
+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 "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;
+
+#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;
+#if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0))
+static int16_t oneshot_time = 0;
+#endif
+#endif
+
+
+void send_keyboard_report(void) {
+ keyboard_report->mods = real_mods;
+ keyboard_report->mods |= weak_mods;
+#ifndef NO_ACTION_ONESHOT
+ if (oneshot_mods) {
+#if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0))
+ if (TIMER_DIFF_16(timer_read(), oneshot_time) >= ONESHOT_TIMEOUT) {
+ 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_nkro) {
+ add_key_bit(key);
+ return;
+ }
+#endif
+ add_key_byte(key);
+}
+
+void del_key(uint8_t key)
+{
+#ifdef NKRO_ENABLE
+ if (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; }
+
+/* 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
+}
+#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_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/common/action_util.h b/common/action_util.h
new file mode 100644
index 0000000000..a955638b46
--- /dev/null
+++ b/common/action_util.h
@@ -0,0 +1,66 @@
+/*
+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);
+
+/* oneshot modifier */
+void set_oneshot_mods(uint8_t mods);
+void clear_oneshot_mods(void);
+void oneshot_toggle(void);
+void oneshot_enable(void);
+void oneshot_disable(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/common/avr/bootloader.c b/common/avr/bootloader.c
new file mode 100644
index 0000000000..cda295b181
--- /dev/null
+++ b/common/avr/bootloader.c
@@ -0,0 +1,148 @@
+#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
+
+
+/* Boot Section Size in *BYTEs*
+ * Teensy halfKay 512
+ * Teensy++ halfKay 1024
+ * Atmel DFU loader 4096
+ * LUFA bootloader 4096
+ * USBaspLoader 2048
+ */
+#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/common/avr/eeconfig.c b/common/avr/eeconfig.c
new file mode 100644
index 0000000000..5bd47dc6ad
--- /dev/null
+++ b/common/avr/eeconfig.c
@@ -0,0 +1,45 @@
+#include <stdint.h>
+#include <stdbool.h>
+#include <avr/eeprom.h>
+#include "eeconfig.h"
+
+void eeconfig_init(void)
+{
+ eeprom_write_word(EECONFIG_MAGIC, EECONFIG_MAGIC_NUMBER);
+ eeprom_write_byte(EECONFIG_DEBUG, 0);
+ eeprom_write_byte(EECONFIG_DEFAULT_LAYER, 0);
+ eeprom_write_byte(EECONFIG_KEYMAP, 0);
+ eeprom_write_byte(EECONFIG_MOUSEKEY_ACCEL, 0);
+#ifdef BACKLIGHT_ENABLE
+ eeprom_write_byte(EECONFIG_BACKLIGHT, 0);
+#endif
+}
+
+void eeconfig_enable(void)
+{
+ eeprom_write_word(EECONFIG_MAGIC, EECONFIG_MAGIC_NUMBER);
+}
+
+void eeconfig_disable(void)
+{
+ eeprom_write_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_write_debug(uint8_t val) { eeprom_write_byte(EECONFIG_DEBUG, val); }
+
+uint8_t eeconfig_read_default_layer(void) { return eeprom_read_byte(EECONFIG_DEFAULT_LAYER); }
+void eeconfig_write_default_layer(uint8_t val) { eeprom_write_byte(EECONFIG_DEFAULT_LAYER, val); }
+
+uint8_t eeconfig_read_keymap(void) { return eeprom_read_byte(EECONFIG_KEYMAP); }
+void eeconfig_write_keymap(uint8_t val) { eeprom_write_byte(EECONFIG_KEYMAP, val); }
+
+#ifdef BACKLIGHT_ENABLE
+uint8_t eeconfig_read_backlight(void) { return eeprom_read_byte(EECONFIG_BACKLIGHT); }
+void eeconfig_write_backlight(uint8_t val) { eeprom_write_byte(EECONFIG_BACKLIGHT, val); }
+#endif
diff --git a/common/avr/suspend.c b/common/avr/suspend.c
new file mode 100644
index 0000000000..80243f02bc
--- /dev/null
+++ b/common/avr/suspend.c
@@ -0,0 +1,122 @@
+#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"
+#ifdef PROTOCOL_LUFA
+#include "lufa.h"
+#endif
+
+
+#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);
+
+ // 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);
+}
+
+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
+ clear_keyboard();
+#ifdef BACKLIGHT_ENABLE
+ backlight_init();
+#endif
+}
+
+#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/common/avr/suspend_avr.h b/common/avr/suspend_avr.h
new file mode 100644
index 0000000000..357102da44
--- /dev/null
+++ b/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/common/avr/timer.c b/common/avr/timer.c
new file mode 100644
index 0000000000..292b41c3a6
--- /dev/null
+++ b/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/common/avr/timer_avr.h b/common/avr/timer_avr.h
new file mode 100644
index 0000000000..0e85eb1017
--- /dev/null
+++ b/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/common/avr/xprintf.S b/common/avr/xprintf.S
new file mode 100644
index 0000000000..0cec70ce22
--- /dev/null
+++ b/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/common/avr/xprintf.h b/common/avr/xprintf.h
new file mode 100644
index 0000000000..59c6f25312
--- /dev/null
+++ b/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/common/backlight.c b/common/backlight.c
new file mode 100644
index 0000000000..558ad9b014
--- /dev/null
+++ b/common/backlight.c
@@ -0,0 +1,85 @@
+/*
+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_write_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_write_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_write_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_write_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_write_backlight(backlight_config.raw);
+ backlight_set(backlight_config.level);
+}
diff --git a/common/backlight.h b/common/backlight.h
new file mode 100644
index 0000000000..525ec8bbef
--- /dev/null
+++ b/common/backlight.h
@@ -0,0 +1,40 @@
+/*
+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);
+
+#endif
diff --git a/common/bootloader.h b/common/bootloader.h
new file mode 100644
index 0000000000..44775039d5
--- /dev/null
+++ b/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/common/bootmagic.c b/common/bootmagic.c
new file mode 100644
index 0000000000..b002a58562
--- /dev/null
+++ b/common/bootmagic.c
@@ -0,0 +1,128 @@
+#include <stdint.h>
+#include <stdbool.h>
+#include <util/delay.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"
+
+
+void bootmagic(void)
+{
+ /* check signature */
+ if (!eeconfig_is_enabled()) {
+ eeconfig_init();
+ }
+
+ /* do scans in case of bounce */
+ print("boogmagic scan: ... ");
+ uint8_t scan = 100;
+ while (scan--) { matrix_scan(); _delay_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_write_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_write_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_write_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);
+}
diff --git a/common/bootmagic.h b/common/bootmagic.h
new file mode 100644
index 0000000000..8f6618f4bd
--- /dev/null
+++ b/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/common/command.c b/common/command.c
new file mode 100644
index 0000000000..fbaa9f2d75
--- /dev/null
+++ b/common/command.c
@@ -0,0 +1,644 @@
+/*
+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 <util/delay.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"
+
+#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
+
+
+static bool command_common(uint8_t code);
+static void command_common_help(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 uint8_t numkey2num(uint8_t code);
+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)
+{
+ return false;
+}
+
+bool command_console_extra(uint8_t code) __attribute__ ((weak));
+bool command_console_extra(uint8_t code)
+{
+ return false;
+}
+
+
+/***********************************************************
+ * Command common
+ ***********************************************************/
+static void command_common_help(void)
+{
+ print("\n\n----- Command Help -----\n");
+ print("c: enter console mode\n");
+ print("d: toggle debug enable\n");
+ print("x: toggle matrix debug\n");
+ print("k: toggle keyboard debug\n");
+ print("m: toggle mouse debug\n");
+#ifdef SLEEP_LED_ENABLE
+ print("z: toggle sleep LED test\n");
+#endif
+ print("v: print device version & info\n");
+ print("t: print timer count\n");
+ print("s: print status\n");
+ print("e: print eeprom config\n");
+#ifdef NKRO_ENABLE
+ print("n: toggle NKRO\n");
+#endif
+ print("0/F10: switch to Layer0 \n");
+ print("1/F1: switch to Layer1 \n");
+ print("2/F2: switch to Layer2 \n");
+ print("3/F3: switch to Layer3 \n");
+ print("4/F4: switch to Layer4 \n");
+ print("PScr: power down/remote wake-up\n");
+ print("Caps: Lock Keyboard(Child Proof)\n");
+ print("Paus: jump to bootloader\n");
+}
+
+#ifdef BOOTMAGIC_ENABLE
+static void print_eeconfig(void)
+{
+ 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
+}
+#endif
+
+static bool command_common(uint8_t code)
+{
+ static host_driver_t *host_driver = 0;
+ switch (code) {
+#ifdef SLEEP_LED_ENABLE
+ case KC_Z:
+ // test breathing sleep LED
+ print("Sleep LED test\n");
+ sleep_led_toggle();
+ led_set(host_keyboard_leds());
+ break;
+#endif
+#ifdef BOOTMAGIC_ENABLE
+ case KC_E:
+ print("eeconfig:\n");
+ print_eeconfig();
+ break;
+#endif
+ case KC_CAPSLOCK:
+ 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;
+ case KC_H:
+ case KC_SLASH: /* ? */
+ command_common_help();
+ break;
+ case KC_C:
+ debug_matrix = false;
+ debug_keyboard = false;
+ debug_mouse = false;
+ debug_enable = false;
+ command_console_help();
+ print("\nEnter Console Mode\n");
+ print("C> ");
+ command_state = CONSOLE;
+ break;
+ case KC_PAUSE:
+ clear_keyboard();
+ print("\n\nJump to bootloader... ");
+ _delay_ms(1000);
+ bootloader_jump(); // not return
+ print("not supported.\n");
+ break;
+ case KC_D:
+ if (debug_enable) {
+ print("\nDEBUG: disabled.\n");
+ debug_matrix = false;
+ debug_keyboard = false;
+ debug_mouse = false;
+ debug_enable = false;
+ } else {
+ print("\nDEBUG: enabled.\n");
+ debug_enable = true;
+ }
+ break;
+ case KC_X: // debug matrix toggle
+ debug_matrix = !debug_matrix;
+ if (debug_matrix) {
+ print("\nDEBUG: matrix enabled.\n");
+ debug_enable = true;
+ } else {
+ print("\nDEBUG: matrix disabled.\n");
+ }
+ break;
+ case KC_K: // debug keyboard toggle
+ debug_keyboard = !debug_keyboard;
+ if (debug_keyboard) {
+ print("\nDEBUG: keyboard enabled.\n");
+ debug_enable = true;
+ } else {
+ print("\nDEBUG: keyboard disabled.\n");
+ }
+ break;
+ case KC_M: // debug mouse toggle
+ debug_mouse = !debug_mouse;
+ if (debug_mouse) {
+ print("\nDEBUG: mouse enabled.\n");
+ debug_enable = true;
+ } else {
+ print("\nDEBUG: mouse disabled.\n");
+ }
+ break;
+ case KC_V: // print version & information
+ print("\n\n----- 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__)
+ " AVR-LIBC: " __AVR_LIBC_VERSION_STRING__
+ " AVR_ARCH: avr" STR(__AVR_ARCH__) "\n");
+ break;
+ case KC_T: // print timer
+ print_val_hex32(timer_count);
+ break;
+ case KC_S:
+ print("\n\n----- Status -----\n");
+ print_val_hex8(host_keyboard_leds());
+ print_val_hex8(keyboard_protocol);
+ print_val_hex8(keyboard_idle);
+#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
+ break;
+#ifdef NKRO_ENABLE
+ case KC_N:
+ clear_keyboard(); //Prevents stuck keys.
+ keyboard_nkro = !keyboard_nkro;
+ if (keyboard_nkro)
+ print("NKRO: enabled\n");
+ else
+ print("NKRO: disabled\n");
+ break;
+#endif
+#ifdef EXTRAKEY_ENABLE
+ case KC_PSCREEN:
+ // TODO: Power key should take this feature? otherwise any key during suspend.
+#ifdef PROTOCOL_PJRC
+ if (suspend && remote_wakeup) {
+ usb_remote_wakeup();
+ } else {
+ host_system_send(SYSTEM_POWER_DOWN);
+ host_system_send(0);
+ _delay_ms(500);
+ }
+#else
+ host_system_send(SYSTEM_POWER_DOWN);
+ _delay_ms(100);
+ host_system_send(0);
+ _delay_ms(500);
+#endif
+ break;
+#endif
+ case KC_ESC:
+ case KC_GRV:
+ case KC_0:
+ switch_default_layer(0);
+ break;
+ case KC_1 ... KC_9:
+ switch_default_layer((code - KC_1) + 1);
+ break;
+ case KC_F1 ... KC_F12:
+ switch_default_layer((code - KC_F1) + 1);
+ break;
+ default:
+ print("?");
+ return false;
+ }
+ return true;
+}
+
+
+/***********************************************************
+ * Command console
+ ***********************************************************/
+static void command_console_help(void)
+{
+ print("\n\n----- Console Help -----\n");
+ print("ESC/q: quit\n");
+#ifdef MOUSEKEY_ENABLE
+ print("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:
+ print("\nQuit Console Mode\n");
+ command_state = ONESHOT;
+ return false;
+#ifdef MOUSEKEY_ENABLE
+ case KC_M:
+ mousekey_console_help();
+ print("\nEnter Mousekey Console\n");
+ print("M0>");
+ 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)
+{
+ print("\n\n----- Mousekey Parameters -----\n");
+ print("1: mk_delay(*10ms): "); pdec(mk_delay); print("\n");
+ print("2: mk_interval(ms): "); pdec(mk_interval); print("\n");
+ print("3: mk_max_speed: "); pdec(mk_max_speed); print("\n");
+ print("4: mk_time_to_max: "); pdec(mk_time_to_max); print("\n");
+ print("5: mk_wheel_max_speed: "); pdec(mk_wheel_max_speed); print("\n");
+ print("6: mk_wheel_time_to_max: "); pdec(mk_wheel_time_to_max); print("\n");
+}
+
+#define PRINT_SET_VAL(v) print(#v " = "); print_dec(v); print("\n");
+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\n----- Mousekey Parameters Help -----\n");
+ print("ESC/q: quit\n");
+ print("1: select mk_delay(*10ms)\n");
+ print("2: select mk_interval(ms)\n");
+ print("3: select mk_max_speed\n");
+ print("4: select mk_time_to_max\n");
+ print("5: select mk_wheel_max_speed\n");
+ print("6: select mk_wheel_time_to_max\n");
+ print("p: print parameters\n");
+ print("d: set default values\n");
+ print("up: increase parameters(+1)\n");
+ print("down: decrease parameters(-1)\n");
+ print("pgup: increase parameters(+10)\n");
+ print("pgdown: decrease parameters(-10)\n");
+ print("\nspeed = delta * max_speed * (repeat / time_to_max)\n");
+ print("where delta: cursor="); pdec(MOUSEKEY_MOVE_DELTA);
+ print(", wheel="); pdec(MOUSEKEY_WHEEL_DELTA); print("\n");
+ print("See http://en.wikipedia.org/wiki/Mouse_keys\n");
+}
+
+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:
+ mousekey_param = 0;
+ print("\nQuit Mousekey Console\n");
+ print("C> ");
+ command_state = CONSOLE;
+ return false;
+ 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:
+ case KC_7:
+ case KC_8:
+ case KC_9:
+ case KC_0:
+ mousekey_param = numkey2num(code);
+ print("selected parameter: "); pdec(mousekey_param); print("\n");
+ 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 values.\n");
+ break;
+ default:
+ print("?");
+ return false;
+ }
+ print("M"); pdec(mousekey_param); print("> ");
+ return true;
+}
+#endif
+
+
+/***********************************************************
+ * Utilities
+ ***********************************************************/
+static 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)
+{
+ print("switch_default_layer: "); print_dec(biton32(default_layer_state));
+ print(" to "); print_dec(layer); print("\n");
+ default_layer_set(1UL<<layer);
+ clear_keyboard();
+}
diff --git a/common/command.h b/common/command.h
new file mode 100644
index 0000000000..b57a6c1ced
--- /dev/null
+++ b/common/command.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 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
+bool command_proc(uint8_t code);
+#else
+#define command_proc(code) false
+#endif
+
+#endif
diff --git a/common/debug.c b/common/debug.c
new file mode 100644
index 0000000000..18613fc28b
--- /dev/null
+++ b/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/common/debug.h b/common/debug.h
new file mode 100644
index 0000000000..3cbe2092d1
--- /dev/null
+++ b/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/common/eeconfig.h b/common/eeconfig.h
new file mode 100644
index 0000000000..3cd1a174f6
--- /dev/null
+++ b/common/eeconfig.h
@@ -0,0 +1,75 @@
+/*
+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
+
+
+/* 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_write_debug(uint8_t val);
+
+uint8_t eeconfig_read_default_layer(void);
+void eeconfig_write_default_layer(uint8_t val);
+
+uint8_t eeconfig_read_keymap(void);
+void eeconfig_write_keymap(uint8_t val);
+
+#ifdef BACKLIGHT_ENABLE
+uint8_t eeconfig_read_backlight(void);
+void eeconfig_write_backlight(uint8_t val);
+#endif
+
+#endif
diff --git a/common/host.c b/common/host.c
new file mode 100644
index 0000000000..e9b7916706
--- /dev/null
+++ b/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_sysytem_report(void)
+{
+ return last_system_report;
+}
+
+uint16_t host_last_consumer_report(void)
+{
+ return last_consumer_report;
+}
diff --git a/common/host.h b/common/host.h
new file mode 100644
index 0000000000..918af69e8f
--- /dev/null
+++ b/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_sysytem_report(void);
+uint16_t host_last_consumer_report(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/common/host_driver.h b/common/host_driver.h
new file mode 100644
index 0000000000..edb9e5dd9c
--- /dev/null
+++ b/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/common/keyboard.c b/common/keyboard.c
new file mode 100644
index 0000000000..1e3fb510a4
--- /dev/null
+++ b/common/keyboard.c
@@ -0,0 +1,150 @@
+/*
+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 "bootmagic.h"
+#include "eeconfig.h"
+#include "backlight.h"
+#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 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
+
+
+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 BOOTMAGIC_ENABLE
+ bootmagic();
+#endif
+
+#ifdef BACKLIGHT_ENABLE
+ backlight_init();
+#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];
+ 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) {
+ if (debug_matrix) matrix_print();
+#ifdef MATRIX_HAS_GHOST
+ if (has_ghost_in_row(r)) {
+ matrix_prev[r] = matrix_row;
+ continue;
+ }
+#endif
+ 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
+
+ // 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/common/keyboard.h b/common/keyboard.h
new file mode 100644
index 0000000000..6442716fc7
--- /dev/null
+++ b/common/keyboard.h
@@ -0,0 +1,72 @@
+/*
+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) \
+}
+
+
+void keyboard_init(void);
+void keyboard_task(void);
+void keyboard_set_leds(uint8_t leds);
+
+__attribute__ ((weak)) void matrix_power_up(void) {}
+__attribute__ ((weak)) void matrix_power_down(void) {}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/common/keycode.h b/common/keycode.h
new file mode 100644
index 0000000000..ac4ef00db6
--- /dev/null
+++ b/common/keycode.h
@@ -0,0 +1,489 @@
+/*
+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
+/* 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 ~ */
+ 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 | */
+ 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 */
+
+ /* 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/common/keymap.c b/common/keymap.c
new file mode 100644
index 0000000000..4c0b61b8c1
--- /dev/null
+++ b/common/keymap.c
@@ -0,0 +1,185 @@
+/*
+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 "keymap.h"
+#include "report.h"
+#include "keycode.h"
+#include "action_layer.h"
+#include "action.h"
+#include "action_macro.h"
+#include "debug.h"
+
+
+static action_t keycode_to_action(uint8_t keycode);
+
+
+/* converts key to action */
+action_t action_for_key(uint8_t layer, keypos_t key)
+{
+ uint8_t keycode = keymap_key_to_keycode(layer, key);
+ switch (keycode) {
+ case KC_FN0 ... KC_FN31:
+ return keymap_fn_to_action(keycode);
+#ifdef BOOTMAGIC_ENABLE
+ case KC_CAPSLOCK:
+ case KC_LOCKING_CAPS:
+ if (keymap_config.swap_control_capslock || keymap_config.capslock_to_control) {
+ return keycode_to_action(KC_LCTL);
+ }
+ return keycode_to_action(keycode);
+ case KC_LCTL:
+ if (keymap_config.swap_control_capslock) {
+ return keycode_to_action(KC_CAPSLOCK);
+ }
+ return keycode_to_action(KC_LCTL);
+ case KC_LALT:
+ if (keymap_config.swap_lalt_lgui) {
+ if (keymap_config.no_gui) {
+ return keycode_to_action(ACTION_NO);
+ }
+ return keycode_to_action(KC_LGUI);
+ }
+ return keycode_to_action(KC_LALT);
+ case KC_LGUI:
+ if (keymap_config.swap_lalt_lgui) {
+ return keycode_to_action(KC_LALT);
+ }
+ if (keymap_config.no_gui) {
+ return keycode_to_action(ACTION_NO);
+ }
+ return keycode_to_action(KC_LGUI);
+ case KC_RALT:
+ if (keymap_config.swap_ralt_rgui) {
+ if (keymap_config.no_gui) {
+ return keycode_to_action(ACTION_NO);
+ }
+ return keycode_to_action(KC_RGUI);
+ }
+ return keycode_to_action(KC_RALT);
+ case KC_RGUI:
+ if (keymap_config.swap_ralt_rgui) {
+ return keycode_to_action(KC_RALT);
+ }
+ if (keymap_config.no_gui) {
+ return keycode_to_action(ACTION_NO);
+ }
+ return keycode_to_action(KC_RGUI);
+ case KC_GRAVE:
+ if (keymap_config.swap_grave_esc) {
+ return keycode_to_action(KC_ESC);
+ }
+ return keycode_to_action(KC_GRAVE);
+ case KC_ESC:
+ if (keymap_config.swap_grave_esc) {
+ return keycode_to_action(KC_GRAVE);
+ }
+ return keycode_to_action(KC_ESC);
+ case KC_BSLASH:
+ if (keymap_config.swap_backslash_backspace) {
+ return keycode_to_action(KC_BSPACE);
+ }
+ return keycode_to_action(KC_BSLASH);
+ case KC_BSPACE:
+ if (keymap_config.swap_backslash_backspace) {
+ return keycode_to_action(KC_BSLASH);
+ }
+ return keycode_to_action(KC_BSPACE);
+#endif
+ default:
+ return keycode_to_action(keycode);
+ }
+}
+
+
+/* Macro */
+__attribute__ ((weak))
+const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt)
+{
+ return MACRO_NONE;
+}
+
+/* Function */
+__attribute__ ((weak))
+void action_function(keyrecord_t *record, uint8_t id, uint8_t opt)
+{
+}
+
+
+
+/* translates keycode to action */
+static action_t keycode_to_action(uint8_t keycode)
+{
+ action_t action;
+ switch (keycode) {
+ case KC_A ... KC_EXSEL:
+ case KC_LCTRL ... KC_RGUI:
+ action.code = ACTION_KEY(keycode);
+ break;
+ case KC_SYSTEM_POWER ... KC_SYSTEM_WAKE:
+ action.code = ACTION_USAGE_SYSTEM(KEYCODE2SYSTEM(keycode));
+ break;
+ case KC_AUDIO_MUTE ... KC_WWW_FAVORITES:
+ action.code = ACTION_USAGE_CONSUMER(KEYCODE2CONSUMER(keycode));
+ break;
+ case KC_MS_UP ... KC_MS_ACCEL2:
+ action.code = ACTION_MOUSEKEY(keycode);
+ break;
+ case KC_TRNS:
+ action.code = ACTION_TRANSPARENT;
+ break;
+ default:
+ action.code = ACTION_NO;
+ break;
+ }
+ return action;
+}
+
+
+
+#ifdef USE_LEGACY_KEYMAP
+/*
+ * Legacy keymap support
+ * Consider using new keymap API instead.
+ */
+__attribute__ ((weak))
+uint8_t keymap_key_to_keycode(uint8_t layer, keypos_t key)
+{
+ return keymap_get_keycode(layer, key.row, key.col);
+}
+
+
+/* Legacy keymap support */
+__attribute__ ((weak))
+action_t keymap_fn_to_action(uint8_t keycode)
+{
+ action_t action = { .code = ACTION_NO };
+ switch (keycode) {
+ case KC_FN0 ... KC_FN31:
+ {
+ uint8_t layer = keymap_fn_layer(FN_INDEX(keycode));
+ uint8_t key = keymap_fn_keycode(FN_INDEX(keycode));
+ if (key) {
+ action.code = ACTION_LAYER_TAP_KEY(layer, key);
+ } else {
+ action.code = ACTION_LAYER_MOMENTARY(layer);
+ }
+ }
+ return action;
+ default:
+ return action;
+ }
+}
+#endif
diff --git a/common/keymap.h b/common/keymap.h
new file mode 100644
index 0000000000..e1a6f992e6
--- /dev/null
+++ b/common/keymap.h
@@ -0,0 +1,71 @@
+/*
+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 KEYMAP_H
+#define KEYMAP_H
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "action.h"
+
+
+#ifdef BOOTMAGIC_ENABLE
+/* NOTE: Not portable. Bit field order depends on implementation */
+typedef union {
+ uint8_t raw;
+ struct {
+ bool swap_control_capslock:1;
+ bool capslock_to_control:1;
+ bool swap_lalt_lgui:1;
+ bool swap_ralt_rgui:1;
+ bool no_gui:1;
+ bool swap_grave_esc:1;
+ bool swap_backslash_backspace:1;
+ bool nkro:1;
+ };
+} keymap_config_t;
+keymap_config_t keymap_config;
+#endif
+
+
+/* translates key to keycode */
+uint8_t keymap_key_to_keycode(uint8_t layer, keypos_t key);
+
+/* translates Fn keycode to action */
+action_t keymap_fn_to_action(uint8_t keycode);
+
+
+
+#ifdef USE_LEGACY_KEYMAP
+/*
+ * Legacy keymap
+ * Consider using new keymap API above instead.
+ */
+/* keycode of key */
+__attribute__ ((deprecated))
+uint8_t keymap_get_keycode(uint8_t layer, uint8_t row, uint8_t col);
+
+/* layer to move during press Fn key */
+__attribute__ ((deprecated))
+uint8_t keymap_fn_layer(uint8_t fn_bits);
+
+/* keycode to send when release Fn key without using */
+__attribute__ ((deprecated))
+uint8_t keymap_fn_keycode(uint8_t fn_bits);
+#endif
+
+#endif
diff --git a/common/led.h b/common/led.h
new file mode 100644
index 0000000000..402a247b9a
--- /dev/null
+++ b/common/led.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 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
+
+
+void led_set(uint8_t usb_led);
+
+#endif
diff --git a/common/matrix.h b/common/matrix.h
new file mode 100644
index 0000000000..107ee72653
--- /dev/null
+++ b/common/matrix.h
@@ -0,0 +1,68 @@
+/*
+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);
+/* intialize matrix for scaning. should be called once. */
+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);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/common/mbed/bootloader.c b/common/mbed/bootloader.c
new file mode 100644
index 0000000000..b51e83943a
--- /dev/null
+++ b/common/mbed/bootloader.c
@@ -0,0 +1,4 @@
+#include "bootloader.h"
+
+
+void bootloader_jump(void) {}
diff --git a/common/mbed/suspend.c b/common/mbed/suspend.c
new file mode 100644
index 0000000000..32651574f8
--- /dev/null
+++ b/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/common/mbed/timer.c b/common/mbed/timer.c
new file mode 100644
index 0000000000..c357ceb786
--- /dev/null
+++ b/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/common/mbed/xprintf.cpp b/common/mbed/xprintf.cpp
new file mode 100644
index 0000000000..3647ece751
--- /dev/null
+++ b/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/common/mbed/xprintf.h b/common/mbed/xprintf.h
new file mode 100644
index 0000000000..26bc529e5b
--- /dev/null
+++ b/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/common/mousekey.c b/common/mousekey.c
new file mode 100644
index 0000000000..23469476e2
--- /dev/null
+++ b/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/common/mousekey.h b/common/mousekey.h
new file mode 100644
index 0000000000..6eede06b44
--- /dev/null
+++ b/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/common/nodebug.h b/common/nodebug.h
new file mode 100644
index 0000000000..93309ada47
--- /dev/null
+++ b/common/nodebug.h
@@ -0,0 +1,25 @@
+/*
+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 1
+
+#define NO_DEBUG
+#include "debug.h"
+#undef NO_DEBUG
+
+#endif
diff --git a/common/print.c b/common/print.c
new file mode 100644
index 0000000000..ca94e1e5d6
--- /dev/null
+++ b/common/print.c
@@ -0,0 +1,48 @@
+/* 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(__arm__)
+
+// TODO
+//void print_set_sendchar(int8_t (*sendchar_func)(uint8_t)) { }
+
+#endif
+
+#endif
diff --git a/common/print.h b/common/print.h
new file mode 100644
index 0000000000..c0e9e14309
--- /dev/null
+++ b/common/print.h
@@ -0,0 +1,137 @@
+/* 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(__arm__)
+
+#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
+#define print
+#define println
+#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/common/progmem.h b/common/progmem.h
new file mode 100644
index 0000000000..199b1bedfe
--- /dev/null
+++ b/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) *(p)
+# define pgm_read_word(p) *(p)
+#endif
+
+#endif
diff --git a/common/report.h b/common/report.h
new file mode 100644
index 0000000000..f6c0a315de
--- /dev/null
+++ b/common/report.h
@@ -0,0 +1,183 @@
+/*
+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)
+
+#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/common/sendchar.h b/common/sendchar.h
new file mode 100644
index 0000000000..7a64d00c7f
--- /dev/null
+++ b/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/common/sendchar_null.c b/common/sendchar_null.c
new file mode 100644
index 0000000000..2933306228
--- /dev/null
+++ b/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/common/sendchar_uart.c b/common/sendchar_uart.c
new file mode 100644
index 0000000000..0241859eb7
--- /dev/null
+++ b/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/common/sleep_led.c b/common/sleep_led.c
new file mode 100644
index 0000000000..dab3eb0f3c
--- /dev/null
+++ b/common/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/common/sleep_led.h b/common/sleep_led.h
new file mode 100644
index 0000000000..6bdcf558a4
--- /dev/null
+++ b/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/common/suspend.h b/common/suspend.h
new file mode 100644
index 0000000000..80617a8244
--- /dev/null
+++ b/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/common/timer.h b/common/timer.h
new file mode 100644
index 0000000000..fe23f87aec
--- /dev/null
+++ b/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/common/uart.c b/common/uart.c
new file mode 100644
index 0000000000..c17649b082
--- /dev/null
+++ b/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/common/uart.h b/common/uart.h
new file mode 100644
index 0000000000..41136a396f
--- /dev/null
+++ b/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/common/util.c b/common/util.c
new file mode 100644
index 0000000000..7e0d542993
--- /dev/null
+++ b/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/common/util.h b/common/util.h
new file mode 100644
index 0000000000..7451cc084d
--- /dev/null
+++ b/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/common/wait.h b/common/wait.h
new file mode 100644
index 0000000000..40d00b0c75
--- /dev/null
+++ b/common/wait.h
@@ -0,0 +1,20 @@
+#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(__arm__)
+# include "wait_api.h"
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif