Update Dvorak, Colemak and Workman keycode aliases (#8217)
[jackhill/qmk/firmware.git] / quantum / matrix.c
1 /*
2 Copyright 2012-2018 Jun Wako, Jack Humbert, Yiancar
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 #include <stdint.h>
18 #include <stdbool.h>
19 #include "util.h"
20 #include "matrix.h"
21 #include "debounce.h"
22 #include "quantum.h"
23
24 #ifdef DIRECT_PINS
25 static pin_t direct_pins[MATRIX_ROWS][MATRIX_COLS] = DIRECT_PINS;
26 #elif (DIODE_DIRECTION == ROW2COL) || (DIODE_DIRECTION == COL2ROW)
27 static const pin_t row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS;
28 static const pin_t col_pins[MATRIX_COLS] = MATRIX_COL_PINS;
29 #endif
30
31 /* matrix state(1:on, 0:off) */
32 extern matrix_row_t raw_matrix[MATRIX_ROWS]; // raw values
33 extern matrix_row_t matrix[MATRIX_ROWS]; // debounced values
34
35 // matrix code
36
37 #ifdef DIRECT_PINS
38
39 static void init_pins(void) {
40 for (int row = 0; row < MATRIX_ROWS; row++) {
41 for (int col = 0; col < MATRIX_COLS; col++) {
42 pin_t pin = direct_pins[row][col];
43 if (pin != NO_PIN) {
44 setPinInputHigh(pin);
45 }
46 }
47 }
48 }
49
50 static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row) {
51 matrix_row_t last_row_value = current_matrix[current_row];
52 current_matrix[current_row] = 0;
53
54 for (uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++) {
55 pin_t pin = direct_pins[current_row][col_index];
56 if (pin != NO_PIN) {
57 current_matrix[current_row] |= readPin(pin) ? 0 : (MATRIX_ROW_SHIFTER << col_index);
58 }
59 }
60
61 return (last_row_value != current_matrix[current_row]);
62 }
63
64 #elif defined(DIODE_DIRECTION)
65 # if (DIODE_DIRECTION == COL2ROW)
66
67 static void select_row(uint8_t row) {
68 setPinOutput(row_pins[row]);
69 writePinLow(row_pins[row]);
70 }
71
72 static void unselect_row(uint8_t row) { setPinInputHigh(row_pins[row]); }
73
74 static void unselect_rows(void) {
75 for (uint8_t x = 0; x < MATRIX_ROWS; x++) {
76 setPinInputHigh(row_pins[x]);
77 }
78 }
79
80 static void init_pins(void) {
81 unselect_rows();
82 for (uint8_t x = 0; x < MATRIX_COLS; x++) {
83 setPinInputHigh(col_pins[x]);
84 }
85 }
86
87 static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row) {
88 // Store last value of row prior to reading
89 matrix_row_t last_row_value = current_matrix[current_row];
90
91 // Clear data in matrix row
92 current_matrix[current_row] = 0;
93
94 // Select row and wait for row selecton to stabilize
95 select_row(current_row);
96 matrix_io_delay();
97
98 // For each col...
99 for (uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++) {
100 // Select the col pin to read (active low)
101 uint8_t pin_state = readPin(col_pins[col_index]);
102
103 // Populate the matrix row with the state of the col pin
104 current_matrix[current_row] |= pin_state ? 0 : (MATRIX_ROW_SHIFTER << col_index);
105 }
106
107 // Unselect row
108 unselect_row(current_row);
109
110 return (last_row_value != current_matrix[current_row]);
111 }
112
113 # elif (DIODE_DIRECTION == ROW2COL)
114
115 static void select_col(uint8_t col) {
116 setPinOutput(col_pins[col]);
117 writePinLow(col_pins[col]);
118 }
119
120 static void unselect_col(uint8_t col) { setPinInputHigh(col_pins[col]); }
121
122 static void unselect_cols(void) {
123 for (uint8_t x = 0; x < MATRIX_COLS; x++) {
124 setPinInputHigh(col_pins[x]);
125 }
126 }
127
128 static void init_pins(void) {
129 unselect_cols();
130 for (uint8_t x = 0; x < MATRIX_ROWS; x++) {
131 setPinInputHigh(row_pins[x]);
132 }
133 }
134
135 static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col) {
136 bool matrix_changed = false;
137
138 // Select col and wait for col selecton to stabilize
139 select_col(current_col);
140 matrix_io_delay();
141
142 // For each row...
143 for (uint8_t row_index = 0; row_index < MATRIX_ROWS; row_index++) {
144 // Store last value of row prior to reading
145 matrix_row_t last_row_value = current_matrix[row_index];
146
147 // Check row pin state
148 if (readPin(row_pins[row_index]) == 0) {
149 // Pin LO, set col bit
150 current_matrix[row_index] |= (MATRIX_ROW_SHIFTER << current_col);
151 } else {
152 // Pin HI, clear col bit
153 current_matrix[row_index] &= ~(MATRIX_ROW_SHIFTER << current_col);
154 }
155
156 // Determine if the matrix changed state
157 if ((last_row_value != current_matrix[row_index]) && !(matrix_changed)) {
158 matrix_changed = true;
159 }
160 }
161
162 // Unselect col
163 unselect_col(current_col);
164
165 return matrix_changed;
166 }
167
168 # else
169 # error DIODE_DIRECTION must be one of COL2ROW or ROW2COL!
170 # endif
171 #else
172 # error DIODE_DIRECTION is not defined!
173 #endif
174
175 void matrix_init(void) {
176 // initialize key pins
177 init_pins();
178
179 // initialize matrix state: all keys off
180 for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
181 raw_matrix[i] = 0;
182 matrix[i] = 0;
183 }
184
185 debounce_init(MATRIX_ROWS);
186
187 matrix_init_quantum();
188 }
189
190 uint8_t matrix_scan(void) {
191 bool changed = false;
192
193 #if defined(DIRECT_PINS) || (DIODE_DIRECTION == COL2ROW)
194 // Set row, read cols
195 for (uint8_t current_row = 0; current_row < MATRIX_ROWS; current_row++) {
196 changed |= read_cols_on_row(raw_matrix, current_row);
197 }
198 #elif (DIODE_DIRECTION == ROW2COL)
199 // Set col, read rows
200 for (uint8_t current_col = 0; current_col < MATRIX_COLS; current_col++) {
201 changed |= read_rows_on_col(raw_matrix, current_col);
202 }
203 #endif
204
205 debounce(raw_matrix, matrix, MATRIX_ROWS, changed);
206
207 matrix_scan_quantum();
208 return (uint8_t)changed;
209 }