diff options
| author | Dimitris Papavasiliou <dpapavas@protonmail.ch> | 2021-03-05 20:25:20 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-03-05 10:25:20 -0800 |
| commit | 73b8f85816c3209f6213e358a0d3737c7a73d45f (patch) | |
| tree | ccedda441d718021fcc2c366a5dd3bcf35f9adda | |
| parent | aadea5ab97d4da9af1d75f39a15f5ce498034105 (diff) | |
| download | qmk_firmware-73b8f85816c3209f6213e358a0d3737c7a73d45f.tar.gz qmk_firmware-73b8f85816c3209f6213e358a0d3737c7a73d45f.zip | |
[Keyboard] Lagrange handwired keyboard (#11374)
* [Keyboard] Add the Lagrange keyboard
* Covert the master side to use the SPI driver.
| -rw-r--r-- | keyboards/handwired/lagrange/config.h | 48 | ||||
| -rw-r--r-- | keyboards/handwired/lagrange/info.json | 21 | ||||
| -rw-r--r-- | keyboards/handwired/lagrange/keymaps/default/keymap.c | 50 | ||||
| -rw-r--r-- | keyboards/handwired/lagrange/keymaps/dpapavas/config.h | 23 | ||||
| -rw-r--r-- | keyboards/handwired/lagrange/keymaps/dpapavas/keymap.c | 202 | ||||
| -rw-r--r-- | keyboards/handwired/lagrange/keymaps/dpapavas/rules.mk | 4 | ||||
| -rw-r--r-- | keyboards/handwired/lagrange/lagrange.c | 59 | ||||
| -rw-r--r-- | keyboards/handwired/lagrange/lagrange.h | 53 | ||||
| -rw-r--r-- | keyboards/handwired/lagrange/readme.md | 21 | ||||
| -rw-r--r-- | keyboards/handwired/lagrange/rules.mk | 27 | ||||
| -rw-r--r-- | keyboards/handwired/lagrange/transport.c | 175 |
11 files changed, 683 insertions, 0 deletions
diff --git a/keyboards/handwired/lagrange/config.h b/keyboards/handwired/lagrange/config.h new file mode 100644 index 000000000..309603ad3 --- /dev/null +++ b/keyboards/handwired/lagrange/config.h | |||
| @@ -0,0 +1,48 @@ | |||
| 1 | /* Copyright 2020 Dimitris Papavasiliou <dpapavas@protonmail.ch> | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 3 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <https://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #pragma once | ||
| 18 | |||
| 19 | #include "config_common.h" | ||
| 20 | |||
| 21 | /* USB Device descriptor parameter */ | ||
| 22 | #define VENDOR_ID 0xFEED | ||
| 23 | #define PRODUCT_ID 0x2718 | ||
| 24 | #define DEVICE_VER 0x0001 | ||
| 25 | #define MANUFACTURER Dimitris Papavasiliou | ||
| 26 | #define PRODUCT Lagrange | ||
| 27 | |||
| 28 | #define EE_HANDS | ||
| 29 | #define SPLIT_USB_DETECT | ||
| 30 | |||
| 31 | /* key matrix size */ | ||
| 32 | #define MATRIX_ROWS 14 | ||
| 33 | #define MATRIX_COLS 6 | ||
| 34 | |||
| 35 | /* pin-out */ | ||
| 36 | #define MATRIX_ROW_PINS { E6, F1, F0, F4, F5, F6, F7 } | ||
| 37 | #define MATRIX_COL_PINS { B4, B5, D7, B6, C6, D6 } | ||
| 38 | #define MATRIX_ROW_PINS_RIGHT { B5, B4, D7, B6, C6, D6, D4 } | ||
| 39 | #define MATRIX_COL_PINS_RIGHT { C7, F7, F6, F5, F4, F1 } | ||
| 40 | #define UNUSED_PINS | ||
| 41 | |||
| 42 | /* COL2ROW or ROW2COL */ | ||
| 43 | #define DIODE_DIRECTION ROW2COL | ||
| 44 | |||
| 45 | #define DEBOUNCE 5 | ||
| 46 | |||
| 47 | #define LED_CAPS_LOCK_PIN D1 | ||
| 48 | #define LED_SCROLL_LOCK_PIN D2 | ||
diff --git a/keyboards/handwired/lagrange/info.json b/keyboards/handwired/lagrange/info.json new file mode 100644 index 000000000..29ee0a5e6 --- /dev/null +++ b/keyboards/handwired/lagrange/info.json | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | { | ||
| 2 | "keyboard_name": "Lagrange", | ||
| 3 | "url": "https://github.com/dpapavas/lagrange-keyboard", | ||
| 4 | "maintainer": "dpapavas", | ||
| 5 | "width": 19, | ||
| 6 | "height": 8.5, | ||
| 7 | "layouts": { | ||
| 8 | "LAYOUT": { | ||
| 9 | "layout": [ | ||
| 10 | {"x":0, "y":0.75, "w":1.5}, {"x":1.5, "y":0.75}, {"x":2.5, "y":0.375}, {"x":3.5, "y":0}, {"x":4.5, "y":0.5}, {"x":5.5, "y":0.5}, {"x":12.5, "y":0.5}, {"x":13.5, "y":0.5}, {"x":14.5, "y":0}, {"x":15.5, "y":0.375}, {"x":16.5, "y":0.75}, {"x":17.5, "y":0.75, "w":1.5}, | ||
| 11 | {"x":0, "y":1.75, "w":1.5}, {"x":1.5, "y":1.75}, {"x":2.5, "y":1.375}, {"x":3.5, "y":1}, {"x":4.5, "y":1.5}, {"x":5.5, "y":1.5}, {"x":12.5, "y":1.5}, {"x":13.5, "y":1.5}, {"x":14.5, "y":1}, {"x":15.5, "y":1.375}, {"x":16.5, "y":1.75}, {"x":17.5, "y":1.75, "w":1.5}, | ||
| 12 | {"x":0, "y":2.75, "w":1.5}, {"x":1.5, "y":2.75}, {"x":2.5, "y":2.375}, {"x":3.5, "y":2}, {"x":4.5, "y":2.5}, {"x":5.5, "y":2.5}, {"x":12.5, "y":2.5}, {"x":13.5, "y":2.5}, {"x":14.5, "y":2}, {"x":15.5, "y":2.375}, {"x":16.5, "y":2.75}, {"x":17.5, "y":2.75, "w":1.5}, | ||
| 13 | {"x":0, "y":3.75, "w":1.5}, {"x":1.5, "y":3.75}, {"x":2.5, "y":3.375}, {"x":3.5, "y":3}, {"x":4.5, "y":3.5}, {"x":5.5, "y":3.5}, {"x":12.5, "y":3.5}, {"x":13.5, "y":3.5}, {"x":14.5, "y":3}, {"x":15.5, "y":3.375}, {"x":16.5, "y":3.75}, {"x":17.5, "y":3.75, "w":1.5}, | ||
| 14 | {"x":0, "y":4.75, "w":1.5}, {"x":2.5, "y":4.375}, {"x":3.5, "y":4}, {"x":14.5, "y":4}, {"x":15.5, "y":4.5}, {"x":17.5, "y":4.75, "w":1.5}, | ||
| 15 | {"x":5, "y":5, "h":1.25}, {"x":6, "y":5, "h":1.5}, {"x":7, "y":5, "h":1.5}, {"x":8, "y":5.5}, {"x":10, "y":5.5}, {"x":11, "y":5, "h":1.5}, {"x":12, "y":5, "h":1.5}, {"x":13, "y":5, "h":1.25}, | ||
| 16 | {"x":5, "y":7}, {"x":6, "y":6.5}, {"x":7, "y":7}, {"x":11, "y":7}, {"x":12, "y":6.5}, {"x":13, "y":7}, | ||
| 17 | {"x":6, "y":7.5}, {"x":12, "y":7.5} | ||
| 18 | ] | ||
| 19 | } | ||
| 20 | } | ||
| 21 | } | ||
diff --git a/keyboards/handwired/lagrange/keymaps/default/keymap.c b/keyboards/handwired/lagrange/keymaps/default/keymap.c new file mode 100644 index 000000000..5f86239a0 --- /dev/null +++ b/keyboards/handwired/lagrange/keymaps/default/keymap.c | |||
| @@ -0,0 +1,50 @@ | |||
| 1 | /* Copyright 2020 Dimitris Papavasiliou <dpapavas@protonmail.ch> | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 3 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <https://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include QMK_KEYBOARD_H | ||
| 18 | |||
| 19 | #define EQL_ALT MT(MOD_RALT, KC_EQL) | ||
| 20 | #define MINS_ALT MT(MOD_LALT, KC_MINS) | ||
| 21 | #define HOME_GUI MT(MOD_LGUI, KC_HOME) | ||
| 22 | #define RGHT_GUI MT(MOD_RGUI, KC_RGHT) | ||
| 23 | |||
| 24 | const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { | ||
| 25 | [0] = LAYOUT( | ||
| 26 | /* Left hand */ /* Right hand */ | ||
| 27 | |||
| 28 | KC_GESC, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, TT(1), | ||
| 29 | KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_BSLS, | ||
| 30 | KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, | ||
| 31 | KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT, | ||
| 32 | |||
| 33 | KC_LCPO, KC_INS, KC_LBRC, MINS_ALT, KC_BSPC, KC_DEL, KC_PSCR, KC_PAUSE, KC_ENT, KC_SPC, EQL_ALT, KC_RBRC, KC_DEL, KC_RCPC, | ||
| 34 | HOME_GUI, KC_PGUP, KC_END, KC_LEFT, KC_UP, RGHT_GUI, | ||
| 35 | KC_PGDN, KC_DOWN | ||
| 36 | ), | ||
| 37 | |||
| 38 | [1] = LAYOUT( | ||
| 39 | /* Left hand */ /* Right hand */ | ||
| 40 | |||
| 41 | KC_TRNS, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_TRNS, | ||
| 42 | KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_F11, | ||
| 43 | KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_F12, | ||
| 44 | KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, | ||
| 45 | |||
| 46 | KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, RESET, RESET, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, | ||
| 47 | KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, | ||
| 48 | KC_TRNS, KC_TRNS | ||
| 49 | ), | ||
| 50 | }; | ||
diff --git a/keyboards/handwired/lagrange/keymaps/dpapavas/config.h b/keyboards/handwired/lagrange/keymaps/dpapavas/config.h new file mode 100644 index 000000000..049ba598a --- /dev/null +++ b/keyboards/handwired/lagrange/keymaps/dpapavas/config.h | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | /* Copyright 2020 Dimitris Papavasiliou <dpapavas@protonmail.ch> | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 3 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <https://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #pragma once | ||
| 18 | |||
| 19 | #undef TAPPING_TERM | ||
| 20 | #define TAPPING_TERM 175 | ||
| 21 | #define TAPPING_TERM_PER_KEY | ||
| 22 | #define PERMISSIVE_HOLD_PER_KEY | ||
| 23 | #define IGNORE_MOD_TAP_INTERRUPT | ||
diff --git a/keyboards/handwired/lagrange/keymaps/dpapavas/keymap.c b/keyboards/handwired/lagrange/keymaps/dpapavas/keymap.c new file mode 100644 index 000000000..bbcb83913 --- /dev/null +++ b/keyboards/handwired/lagrange/keymaps/dpapavas/keymap.c | |||
| @@ -0,0 +1,202 @@ | |||
| 1 | /* Copyright 2020 Dimitris Papavasiliou <dpapavas@protonmail.ch> | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 3 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <https://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include QMK_KEYBOARD_H | ||
| 18 | |||
| 19 | #define CAPS_SFT MT(MOD_LSFT, KC_CAPS) | ||
| 20 | #define QUOT_SFT MT(MOD_RSFT, KC_QUOT) | ||
| 21 | #define PSCR_SFT MT(MOD_LSFT, KC_PSCR) | ||
| 22 | #define PAUSE_SFT MT(MOD_RSFT, KC_PAUSE) | ||
| 23 | #define F_SFT MT(MOD_LSFT, KC_F) | ||
| 24 | #define J_SFT MT(MOD_RSFT, KC_J) | ||
| 25 | #define PGUP_GUI MT(MOD_LGUI, KC_PGUP) | ||
| 26 | #define END_GUI MT(MOD_LGUI, KC_END) | ||
| 27 | #define UP_GUI MT(MOD_RGUI, KC_UP) | ||
| 28 | #define LEFT_GUI MT(MOD_RGUI, KC_LEFT) | ||
| 29 | #define EQL_CTL MT(MOD_RCTL, KC_EQL) | ||
| 30 | #define MINS_CTL MT(MOD_LCTL, KC_MINS) | ||
| 31 | #define BSPC_ALT LALT_T(KC_BSPC) | ||
| 32 | #define ENT_ALT LALT_T(KC_ENT) | ||
| 33 | #define SPC_ALT RALT_T(KC_SPC) | ||
| 34 | #define DEL_ALT RALT_T(KC_DEL) | ||
| 35 | |||
| 36 | enum tapdance_keycodes { | ||
| 37 | TD_LEFT, | ||
| 38 | TD_RGHT, | ||
| 39 | TD_C_X | ||
| 40 | }; | ||
| 41 | |||
| 42 | const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { | ||
| 43 | [0] = LAYOUT( | ||
| 44 | /* Left hand */ /* Right hand */ | ||
| 45 | |||
| 46 | KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_ESC, | ||
| 47 | KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_BSLS, | ||
| 48 | CAPS_SFT, KC_A, KC_S, KC_D, F_SFT, KC_G, KC_H, J_SFT, KC_K, KC_L, KC_SCLN, QUOT_SFT, | ||
| 49 | PSCR_SFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, PAUSE_SFT, | ||
| 50 | |||
| 51 | TD(TD_LEFT), KC_INS, KC_LBRC, MINS_CTL, BSPC_ALT, DEL_ALT, TD(TD_C_X), TD(TD_C_X), ENT_ALT, SPC_ALT, EQL_CTL, KC_RBRC, KC_DEL, TD(TD_RGHT), | ||
| 52 | KC_HOME, PGUP_GUI, END_GUI, LEFT_GUI, UP_GUI, KC_RGHT, | ||
| 53 | KC_PGDN, KC_DOWN | ||
| 54 | ), | ||
| 55 | |||
| 56 | [1] = LAYOUT( | ||
| 57 | /* Left hand */ /* Right hand */ | ||
| 58 | |||
| 59 | KC_TRNS, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_TRNS, | ||
| 60 | KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_F11, | ||
| 61 | KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_F12, | ||
| 62 | KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, | ||
| 63 | |||
| 64 | KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, RESET, RESET, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, | ||
| 65 | KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, | ||
| 66 | KC_TRNS, KC_TRNS | ||
| 67 | ), | ||
| 68 | }; | ||
| 69 | |||
| 70 | /* The following helper macros define tap dances that support | ||
| 71 | * separated press, release, tap and double-tap functions. */ | ||
| 72 | |||
| 73 | #define STEPS(DANCE) [DANCE] = ACTION_TAP_DANCE_FN_ADVANCED( \ | ||
| 74 | NULL, \ | ||
| 75 | dance_ ## DANCE ## _finished, \ | ||
| 76 | dance_ ## DANCE ## _reset) | ||
| 77 | |||
| 78 | #define CHOREOGRAPH(DANCE, PRESS, RELEASE, TAP, DOUBLETAP) \ | ||
| 79 | static bool dance_ ## DANCE ## _pressed; \ | ||
| 80 | \ | ||
| 81 | void dance_ ## DANCE ## _finished(qk_tap_dance_state_t *state, void *user_data) { \ | ||
| 82 | if (state->count == 1) { \ | ||
| 83 | if (state->pressed) { \ | ||
| 84 | dance_ ## DANCE ## _pressed = true; \ | ||
| 85 | PRESS; \ | ||
| 86 | } else { \ | ||
| 87 | TAP; \ | ||
| 88 | } \ | ||
| 89 | } else if (state->count == 2) { \ | ||
| 90 | if (!state->pressed) { \ | ||
| 91 | DOUBLETAP; \ | ||
| 92 | } \ | ||
| 93 | } \ | ||
| 94 | } \ | ||
| 95 | \ | ||
| 96 | void dance_ ## DANCE ## _reset(qk_tap_dance_state_t *state, void *user_data) { \ | ||
| 97 | if (state->count == 1) { \ | ||
| 98 | if (dance_ ## DANCE ## _pressed) { \ | ||
| 99 | RELEASE; \ | ||
| 100 | dance_ ## DANCE ## _pressed = false; \ | ||
| 101 | } \ | ||
| 102 | } \ | ||
| 103 | } | ||
| 104 | |||
| 105 | /* Define dance for left palm key. */ | ||
| 106 | |||
| 107 | CHOREOGRAPH(TD_LEFT, | ||
| 108 | layer_invert(1), /* Temporarily toggle layer when held. */ | ||
| 109 | layer_invert(1), | ||
| 110 | |||
| 111 | /* Press and release both shifts on tap, to change | ||
| 112 | * keyboard layout (i.e. language). */ | ||
| 113 | |||
| 114 | SEND_STRING(SS_DOWN(X_LSFT) SS_DOWN(X_RSFT) | ||
| 115 | SS_UP(X_LSFT) SS_UP(X_RSFT)), | ||
| 116 | |||
| 117 | layer_invert(1)); /* Toggle layer (permanently) on | ||
| 118 | * double-tap. */ | ||
| 119 | |||
| 120 | /* Define dance for right palm key. */ | ||
| 121 | |||
| 122 | CHOREOGRAPH(TD_RGHT, | ||
| 123 | layer_invert(1), /* Same as above */ | ||
| 124 | layer_invert(1), | ||
| 125 | /* Send a complex macro: C-x C-s Mod-t up. (Save in | ||
| 126 | * Emacs, switch to terminal and recall previous command, | ||
| 127 | * hopefully a compile command.) */ | ||
| 128 | SEND_STRING(SS_DOWN(X_LCTRL) SS_TAP(X_X) SS_TAP(X_S) SS_UP(X_LCTRL) | ||
| 129 | SS_DOWN(X_LGUI) SS_TAP(X_T) SS_UP(X_LGUI) SS_TAP(X_UP)), | ||
| 130 | layer_invert(1)); | ||
| 131 | |||
| 132 | /* This facilitates C-x chords in Emacs. Used as a modifier along | ||
| 133 | * with, say, the s-key, it saves, by sending C-x C-s. When tapped it | ||
| 134 | * just sends C-x. */ | ||
| 135 | |||
| 136 | CHOREOGRAPH(TD_C_X, | ||
| 137 | SEND_STRING(SS_DOWN(X_LCTRL) SS_TAP(X_X)), | ||
| 138 | SEND_STRING(SS_UP(X_LCTRL)), | ||
| 139 | SEND_STRING(SS_DOWN(X_LCTRL) SS_TAP(X_X) SS_UP(X_LCTRL)),); | ||
| 140 | |||
| 141 | qk_tap_dance_action_t tap_dance_actions[] = { | ||
| 142 | STEPS(TD_LEFT), STEPS(TD_RGHT), STEPS(TD_C_X) | ||
| 143 | }; | ||
| 144 | |||
| 145 | /* Set a longer tapping term for palm keys to allow comfortable | ||
| 146 | * permanent layer toggle. Also set an essentially infinite tapping | ||
| 147 | * term for certain mod-tap keys one tends to keep pressed (such as | ||
| 148 | * space, backspace, etc.). This prevents sending the modifier | ||
| 149 | * keycode by accident (allowing re-tap to get repeated key-press) | ||
| 150 | * and, in combination with permissive hold, they can still be used | ||
| 151 | * fine as modifiers. */ | ||
| 152 | |||
| 153 | uint16_t get_tapping_term(uint16_t keycode, keyrecord_t *record) { | ||
| 154 | switch (keycode) { | ||
| 155 | case TD(TD_LEFT): | ||
| 156 | case TD(TD_RGHT): | ||
| 157 | return 250; | ||
| 158 | case BSPC_ALT: | ||
| 159 | case UP_GUI: | ||
| 160 | case LEFT_GUI: | ||
| 161 | return 5000; | ||
| 162 | default: | ||
| 163 | return TAPPING_TERM; | ||
| 164 | } | ||
| 165 | } | ||
| 166 | |||
| 167 | bool get_permissive_hold(uint16_t keycode, keyrecord_t *record) { | ||
| 168 | switch (keycode) { | ||
| 169 | case TD(TD_LEFT): | ||
| 170 | case TD(TD_RGHT): | ||
| 171 | case BSPC_ALT: | ||
| 172 | case UP_GUI: | ||
| 173 | case LEFT_GUI: | ||
| 174 | return true; | ||
| 175 | default: | ||
| 176 | return false; | ||
| 177 | } | ||
| 178 | } | ||
| 179 | |||
| 180 | /* Use the first LED to indicate the active layer. */ | ||
| 181 | |||
| 182 | layer_state_t layer_state_set_user(layer_state_t state) { | ||
| 183 | writePin(D0, (get_highest_layer(state) > 0)); | ||
| 184 | |||
| 185 | return state; | ||
| 186 | } | ||
| 187 | |||
| 188 | /* Cycle through the LEDs after initialization. */ | ||
| 189 | |||
| 190 | void keyboard_post_init_user(void) { | ||
| 191 | const pin_t pins[] = {D0, D1, D2}; | ||
| 192 | uint8_t i, j; | ||
| 193 | |||
| 194 | for (i = 0 ; i < sizeof(pins) / sizeof(pins[0]) + 2 ; i += 1) { | ||
| 195 | for (j = 0 ; j < sizeof(pins) / sizeof(pins[0]) ; j += 1) { | ||
| 196 | setPinOutput(pins[j]); | ||
| 197 | writePin(pins[j], (j == i || j == i - 1)); | ||
| 198 | } | ||
| 199 | |||
| 200 | wait_ms(100); | ||
| 201 | } | ||
| 202 | } | ||
diff --git a/keyboards/handwired/lagrange/keymaps/dpapavas/rules.mk b/keyboards/handwired/lagrange/keymaps/dpapavas/rules.mk new file mode 100644 index 000000000..42f42f627 --- /dev/null +++ b/keyboards/handwired/lagrange/keymaps/dpapavas/rules.mk | |||
| @@ -0,0 +1,4 @@ | |||
| 1 | # Enable additional features. | ||
| 2 | |||
| 3 | DEBOUNCE_TYPE = sym_defer_pk | ||
| 4 | TAP_DANCE_ENABLE = yes | ||
diff --git a/keyboards/handwired/lagrange/lagrange.c b/keyboards/handwired/lagrange/lagrange.c new file mode 100644 index 000000000..0c76512c5 --- /dev/null +++ b/keyboards/handwired/lagrange/lagrange.c | |||
| @@ -0,0 +1,59 @@ | |||
| 1 | /* Copyright 2020 Dimitris Papavasiliou <dpapavas@protonmail.ch> | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 3 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <https://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <LUFA/Drivers/USB/USB.h> | ||
| 18 | |||
| 19 | #include "lagrange.h" | ||
| 20 | |||
| 21 | #ifndef SPLIT_USB_TIMEOUT_POLL | ||
| 22 | # define SPLIT_USB_TIMEOUT_POLL 10 | ||
| 23 | #endif | ||
| 24 | |||
| 25 | /* Instead of timing out, the slave waits indefinitely for the other | ||
| 26 | * side to signal that it has become master. This avoids both sides | ||
| 27 | * assuming the slave role when the USB port is powered but not | ||
| 28 | * otherwise active (e.g. when the host is turned off, or suspended). | ||
| 29 | * The SPI SS line is used for signaling. On power-up it is | ||
| 30 | * configured as input with pull-up enabled. When one side assumes | ||
| 31 | * the master role, it reconfigures the line for SPI, and pulls it low | ||
| 32 | * to select the slave, which doubles as the signal. */ | ||
| 33 | |||
| 34 | bool is_keyboard_master(void) { | ||
| 35 | static int8_t is_master = -1; | ||
| 36 | |||
| 37 | if (is_master < 0) { | ||
| 38 | while (readPin(SPI_SS_PIN)) { | ||
| 39 | if (USB_Device_IsAddressSet()) { | ||
| 40 | is_master = 1; | ||
| 41 | return is_master; | ||
| 42 | } | ||
| 43 | wait_ms(SPLIT_USB_TIMEOUT_POLL); | ||
| 44 | } | ||
| 45 | |||
| 46 | is_master = 0; | ||
| 47 | |||
| 48 | USB_Disable(); | ||
| 49 | USB_DeviceState = DEVICE_STATE_Unattached; | ||
| 50 | } | ||
| 51 | |||
| 52 | return is_master; | ||
| 53 | } | ||
| 54 | |||
| 55 | void keyboard_pre_init_kb(void) { | ||
| 56 | setPinInputHigh(SPI_SS_PIN); | ||
| 57 | |||
| 58 | keyboard_pre_init_user(); | ||
| 59 | } | ||
diff --git a/keyboards/handwired/lagrange/lagrange.h b/keyboards/handwired/lagrange/lagrange.h new file mode 100644 index 000000000..6f808ba8e --- /dev/null +++ b/keyboards/handwired/lagrange/lagrange.h | |||
| @@ -0,0 +1,53 @@ | |||
| 1 | /* Copyright 2020 Dimitris Papavasiliou <dpapavas@protonmail.ch> | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 3 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <https://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #pragma once | ||
| 18 | |||
| 19 | #include "quantum.h" | ||
| 20 | |||
| 21 | #if !defined(SPI_SS_PIN) | ||
| 22 | # define SPI_SS_PIN B0 | ||
| 23 | #endif | ||
| 24 | |||
| 25 | #define SPI_SCK_PIN B1 | ||
| 26 | #define SPI_MOSI_PIN B2 | ||
| 27 | #define SPI_MISO_PIN B3 | ||
| 28 | |||
| 29 | #define LAYOUT( \ | ||
| 30 | l00, l01, l02, l03, l04, l05, r05, r04, r03, r02, r01, r00, \ | ||
| 31 | l10, l11, l12, l13, l14, l15, r15, r14, r13, r12, r11, r10, \ | ||
| 32 | l20, l21, l22, l23, l24, l25, r25, r24, r23, r22, r21, r20, \ | ||
| 33 | l30, l31, l32, l33, l34, l35, r35, r34, r33, r32, r31, r30, \ | ||
| 34 | l40, l42, l43, l44, l45, l46, l47, r47, r46, r45, r44, r43, r42, r40, \ | ||
| 35 | l50, l51, l52, r52, r51, r50, \ | ||
| 36 | l70, r70) \ | ||
| 37 | { \ | ||
| 38 | {l00, l01, l02, l03, l04, l05}, \ | ||
| 39 | {l10, l11, l12, l13, l14, l15}, \ | ||
| 40 | {l20, l21, l22, l23, l24, l25}, \ | ||
| 41 | {l30, l31, l32, l33, l34, l35}, \ | ||
| 42 | {l40, KC_NO, l42, l43, l44, l45}, \ | ||
| 43 | {KC_NO, KC_NO, KC_NO, l50, l51, l46}, \ | ||
| 44 | {KC_NO, KC_NO, KC_NO, l70, l52, l47}, \ | ||
| 45 | \ | ||
| 46 | {r00, r01, r02, r03, r04, r05}, \ | ||
| 47 | {r10, r11, r12, r13, r14, r15}, \ | ||
| 48 | {r20, r21, r22, r23, r24, r25}, \ | ||
| 49 | {r30, r31, r32, r33, r34, r35}, \ | ||
| 50 | {r40, KC_NO, r42, r43, r44, r45}, \ | ||
| 51 | {KC_NO, KC_NO, KC_NO, r50, r51, r46}, \ | ||
| 52 | {KC_NO, KC_NO, KC_NO, r70, r52, r47} \ | ||
| 53 | } | ||
diff --git a/keyboards/handwired/lagrange/readme.md b/keyboards/handwired/lagrange/readme.md new file mode 100644 index 000000000..5d7f5bb08 --- /dev/null +++ b/keyboards/handwired/lagrange/readme.md | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | # Lagrange | ||
| 2 | |||
| 3 | An ergonomic, split, concave keyboard, with convex thumb pads. See the [project page](https://github.com/dpapavas/lagrange-keyboard) for more info. | ||
| 4 | |||
| 5 |  | ||
| 6 | |||
| 7 | * Keyboard Maintainer: [Dimitris Papavasiliou](https://github.com/dpapavas) | ||
| 8 | * Hardware Supported: Lagrange PCB Rev A | ||
| 9 | * Hardware Availability: See the build guide on the [project page](https://github.com/dpapavas/lagrange-keyboard). | ||
| 10 | |||
| 11 | Make example for this keyboard (after setting up your build environment): | ||
| 12 | |||
| 13 | make handwired/lagrange:default | ||
| 14 | |||
| 15 | Flashing example for this keyboard: | ||
| 16 | |||
| 17 | make handwired/lagrange:default:flash | ||
| 18 | |||
| 19 | To program the keyboard you'll need to reset it. This can be accomplished, either through the reset button, accessible via a hole in the bottom cover, or, if you've assigned the `RESET` keycode to a key, by pressing that key. | ||
| 20 | |||
| 21 | See the [build environment setup](https://docs.qmk.fm/#/getting_started_build_tools) and the [make instructions](https://docs.qmk.fm/#/getting_started_make_guide) for more information. Brand new to QMK? Start with our [Complete Newbs Guide](https://docs.qmk.fm/#/newbs). | ||
diff --git a/keyboards/handwired/lagrange/rules.mk b/keyboards/handwired/lagrange/rules.mk new file mode 100644 index 000000000..ea7413b97 --- /dev/null +++ b/keyboards/handwired/lagrange/rules.mk | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | # MCU name | ||
| 2 | MCU = atmega32u4 | ||
| 3 | |||
| 4 | # Bootloader selection | ||
| 5 | BOOTLOADER = atmel-dfu | ||
| 6 | |||
| 7 | # Build Options | ||
| 8 | # change yes to no to disable | ||
| 9 | # | ||
| 10 | BOOTMAGIC_ENABLE = no # Virtual DIP switch configuration | ||
| 11 | MOUSEKEY_ENABLE = no # Mouse keys | ||
| 12 | EXTRAKEY_ENABLE = yes # Audio control and System control | ||
| 13 | CONSOLE_ENABLE = yes # Console for debug | ||
| 14 | COMMAND_ENABLE = no # Commands for debug and configuration | ||
| 15 | # Do not enable SLEEP_LED_ENABLE. it uses the same timer as BACKLIGHT_ENABLE | ||
| 16 | SLEEP_LED_ENABLE = no # Breathing sleep LED during USB suspend | ||
| 17 | # if this doesn't work, see here: https://github.com/tmk/tmk_keyboard/wiki/FAQ#nkro-doesnt-work | ||
| 18 | NKRO_ENABLE = no # USB Nkey Rollover | ||
| 19 | BACKLIGHT_ENABLE = no # Enable keyboard backlight functionality | ||
| 20 | RGBLIGHT_ENABLE = no # Enable keyboard RGB underglow | ||
| 21 | BLUETOOTH_ENABLE = no # Enable Bluetooth | ||
| 22 | AUDIO_ENABLE = no # Audio output | ||
| 23 | UNICODE_ENABLE = yes | ||
| 24 | SPLIT_KEYBOARD = yes | ||
| 25 | SPLIT_TRANSPORT = custom | ||
| 26 | |||
| 27 | SRC += transport.c spi_master.c | ||
diff --git a/keyboards/handwired/lagrange/transport.c b/keyboards/handwired/lagrange/transport.c new file mode 100644 index 000000000..2a567f24b --- /dev/null +++ b/keyboards/handwired/lagrange/transport.c | |||
| @@ -0,0 +1,175 @@ | |||
| 1 | /* Copyright 2020 Dimitris Papavasiliou <dpapavas@protonmail.ch> | ||
| 2 | * | ||
| 3 | * This program is free software: you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License as published by | ||
| 5 | * the Free Software Foundation, either version 3 of the License, or | ||
| 6 | * (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <https://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <spi_master.h> | ||
| 18 | |||
| 19 | #include "quantum.h" | ||
| 20 | #include "split_util.h" | ||
| 21 | #include "timer.h" | ||
| 22 | |||
| 23 | #include "lagrange.h" | ||
| 24 | |||
| 25 | struct led_context { | ||
| 26 | led_t led_state; | ||
| 27 | layer_state_t layer_state; | ||
| 28 | }; | ||
| 29 | |||
| 30 | uint8_t transceive(uint8_t b) { | ||
| 31 | for (SPDR = b ; !(SPSR & _BV(SPIF)) ; ); | ||
| 32 | return SPDR; | ||
| 33 | } | ||
| 34 | |||
| 35 | /* The SPI bus, doens't have any form of protocol built in, so when | ||
| 36 | * the other side isn't present, any old noise on the line will appear | ||
| 37 | * as matrix data. To avoid interpreting data as keystrokes, we do a | ||
| 38 | * simple n-way (8-way here) handshake before each scan, where each | ||
| 39 | * side sends a prearranged sequence of bytes. */ | ||
| 40 | |||
| 41 | void shake_hands(bool master) { | ||
| 42 | const uint8_t m = master ? 0xf8 : 0; | ||
| 43 | const uint8_t a = 0xa8 ^ m, b = 0x50 ^ m; | ||
| 44 | |||
| 45 | uint8_t i; | ||
| 46 | |||
| 47 | i = SPSR; | ||
| 48 | i = SPDR; | ||
| 49 | |||
| 50 | do { | ||
| 51 | /* Cylcling the SS pin on each attempt is necessary, as it | ||
| 52 | * resets the AVR's SPI core and guarantees proper | ||
| 53 | * alignment. */ | ||
| 54 | |||
| 55 | if (master) { | ||
| 56 | writePinLow(SPI_SS_PIN); | ||
| 57 | } | ||
| 58 | |||
| 59 | for (i = 0 ; i < 8 ; i += 1) { | ||
| 60 | if (transceive(a + i) != b + i) { | ||
| 61 | break; | ||
| 62 | } | ||
| 63 | } | ||
| 64 | |||
| 65 | if (master) { | ||
| 66 | writePinHigh(SPI_SS_PIN); | ||
| 67 | } | ||
| 68 | } while (i < 8); | ||
| 69 | } | ||
| 70 | |||
| 71 | bool transport_master(matrix_row_t matrix[]) { | ||
| 72 | const struct led_context context = { | ||
| 73 | host_keyboard_led_state(), | ||
| 74 | layer_state | ||
| 75 | }; | ||
| 76 | |||
| 77 | uint8_t i; | ||
| 78 | |||
| 79 | /* Shake hands and then receive the matrix from the other side, | ||
| 80 | * while transmitting LED and layer states. */ | ||
| 81 | |||
| 82 | shake_hands(true); | ||
| 83 | |||
| 84 | spi_start(SPI_SS_PIN, 0, 0, 4); | ||
| 85 | |||
| 86 | for (i = 0 ; i < sizeof(matrix_row_t[MATRIX_ROWS / 2]) ; i += 1) { | ||
| 87 | spi_status_t x; | ||
| 88 | |||
| 89 | x = spi_write(i < sizeof(struct led_context) ? | ||
| 90 | ((uint8_t *)&context)[i] : 0); | ||
| 91 | |||
| 92 | if (x == SPI_STATUS_TIMEOUT) { | ||
| 93 | return false; | ||
| 94 | } | ||
| 95 | |||
| 96 | ((uint8_t *)matrix)[i] = (uint8_t)x; | ||
| 97 | } | ||
| 98 | |||
| 99 | spi_stop(); | ||
| 100 | |||
| 101 | return true; | ||
| 102 | } | ||
| 103 | |||
| 104 | void transport_slave(matrix_row_t matrix[]) { | ||
| 105 | static struct led_context context; | ||
| 106 | struct led_context new_context; | ||
| 107 | |||
| 108 | uint8_t i; | ||
| 109 | |||
| 110 | /* Do the reverse of master above. Note that timing is critical, | ||
| 111 | * so interrupts must be turned off. */ | ||
| 112 | |||
| 113 | cli(); | ||
| 114 | shake_hands(false); | ||
| 115 | |||
| 116 | for (i = 0 ; i < sizeof(matrix_row_t[MATRIX_ROWS / 2]) ; i += 1) { | ||
| 117 | uint8_t b; | ||
| 118 | |||
| 119 | b = transceive(((uint8_t *)matrix)[i]); | ||
| 120 | |||
| 121 | if (i < sizeof(struct led_context)) { | ||
| 122 | ((uint8_t *)&new_context)[i] = b; | ||
| 123 | } | ||
| 124 | } | ||
| 125 | |||
| 126 | sei(); | ||
| 127 | |||
| 128 | /* Update the layer and LED state if necessary. */ | ||
| 129 | |||
| 130 | if (!isLeftHand) { | ||
| 131 | if (context.led_state.raw != new_context.led_state.raw) { | ||
| 132 | context.led_state.raw = new_context.led_state.raw; | ||
| 133 | led_update_kb(context.led_state); | ||
| 134 | } | ||
| 135 | |||
| 136 | if (context.layer_state != new_context.layer_state) { | ||
| 137 | context.layer_state = new_context.layer_state; | ||
| 138 | layer_state_set_kb(context.layer_state); | ||
| 139 | } | ||
| 140 | } | ||
| 141 | } | ||
| 142 | |||
| 143 | void transport_master_init(void) { | ||
| 144 | /* We need to set the SS pin as output as the handshake logic | ||
| 145 | * above depends on it and the SPI master driver won't do it | ||
| 146 | * before we call spi_start(). */ | ||
| 147 | |||
| 148 | writePinHigh(SPI_SS_PIN); | ||
| 149 | setPinOutput(SPI_SS_PIN); | ||
| 150 | |||
| 151 | spi_init(); | ||
| 152 | |||
| 153 | shake_hands(true); | ||
| 154 | } | ||
| 155 | |||
| 156 | void transport_slave_init(void) { | ||
| 157 | /* The datasheet isn't very clear on whether the internal pull-up | ||
| 158 | * is selectable when the SS pin is used by the SPI slave, but | ||
| 159 | * experimentations shows that it is, at least on the ATMega32u4. | ||
| 160 | * We enable the pull-up to guard against the case where both | ||
| 161 | * halves end up as slaves. In that case the SS pin would | ||
| 162 | * otherwise be floating and free to fluctuate due to picked up | ||
| 163 | * noise, etc. When reading low it would make both halves think | ||
| 164 | * they're asserted making the MISO pin an output on both ends and | ||
| 165 | * leading to potential shorts. */ | ||
| 166 | |||
| 167 | setPinInputHigh(SPI_SS_PIN); | ||
| 168 | setPinInput(SPI_SCK_PIN); | ||
| 169 | setPinInput(SPI_MOSI_PIN); | ||
| 170 | setPinOutput(SPI_MISO_PIN); | ||
| 171 | |||
| 172 | SPCR = _BV(SPE); | ||
| 173 | |||
| 174 | shake_hands(false); | ||
| 175 | } | ||
