matrix.c (10422B)
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 <string.h> 20 #include "util.h" 21 #include "matrix.h" 22 #include "debounce.h" 23 #include "atomic_util.h" 24 25 #ifdef SPLIT_KEYBOARD 26 # include "split_common/split_util.h" 27 # include "split_common/transactions.h" 28 #endif 29 30 #ifdef DIRECT_PINS_RIGHT 31 # define SPLIT_MUTABLE 32 #else 33 # define SPLIT_MUTABLE const 34 #endif 35 #ifdef MATRIX_ROW_PINS_RIGHT 36 # define SPLIT_MUTABLE_ROW 37 #else 38 # define SPLIT_MUTABLE_ROW const 39 #endif 40 #ifdef MATRIX_COL_PINS_RIGHT 41 # define SPLIT_MUTABLE_COL 42 #else 43 # define SPLIT_MUTABLE_COL const 44 #endif 45 46 #ifndef MATRIX_INPUT_PRESSED_STATE 47 # define MATRIX_INPUT_PRESSED_STATE 0 48 #endif 49 50 #ifdef DIRECT_PINS 51 static SPLIT_MUTABLE pin_t direct_pins[MATRIX_ROWS_PER_HAND][MATRIX_COLS] = DIRECT_PINS; 52 #elif (DIODE_DIRECTION == ROW2COL) || (DIODE_DIRECTION == COL2ROW) 53 # ifdef MATRIX_ROW_PINS 54 static SPLIT_MUTABLE_ROW pin_t row_pins[MATRIX_ROWS_PER_HAND] = MATRIX_ROW_PINS; 55 # endif // MATRIX_ROW_PINS 56 # ifdef MATRIX_COL_PINS 57 static SPLIT_MUTABLE_COL pin_t col_pins[MATRIX_COLS] = MATRIX_COL_PINS; 58 # endif // MATRIX_COL_PINS 59 #endif 60 61 /* matrix state(1:on, 0:off) */ 62 extern matrix_row_t raw_matrix[MATRIX_ROWS]; // raw values 63 extern matrix_row_t matrix[MATRIX_ROWS]; // debounced values 64 65 #ifdef SPLIT_KEYBOARD 66 // row offsets for each hand 67 extern uint8_t thisHand, thatHand; 68 #endif 69 70 // user-defined overridable functions 71 __attribute__((weak)) void matrix_init_pins(void); 72 __attribute__((weak)) void matrix_read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row); 73 __attribute__((weak)) void matrix_read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col, matrix_row_t row_shifter); 74 75 static inline void gpio_atomic_set_pin_output_low(pin_t pin) { 76 ATOMIC_BLOCK_FORCEON { 77 gpio_set_pin_output(pin); 78 gpio_write_pin_low(pin); 79 } 80 } 81 82 static inline void gpio_atomic_set_pin_output_high(pin_t pin) { 83 ATOMIC_BLOCK_FORCEON { 84 gpio_set_pin_output(pin); 85 gpio_write_pin_high(pin); 86 } 87 } 88 89 static inline void gpio_atomic_set_pin_input_high(pin_t pin) { 90 ATOMIC_BLOCK_FORCEON { 91 gpio_set_pin_input_high(pin); 92 } 93 } 94 95 static inline uint8_t readMatrixPin(pin_t pin) { 96 if (pin != NO_PIN) { 97 return (gpio_read_pin(pin) == MATRIX_INPUT_PRESSED_STATE) ? 0 : 1; 98 } else { 99 return 1; 100 } 101 } 102 103 // matrix code 104 105 #ifdef DIRECT_PINS 106 107 __attribute__((weak)) void matrix_init_pins(void) { 108 for (int row = 0; row < MATRIX_ROWS_PER_HAND; row++) { 109 for (int col = 0; col < MATRIX_COLS; col++) { 110 pin_t pin = direct_pins[row][col]; 111 if (pin != NO_PIN) { 112 gpio_set_pin_input_high(pin); 113 } 114 } 115 } 116 } 117 118 __attribute__((weak)) void matrix_read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row) { 119 // Start with a clear matrix row 120 matrix_row_t current_row_value = 0; 121 122 matrix_row_t row_shifter = MATRIX_ROW_SHIFTER; 123 for (uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++, row_shifter <<= 1) { 124 pin_t pin = direct_pins[current_row][col_index]; 125 current_row_value |= readMatrixPin(pin) ? 0 : row_shifter; 126 } 127 128 // Update the matrix 129 current_matrix[current_row] = current_row_value; 130 } 131 132 #elif defined(DIODE_DIRECTION) 133 # if defined(MATRIX_ROW_PINS) && defined(MATRIX_COL_PINS) 134 # if (DIODE_DIRECTION == COL2ROW) 135 136 static bool select_row(uint8_t row) { 137 pin_t pin = row_pins[row]; 138 if (pin != NO_PIN) { 139 gpio_atomic_set_pin_output_low(pin); 140 return true; 141 } 142 return false; 143 } 144 145 static void unselect_row(uint8_t row) { 146 pin_t pin = row_pins[row]; 147 if (pin != NO_PIN) { 148 # ifdef MATRIX_UNSELECT_DRIVE_HIGH 149 gpio_atomic_set_pin_output_high(pin); 150 # else 151 gpio_atomic_set_pin_input_high(pin); 152 # endif 153 } 154 } 155 156 static void unselect_rows(void) { 157 for (uint8_t x = 0; x < MATRIX_ROWS_PER_HAND; x++) { 158 unselect_row(x); 159 } 160 } 161 162 __attribute__((weak)) void matrix_init_pins(void) { 163 unselect_rows(); 164 for (uint8_t x = 0; x < MATRIX_COLS; x++) { 165 if (col_pins[x] != NO_PIN) { 166 gpio_atomic_set_pin_input_high(col_pins[x]); 167 } 168 } 169 } 170 171 __attribute__((weak)) void matrix_read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row) { 172 // Start with a clear matrix row 173 matrix_row_t current_row_value = 0; 174 175 if (!select_row(current_row)) { // Select row 176 return; // skip NO_PIN row 177 } 178 matrix_output_select_delay(); 179 180 // For each col... 181 matrix_row_t row_shifter = MATRIX_ROW_SHIFTER; 182 for (uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++, row_shifter <<= 1) { 183 uint8_t pin_state = readMatrixPin(col_pins[col_index]); 184 185 // Populate the matrix row with the state of the col pin 186 current_row_value |= pin_state ? 0 : row_shifter; 187 } 188 189 // Unselect row 190 unselect_row(current_row); 191 matrix_output_unselect_delay(current_row, current_row_value != 0); // wait for all Col signals to go HIGH 192 193 // Update the matrix 194 current_matrix[current_row] = current_row_value; 195 } 196 197 # elif (DIODE_DIRECTION == ROW2COL) 198 199 static bool select_col(uint8_t col) { 200 pin_t pin = col_pins[col]; 201 if (pin != NO_PIN) { 202 gpio_atomic_set_pin_output_low(pin); 203 return true; 204 } 205 return false; 206 } 207 208 static void unselect_col(uint8_t col) { 209 pin_t pin = col_pins[col]; 210 if (pin != NO_PIN) { 211 # ifdef MATRIX_UNSELECT_DRIVE_HIGH 212 gpio_atomic_set_pin_output_high(pin); 213 # else 214 gpio_atomic_set_pin_input_high(pin); 215 # endif 216 } 217 } 218 219 static void unselect_cols(void) { 220 for (uint8_t x = 0; x < MATRIX_COLS; x++) { 221 unselect_col(x); 222 } 223 } 224 225 __attribute__((weak)) void matrix_init_pins(void) { 226 unselect_cols(); 227 for (uint8_t x = 0; x < MATRIX_ROWS_PER_HAND; x++) { 228 if (row_pins[x] != NO_PIN) { 229 gpio_atomic_set_pin_input_high(row_pins[x]); 230 } 231 } 232 } 233 234 __attribute__((weak)) void matrix_read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col, matrix_row_t row_shifter) { 235 bool key_pressed = false; 236 237 // Select col 238 if (!select_col(current_col)) { // select col 239 return; // skip NO_PIN col 240 } 241 matrix_output_select_delay(); 242 243 // For each row... 244 for (uint8_t row_index = 0; row_index < MATRIX_ROWS_PER_HAND; row_index++) { 245 // Check row pin state 246 if (readMatrixPin(row_pins[row_index]) == 0) { 247 // Pin LO, set col bit 248 current_matrix[row_index] |= row_shifter; 249 key_pressed = true; 250 } else { 251 // Pin HI, clear col bit 252 current_matrix[row_index] &= ~row_shifter; 253 } 254 } 255 256 // Unselect col 257 unselect_col(current_col); 258 matrix_output_unselect_delay(current_col, key_pressed); // wait for all Row signals to go HIGH 259 } 260 261 # else 262 # error DIODE_DIRECTION must be one of COL2ROW or ROW2COL! 263 # endif 264 # endif // defined(MATRIX_ROW_PINS) && defined(MATRIX_COL_PINS) 265 #else 266 # error DIODE_DIRECTION is not defined! 267 #endif 268 269 void matrix_init(void) { 270 #ifdef SPLIT_KEYBOARD 271 // Set pinout for right half if pinout for that half is defined 272 if (!isLeftHand) { 273 # ifdef DIRECT_PINS_RIGHT 274 const pin_t direct_pins_right[MATRIX_ROWS_PER_HAND][MATRIX_COLS] = DIRECT_PINS_RIGHT; 275 for (uint8_t i = 0; i < MATRIX_ROWS_PER_HAND; i++) { 276 for (uint8_t j = 0; j < MATRIX_COLS; j++) { 277 direct_pins[i][j] = direct_pins_right[i][j]; 278 } 279 } 280 # endif 281 # ifdef MATRIX_ROW_PINS_RIGHT 282 const pin_t row_pins_right[MATRIX_ROWS_PER_HAND] = MATRIX_ROW_PINS_RIGHT; 283 for (uint8_t i = 0; i < MATRIX_ROWS_PER_HAND; i++) { 284 row_pins[i] = row_pins_right[i]; 285 } 286 # endif 287 # ifdef MATRIX_COL_PINS_RIGHT 288 const pin_t col_pins_right[MATRIX_COLS] = MATRIX_COL_PINS_RIGHT; 289 for (uint8_t i = 0; i < MATRIX_COLS; i++) { 290 col_pins[i] = col_pins_right[i]; 291 } 292 # endif 293 } 294 295 thisHand = isLeftHand ? 0 : (MATRIX_ROWS_PER_HAND); 296 thatHand = MATRIX_ROWS_PER_HAND - thisHand; 297 #endif 298 299 // initialize key pins 300 matrix_init_pins(); 301 302 // initialize matrix state: all keys off 303 memset(matrix, 0, sizeof(matrix)); 304 memset(raw_matrix, 0, sizeof(raw_matrix)); 305 306 debounce_init(); 307 308 matrix_init_kb(); 309 } 310 311 #ifdef SPLIT_KEYBOARD 312 // Fallback implementation for keyboards not using the standard split_util.c 313 __attribute__((weak)) bool transport_master_if_connected(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) { 314 transport_master(master_matrix, slave_matrix); 315 return true; // Treat the transport as always connected 316 } 317 #endif 318 319 uint8_t matrix_scan(void) { 320 matrix_row_t curr_matrix[MATRIX_ROWS] = {0}; 321 322 #if defined(DIRECT_PINS) || (DIODE_DIRECTION == COL2ROW) 323 // Set row, read cols 324 for (uint8_t current_row = 0; current_row < MATRIX_ROWS_PER_HAND; current_row++) { 325 matrix_read_cols_on_row(curr_matrix, current_row); 326 } 327 #elif (DIODE_DIRECTION == ROW2COL) 328 // Set col, read rows 329 matrix_row_t row_shifter = MATRIX_ROW_SHIFTER; 330 for (uint8_t current_col = 0; current_col < MATRIX_COLS; current_col++, row_shifter <<= 1) { 331 matrix_read_rows_on_col(curr_matrix, current_col, row_shifter); 332 } 333 #endif 334 335 bool changed = memcmp(raw_matrix, curr_matrix, sizeof(curr_matrix)) != 0; 336 if (changed) memcpy(raw_matrix, curr_matrix, sizeof(curr_matrix)); 337 338 #ifdef SPLIT_KEYBOARD 339 changed = debounce(raw_matrix, matrix + thisHand, changed) | matrix_post_scan(); 340 #else 341 changed = debounce(raw_matrix, matrix, changed); 342 matrix_scan_kb(); 343 #endif 344 return (uint8_t)changed; 345 }