diff options
Diffstat (limited to 'keyboards/moonlander/matrix.c')
-rw-r--r-- | keyboards/moonlander/matrix.c | 270 |
1 files changed, 270 insertions, 0 deletions
diff --git a/keyboards/moonlander/matrix.c b/keyboards/moonlander/matrix.c new file mode 100644 index 000000000..774b01187 --- /dev/null +++ b/keyboards/moonlander/matrix.c | |||
@@ -0,0 +1,270 @@ | |||
1 | /* Copyright 2020 ZSA Technology Labs, Inc <@zsa> | ||
2 | * Copyright 2020 Jack Humbert <jack.humb@gmail.com> | ||
3 | * Copyright 2020 Drashna Jael're <drashna@live.com> | ||
4 | * | ||
5 | * This program is free software: you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation, either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | |||
19 | |||
20 | |||
21 | #include <stdint.h> | ||
22 | #include <stdbool.h> | ||
23 | #include <string.h> | ||
24 | #include "hal.h" | ||
25 | #include "timer.h" | ||
26 | #include "wait.h" | ||
27 | #include "printf.h" | ||
28 | #include "matrix.h" | ||
29 | #include "action.h" | ||
30 | #include "keycode.h" | ||
31 | #include <string.h> | ||
32 | #include "moonlander.h" | ||
33 | #include "i2c_master.h" | ||
34 | #include "debounce.h" | ||
35 | |||
36 | /* | ||
37 | #define MATRIX_ROW_PINS { B10, B11, B12, B13, B14, B15 } outputs | ||
38 | #define MATRIX_COL_PINS { A0, A1, A2, A3, A6, A7, B0 } inputs | ||
39 | */ | ||
40 | /* matrix state(1:on, 0:off) */ | ||
41 | static matrix_row_t matrix[MATRIX_ROWS]; | ||
42 | static matrix_row_t matrix_debouncing[MATRIX_ROWS]; | ||
43 | static matrix_row_t matrix_debouncing_right[MATRIX_COLS]; | ||
44 | static bool debouncing = false; | ||
45 | static uint16_t debouncing_time = 0; | ||
46 | static bool debouncing_right = false; | ||
47 | static uint16_t debouncing_time_right = 0; | ||
48 | |||
49 | #define ROWS_PER_HAND (MATRIX_ROWS / 2) | ||
50 | |||
51 | #ifndef MATRIX_IO_DELAY | ||
52 | # define MATRIX_IO_DELAY 20 | ||
53 | #endif | ||
54 | |||
55 | extern bool mcp23018_leds[3]; | ||
56 | extern bool is_launching; | ||
57 | |||
58 | __attribute__((weak)) void matrix_init_user(void) {} | ||
59 | |||
60 | __attribute__((weak)) void matrix_scan_user(void) {} | ||
61 | |||
62 | __attribute__((weak)) void matrix_init_kb(void) { matrix_init_user(); } | ||
63 | |||
64 | __attribute__((weak)) void matrix_scan_kb(void) { matrix_scan_user(); } | ||
65 | |||
66 | __attribute__((weak)) void matrix_io_delay(void) { wait_us(MATRIX_IO_DELAY); } | ||
67 | |||
68 | bool mcp23018_initd = false; | ||
69 | static uint8_t mcp23018_reset_loop; | ||
70 | |||
71 | uint8_t mcp23018_tx[3]; | ||
72 | uint8_t mcp23018_rx[1]; | ||
73 | |||
74 | void mcp23018_init(void) { | ||
75 | i2c_init(); | ||
76 | |||
77 | // #define MCP23_ROW_PINS { GPB5, GBP4, GBP3, GBP2, GBP1, GBP0 } outputs | ||
78 | // #define MCP23_COL_PINS { GPA0, GBA1, GBA2, GBA3, GBA4, GBA5, GBA6 } inputs | ||
79 | |||
80 | mcp23018_tx[0] = 0x00; // IODIRA | ||
81 | mcp23018_tx[1] = 0b00000000; // A is output | ||
82 | mcp23018_tx[2] = 0b00111111; // B is inputs | ||
83 | |||
84 | if (MSG_OK != i2c_transmit(MCP23018_DEFAULT_ADDRESS << 1, mcp23018_tx, 3, I2C_TIMEOUT)) { | ||
85 | printf("error hori\n"); | ||
86 | } else { | ||
87 | mcp23018_tx[0] = 0x0C; // GPPUA | ||
88 | mcp23018_tx[1] = 0b10000000; // A is not pulled-up | ||
89 | mcp23018_tx[2] = 0b11111111; // B is pulled-up | ||
90 | |||
91 | if (MSG_OK != i2c_transmit(MCP23018_DEFAULT_ADDRESS << 1, mcp23018_tx, 3, I2C_TIMEOUT)) { | ||
92 | printf("error hori\n"); | ||
93 | } else { | ||
94 | mcp23018_initd = is_launching = true; | ||
95 | } | ||
96 | } | ||
97 | } | ||
98 | |||
99 | void matrix_init(void) { | ||
100 | printf("matrix init\n"); | ||
101 | // debug_matrix = true; | ||
102 | |||
103 | // outputs | ||
104 | setPinOutput(B10); | ||
105 | setPinOutput(B11); | ||
106 | setPinOutput(B12); | ||
107 | setPinOutput(B13); | ||
108 | setPinOutput(B14); | ||
109 | setPinOutput(B15); | ||
110 | |||
111 | // inputs | ||
112 | setPinInputLow(A0); | ||
113 | setPinInputLow(A1); | ||
114 | setPinInputLow(A2); | ||
115 | setPinInputLow(A3); | ||
116 | setPinInputLow(A6); | ||
117 | setPinInputLow(A7); | ||
118 | setPinInputLow(B0); | ||
119 | |||
120 | memset(matrix, 0, MATRIX_ROWS * sizeof(matrix_row_t)); | ||
121 | memset(matrix_debouncing, 0, MATRIX_ROWS * sizeof(matrix_row_t)); | ||
122 | memset(matrix_debouncing_right, 0, MATRIX_COLS * sizeof(matrix_row_t)); | ||
123 | |||
124 | mcp23018_init(); | ||
125 | |||
126 | matrix_init_quantum(); | ||
127 | } | ||
128 | |||
129 | uint8_t matrix_scan(void) { | ||
130 | bool changed = false; | ||
131 | |||
132 | matrix_row_t data = 0; | ||
133 | // actual matrix | ||
134 | for (uint8_t row = 0; row < ROWS_PER_HAND; row++) { | ||
135 | // strobe row | ||
136 | switch (row) { | ||
137 | case 0: writePinHigh(B10); break; | ||
138 | case 1: writePinHigh(B11); break; | ||
139 | case 2: writePinHigh(B12); break; | ||
140 | case 3: writePinHigh(B13); break; | ||
141 | case 4: writePinHigh(B14); break; | ||
142 | case 5: writePinHigh(B15); break; | ||
143 | } | ||
144 | |||
145 | // need wait to settle pin state | ||
146 | matrix_io_delay(); | ||
147 | |||
148 | // read col data | ||
149 | data = ( | ||
150 | (readPin(A0) << 0 ) | | ||
151 | (readPin(A1) << 1 ) | | ||
152 | (readPin(A2) << 2 ) | | ||
153 | (readPin(A3) << 3 ) | | ||
154 | (readPin(A6) << 4 ) | | ||
155 | (readPin(A7) << 5 ) | | ||
156 | (readPin(B0) << 6 ) | ||
157 | ); | ||
158 | |||
159 | // unstrobe row | ||
160 | switch (row) { | ||
161 | case 0: writePinLow(B10); break; | ||
162 | case 1: writePinLow(B11); break; | ||
163 | case 2: writePinLow(B12); break; | ||
164 | case 3: writePinLow(B13); break; | ||
165 | case 4: writePinLow(B14); break; | ||
166 | case 5: writePinLow(B15); break; | ||
167 | } | ||
168 | |||
169 | if (matrix_debouncing[row] != data) { | ||
170 | matrix_debouncing[row] = data; | ||
171 | debouncing = true; | ||
172 | debouncing_time = timer_read(); | ||
173 | changed = true; | ||
174 | } | ||
175 | } | ||
176 | |||
177 | for (uint8_t row = 0; row <= ROWS_PER_HAND; row++) { | ||
178 | // right side | ||
179 | |||
180 | if (!mcp23018_initd) { | ||
181 | if (++mcp23018_reset_loop == 0) { | ||
182 | // if (++mcp23018_reset_loop >= 1300) { | ||
183 | // since mcp23018_reset_loop is 8 bit - we'll try to reset once in 255 matrix scans | ||
184 | // this will be approx bit more frequent than once per second | ||
185 | print("trying to reset mcp23018\n"); | ||
186 | mcp23018_init(); | ||
187 | if (!mcp23018_initd) { | ||
188 | print("left side not responding\n"); | ||
189 | } else { | ||
190 | print("left side attached\n"); | ||
191 | #ifdef RGB_MATRIX_ENABLE | ||
192 | rgb_matrix_init(); | ||
193 | #endif | ||
194 | } | ||
195 | } | ||
196 | } | ||
197 | |||
198 | // #define MCP23_ROW_PINS { GPB5, GBP4, GBP3, GBP2, GBP1, GBP0 } outputs | ||
199 | // #define MCP23_COL_PINS { GPA0, GBA1, GBA2, GBA3, GBA4, GBA5, GBA6 } inputs | ||
200 | |||
201 | // select row | ||
202 | |||
203 | mcp23018_tx[0] = 0x12; // GPIOA | ||
204 | mcp23018_tx[1] = (0b01111111 & ~(1 << (row))) | ((uint8_t)!mcp23018_leds[2] << 7); // activate row | ||
205 | mcp23018_tx[2] = ((uint8_t)!mcp23018_leds[1] << 6) | ((uint8_t)!mcp23018_leds[0] << 7); // activate row | ||
206 | |||
207 | if (MSG_OK != i2c_transmit(MCP23018_DEFAULT_ADDRESS << 1, mcp23018_tx, 3, I2C_TIMEOUT)) { | ||
208 | printf("error hori\n"); | ||
209 | mcp23018_initd = false; | ||
210 | } | ||
211 | |||
212 | // read col | ||
213 | |||
214 | mcp23018_tx[0] = 0x13; // GPIOB | ||
215 | if (MSG_OK != i2c_readReg(MCP23018_DEFAULT_ADDRESS << 1, mcp23018_tx[0], &mcp23018_rx[0], 1, I2C_TIMEOUT)) { | ||
216 | printf("error vert\n"); | ||
217 | mcp23018_initd = false; | ||
218 | } | ||
219 | |||
220 | data = ~(mcp23018_rx[0] & 0b00111111); | ||
221 | // data = 0x01; | ||
222 | |||
223 | if (matrix_debouncing_right[row] != data) { | ||
224 | matrix_debouncing_right[row] = data; | ||
225 | debouncing_right = true; | ||
226 | debouncing_time_right = timer_read(); | ||
227 | changed = true; | ||
228 | } | ||
229 | } | ||
230 | |||
231 | if (debouncing && timer_elapsed(debouncing_time) > DEBOUNCE) { | ||
232 | for (int row = 0; row < ROWS_PER_HAND; row++) { | ||
233 | matrix[row] = matrix_debouncing[row]; | ||
234 | } | ||
235 | debouncing = false; | ||
236 | } | ||
237 | |||
238 | if (debouncing_right && timer_elapsed(debouncing_time_right) > DEBOUNCE && mcp23018_initd) { | ||
239 | for (int row = 0; row < ROWS_PER_HAND; row++) { | ||
240 | matrix[11 - row] = 0; | ||
241 | for (int col = 0; col < MATRIX_COLS; col++) { | ||
242 | matrix[11 - row] |= ((matrix_debouncing_right[6 - col] & (1 << row) ? 1 : 0) << col); | ||
243 | } | ||
244 | } | ||
245 | debouncing_right = false; | ||
246 | } | ||
247 | |||
248 | matrix_scan_quantum(); | ||
249 | |||
250 | return (uint8_t)changed; | ||
251 | } | ||
252 | |||
253 | bool matrix_is_on(uint8_t row, uint8_t col) { return (matrix[row] & (1 << col)); } | ||
254 | |||
255 | matrix_row_t matrix_get_row(uint8_t row) { return matrix[row]; } | ||
256 | |||
257 | void matrix_print(void) { | ||
258 | printf("\nr/c 01234567\n"); | ||
259 | for (uint8_t row = 0; row < MATRIX_ROWS; row++) { | ||
260 | printf("%X0: ", row); | ||
261 | matrix_row_t data = matrix_get_row(row); | ||
262 | for (int col = 0; col < MATRIX_COLS; col++) { | ||
263 | if (data & (1 << col)) | ||
264 | printf("1"); | ||
265 | else | ||
266 | printf("0"); | ||
267 | } | ||
268 | printf("\n"); | ||
269 | } | ||
270 | } | ||