aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy Bernhardt <jeremythegeek@gmail.com>2019-03-14 14:59:34 -0600
committerDrashna Jaelre <drashna@live.com>2019-03-14 13:59:34 -0700
commit980a41e9049aad53c49b667066a3c5e5cabda113 (patch)
tree68edfd6f3948e13852ae0c1b91f6d1119e4d96ac
parent2558372b3f5b383582ee35f318d75a2dc7a28c6e (diff)
downloadqmk_firmware-980a41e9049aad53c49b667066a3c5e5cabda113.tar.gz
qmk_firmware-980a41e9049aad53c49b667066a3c5e5cabda113.zip
[Keyboard] Georgi Support (#5384)
* Working on chording * Working on chording * Got layouts in order * Initial Georgi support * forgot to add keymaps * Updated readme * Update keyboards/georgi/keymaps/template/readme.md Co-Authored-By: germ <jeremythegeek@gmail.com> * Update keyboards/georgi/georgi.h Co-Authored-By: germ <jeremythegeek@gmail.com> * Update keyboards/georgi/keymaps/default/keymap.c Co-Authored-By: germ <jeremythegeek@gmail.com> * Update keyboards/georgi/keymaps/default/keymap.c Co-Authored-By: germ <jeremythegeek@gmail.com> * Update keyboards/georgi/rules.mk Co-Authored-By: germ <jeremythegeek@gmail.com> * Update keyboards/georgi/rules.mk Co-Authored-By: germ <jeremythegeek@gmail.com> * Update keyboards/georgi/matrix.c Co-Authored-By: germ <jeremythegeek@gmail.com> * Update keyboards/georgi/georgi.c Co-Authored-By: germ <jeremythegeek@gmail.com> * Update keyboards/georgi/georgi.c Co-Authored-By: germ <jeremythegeek@gmail.com> * Update keyboards/georgi/rules.mk Co-Authored-By: germ <jeremythegeek@gmail.com> * Update keyboards/georgi/keymaps/default/keymap.c Co-Authored-By: germ <jeremythegeek@gmail.com> * Update keyboards/georgi/keymaps/template/keymap.c Co-Authored-By: germ <jeremythegeek@gmail.com> * Update keyboards/georgi/matrix.c Co-Authored-By: germ <jeremythegeek@gmail.com> * Disabled features, updated info * Update keyboards/georgi/config.h Co-Authored-By: germ <jeremythegeek@gmail.com> * Update keyboards/georgi/config.h Co-Authored-By: germ <jeremythegeek@gmail.com> * Fixed info.json
-rw-r--r--keyboards/georgi/config.h74
-rw-r--r--keyboards/georgi/georgi.c68
-rw-r--r--keyboards/georgi/georgi.h82
-rw-r--r--keyboards/georgi/info.json133
-rw-r--r--keyboards/georgi/keymaps/default/keymap.c229
-rw-r--r--keyboards/georgi/keymaps/default/readme.md11
-rw-r--r--keyboards/georgi/keymaps/default/rules.mk27
-rw-r--r--keyboards/georgi/keymaps/template/keymap.c216
-rw-r--r--keyboards/georgi/keymaps/template/readme.md6
-rw-r--r--keyboards/georgi/keymaps/template/rules.mk27
-rw-r--r--keyboards/georgi/matrix.c402
-rw-r--r--keyboards/georgi/readme.md29
-rw-r--r--keyboards/georgi/rules.mk22
-rw-r--r--keyboards/georgi/sten.c2
-rw-r--r--keyboards/georgi/sten.h290
15 files changed, 1618 insertions, 0 deletions
diff --git a/keyboards/georgi/config.h b/keyboards/georgi/config.h
new file mode 100644
index 000000000..041567719
--- /dev/null
+++ b/keyboards/georgi/config.h
@@ -0,0 +1,74 @@
1/*
2Copyright 2012 Jun Wako <wakojun@gmail.com>
3Copyright 2013 Oleg Kostyuk <cub.uanic@gmail.com>
4
5This program is free software: you can redistribute it and/or modify
6it under the terms of the GNU General Public License as published by
7the Free Software Foundation, either version 2 of the License, or
8(at your option) any later version.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19// Copy and worked on with love from the EZ team
20
21#pragma once
22#include "config_common.h"
23
24/* Defaults */
25
26#define VERSION "Alpha 01: Ted "
27#define VERBOSE
28
29#define FORCE_NKRO
30#define NO_ACTION_MACRO
31#define NO_ACTION_FUNCTION
32#define NO_DEBUG
33#define NO_ACTION_ONESHOT
34#define NO_ACTION_FUNCTION
35
36/* USB Device descriptor parameter */
37#define VENDOR_ID 0xFEED
38#define PRODUCT_ID 0x1337
39#define DEVICE_VER 0x0001
40#define MANUFACTURER g Heavy Industries
41#define PRODUCT Georgi
42#define DESCRIPTION QMK keyboard firmware for Georgi
43
44/* key matrix size */
45#define MATRIX_ROWS 14
46#define MATRIX_ROWS_PER_SIDE (MATRIX_ROWS / 2)
47#define MATRIX_COLS 4
48
49#define MOUSEKEY_INTERVAL 20
50#define MOUSEKEY_DELAY 0
51#define MOUSEKEY_TIME_TO_MAX 60
52#define MOUSEKEY_MAX_SPEED 7
53#define MOUSEKEY_WHEEL_DELAY 0
54#define TAPPING_TOGGLE 2
55
56/* define if matrix has ghost */
57//#define MATRIX_HAS_GHOST
58
59#define TAPPING_TERM 200
60#define IGNORE_MOD_TAP_INTERRUPT // this makes it possible to do rolling combos (zx) with keys that convert to other keys on hold (z becomes ctrl when you hold it, and when this option isn't enabled, z rapidly followed by x actually sends Ctrl-x. That's bad.)
61
62/* Mechanical locking support. Use KC_LCAP, KC_LNUM or KC_LSCR instead in keymap */
63#define LOCKING_SUPPORT_ENABLE
64/* Locking resynchronize hack */
65#define LOCKING_RESYNC_ENABLE
66
67/* key combination for command */
68#define IS_COMMAND() ( \
69 keyboard_report->mods == (MOD_BIT(KC_LCTL) | MOD_BIT(KC_RCTL)) || \
70 keyboard_report->mods == (MOD_BIT(KC_LSFT) | MOD_BIT(KC_RSFT)) \
71)
72
73#define DEBOUNCE 5
74#define USB_MAX_POWER_CONSUMPTION 500
diff --git a/keyboards/georgi/georgi.c b/keyboards/georgi/georgi.c
new file mode 100644
index 000000000..8866886ce
--- /dev/null
+++ b/keyboards/georgi/georgi.c
@@ -0,0 +1,68 @@
1#include QMK_KEYBOARD_H
2
3bool i2c_initialized = 0;
4i2c_status_t mcp23018_status = 0x20;
5
6void matrix_init_kb(void) {
7 steno_set_mode(STENO_MODE_GEMINI); // or STENO_MODE_BOLT
8
9 // (tied to Vcc for hardware convenience)
10 //DDRB &= ~(1<<4); // set B(4) as input
11 //PORTB &= ~(1<<4); // set B(4) internal pull-up disabled
12
13 // unused pins - C7, D4, D5, D7, E6
14 // set as input with internal pull-up enabled
15 DDRC &= ~(1<<7);
16 DDRD &= ~(1<<5 | 1<<4 | 1<<6 | 1<<7);
17 DDRE &= ~(1<<6);
18 PORTC |= (1<<7);
19 PORTD |= (1<<5 | 1<<4 | 1<<6 | 1<<7);
20 PORTE |= (1<<6);
21
22 matrix_init_user();
23}
24
25
26uint8_t init_mcp23018(void) {
27 print("starting init");
28 mcp23018_status = 0x20;
29
30 // I2C subsystem
31
32 // uint8_t sreg_prev;
33 // sreg_prev=SREG;
34 // cli();
35
36 if (i2c_initialized == 0) {
37 i2c_init(); // on pins D(1,0)
38 i2c_initialized = true;
39 _delay_ms(1000);
40 }
41 // i2c_init(); // on pins D(1,0)
42 // _delay_ms(1000);
43
44 // set pin direction
45 // - unused : input : 1
46 // - input : input : 1
47 // - driving : output : 0
48 mcp23018_status = i2c_start(I2C_ADDR_WRITE, ERGODOX_EZ_I2C_TIMEOUT); if (mcp23018_status) goto out;
49 mcp23018_status = i2c_write(IODIRA, ERGODOX_EZ_I2C_TIMEOUT); if (mcp23018_status) goto out;
50 mcp23018_status = i2c_write(0b10000000, ERGODOX_EZ_I2C_TIMEOUT); if (mcp23018_status) goto out;
51 mcp23018_status = i2c_write(0b11111111, ERGODOX_EZ_I2C_TIMEOUT); if (mcp23018_status) goto out;
52 i2c_stop();
53
54 // set pull-up
55 // - unused : on : 1
56 // - input : on : 1
57 // - driving : off : 0
58 mcp23018_status = i2c_start(I2C_ADDR_WRITE, ERGODOX_EZ_I2C_TIMEOUT); if (mcp23018_status) goto out;
59 mcp23018_status = i2c_write(GPPUA, ERGODOX_EZ_I2C_TIMEOUT); if (mcp23018_status) goto out;
60 mcp23018_status = i2c_write(0b10000000, ERGODOX_EZ_I2C_TIMEOUT); if (mcp23018_status) goto out;
61 mcp23018_status = i2c_write(0b11111111, ERGODOX_EZ_I2C_TIMEOUT); if (mcp23018_status) goto out;
62
63out:
64 i2c_stop();
65 // SREG=sreg_prev;
66 //uprintf("Init %x\n", mcp23018_status);
67 return mcp23018_status;
68}
diff --git a/keyboards/georgi/georgi.h b/keyboards/georgi/georgi.h
new file mode 100644
index 000000000..df6bb6ea9
--- /dev/null
+++ b/keyboards/georgi/georgi.h
@@ -0,0 +1,82 @@
1#pragma once
2#include <util/delay.h>
3#include <stdint.h>
4#include <stdbool.h>
5#include "quantum.h"
6#include "i2c_master.h"
7#include "matrix.h"
8
9
10extern i2c_status_t mcp23018_status;
11#define ERGODOX_EZ_I2C_TIMEOUT 1000
12#define CPU_PRESCALE(n) (CLKPR = 0x80, CLKPR = (n))
13#define CPU_16MHz 0x00
14
15// I2C aliases and register addresses (see "mcp23018.md")
16//#define I2C_ADDR 0b0100000
17#define I2C_ADDR 0x20
18#define I2C_ADDR_WRITE ( (I2C_ADDR<<1) | I2C_WRITE )
19#define I2C_ADDR_READ ( (I2C_ADDR<<1) | I2C_READ )
20#define IODIRA 0x00 // i/o direction register
21#define IODIRB 0x01
22#define GPPUA 0x0C // GPIO pull-up resistor register
23#define GPPUB 0x0D
24#define GPIOA 0x12 // general purpose i/o port register (write modifies OLAT)
25#define GPIOB 0x13
26#define OLATA 0x14 // output latch register
27#define OLATB 0x15
28
29void init_ergodox(void);
30uint8_t init_mcp23018(void);
31
32/* ---------- LEFT HAND ----------- ---------- RIGHT HAND ---------- */
33#define LAYOUT_georgi( \
34 L00,L01,L02,L03,L04,L05, R00,R01,R02,R03,R04,R05, \
35 L10,L11,L12,L13,L14,L15, R10,R11,R12,R13,R14,R15, \
36 L20,L21,L22, R20,R21,R22) \
37 \
38 { \
39 { KC_NO, R00, R10, R21}, \
40 { KC_NO, R01, R11, R20}, \
41 { KC_NO, R02, R12, R22}, \
42 { KC_NO, R03, R13, KC_NO}, \
43 { KC_NO, R04, R14, KC_NO}, \
44 { KC_NO, R05, R15, KC_NO}, \
45 { KC_NO, KC_NO, KC_NO, KC_NO}, \
46 \
47 { KC_NO, L05, L15, L22}, \
48 { KC_NO, L04, L14, L21}, \
49 { KC_NO, L03, L13, L20}, \
50 { KC_NO, L02, L12, KC_NO}, \
51 { KC_NO, L01, L11, KC_NO}, \
52 { KC_NO, L00, L10, KC_NO}, \
53 { KC_NO, KC_NO, KC_NO, KC_NO}, \
54 \
55}
56
57/* ---------- LEFT HAND ----------- ---------- RIGHT HAND ----------
58#define LAYOUT_GERGO( \
59 L00,L01,L02,L03,L04,L05, R00,R01,R02,R03,R04,R05, \
60 L10,L11,L12,L13,L14,L15,L16, R10,R11,R12,R13,R14,R15,R16, \
61 L20,L21,L22,L23,L24,L25,L26, R20,R21,R22,R23,R24,R25,R26, \
62 L31,L32, R33,R34, \
63 L30, R30, \
64 L33,L34, R31,R32) \
65 \
66 { \
67 { KC_NO, L16, L26, L30}, \
68 { L05, L15, L25, L34}, \
69 { L04, L14, L24, L33}, \
70 { L03, L13, L23, L32}, \
71 { L02, L12, L22, L31}, \
72 { L01, L11, L21, KC_NO}, \
73 { L00, L10, L20, KC_NO}, \
74 \
75 { KC_NO, R10, R20, R30}, \
76 { R00, R11, R21, R31}, \
77 { R01, R12, R22, R32}, \
78 { R02, R13, R23, R33}, \
79 { R03, R14, R24, R34}, \
80 { R04, R15, R25, KC_NO}, \
81 { R05, R16, R26, KC_NO}, \
82} */
diff --git a/keyboards/georgi/info.json b/keyboards/georgi/info.json
new file mode 100644
index 000000000..d0752e2cd
--- /dev/null
+++ b/keyboards/georgi/info.json
@@ -0,0 +1,133 @@
1{
2 "keyboard_name": "Georgi",
3 "url": "http://gboards.ca",
4 "maintainer": "germ",
5 "width": 13.2,
6 "height": 3.68,
7 "layouts": {
8 "LAYOUT_georgi": {
9 "layout": [
10 {
11 "x": 0.05,
12 "y": 0.54
13 },
14 {
15 "x": 1.06,
16 "y": 0.55
17 },
18 {
19 "x": 2.06,
20 "y": 0.29
21 },
22 {
23 "x": 3.05,
24 "y": 0.16
25 },
26 {
27 "x": 4.06,
28 "y": 0.41
29 },
30 {
31 "x": 5.06,
32 "y": 0.54
33 },
34 {
35 "x": 7.1899999999999995,
36 "y": 0.41
37 },
38 {
39 "x": 8.2,
40 "y": 0.3
41 },
42 {
43 "x": 9.2,
44 "y": 0.05
45 },
46 {
47 "x": 10.2,
48 "y": 0.29
49 },
50 {
51 "x": 11.2,
52 "y": 0.43
53 },
54 {
55 "x": 12.2,
56 "y": 0.42
57 },
58 {
59 "x": 0.05,
60 "y": 1.54
61 },
62 {
63 "x": 1.06,
64 "y": 1.54
65 },
66 {
67 "x": 2.06,
68 "y": 1.28
69 },
70 {
71 "x": 3.05,
72 "y": 1.16
73 },
74 {
75 "x": 4.06,
76 "y": 1.4
77 },
78 {
79 "x": 5.06,
80 "y": 1.54
81 },
82 {
83 "x": 7.1899999999999995,
84 "y": 1.4
85 },
86 {
87 "x": 8.2,
88 "y": 1.28
89 },
90 {
91 "x": 9.2,
92 "y": 1.04
93 },
94 {
95 "x": 10.2,
96 "y": 1.28
97 },
98 {
99 "x": 11.2,
100 "y": 1.42
101 },
102 {
103 "x": 12.2,
104 "y": 1.42
105 },
106 {
107 "x": 3.05,
108 "y": 2.67
109 },
110 {
111 "x": 4.06,
112 "y": 2.68
113 },
114 {
115 "x": 5.06,
116 "y": 2.68
117 },
118 {
119 "x": 7.19,
120 "y": 2.67
121 },
122 {
123 "x": 8.2,
124 "y": 2.67
125 },
126 {
127 "x": 9.2,
128 "y": 2.66
129 }
130 ]
131 }
132 }
133}
diff --git a/keyboards/georgi/keymaps/default/keymap.c b/keyboards/georgi/keymaps/default/keymap.c
new file mode 100644
index 000000000..c3d69eb8a
--- /dev/null
+++ b/keyboards/georgi/keymaps/default/keymap.c
@@ -0,0 +1,229 @@
1/*
2 * Good on you for modifying your layout, this is the most nonQMK layout you will come across
3 * There are three modes, Steno (the default), QWERTY (Toggleable) and a Momentary symbol layer
4 *
5 * Don't modify the steno layer directly, instead add chords using the keycodes and macros
6 * from sten.h to the layout you want to modify.
7 *
8 * Observe the comment above processQWERTY!
9 *
10 * http://docs.gboards.ca
11 */
12
13#include QMK_KEYBOARD_H
14#include "sten.h"
15#include "keymap_steno.h"
16#define IGNORE_MOD_TAP_INTERRUPT
17
18int getKeymapCount(void);
19
20// Proper Layers
21#define FUNCT (LSD | LK | LP | LH)
22#define MEDIA (LSD | LK | LW | LR)
23#define MOVE (ST1 | ST2)
24
25/* Keyboard Layout
26 * ,---------------------------------. ,------------------------------.
27 * | FN | LSU | LFT | LP | LH | ST1 | | ST3 | RF | RP | RL | RT | RD |
28 * |-----+-----+-----+----+----|-----| |-----|----+----+----+----+----|
29 * | PWR | LSD | LK | LW | LR | ST2 | | ST4 | RR | RG | RB | RS | RZ |
30 * `---------------------------------' `------------------------------'
31 * ,---------------, .---------------.
32 * | NUM | LA | LO | | RE | RU | NUM |
33 * `---------------' `---------------'
34 */
35
36// YOU MUST ORDER THIS!
37// P Will return from processing on the first match it finds. Therefore
38// PJ Will run the requested action, remove the matched chord and continue
39//
40// First any chords that would conflict with PJs need to be checked, then PJs, lastly Ps.
41// For all chords should be ordered by length in their section!
42//
43// http://docs.gboards.ca
44bool processQwerty(void) {
45 // Place P's that would be trashed by PJ's here
46 P( RT | RS | RD | RZ | NUM, SEND_STRING(VERSION); SEND_STRING(__DATE__));
47 P( NUM | LA | LO | RE | RU, SEND(KC_MPLY));
48 P( ST1 | ST2 | ST3 | ST4, SEND(KC_BSPC));
49
50 // Thumb Chords
51 P( LA | LO | RE | RU, SEND(KC_CAPS));
52 P( LA | RU, SEND(KC_ESC));
53 PJ( LO | RE, SEND(KC_LCTL));
54 PJ( NUM | LA | RU, SEND(KC_LCTL); SEND(KC_LSFT));
55 PJ( NUM | LA | RE, SEND(KC_LCTL); SEND(KC_LSFT); SEND(KC_LALT));
56
57 // Mods
58 PJ( RT | RD | RS | RZ, SEND(KC_LGUI));
59 PJ( RT | RD, SEND(KC_LCTL));
60 PJ( RS | RZ, SEND(KC_LALT));
61 PJ( LA | NUM, SEND(KC_LCTL));
62 PJ( LA | LO, SEND(KC_LALT));
63 PJ( LO, SEND(KC_LSFT));
64
65 // Function Layer
66 P( FUNCT | RF | RR, SEND(KC_F5));
67 P( FUNCT | RP | RB, SEND(KC_F6));
68 P( FUNCT | RL | RG, SEND(KC_F7));
69 P( FUNCT | RT | RS, SEND(KC_F8));
70 P( FUNCT | RF, SEND(KC_F1));
71 P( FUNCT | RP, SEND(KC_F2));
72 P( FUNCT | RL, SEND(KC_F3));
73 P( FUNCT | RT, SEND(KC_F4));
74 P( FUNCT | RR, SEND(KC_F9));
75 P( FUNCT | RG, SEND(KC_F10));
76 P( FUNCT | RB, SEND(KC_F11));
77 P( FUNCT | RS, SEND(KC_F12));
78
79 // Movement Layer
80 P( MOVE | RF, SEND(KC_LEFT));
81 P( MOVE | RP, SEND(KC_DOWN));
82 P( MOVE | RL, SEND(KC_UP));
83 P( MOVE | RT, SEND(KC_RIGHT));
84 P( MOVE | ST3, SEND(KC_PGUP));
85 P( MOVE | ST4, SEND(KC_PGDN));
86
87 // Media Layer
88 P( MEDIA | RF, SEND(KC_MPRV));
89 P( MEDIA | RP, SEND(KC_MPLY));
90 P( MEDIA | RL, SEND(KC_MPLY));
91 P( MEDIA | RT, SEND(KC_MNXT));
92 P( MEDIA | RD, SEND(KC_VOLU));
93 P( MEDIA | RZ, SEND(KC_VOLD));
94 P( MEDIA | RS, SEND(KC_MUTE));
95
96 // Mouse Keys
97 P( LP | LH, clickMouse(KC_MS_BTN1));
98 P( LW | LR, clickMouse(KC_MS_BTN2));
99
100 // Number Row
101 P( NUM | LSU, SEND(KC_1));
102 P( NUM | LFT, SEND(KC_2));
103 P( NUM | LP, SEND(KC_3));
104 P( NUM | LH, SEND(KC_4));
105 P( NUM | ST1, SEND(KC_5));
106 P( NUM | ST3, SEND(KC_6));
107 P( NUM | RF, SEND(KC_7));
108 P( NUM | RP, SEND(KC_8));
109 P( NUM | RL, SEND(KC_9));
110 P( NUM | RT, SEND(KC_0));
111 P( NUM | LA, SEND(KC_5));
112 P( NUM | RT, SEND(KC_0));
113
114 // Specials
115 P( LA | NUM, SEND(KC_ESC));
116 P( RU | NUM, SEND(KC_TAB));
117 P( RE | RU, SEND(KC_BSPC));
118 P( RD | RZ, SEND(KC_ENT));
119 P( RE, SEND(KC_ENT));
120 P( RD, SEND(KC_BSPC));
121 P( NUM, SEND(KC_BSPC));
122 P( LA, SEND(KC_SPC));
123 P( RU, SEND(KC_SPC));
124 P( RZ, SEND(KC_ESC));
125
126 // Letters
127 P( LSU | LSD, SEND(KC_A));
128 P( LFT | LK, SEND(KC_S));
129 P( LP | LW, SEND(KC_D));
130 P( LH | LR, SEND(KC_F));
131 P( ST1 | ST2, SEND(KC_G));
132 P( ST3 | ST4, SEND(KC_H));
133 P( RF | RR, SEND(KC_J));
134 P( RT | RS, SEND(KC_SCLN))
135 P( RG | RL, SEND(KC_L));
136 P( RP | RB, SEND(KC_K));
137 P( LSU, SEND(KC_Q));
138 P( LSD, SEND(KC_Z));
139 P( LFT, SEND(KC_W));
140 P( LK, SEND(KC_X));
141 P( LP, SEND(KC_E));
142 P( LW, SEND(KC_C));
143 P( LH, SEND(KC_R));
144 P( LR, SEND(KC_V));
145 P( ST1, SEND(KC_T));
146 P( ST2, SEND(KC_B));
147 P( ST3, SEND(KC_Y));
148 P( ST4, SEND(KC_N));
149 P( RF, SEND(KC_U));
150 P( RR, SEND(KC_M));
151 P( RP, SEND(KC_I));
152 P( RB, SEND(KC_COMM));
153 P( RL, SEND(KC_O));
154 P( RG, SEND(KC_DOT));
155 P( RT, SEND(KC_P));
156 P( RS, SEND(KC_SLSH));
157
158 // Symbols and Numbers
159 P( PWR | RE | RU, SEND(KC_ENT));
160 P( PWR | LA | LO, SEND(KC_SPC));
161 P( PWR | LP | LW, SEND(KC_LSFT); SEND(KC_9)); // (
162 P( PWR | LH | LR, SEND(KC_LSFT); SEND(KC_0)); // )
163 P( PWR | ST1 | ST2, SEND(KC_GRV)); // `
164 P( PWR | RD | RZ, SEND(KC_ESC));
165 P( PWR | LSU | LSD, SEND(KC_LSFT); SEND(KC_3)); // #
166 P( PWR | LFT | LK, SEND(KC_LSFT); SEND(KC_4)); // $
167 P( PWR | LSU, SEND(KC_LSFT); SEND(KC_1)); // !
168 P( PWR | LSD, SEND(KC_LSFT); SEND(KC_5)); // %
169 P( PWR | LFT, SEND(KC_LSFT); SEND(KC_2)); // @
170 P( PWR | LK, SEND(KC_LSFT); SEND(KC_6)); // ^
171 P( PWR | LP, SEND(KC_LSFT); SEND(KC_LBRC)); // {
172 P( PWR | LW, SEND(KC_LBRC));
173 P( PWR | LH, SEND(KC_LSFT); SEND(KC_RBRC)); // }
174 P( PWR | LR, SEND(KC_RBRC));
175 P( PWR | ST1, SEND(KC_LSFT); SEND(KC_BSLS)); // |
176 P( PWR | ST2, SEND(KC_LSFT); SEND(KC_GRV)); // ~
177 P( PWR | ST3, SEND(KC_QUOT));
178 P( PWR | ST4, SEND(KC_LSFT); SEND(KC_QUOT)); // "
179 P( PWR | RF, SEND(KC_KP_PLUS));
180 P( PWR | RR, SEND(KC_LSFT); SEND(KC_7)); // &
181 P( PWR | RP, SEND(KC_MINS));
182 P( PWR | RB, SEND(KC_EQL));
183 P( PWR | RL, SEND(KC_SLSH));
184 P( PWR | RG, SEND(KC_COMM));
185 P( PWR | RT, SEND(KC_PAST));
186 P( PWR | RS, SEND(KC_DOT));
187 P( PWR | RD, SEND(KC_TAB));
188 P( PWR | LA, SEND(KC_SCLN));
189 P( PWR | LO, SEND(KC_SLSH));
190 P( PWR | RE, SEND(KC_SCLN));
191 P( PWR | RU, SEND(KC_SLSH));
192
193
194 // If we make here, send as a steno chord
195 // If plover is running we can hook that host side
196 return false;
197}
198
199#define STENO_LAYER 0
200#define GAMING 1
201#define GAMING_2 2
202
203// "Layers"
204// Steno layer should be first in your map.
205// When PWR | FN | RR | RG | RB | RS is pressed, the layer is increased to the next map. You must return to STENO_LAYER at the end.
206// If you have only a single layer, you must set SINGLELAYER = yes in your rules.mk, otherwise you may experince undefined behaviour
207
208const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
209// Main layer, everything goes through here
210[STENO_LAYER] = LAYOUT_georgi(
211STN_FN, STN_S1, STN_TL, STN_PL, STN_HL, STN_ST1, STN_ST3, STN_FR, STN_PR, STN_LR, STN_TR, STN_DR,
212STN_PWR, STN_S2, STN_KL, STN_WL, STN_RL, STN_ST2, STN_ST4, STN_RR, STN_BR, STN_GR, STN_SR, STN_ZR,
213 STN_N1, STN_A, STN_O, STN_E, STN_U, STN_N1)
214,
215// Gaming layer with Numpad, Very limited
216[GAMING] = LAYOUT_georgi(
217KC_LSFT, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_ENT,
218KC_LCTL, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_DQUO,
219KC_LALT, KC_SPC, LT(GAMING_2, KC_ENT), KC_DEL, KC_ASTR, TO(STENO_LAYER)),
220
221[GAMING_2] = LAYOUT_georgi(
222KC_LSFT, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS,
223KC_LCTL, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_LT, KC_GT, KC_QUES, KC_RSFT,
224 KC_LALT, KC_SPC, KC_ENT, KC_DEL, KC_ASTR, TO(STENO_LAYER))
225};
226
227int getKeymapCount(void) {
228 return sizeof(keymaps)/sizeof(keymaps[0]);
229}
diff --git a/keyboards/georgi/keymaps/default/readme.md b/keyboards/georgi/keymaps/default/readme.md
new file mode 100644
index 000000000..f9da34b02
--- /dev/null
+++ b/keyboards/georgi/keymaps/default/readme.md
@@ -0,0 +1,11 @@
1# Georgi QWERTY/Steno firmware
2
3This is the default keymap for Georgi, it's based heavily off of the naps62 ErgoDox and the Gergo layout.
4It is both a ergonomic and programmer friendly keymap.
5
6Ideally you should copy this directory and make your changes there. If you come up with a good layout submit a PR!
7
8## Space issues
9If you find yourself running out of space for dictionary entries, disabling mousekeys in rules.mk will save
10you about 4k for entries!
11Get a free 1k by deleting the Gaming layers from the keymap!
diff --git a/keyboards/georgi/keymaps/default/rules.mk b/keyboards/georgi/keymaps/default/rules.mk
new file mode 100644
index 000000000..2973c4591
--- /dev/null
+++ b/keyboards/georgi/keymaps/default/rules.mk
@@ -0,0 +1,27 @@
1#----------------------------------------------------------------------------
2# make georgi:extrakey:dfu
3# Make sure you have dfu-programmer installed!
4#----------------------------------------------------------------------------
5
6#Debug options
7VERBOSE = yes
8CONSOLE_ENABLE = yes
9DEBUG_MATRIX_SCAN_RATE = no
10DEBUG_MATRIX = no
11KEYBOARD_SHARED_EP = yes
12CUSTOM_MATRIX = yes
13MOUSEKEY_ENABLE = yes
14SINGLE_LAYER = no
15
16
17# A bunch of stuff that you shouldn't touch unless you
18# know what you're doing.
19#
20# No touchy, capiche?
21SRC += matrix.c i2c_master.c
22ifeq ($(strip $(DEBUG_MATRIX)), yes)
23 OPT_DEFS += -DDEBUG_MATRIX
24endif
25ifeq ($(strip $(SINGLE_LAYER)), yes)
26 OPT_DEFS += -DSINGLE_LAYER
27endif
diff --git a/keyboards/georgi/keymaps/template/keymap.c b/keyboards/georgi/keymaps/template/keymap.c
new file mode 100644
index 000000000..b17d7ed9f
--- /dev/null
+++ b/keyboards/georgi/keymaps/template/keymap.c
@@ -0,0 +1,216 @@
1/*
2 * Good on you for modifying your layout, this is the most nonQMK layout you will come across
3 * There are three modes, Steno (the default), QWERTY (Toggleable) and a Momentary symbol layer
4 *
5 * Don't modify the steno layer directly, instead add chords using the keycodes and macros
6 * from sten.h to the layout you want to modify.
7 *
8 * Observe the comment above processQWERTY!
9 *
10 * http://docs.gboards.ca
11 */
12
13#include QMK_KEYBOARD_H
14#include "sten.h"
15#include "keymap_steno.h"
16#define IGNORE_MOD_TAP_INTERRUPT
17
18int getKeymapCount(void);
19
20// Proper Layers
21#define FUNCT (LSD | LK | LP | LH)
22#define MEDIA (LSD | LK | LW | LR)
23#define MOVE (ST1 | ST2)
24
25/* Keyboard Layout
26 * ,---------------------------------. ,------------------------------.
27 * | FN | LSU | LFT | LP | LH | ST1 | | ST3 | RF | RP | RL | RT | RD |
28 * |-----+-----+-----+----+----|-----| |-----|----+----+----+----+----|
29 * | PWR | LSD | LK | LW | LR | ST2 | | ST4 | RR | RG | RB | RS | RZ |
30 * `---------------------------------' `------------------------------'
31 * ,---------------, .---------------.
32 * | NUM | LA | LO | | RE | RU | NUM |
33 * `---------------' `---------------'
34 */
35
36// YOU MUST ORDER THIS!
37// P Will return from processing on the first match it finds. Therefore
38// PJ Will run the requested action, remove the matched chord and continue
39//
40// First any chords that would conflict with PJs need to be checked, then PJs, lastly Ps.
41// For all chords should be ordered by length in their section!
42//
43// http://docs.gboards.ca
44bool processQwerty(void) {
45 // Place P's that would be trashed by PJ's here
46 P( RT | RS | RD | RZ | NUM, SEND_STRING(VERSION); SEND_STRING(__DATE__));
47 P( NUM | LA | LO | RE | RU, SEND(KC_MPLY));
48 P( ST1 | ST2 | ST3 | ST4, SEND(KC_BSPC));
49
50 // Thumb Chords
51 P( LA | LO | RE | RU, SEND(KC_CAPS));
52 P( LA | RU, SEND(KC_ESC));
53 PJ( LO | RE, SEND(KC_LCTL));
54 PJ( NUM | LA | RU, SEND(KC_LCTL); SEND(KC_LSFT));
55 PJ( NUM | LA | RE, SEND(KC_LCTL); SEND(KC_LSFT); SEND(KC_LALT));
56
57 // Mods
58 PJ( RT | RD | RS | RZ, SEND(KC_LGUI));
59 PJ( RT | RD, SEND(KC_LCTL));
60 PJ( RS | RZ, SEND(KC_LALT));
61 PJ( LA | NUM, SEND(KC_LCTL));
62 PJ( LA | LO, SEND(KC_LALT));
63 PJ( LO, SEND(KC_LSFT));
64
65 // Function Layer
66 P( FUNCT | RF | RR, SEND(KC_F5));
67 P( FUNCT | RP | RB, SEND(KC_F6));
68 P( FUNCT | RL | RG, SEND(KC_F7));
69 P( FUNCT | RT | RS, SEND(KC_F8));
70 P( FUNCT | RF, SEND(KC_F1));
71 P( FUNCT | RP, SEND(KC_F2));
72 P( FUNCT | RL, SEND(KC_F3));
73 P( FUNCT | RT, SEND(KC_F4));
74 P( FUNCT | RR, SEND(KC_F9));
75 P( FUNCT | RG, SEND(KC_F10));
76 P( FUNCT | RB, SEND(KC_F11));
77 P( FUNCT | RS, SEND(KC_F12));
78
79 // Movement Layer
80 P( MOVE | RF, SEND(KC_LEFT));
81 P( MOVE | RP, SEND(KC_DOWN));
82 P( MOVE | RL, SEND(KC_UP));
83 P( MOVE | RT, SEND(KC_RIGHT));
84 P( MOVE | ST3, SEND(KC_PGUP));
85 P( MOVE | ST4, SEND(KC_PGDN));
86
87 // Media Layer
88 P( MEDIA | RF, SEND(KC_MPRV));
89 P( MEDIA | RP, SEND(KC_MPLY));
90 P( MEDIA | RL, SEND(KC_MPLY));
91 P( MEDIA | RT, SEND(KC_MNXT));
92 P( MEDIA | RD, SEND(KC_VOLU));
93 P( MEDIA | RZ, SEND(KC_VOLD));
94 P( MEDIA | RS, SEND(KC_MUTE));
95
96 // Mouse Keys
97 P( LP | LH, clickMouse(KC_MS_BTN1));
98 P( LW | LR, clickMouse(KC_MS_BTN2));
99
100 // Number Row
101 P( NUM | LSU, SEND(KC_1));
102 P( NUM | LFT, SEND(KC_2));
103 P( NUM | LP, SEND(KC_3));
104 P( NUM | LH, SEND(KC_4));
105 P( NUM | ST1, SEND(KC_5));
106 P( NUM | ST3, SEND(KC_6));
107 P( NUM | RF, SEND(KC_7));
108 P( NUM | RP, SEND(KC_8));
109 P( NUM | RL, SEND(KC_9));
110 P( NUM | RT, SEND(KC_0));
111 P( NUM | LA, SEND(KC_5));
112 P( NUM | RT, SEND(KC_0));
113
114 // Specials
115 P( LA | NUM, SEND(KC_ESC));
116 P( RU | NUM, SEND(KC_TAB));
117 P( RE | RU, SEND(KC_BSPC));
118 P( RD | RZ, SEND(KC_ENT));
119 P( RE, SEND(KC_ENT));
120 P( RD, SEND(KC_BSPC));
121 P( NUM, SEND(KC_BSPC));
122 P( LA, SEND(KC_SPC));
123 P( RU, SEND(KC_SPC));
124 P( RZ, SEND(KC_ESC));
125
126 // Letters
127 P( LSU | LSD, SEND(KC_A));
128 P( LFT | LK, SEND(KC_S));
129 P( LP | LW, SEND(KC_D));
130 P( LH | LR, SEND(KC_F));
131 P( ST1 | ST2, SEND(KC_G));
132 P( ST3 | ST4, SEND(KC_H));
133 P( RF | RR, SEND(KC_J));
134 P( RT | RS, SEND(KC_SCLN))
135 P( RG | RL, SEND(KC_L));
136 P( RP | RB, SEND(KC_K));
137 P( LSU, SEND(KC_Q));
138 P( LSD, SEND(KC_Z));
139 P( LFT, SEND(KC_W));
140 P( LK, SEND(KC_X));
141 P( LP, SEND(KC_E));
142 P( LW, SEND(KC_C));
143 P( LH, SEND(KC_R));
144 P( LR, SEND(KC_V));
145 P( ST1, SEND(KC_T));
146 P( ST2, SEND(KC_B));
147 P( ST3, SEND(KC_Y));
148 P( ST4, SEND(KC_N));
149 P( RF, SEND(KC_U));
150 P( RR, SEND(KC_M));
151 P( RP, SEND(KC_I));
152 P( RB, SEND(KC_COMM));
153 P( RL, SEND(KC_O));
154 P( RG, SEND(KC_DOT));
155 P( RT, SEND(KC_P));
156 P( RS, SEND(KC_SLSH));
157
158 // Symbols and Numbers
159 P( PWR | RE | RU, SEND(KC_ENT));
160 P( PWR | LA | LO, SEND(KC_SPC));
161 P( PWR | LP | LW, SEND(KC_LSFT); SEND(KC_9)); // (
162 P( PWR | LH | LR, SEND(KC_LSFT); SEND(KC_0)); // )
163 P( PWR | ST1 | ST2, SEND(KC_GRV)); // `
164 P( PWR | RD | RZ, SEND(KC_ESC));
165 P( PWR | LSU | LSD, SEND(KC_LSFT); SEND(KC_3)); // #
166 P( PWR | LFT | LK, SEND(KC_LSFT); SEND(KC_4)); // $
167 P( PWR | LSU, SEND(KC_LSFT); SEND(KC_1)); // !
168 P( PWR | LSD, SEND(KC_LSFT); SEND(KC_5)); // %
169 P( PWR | LFT, SEND(KC_LSFT); SEND(KC_2)); // @
170 P( PWR | LK, SEND(KC_LSFT); SEND(KC_6)); // ^
171 P( PWR | LP, SEND(KC_LSFT); SEND(KC_LBRC)); // {
172 P( PWR | LW, SEND(KC_LBRC));
173 P( PWR | LH, SEND(KC_LSFT); SEND(KC_RBRC)); // }
174 P( PWR | LR, SEND(KC_RBRC));
175 P( PWR | ST1, SEND(KC_LSFT); SEND(KC_BSLS)); // |
176 P( PWR | ST2, SEND(KC_LSFT); SEND(KC_GRV)); // ~
177 P( PWR | ST3, SEND(KC_QUOT));
178 P( PWR | ST4, SEND(KC_LSFT); SEND(KC_QUOT)); // "
179 P( PWR | RF, SEND(KC_KP_PLUS));
180 P( PWR | RR, SEND(KC_LSFT); SEND(KC_7)); // &
181 P( PWR | RP, SEND(KC_MINS));
182 P( PWR | RB, SEND(KC_EQL));
183 P( PWR | RL, SEND(KC_SLSH));
184 P( PWR | RG, SEND(KC_COMM));
185 P( PWR | RT, SEND(KC_PAST));
186 P( PWR | RS, SEND(KC_DOT));
187 P( PWR | RD, SEND(KC_TAB));
188 P( PWR | LA, SEND(KC_SCLN));
189 P( PWR | LO, SEND(KC_SLSH));
190 P( PWR | RE, SEND(KC_SCLN));
191 P( PWR | RU, SEND(KC_SLSH));
192
193
194 // If we make here, send as a steno chord
195 // If plover is running we can hook that host side
196 return false;
197}
198
199#define STENO_LAYER 0
200
201// "Layers"
202// Steno layer should be first in your map.
203// When PWR | FN | RR | RG | RB | RS is pressed, the layer is increased to the next map. You must return to STENO_LAYER at the end.
204// If you have only a single layer, you must set SINGLELAYER = yes in your rules.mk, otherwise you may experince undefined behaviour
205
206const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
207// Main layer, everything goes through here
208[STENO_LAYER] = LAYOUT_georgi(
209STN_FN, STN_S1, STN_TL, STN_PL, STN_HL, STN_ST1, STN_ST3, STN_FR, STN_PR, STN_LR, STN_TR, STN_DR,
210STN_PWR, STN_S2, STN_KL, STN_WL, STN_RL, STN_ST2, STN_ST4, STN_RR, STN_BR, STN_GR, STN_SR, STN_ZR,
211 STN_N1, STN_A, STN_O, STN_E, STN_U, STN_N1)
212};
213
214int getKeymapCount(void) {
215 return sizeof(keymaps)/sizeof(keymaps[0]);
216}
diff --git a/keyboards/georgi/keymaps/template/readme.md b/keyboards/georgi/keymaps/template/readme.md
new file mode 100644
index 000000000..7c6fc3512
--- /dev/null
+++ b/keyboards/georgi/keymaps/template/readme.md
@@ -0,0 +1,6 @@
1# Georgi QWERTY/Steno firmware
2
3This is a blank template configured with 5K of free space for your onboard dictionary!
4Read the docs over at [gBoards](http://docs.gboards.ca)
5
6Ideally you should copy this directory and make your changes there. If you come up with a good layout submit a PR!
diff --git a/keyboards/georgi/keymaps/template/rules.mk b/keyboards/georgi/keymaps/template/rules.mk
new file mode 100644
index 000000000..1178fd80d
--- /dev/null
+++ b/keyboards/georgi/keymaps/template/rules.mk
@@ -0,0 +1,27 @@
1#----------------------------------------------------------------------------
2# make georgi:extrakey:dfu
3# Make sure you have dfu-programmer installed!
4#----------------------------------------------------------------------------
5
6#Debug options
7VERBOSE = yes
8CONSOLE_ENABLE = yes
9DEBUG_MATRIX_SCAN_RATE = no
10DEBUG_MATRIX = no
11KEYBOARD_SHARED_EP = yes
12CUSTOM_MATRIX = yes
13MOUSEKEY_ENABLE = no
14SINGLE_LAYER = no
15
16
17# A bunch of stuff that you shouldn't touch unless you
18# know what you're doing.
19#
20# No touchy, capiche?
21SRC += matrix.c i2c_master.c
22ifeq ($(strip $(DEBUG_MATRIX)), yes)
23 OPT_DEFS += -DDEBUG_MATRIX
24endif
25ifeq ($(strip $(SINGLE_LAYER)), yes)
26 OPT_DEFS += -DSINGLE_LAYER
27endif
diff --git a/keyboards/georgi/matrix.c b/keyboards/georgi/matrix.c
new file mode 100644
index 000000000..22079ac61
--- /dev/null
+++ b/keyboards/georgi/matrix.c
@@ -0,0 +1,402 @@
1/*
2Note for ErgoDox EZ customizers: Here be dragons!
3This is not a file you want to be messing with.
4All of the interesting stuff for you is under keymaps/ :)
5Love, Erez
6
7Copyright 2013 Oleg Kostyuk <cub.uanic@gmail.com>
8
9This program is free software: you can redistribute it and/or modify
10it under the terms of the GNU General Public License as published by
11the Free Software Foundation, either version 2 of the License, or
12(at your option) any later version.
13
14This program is distributed in the hope that it will be useful,
15but WITHOUT ANY WARRANTY; without even the implied warranty of
16MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17GNU General Public License for more details.
18
19You should have received a copy of the GNU General Public License
20along with this program. If not, see <http://www.gnu.org/licenses/>.
21*/
22
23#include "matrix.h"
24#include <stdint.h>
25#include <stdbool.h>
26#include <avr/io.h>
27#include "wait.h"
28#include "action_layer.h"
29#include "print.h"
30#include "debug.h"
31#include "util.h"
32#include "keymap_steno.h"
33#include QMK_KEYBOARD_H
34#ifdef DEBUG_MATRIX_SCAN_RATE
35#include "timer.h"
36#endif
37
38
39#ifndef DEBOUNCE
40# define DEBOUNCE 5
41#endif
42
43// MCP Pin Defs
44#define RROW1 (1<<3)
45#define RROW2 (1<<2)
46#define RROW3 (1<<1)
47#define RROW4 (1<<0)
48#define COL0 (1<<0)
49#define COL1 (1<<1)
50#define COL2 (1<<2)
51#define COL3 (1<<3)
52#define COL4 (1<<4)
53#define COL5 (1<<5)
54#define COL6 (1<<6)
55
56// ATmega pin defs
57#define ROW1 (1<<6)
58#define ROW2 (1<<5)
59#define ROW3 (1<<4)
60#define ROW4 (1<<1)
61#define COL7 (1<<0)
62#define COL8 (1<<1)
63#define COL9 (1<<2)
64#define COL10 (1<<3)
65#define COL11 (1<<2)
66#define COL12 (1<<3)
67#define COL13 (1<<6)
68
69
70// bit masks
71#define BMASK (COL7 | COL8 | COL9 | COL10)
72#define CMASK (COL13)
73#define DMASK (COL11 | COL12)
74#define FMASK (ROW1 | ROW2 | ROW3 | ROW4)
75#define RROWMASK (RROW1 | RROW2 | RROW3 | RROW4)
76#define MCPMASK (COL0 | COL1 | COL2 | COL3 | COL4 | COL5 | COL6)
77
78/* matrix state(1:on, 0:off) */
79static matrix_row_t matrix[MATRIX_ROWS];
80/*
81 * matrix state(1:on, 0:off)
82 * contains the raw values without debounce filtering of the last read cycle.
83 */
84static matrix_row_t raw_matrix[MATRIX_ROWS];
85
86// Debouncing: store for each key the number of scans until it's eligible to
87// change. When scanning the matrix, ignore any changes in keys that have
88// already changed in the last DEBOUNCE scans.
89static uint8_t debounce_matrix[MATRIX_ROWS * MATRIX_COLS];
90
91static matrix_row_t read_cols(uint8_t row);
92static void init_cols(void);
93static void unselect_rows(void);
94static void select_row(uint8_t row);
95
96static uint8_t mcp23018_reset_loop;
97// static uint16_t mcp23018_reset_loop;
98
99#ifdef DEBUG_MATRIX_SCAN_RATE
100uint32_t matrix_timer;
101uint32_t matrix_scan_count;
102#endif
103
104
105__attribute__ ((weak))
106void matrix_init_user(void) {}
107
108__attribute__ ((weak))
109void matrix_scan_user(void) {}
110
111__attribute__ ((weak))
112void matrix_init_kb(void) {
113 matrix_init_user();
114}
115
116__attribute__ ((weak))
117void matrix_scan_kb(void) {
118 matrix_scan_user();
119}
120
121inline
122uint8_t matrix_rows(void)
123{
124 return MATRIX_ROWS;
125}
126
127inline
128uint8_t matrix_cols(void)
129{
130 return MATRIX_COLS;
131}
132
133
134void matrix_init(void)
135{
136 // initialize row and col
137 mcp23018_status = init_mcp23018();
138 unselect_rows();
139 init_cols();
140
141 // initialize matrix state: all keys off
142 for (uint8_t i=0; i < MATRIX_ROWS; i++) {
143 matrix[i] = 0;
144 raw_matrix[i] = 0;
145 for (uint8_t j=0; j < MATRIX_COLS; ++j) {
146 debounce_matrix[i * MATRIX_COLS + j] = 0;
147 }
148 }
149
150#ifdef DEBUG_MATRIX_SCAN_RATE
151 matrix_timer = timer_read32();
152 matrix_scan_count = 0;
153#endif
154 matrix_init_quantum();
155}
156
157void matrix_power_up(void) {
158 mcp23018_status = init_mcp23018();
159
160 unselect_rows();
161 init_cols();
162
163 // initialize matrix state: all keys off
164 for (uint8_t i=0; i < MATRIX_ROWS; i++) {
165 matrix[i] = 0;
166 }
167
168#ifdef DEBUG_MATRIX_SCAN_RATE
169 matrix_timer = timer_read32();
170 matrix_scan_count = 0;
171#endif
172
173}
174
175// Returns a matrix_row_t whose bits are set if the corresponding key should be
176// eligible to change in this scan.
177matrix_row_t debounce_mask(matrix_row_t rawcols, uint8_t row) {
178 matrix_row_t result = 0;
179 matrix_row_t change = rawcols ^ raw_matrix[row];
180 raw_matrix[row] = rawcols;
181 for (uint8_t i = 0; i < MATRIX_COLS; ++i) {
182 if (debounce_matrix[row * MATRIX_COLS + i]) {
183 --debounce_matrix[row * MATRIX_COLS + i];
184 } else {
185 result |= (1 << i);
186 }
187 if (change & (1 << i)) {
188 debounce_matrix[row * MATRIX_COLS + i] = DEBOUNCE;
189 }
190 }
191 return result;
192}
193
194matrix_row_t debounce_read_cols(uint8_t row) {
195 // Read the row without debouncing filtering and store it for later usage.
196 matrix_row_t cols = read_cols(row);
197 // Get the Debounce mask.
198 matrix_row_t mask = debounce_mask(cols, row);
199 // debounce the row and return the result.
200 return (cols & mask) | (matrix[row] & ~mask);;
201}
202
203uint8_t matrix_scan(void)
204{
205 // Then the keyboard
206 if (mcp23018_status) { // if there was an error
207 if (++mcp23018_reset_loop == 0) {
208 // if (++mcp23018_reset_loop >= 1300) {
209 // since mcp23018_reset_loop is 8 bit - we'll try to reset once in 255 matrix scans
210 // this will be approx bit more frequent than once per second
211 print("trying to reset mcp23018\n");
212 mcp23018_status = init_mcp23018();
213 if (mcp23018_status) {
214 print("left side not responding\n");
215 } else {
216 print("left side attached\n");
217 }
218 }
219 }
220
221#ifdef DEBUG_MATRIX_SCAN_RATE
222 matrix_scan_count++;
223 uint32_t timer_now = timer_read32();
224 if (TIMER_DIFF_32(timer_now, matrix_timer)>1000) {
225 print("matrix scan frequency: ");
226 pdec(matrix_scan_count);
227 print("\n");
228
229 matrix_timer = timer_now;
230 matrix_scan_count = 0;
231 }
232#endif
233 for (uint8_t i = 0; i < MATRIX_ROWS_PER_SIDE; i++) {
234 select_row(i);
235 // and select on left hand
236 select_row(i + MATRIX_ROWS_PER_SIDE);
237 // we don't need a 30us delay anymore, because selecting a
238 // left-hand row requires more than 30us for i2c.
239
240 // grab cols from left hand
241 matrix[i] = debounce_read_cols(i);
242 // grab cols from right hand
243 matrix[i + MATRIX_ROWS_PER_SIDE] = debounce_read_cols(i + MATRIX_ROWS_PER_SIDE);
244
245 unselect_rows();
246 }
247
248 matrix_scan_quantum();
249
250#ifdef DEBUG_MATRIX
251 for (uint8_t c = 0; c < MATRIX_COLS; c++)
252 for (uint8_t r = 0; r < MATRIX_ROWS; r++)
253 if (matrix_is_on(r, c)) xprintf("r:%d c:%d \n", r, c);
254#endif
255
256 return 1;
257}
258
259bool matrix_is_modified(void) // deprecated and evidently not called.
260{
261 return true;
262}
263
264inline
265bool matrix_is_on(uint8_t row, uint8_t col)
266{
267 return (matrix[row] & ((matrix_row_t)1<<col));
268}
269
270inline
271matrix_row_t matrix_get_row(uint8_t row)
272{
273 return matrix[row];
274}
275
276void matrix_print(void)
277{
278 print("\nr/c 0123456789ABCDEF\n");
279 for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
280 phex(row); print(": ");
281 pbin_reverse16(matrix_get_row(row));
282 print("\n");
283 }
284}
285
286uint8_t matrix_key_count(void)
287{
288 uint8_t count = 0;
289 for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
290 count += bitpop16(matrix[i]);
291 }
292 return count;
293}
294
295// Remember this means ROWS
296static void init_cols(void)
297{
298 // init on mcp23018
299 // not needed, already done as part of init_mcp23018()
300
301 // Input with pull-up(DDR:0, PORT:1)
302 DDRF &= ~FMASK;
303 PORTF |= FMASK;
304}
305
306static matrix_row_t read_cols(uint8_t row)
307{
308 if (row < 7) {
309 if (mcp23018_status) { // if there was an error
310 return 0;
311 } else {
312 uint8_t data = 0;
313 mcp23018_status = i2c_start(I2C_ADDR_WRITE, ERGODOX_EZ_I2C_TIMEOUT); if (mcp23018_status) goto out;
314 mcp23018_status = i2c_write(GPIOB, ERGODOX_EZ_I2C_TIMEOUT); if (mcp23018_status) goto out;
315 mcp23018_status = i2c_start(I2C_ADDR_READ, ERGODOX_EZ_I2C_TIMEOUT); if (mcp23018_status) goto out;
316 mcp23018_status = i2c_read_nack(ERGODOX_EZ_I2C_TIMEOUT); if (mcp23018_status < 0) goto out;
317 data = ~((uint8_t)mcp23018_status);
318 mcp23018_status = I2C_STATUS_SUCCESS;
319 out:
320 i2c_stop();
321
322#ifdef DEBUG_MATRIX
323 if (data != 0x00) xprintf("I2C: %d\n", data);
324#endif
325 return data;
326 }
327 } else {
328 /* read from teensy
329 * bitmask is 0b0111001, but we want the lower four
330 * we'll return 1s for the top two, but that's harmless.
331 */
332 // So I need to confuckulate all this
333 //return ~(((PIND & DMASK) >> 1 | ((PINC & CMASK) >> 6) | (PIN)));
334 //return ~((PINF & 0x03) | ((PINF & 0xF0) >> 2));
335 return ~(
336 (((PINF & ROW4) >> 1)
337 | ((PINF & (ROW1 | ROW2 | ROW3)) >> 3))
338 & 0xF);
339 }
340}
341
342// Row pin configuration
343static void unselect_rows(void)
344{
345 // no need to unselect on mcp23018, because the select step sets all
346 // the other row bits high, and it's not changing to a different
347 // direction
348 // Hi-Z(DDR:0, PORT:0) to unselect
349 DDRB &= ~(BMASK);
350 PORTB &= ~(BMASK);
351 DDRC &= ~CMASK;
352 PORTC &= ~CMASK;
353 DDRD &= ~DMASK;
354 PORTD &= ~DMASK;
355}
356
357static void select_row(uint8_t row)
358{
359 if (row < 7) {
360 // select on mcp23018
361 if (mcp23018_status) { // do nothing on error
362 } else { // set active row low : 0 // set other rows hi-Z : 1
363 mcp23018_status = i2c_start(I2C_ADDR_WRITE, ERGODOX_EZ_I2C_TIMEOUT); if (mcp23018_status) goto out;
364 mcp23018_status = i2c_write(GPIOA, ERGODOX_EZ_I2C_TIMEOUT); if (mcp23018_status) goto out;
365 mcp23018_status = i2c_write(0xFF & ~(1<<row), ERGODOX_EZ_I2C_TIMEOUT); if (mcp23018_status) goto out;
366 out:
367 i2c_stop();
368 }
369 } else {
370 // Output low(DDR:1, PORT:0) to select
371 switch (row) {
372 case 7:
373 DDRB |= COL7;
374 PORTB &= ~COL7;
375 break;
376 case 8:
377 DDRB |= COL8;
378 PORTB &= ~COL8;
379 break;
380 case 9:
381 DDRB |= COL9;
382 PORTB &= ~COL9;
383 break;
384 case 10:
385 DDRB |= COL10;
386 PORTB &= ~COL10;
387 break;
388 case 11:
389 DDRD |= COL11;
390 PORTD &= ~COL11;
391 break;
392 case 12:
393 DDRD |= COL12;
394 PORTD &= ~COL12;
395 break;
396 case 13:
397 DDRC |= COL13;
398 PORTC &= ~COL13;
399 break;
400 }
401 }
402}
diff --git a/keyboards/georgi/readme.md b/keyboards/georgi/readme.md
new file mode 100644
index 000000000..03e2e3d83
--- /dev/null
+++ b/keyboards/georgi/readme.md
@@ -0,0 +1,29 @@
1# Georgi
2
3![Georgi](https://i.imgur.com/3kUpRrj.jpg)
4
5A compact 20% (12x2) Split Keyboard for steno and QWERTY.
6
7[More info on qmk.fm](http://qmk.fm/georgi/)
8
9Keyboard Maintainer: [Jeremy Bernhardt](https://github.com/germ)
10Hardware Supported: Georgi
11Hardware Availability: [gboards.ca](http://gboards.ca)
12
13## Firmware building
14After cloning the QMK repo and installing dfu-programmer build and flash with. Be sure to reset your keyboard!
15
16 make georgi:default:dfu
17
18To just test your build with the default keymap
19
20 make georgi:default
21
22Build options can be enabled/disabled in keyboards/georgi/keymaps/default/rules.mk . Copy the default directory and make any changes to your layout, if you think they're worth sharing submit a PR!
23
24# Space
25The stock firmware uses nearly all of the flash avalible. For custom dictionary modifications, disable mousekeys in your keymaps rules.mk (4K of space) and remove the Gaming layers. I've done this already in the provided keymap 'template'.
26
27See 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).
28
29## Have an idea? [Reach out to me!](mailto:bernhardtjeremy@gmail.com)
diff --git a/keyboards/georgi/rules.mk b/keyboards/georgi/rules.mk
new file mode 100644
index 000000000..0f730f3b7
--- /dev/null
+++ b/keyboards/georgi/rules.mk
@@ -0,0 +1,22 @@
1#----------------------------------------------------------------------------
2# make georgi:default:dfu
3# Make sure you have dfu-programmer installed!
4# Do not edit this file! Make a copy of keymaps/default and modify that!
5#----------------------------------------------------------------------------
6# Source includes
7SRC += matrix.c i2c_master.c
8
9# Hardware info
10MCU = atmega32u4
11F_CPU = 16000000
12ARCH = AVR8
13BOOTLOADER = atmel-dfu
14F_USB = $(F_CPU)
15EXTRAFLAGS += -flto
16
17CUSTOM_MATRIX = yes
18STENO_ENABLE = yes
19EXTRAKEY_ENABLE = yes
20CONSOLE_ENABLE = no
21COMMAND_ENABLE = no
22NKRO_ENABLE = yes
diff --git a/keyboards/georgi/sten.c b/keyboards/georgi/sten.c
new file mode 100644
index 000000000..3b33b11d6
--- /dev/null
+++ b/keyboards/georgi/sten.c
@@ -0,0 +1,2 @@
1#include "sten.h"
2
diff --git a/keyboards/georgi/sten.h b/keyboards/georgi/sten.h
new file mode 100644
index 000000000..fee05deca
--- /dev/null
+++ b/keyboards/georgi/sten.h
@@ -0,0 +1,290 @@
1// 2019, g Heavy Industries
2
3#include QMK_KEYBOARD_H
4#include "mousekey.h"
5#include "keymap.h"
6#include "keymap_steno.h"
7
8// Bitfield representing the current chord
9uint32_t cChord = 0;
10
11// See if a given chord is pressed.
12// P will return
13// PJ will continue processing, removing the found chord
14#define P(chord, act) if (cChord == (chord)) { act; return true; }
15#define PJ(chord, act) if ((cChord & (chord)) == (chord)) { cChord ^= chord; act; }
16
17// All Steno Codes
18// Shift to internal representation
19#define STN(n) (1L<<n)
20
21//i.e) S(teno)R(ight)F
22enum ORDER {
23 SFN = 0, SPWR, SST1, SST2, SST3, SST4, SNUM,
24 SLSU, SLSD, SLT, SLK, SLP, SLW, SLH, SLR, SLA, SLO,
25 SRE, SRU, SRF, SRR, SRP, SRB, SRL, SRG, SRT, SRS, SRD, SRZ
26};
27
28// Break it all out
29#define FN STN(SFN)
30#define PWR STN(SPWR)
31#define ST1 STN(SST1)
32#define ST2 STN(SST2)
33#define ST3 STN(SST3)
34#define ST4 STN(SST4)
35#define NUM STN(SNUM) // No distinction between left and right
36
37#define LSU STN(SLSU)
38#define LSD STN(SLSD)
39#define LFT STN(SLT) // (L)e(F)t (T), preprocessor conflict
40#define LK STN(SLK)
41#define LP STN(SLP)
42#define LW STN(SLW)
43#define LH STN(SLH)
44#define LR STN(SLR)
45#define LA STN(SLA)
46#define LO STN(SLO)
47
48#define RE STN(SRE)
49#define RU STN(SRU)
50#define RF STN(SRF)
51#define RR STN(SRR)
52#define RP STN(SRP)
53#define RB STN(SRB)
54#define RL STN(SRL)
55#define RG STN(SRG)
56#define RT STN(SRT)
57#define RS STN(SRS)
58#define RD STN(SRD)
59#define RZ STN(SRZ)
60
61bool processQwerty(void);
62bool processFakeSteno(void);
63void clickMouse(uint8_t kc);
64void SEND(uint8_t kc);
65extern int getKeymapCount(void);
66
67// Mode state
68enum MODE { STENO = 0, QWERTY, COMMAND };
69enum MODE cMode = STENO;
70enum MODE pMode;
71bool QWERSTENO = false;
72
73// Command State
74#define MAX_CMD_BUF 20
75uint8_t CMDBUF[MAX_CMD_BUF];
76uint8_t CMDLEN = 0;
77
78// Key Repeat state
79bool inChord = false;
80uint16_t repTimer = 0;
81#define REP_DELAY 300
82
83// Mousekeys state
84bool inMouse = false;
85int8_t mousePress;
86
87// All processing done at chordUp goes through here
88bool send_steno_chord_user(steno_mode_t mode, uint8_t chord[6]) {
89 // Check for mousekeys, this is release
90#ifdef MOUSEKEY_ENABLE
91 if (inMouse) {
92 inMouse = false;
93 mousekey_off(mousePress);
94 mousekey_send();
95 }
96#endif
97
98 // Toggle Serial/QWERTY steno
99 if (cChord == (PWR | FN | ST1 | ST2)) {
100 uprintf("Fallback Toggle\n");
101 QWERSTENO = !QWERSTENO;
102
103 goto out;
104 }
105
106 // handle command mode
107 if (cChord == (PWR | FN | RD | RZ)) {
108 uprintf("COMMAND Toggle\n");
109 if (cMode != COMMAND) { // Entering Command Mode
110 CMDLEN = 0;
111 pMode = cMode;
112 cMode = COMMAND;
113 } else { // Exiting Command Mode
114 cMode = pMode;
115
116 // Press all and release all
117 for (int i = 0; i < CMDLEN; i++) {
118 register_code(CMDBUF[i]);
119 }
120 clear_keyboard();
121 }
122
123 goto out;
124 }
125
126 // Handle Gaming Toggle,
127 if (cChord == (PWR | FN | ST2 | ST3) && getKeymapCount() > 1) {
128 uprintf("Switching to QMK\n");
129 layer_on(1);
130 goto out;
131 }
132
133 // Lone FN press, toggle QWERTY
134 if (cChord == FN) {
135 (cMode == STENO) ? (cMode = QWERTY) : (cMode = STENO);
136 goto out;
137 }
138
139 // Check for Plover momentary
140 if (cMode == QWERTY && (cChord & FN)) {
141 cChord ^= FN;
142 goto steno;
143 }
144
145 // Do QWERTY and Momentary QWERTY
146 if (cMode == QWERTY || (cMode == COMMAND) || (cChord & (FN | PWR))) {
147 if (cChord & FN) cChord ^= FN;
148 processQwerty();
149 goto out;
150 }
151
152 // Fallback NKRO Steno
153 if (cMode == STENO && QWERSTENO) {
154 processFakeSteno();
155 goto out;
156 }
157
158steno:
159 // Hey that's a steno chord!
160 inChord = false;
161 cChord = 0;
162 return true;
163
164out:
165 inChord = false;
166 clear_keyboard();
167 cChord = 0;
168 return false;
169}
170
171// Update Chord State
172bool process_steno_user(uint16_t keycode, keyrecord_t *record) {
173 // Everything happens in here when steno keys come in.
174 // Bail on keyup
175 if (!record->event.pressed) return true;
176
177 // Update key repeat timers
178 repTimer = timer_read();
179 inChord = true;
180
181 // Switch on the press adding to chord
182 bool pr = record->event.pressed;
183 switch (keycode) {
184 // Mods and stuff
185 case STN_ST1: pr ? (cChord |= (ST1)): (cChord &= ~(ST1)); break;
186 case STN_ST2: pr ? (cChord |= (ST2)): (cChord &= ~(ST2)); break;
187 case STN_ST3: pr ? (cChord |= (ST3)): (cChord &= ~(ST3)); break;
188 case STN_ST4: pr ? (cChord |= (ST4)): (cChord &= ~(ST4)); break;
189 case STN_FN: pr ? (cChord |= (FN)) : (cChord &= ~(FN)); break;
190 case STN_PWR: pr ? (cChord |= (PWR)): (cChord &= ~(PWR)); break;
191 case STN_N1...STN_N6:
192 case STN_N7...STN_NC: pr ? (cChord |= (NUM)): (cChord &= ~(NUM)); break;
193
194 // All the letter keys
195 case STN_S1: pr ? (cChord |= (LSU)) : (cChord &= ~(LSU)); break;
196 case STN_S2: pr ? (cChord |= (LSD)) : (cChord &= ~(LSD)); break;
197 case STN_TL: pr ? (cChord |= (LFT)) : (cChord &= ~(LFT)); break;
198 case STN_KL: pr ? (cChord |= (LK)) : (cChord &= ~(LK)); break;
199 case STN_PL: pr ? (cChord |= (LP)) : (cChord &= ~(LP)); break;
200 case STN_WL: pr ? (cChord |= (LW)) : (cChord &= ~(LW)); break;
201 case STN_HL: pr ? (cChord |= (LH)) : (cChord &= ~(LH)); break;
202 case STN_RL: pr ? (cChord |= (LR)) : (cChord &= ~(LR)); break;
203 case STN_A: pr ? (cChord |= (LA)) : (cChord &= ~(LA)); break;
204 case STN_O: pr ? (cChord |= (LO)) : (cChord &= ~(LO)); break;
205 case STN_E: pr ? (cChord |= (RE)) : (cChord &= ~(RE)); break;
206 case STN_U: pr ? (cChord |= (RU)) : (cChord &= ~(RU)); break;
207 case STN_FR: pr ? (cChord |= (RF)) : (cChord &= ~(RF)); break;
208 case STN_RR: pr ? (cChord |= (RR)) : (cChord &= ~(RR)); break;
209 case STN_PR: pr ? (cChord |= (RP)) : (cChord &= ~(RP)); break;
210 case STN_BR: pr ? (cChord |= (RB)) : (cChord &= ~(RB)); break;
211 case STN_LR: pr ? (cChord |= (RL)) : (cChord &= ~(RL)); break;
212 case STN_GR: pr ? (cChord |= (RG)) : (cChord &= ~(RG)); break;
213 case STN_TR: pr ? (cChord |= (RT)) : (cChord &= ~(RT)); break;
214 case STN_SR: pr ? (cChord |= (RS)) : (cChord &= ~(RS)); break;
215 case STN_DR: pr ? (cChord |= (RD)) : (cChord &= ~(RD)); break;
216 case STN_ZR: pr ? (cChord |= (RZ)) : (cChord &= ~(RZ)); break;
217 }
218
219 // Check for key repeat in QWERTY mode
220 return true;
221}
222void matrix_scan_user(void) {
223 // We abuse this for early sending of key
224 // Key repeat only on QWER/SYMB layers
225 if (cMode != QWERTY) return;
226
227 // Check timers
228 if (timer_elapsed(repTimer) > REP_DELAY) {
229 // Process Key for report
230 processQwerty();
231
232 // Send report to host
233 send_keyboard_report();
234 repTimer = timer_read();
235 }
236};
237
238// Helpers
239bool processFakeSteno(void) {
240 PJ( LSU, SEND(KC_Q););
241 PJ( LSD, SEND(KC_A););
242 PJ( LFT, SEND(KC_W););
243 PJ( LP, SEND(KC_E););
244 PJ( LH, SEND(KC_R););
245 PJ( LK, SEND(KC_S););
246 PJ( LW, SEND(KC_D););
247 PJ( LR, SEND(KC_F););
248 PJ( ST1, SEND(KC_T););
249 PJ( ST2, SEND(KC_G););
250 PJ( LA, SEND(KC_C););
251 PJ( LO, SEND(KC_V););
252 PJ( RE, SEND(KC_N););
253 PJ( RU, SEND(KC_M););
254 PJ( ST3, SEND(KC_Y););
255 PJ( ST4, SEND(KC_H););
256 PJ( RF, SEND(KC_U););
257 PJ( RP, SEND(KC_I););
258 PJ( RL, SEND(KC_O););
259 PJ( RT, SEND(KC_P););
260 PJ( RD, SEND(KC_LBRC););
261 PJ( RR, SEND(KC_J););
262 PJ( RB, SEND(KC_K););
263 PJ( RG, SEND(KC_L););
264 PJ( RS, SEND(KC_SCLN););
265 PJ( RZ, SEND(KC_COMM););
266 PJ( NUM, SEND(KC_1););
267
268 return false;
269}
270void clickMouse(uint8_t kc) {
271#ifdef MOUSEKEY_ENABLE
272 mousekey_on(kc);
273 mousekey_send();
274
275 // Store state for later use
276 inMouse = true;
277 mousePress = kc;
278#endif
279}
280void SEND(uint8_t kc) {
281 // Send Keycode, Does not work for Quantum Codes
282 if (cMode == COMMAND && CMDLEN < MAX_CMD_BUF) {
283 uprintf("CMD LEN: %d BUF: %d\n", CMDLEN, MAX_CMD_BUF);
284 CMDBUF[CMDLEN] = kc;
285 CMDLEN++;
286 }
287
288 if (cMode != COMMAND) register_code(kc);
289 return;
290}