matrix.c
8300 bytes
1/*
2Copyright 2012 Jun Wako <wakojun@gmail.com>
3
4This program is free software: you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation, either version 2 of the License, or
7(at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program. If not, see <http://www.gnu.org/licenses/>.
16*/
17#include "matrix.h"
18#include "atomic_util.h"
19#include "split_util.h"
20#include "transport.h"
21#include "debounce.h"
22#include "wait.h"
23
24#define ERROR_DISCONNECT_COUNT 5
25
26#define ROWS_PER_HAND (MATRIX_ROWS / 2)
27
28static pin_t row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS;
29static pin_t col_pins[MATRIX_COLS] = MATRIX_COL_PINS;
30
31/* matrix state(1:on, 0:off) */
32static matrix_row_t raw_matrix[MATRIX_ROWS]; // raw values
33static matrix_row_t matrix[MATRIX_ROWS]; // debounced values
34
35// row offsets for each hand
36uint8_t thisHand, thatHand;
37
38// user-defined overridable functions
39__attribute__((weak)) void matrix_init_kb(void) { matrix_init_user(); }
40
41__attribute__((weak)) void matrix_scan_kb(void) { matrix_scan_user(); }
42
43__attribute__((weak)) void matrix_init_user(void) {}
44
45__attribute__((weak)) void matrix_scan_user(void) {}
46
47__attribute__((weak)) void matrix_slave_scan_user(void) {}
48
49matrix_row_t matrix_get_row(uint8_t row) { return matrix[row]; }
50
51void matrix_print(void) {}
52
53static inline void gpio_atomic_set_pin_output_low(pin_t pin) {
54 ATOMIC_BLOCK_FORCEON {
55 gpio_set_pin_output(pin);
56 gpio_write_pin_low(pin);
57 }
58}
59
60static inline void gpio_atomic_set_pin_input_high(pin_t pin) {
61 ATOMIC_BLOCK_FORCEON { gpio_set_pin_input_high(pin); }
62}
63
64// matrix code
65static void select_row(uint8_t row) { gpio_atomic_set_pin_output_low(row_pins[row]); }
66
67static void unselect_row(uint8_t row) { gpio_atomic_set_pin_input_high(row_pins[row]); }
68
69static void unselect_rows(void) {
70 for (uint8_t x = 0; x < ROWS_PER_HAND; x++) {
71 gpio_atomic_set_pin_input_high(row_pins[x]);
72 }
73}
74
75static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row) {
76 // Start with a clear matrix row
77 matrix_row_t current_row_value = 0;
78
79 // Select row
80 select_row(current_row);
81 wait_us(30);
82
83 // For each col...
84 for (uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++) {
85 // Select the col pin to read (active low)
86 uint8_t pin_state = gpio_read_pin(col_pins[col_index]);
87
88 // Populate the matrix row with the state of the col pin
89 current_row_value |= pin_state ? 0 : (MATRIX_ROW_SHIFTER << col_index);
90 }
91
92 // Unselect row
93 unselect_row(current_row);
94 if (current_row + 1 < MATRIX_ROWS) {
95 wait_us(30); // wait for row signal to go HIGH
96 }
97
98 // If the row has changed, store the row and return the changed flag.
99 if (current_matrix[current_row] != current_row_value) {
100 current_matrix[current_row] = current_row_value;
101 return true;
102 }
103 return false;
104}
105
106static void select_col(uint8_t col) { gpio_atomic_set_pin_output_low(col_pins[col]); }
107
108static void unselect_col(uint8_t col) { gpio_atomic_set_pin_input_high(col_pins[col]); }
109
110static void unselect_cols(void) {
111 for (uint8_t x = 0; x < MATRIX_COLS; x++) {
112 gpio_atomic_set_pin_input_high(col_pins[x]);
113 }
114}
115
116static void init_pins(void) {
117 unselect_rows();
118 for (uint8_t x = 0; x < MATRIX_COLS; x++) {
119 gpio_atomic_set_pin_input_high(col_pins[x]);
120 }
121 unselect_cols();
122 for (uint8_t x = 0; x < ROWS_PER_HAND; x++) {
123 gpio_atomic_set_pin_input_high(row_pins[x]);
124 }
125}
126
127static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col) {
128 bool matrix_changed = false;
129
130 // Select col
131 select_col(current_col);
132 wait_us(30);
133
134 // For each row...
135 for (uint8_t row_index = 0; row_index < ROWS_PER_HAND; row_index++) {
136 // Store last value of row prior to reading
137 matrix_row_t last_row_value = current_matrix[row_index];
138 matrix_row_t current_row_value = last_row_value;
139
140 // Check row pin state
141 if (gpio_read_pin(row_pins[row_index]) == 0) {
142 // Pin LO, set col bit
143 current_row_value |= (MATRIX_ROW_SHIFTER << current_col);
144 } else {
145 // Pin HI, clear col bit
146 current_row_value &= ~(MATRIX_ROW_SHIFTER << current_col);
147 }
148
149 // Determine if the matrix changed state
150 if ((last_row_value != current_row_value)) {
151 matrix_changed |= true;
152 current_matrix[row_index] = current_row_value;
153 }
154 }
155
156 // Unselect col
157 unselect_col(current_col);
158 if (current_col + 1 < MATRIX_COLS) {
159 wait_us(30); // wait for col signal to go HIGH
160 }
161
162 return matrix_changed;
163}
164
165void matrix_init(void) {
166 split_pre_init();
167
168 // Set pinout for right half if pinout for that half is defined
169 if (!isLeftHand) {
170#ifdef DIRECT_PINS_RIGHT
171 const pin_t direct_pins_right[MATRIX_ROWS][MATRIX_COLS] = DIRECT_PINS_RIGHT;
172 for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
173 for (uint8_t j = 0; j < MATRIX_COLS; j++) {
174 direct_pins[i][j] = direct_pins_right[i][j];
175 }
176 }
177#endif
178#ifdef MATRIX_ROW_PINS_RIGHT
179 const pin_t row_pins_right[MATRIX_ROWS] = MATRIX_ROW_PINS_RIGHT;
180 for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
181 row_pins[i] = row_pins_right[i];
182 }
183#endif
184#ifdef MATRIX_COL_PINS_RIGHT
185 const pin_t col_pins_right[MATRIX_COLS] = MATRIX_COL_PINS_RIGHT;
186 for (uint8_t i = 0; i < MATRIX_COLS; i++) {
187 col_pins[i] = col_pins_right[i];
188 }
189#endif
190 }
191
192 thisHand = isLeftHand ? 0 : (ROWS_PER_HAND);
193 thatHand = ROWS_PER_HAND - thisHand;
194
195 // initialize key pins
196 init_pins();
197
198 // initialize matrix state: all keys off
199 for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
200 raw_matrix[i] = 0;
201 matrix[i] = 0;
202 }
203
204 debounce_init(ROWS_PER_HAND);
205
206 matrix_init_kb();
207
208 split_post_init();
209}
210
211bool matrix_post_scan(void) {
212 bool changed = false;
213 if (is_keyboard_master()) {
214 static uint8_t error_count;
215
216 matrix_row_t slave_matrix[ROWS_PER_HAND] = {0};
217 if (!transport_master(matrix + thisHand, slave_matrix)) {
218 error_count++;
219
220 if (error_count > ERROR_DISCONNECT_COUNT) {
221 // reset other half if disconnected
222 for (int i = 0; i < ROWS_PER_HAND; ++i) {
223 matrix[thatHand + i] = 0;
224 slave_matrix[i] = 0;
225 }
226
227 changed = true;
228 }
229 } else {
230 error_count = 0;
231
232 for (int i = 0; i < ROWS_PER_HAND; ++i) {
233 if (matrix[thatHand + i] != slave_matrix[i]) {
234 matrix[thatHand + i] = slave_matrix[i];
235 changed = true;
236 }
237 }
238 }
239
240 matrix_scan_kb();
241 } else {
242 transport_slave(matrix + thatHand, matrix + thisHand);
243
244 matrix_slave_scan_user();
245 }
246
247 return changed;
248}
249
250uint8_t matrix_scan(void) {
251 bool local_changed = false;
252 static matrix_row_t temp_raw_matrix[MATRIX_ROWS]; // temp raw values
253
254 // Set row, read cols
255 for (uint8_t current_row = 0; current_row < ROWS_PER_HAND/2; current_row++) {
256 local_changed |= read_cols_on_row(raw_matrix, current_row);
257 }
258
259 // Set col, read rows
260 for (uint8_t current_col = 0; current_col < MATRIX_COLS; current_col++) {
261 local_changed |= read_rows_on_col(temp_raw_matrix, current_col);
262 //Updated key matrix on lines 6-10 (or lines 16-20)
263 if(local_changed) {
264 for (uint8_t i = ROWS_PER_HAND/2; i < ROWS_PER_HAND; i++) {
265 raw_matrix[i] = temp_raw_matrix[i];
266 }
267 }
268 }
269
270 debounce(raw_matrix, matrix + thisHand, ROWS_PER_HAND, local_changed);
271
272 bool remote_changed = matrix_post_scan();
273 return (uint8_t)(local_changed || remote_changed);
274}