]> git.donarmstrong.com Git - qmk_firmware.git/blob - quantum/split_common/matrix.c
c3d2857ed50bfd9b8894817f88e76b77d305f60c
[qmk_firmware.git] / quantum / split_common / matrix.c
1 /*
2 Copyright 2012 Jun Wako <wakojun@gmail.com>
3
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 /*
19  * scan matrix
20  */
21 #include <stdint.h>
22 #include <stdbool.h>
23 #include "wait.h"
24 #include "util.h"
25 #include "matrix.h"
26 #include "split_util.h"
27 #include "config.h"
28 #include "split_flags.h"
29 #include "quantum.h"
30 #include "debounce.h"
31 #include "transport.h"
32
33 #if (MATRIX_COLS <= 8)
34 #  define print_matrix_header() print("\nr/c 01234567\n")
35 #  define print_matrix_row(row) print_bin_reverse8(matrix_get_row(row))
36 #  define matrix_bitpop(i) bitpop(matrix[i])
37 #  define ROW_SHIFTER ((uint8_t)1)
38 #elif (MATRIX_COLS <= 16)
39 #  define print_matrix_header() print("\nr/c 0123456789ABCDEF\n")
40 #  define print_matrix_row(row) print_bin_reverse16(matrix_get_row(row))
41 #  define matrix_bitpop(i) bitpop16(matrix[i])
42 #  define ROW_SHIFTER ((uint16_t)1)
43 #elif (MATRIX_COLS <= 32)
44 #  define print_matrix_header() print("\nr/c 0123456789ABCDEF0123456789ABCDEF\n")
45 #  define print_matrix_row(row) print_bin_reverse32(matrix_get_row(row))
46 #  define matrix_bitpop(i) bitpop32(matrix[i])
47 #  define ROW_SHIFTER ((uint32_t)1)
48 #endif
49
50 #define ERROR_DISCONNECT_COUNT 5
51
52 #define ROWS_PER_HAND (MATRIX_ROWS / 2)
53
54 #ifdef DIRECT_PINS
55 static pin_t direct_pins[MATRIX_ROWS][MATRIX_COLS] = DIRECT_PINS;
56 #else
57 static pin_t row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS;
58 static pin_t col_pins[MATRIX_COLS] = MATRIX_COL_PINS;
59 #endif
60
61 /* matrix state(1:on, 0:off) */
62 static matrix_row_t matrix[MATRIX_ROWS];
63 static matrix_row_t raw_matrix[ROWS_PER_HAND];
64
65 // row offsets for each hand
66 uint8_t thisHand, thatHand;
67
68 // user-defined overridable functions
69
70 __attribute__((weak)) void matrix_init_kb(void) { matrix_init_user(); }
71
72 __attribute__((weak)) void matrix_scan_kb(void) { matrix_scan_user(); }
73
74 __attribute__((weak)) void matrix_init_user(void) {}
75
76 __attribute__((weak)) void matrix_scan_user(void) {}
77
78 __attribute__((weak)) void matrix_slave_scan_user(void) {}
79
80 // helper functions
81
82 inline uint8_t matrix_rows(void) { return MATRIX_ROWS; }
83
84 inline uint8_t matrix_cols(void) { return MATRIX_COLS; }
85
86 bool matrix_is_modified(void) {
87   if (debounce_active()) return false;
88   return true;
89 }
90
91 inline bool matrix_is_on(uint8_t row, uint8_t col) { return (matrix[row] & ((matrix_row_t)1 << col)); }
92
93 inline matrix_row_t matrix_get_row(uint8_t row) { return matrix[row]; }
94
95 void matrix_print(void) {
96   print_matrix_header();
97
98   for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
99     phex(row);
100     print(": ");
101     print_matrix_row(row);
102     print("\n");
103   }
104 }
105
106 uint8_t matrix_key_count(void) {
107   uint8_t count = 0;
108   for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
109     count += matrix_bitpop(i);
110   }
111   return count;
112 }
113
114 // matrix code
115
116 #ifdef DIRECT_PINS
117
118 static void init_pins(void) {
119   for (int row = 0; row < MATRIX_ROWS; row++) {
120     for (int col = 0; col < MATRIX_COLS; col++) {
121       pin_t pin = direct_pins[row][col];
122       if (pin != NO_PIN) {
123         setPinInputHigh(pin);
124       }
125     }
126   }
127 }
128
129 static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row) {
130   matrix_row_t last_row_value = current_matrix[current_row];
131   current_matrix[current_row] = 0;
132
133   for (uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++) {
134     pin_t pin = direct_pins[current_row][col_index];
135     if (pin != NO_PIN) {
136       current_matrix[current_row] |= readPin(pin) ? 0 : (ROW_SHIFTER << col_index);
137     }
138   }
139
140   return (last_row_value != current_matrix[current_row]);
141 }
142
143 #elif (DIODE_DIRECTION == COL2ROW)
144
145 static void select_row(uint8_t row) {
146   writePinLow(row_pins[row]);
147   setPinOutput(row_pins[row]);
148 }
149
150 static void unselect_row(uint8_t row) { setPinInputHigh(row_pins[row]); }
151
152 static void unselect_rows(void) {
153   for (uint8_t x = 0; x < ROWS_PER_HAND; x++) {
154     setPinInputHigh(row_pins[x]);
155   }
156 }
157
158 static void init_pins(void) {
159   unselect_rows();
160   for (uint8_t x = 0; x < MATRIX_COLS; x++) {
161     setPinInputHigh(col_pins[x]);
162   }
163 }
164
165 static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row) {
166   // Store last value of row prior to reading
167   matrix_row_t last_row_value = current_matrix[current_row];
168
169   // Clear data in matrix row
170   current_matrix[current_row] = 0;
171
172   // Select row and wait for row selecton to stabilize
173   select_row(current_row);
174   wait_us(30);
175
176   // For each col...
177   for (uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++) {
178     // Populate the matrix row with the state of the col pin
179     current_matrix[current_row] |= readPin(col_pins[col_index]) ? 0 : (ROW_SHIFTER << col_index);
180   }
181
182   // Unselect row
183   unselect_row(current_row);
184
185   return (last_row_value != current_matrix[current_row]);
186 }
187
188 #elif (DIODE_DIRECTION == ROW2COL)
189
190 static void select_col(uint8_t col) {
191   writePinLow(col_pins[col]);
192   setPinOutput(col_pins[col]);
193 }
194
195 static void unselect_col(uint8_t col) { setPinInputHigh(col_pins[col]); }
196
197 static void unselect_cols(void) {
198   for (uint8_t x = 0; x < MATRIX_COLS; x++) {
199     setPinInputHigh(col_pins[x]);
200   }
201 }
202
203 static void init_pins(void) {
204   unselect_cols();
205   for (uint8_t x = 0; x < ROWS_PER_HAND; x++) {
206     setPinInputHigh(row_pins[x]);
207   }
208 }
209
210 static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col) {
211   bool matrix_changed = false;
212
213   // Select col and wait for col selecton to stabilize
214   select_col(current_col);
215   wait_us(30);
216
217   // For each row...
218   for (uint8_t row_index = 0; row_index < ROWS_PER_HAND; row_index++) {
219     // Store last value of row prior to reading
220     matrix_row_t last_row_value = current_matrix[row_index];
221
222     // Check row pin state
223     if (readPin(row_pins[row_index])) {
224       // Pin HI, clear col bit
225       current_matrix[row_index] &= ~(ROW_SHIFTER << current_col);
226     } else {
227       // Pin LO, set col bit
228       current_matrix[row_index] |= (ROW_SHIFTER << current_col);
229     }
230
231     // Determine if the matrix changed state
232     if ((last_row_value != current_matrix[row_index]) && !(matrix_changed)) {
233       matrix_changed = true;
234     }
235   }
236
237   // Unselect col
238   unselect_col(current_col);
239
240   return matrix_changed;
241 }
242
243 #endif
244
245 void matrix_init(void) {
246   debug_enable = true;
247   debug_matrix = true;
248   debug_mouse  = true;
249
250   // Set pinout for right half if pinout for that half is defined
251   if (!isLeftHand) {
252 #ifdef MATRIX_ROW_PINS_RIGHT
253     const uint8_t row_pins_right[MATRIX_ROWS] = MATRIX_ROW_PINS_RIGHT;
254     for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
255       row_pins[i] = row_pins_right[i];
256     }
257 #endif
258 #ifdef MATRIX_COL_PINS_RIGHT
259     const uint8_t col_pins_right[MATRIX_COLS] = MATRIX_COL_PINS_RIGHT;
260     for (uint8_t i = 0; i < MATRIX_COLS; i++) {
261       col_pins[i] = col_pins_right[i];
262     }
263 #endif
264   }
265
266   thisHand = isLeftHand ? 0 : (ROWS_PER_HAND);
267   thatHand = ROWS_PER_HAND - thisHand;
268
269   // initialize key pins
270   init_pins();
271
272   // initialize matrix state: all keys off
273   for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
274     matrix[i] = 0;
275   }
276
277   debounce_init(ROWS_PER_HAND);
278
279   matrix_init_quantum();
280 }
281
282 uint8_t _matrix_scan(void) {
283   bool changed = false;
284
285 #if defined(DIRECT_PINS) || (DIODE_DIRECTION == COL2ROW)
286   // Set row, read cols
287   for (uint8_t current_row = 0; current_row < ROWS_PER_HAND; current_row++) {
288     changed |= read_cols_on_row(raw_matrix, current_row);
289   }
290 #elif (DIODE_DIRECTION == ROW2COL)
291   // Set col, read rows
292   for (uint8_t current_col = 0; current_col < MATRIX_COLS; current_col++) {
293     changed |= read_rows_on_col(raw_matrix, current_col);
294   }
295 #endif
296
297   debounce(raw_matrix, matrix + thisHand, ROWS_PER_HAND, changed);
298
299   return 1;
300 }
301
302 uint8_t matrix_scan(void) {
303   uint8_t ret = _matrix_scan();
304
305   if (is_keyboard_master()) {
306     static uint8_t error_count;
307
308     if (!transport_master(matrix + thatHand)) {
309       error_count++;
310
311       if (error_count > ERROR_DISCONNECT_COUNT) {
312         // reset other half if disconnected
313         for (int i = 0; i < ROWS_PER_HAND; ++i) {
314           matrix[thatHand + i] = 0;
315         }
316       }
317     } else {
318       error_count = 0;
319     }
320
321     matrix_scan_quantum();
322   } else {
323     transport_slave(matrix + thisHand);
324     matrix_slave_scan_user();
325   }
326
327   return ret;
328 }