matrix.c (8340B)
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 #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 28 static pin_t row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS; 29 static pin_t col_pins[MATRIX_COLS] = MATRIX_COL_PINS; 30 31 /* matrix state(1:on, 0:off) */ 32 static matrix_row_t raw_matrix[MATRIX_ROWS]; // raw values 33 static matrix_row_t matrix[MATRIX_ROWS]; // debounced values 34 35 // row offsets for each hand 36 uint8_t thisHand, thatHand; 37 38 // user-defined overridable functions 39 __attribute__((weak)) void matrix_init_kb(void) { 40 matrix_init_user(); 41 } 42 43 __attribute__((weak)) void matrix_scan_kb(void) { 44 matrix_scan_user(); 45 } 46 47 __attribute__((weak)) void matrix_init_user(void) {} 48 49 __attribute__((weak)) void matrix_scan_user(void) {} 50 51 __attribute__((weak)) void matrix_slave_scan_user(void) {} 52 53 matrix_row_t matrix_get_row(uint8_t row) { 54 return matrix[row]; 55 } 56 57 void matrix_print(void) {} 58 59 static inline void gpio_atomic_set_pin_output_low(pin_t pin) { 60 ATOMIC_BLOCK_FORCEON { 61 gpio_set_pin_output(pin); 62 gpio_write_pin_low(pin); 63 } 64 } 65 66 static inline void gpio_atomic_set_pin_input_high(pin_t pin) { 67 ATOMIC_BLOCK_FORCEON { 68 gpio_set_pin_input_high(pin); 69 } 70 } 71 72 // matrix code 73 static void select_row(uint8_t row) { 74 gpio_atomic_set_pin_output_low(row_pins[row]); 75 } 76 77 static void unselect_row(uint8_t row) { 78 gpio_atomic_set_pin_input_high(row_pins[row]); 79 } 80 81 static void unselect_rows(void) { 82 for (uint8_t x = 0; x < ROWS_PER_HAND; x++) { 83 gpio_atomic_set_pin_input_high(row_pins[x]); 84 } 85 } 86 87 static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row) { 88 // Start with a clear matrix row 89 matrix_row_t current_row_value = 0; 90 91 // Select row 92 select_row(current_row); 93 wait_us(30); 94 95 // For each col... 96 for (uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++) { 97 // Select the col pin to read (active low) 98 uint8_t pin_state = gpio_read_pin(col_pins[col_index]); 99 100 // Populate the matrix row with the state of the col pin 101 current_row_value |= pin_state ? 0 : (MATRIX_ROW_SHIFTER << col_index); 102 } 103 104 // Unselect row 105 unselect_row(current_row); 106 if (current_row + 1 < MATRIX_ROWS) { 107 wait_us(30); // wait for row signal to go HIGH 108 } 109 110 // If the row has changed, store the row and return the changed flag. 111 if (current_matrix[current_row] != current_row_value) { 112 current_matrix[current_row] = current_row_value; 113 return true; 114 } 115 return false; 116 } 117 118 static void select_col(uint8_t col) { 119 gpio_atomic_set_pin_output_low(col_pins[col]); 120 } 121 122 static void unselect_col(uint8_t col) { 123 gpio_atomic_set_pin_input_high(col_pins[col]); 124 } 125 126 static void unselect_cols(void) { 127 for (uint8_t x = 0; x < MATRIX_COLS; x++) { 128 gpio_atomic_set_pin_input_high(col_pins[x]); 129 } 130 } 131 132 static void init_pins(void) { 133 unselect_rows(); 134 for (uint8_t x = 0; x < MATRIX_COLS; x++) { 135 gpio_atomic_set_pin_input_high(col_pins[x]); 136 } 137 unselect_cols(); 138 for (uint8_t x = 0; x < ROWS_PER_HAND; x++) { 139 gpio_atomic_set_pin_input_high(row_pins[x]); 140 } 141 } 142 143 static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col) { 144 bool matrix_changed = false; 145 146 // Select col 147 select_col(current_col); 148 wait_us(30); 149 150 // For each row... 151 for (uint8_t row_index = 0; row_index < ROWS_PER_HAND; row_index++) { 152 // Store last value of row prior to reading 153 matrix_row_t last_row_value = current_matrix[row_index]; 154 matrix_row_t current_row_value = last_row_value; 155 156 // Check row pin state 157 if (gpio_read_pin(row_pins[row_index]) == 0) { 158 // Pin LO, set col bit 159 current_row_value |= (MATRIX_ROW_SHIFTER << current_col); 160 } else { 161 // Pin HI, clear col bit 162 current_row_value &= ~(MATRIX_ROW_SHIFTER << current_col); 163 } 164 165 // Determine if the matrix changed state 166 if ((last_row_value != current_row_value)) { 167 matrix_changed |= true; 168 current_matrix[row_index] = current_row_value; 169 } 170 } 171 172 // Unselect col 173 unselect_col(current_col); 174 if (current_col + 1 < MATRIX_COLS) { 175 wait_us(30); // wait for col signal to go HIGH 176 } 177 178 return matrix_changed; 179 } 180 181 void matrix_init(void) { 182 split_pre_init(); 183 184 // Set pinout for right half if pinout for that half is defined 185 if (!isLeftHand) { 186 #ifdef DIRECT_PINS_RIGHT 187 const pin_t direct_pins_right[MATRIX_ROWS][MATRIX_COLS] = DIRECT_PINS_RIGHT; 188 for (uint8_t i = 0; i < MATRIX_ROWS; i++) { 189 for (uint8_t j = 0; j < MATRIX_COLS; j++) { 190 direct_pins[i][j] = direct_pins_right[i][j]; 191 } 192 } 193 #endif 194 #ifdef MATRIX_ROW_PINS_RIGHT 195 const pin_t row_pins_right[MATRIX_ROWS] = MATRIX_ROW_PINS_RIGHT; 196 for (uint8_t i = 0; i < MATRIX_ROWS; i++) { 197 row_pins[i] = row_pins_right[i]; 198 } 199 #endif 200 #ifdef MATRIX_COL_PINS_RIGHT 201 const pin_t col_pins_right[MATRIX_COLS] = MATRIX_COL_PINS_RIGHT; 202 for (uint8_t i = 0; i < MATRIX_COLS; i++) { 203 col_pins[i] = col_pins_right[i]; 204 } 205 #endif 206 } 207 208 thisHand = isLeftHand ? 0 : (ROWS_PER_HAND); 209 thatHand = ROWS_PER_HAND - thisHand; 210 211 // initialize key pins 212 init_pins(); 213 214 // initialize matrix state: all keys off 215 for (uint8_t i = 0; i < MATRIX_ROWS; i++) { 216 raw_matrix[i] = 0; 217 matrix[i] = 0; 218 } 219 220 debounce_init(); 221 222 matrix_init_kb(); 223 224 split_post_init(); 225 } 226 227 bool matrix_post_scan(void) { 228 bool changed = false; 229 if (is_keyboard_master()) { 230 static uint8_t error_count; 231 232 matrix_row_t slave_matrix[ROWS_PER_HAND] = {0}; 233 if (!transport_master(matrix + thisHand, slave_matrix)) { 234 error_count++; 235 236 if (error_count > ERROR_DISCONNECT_COUNT) { 237 // reset other half if disconnected 238 for (int i = 0; i < ROWS_PER_HAND; ++i) { 239 matrix[thatHand + i] = 0; 240 slave_matrix[i] = 0; 241 } 242 243 changed = true; 244 } 245 } else { 246 error_count = 0; 247 248 for (int i = 0; i < ROWS_PER_HAND; ++i) { 249 if (matrix[thatHand + i] != slave_matrix[i]) { 250 matrix[thatHand + i] = slave_matrix[i]; 251 changed = true; 252 } 253 } 254 } 255 256 matrix_scan_kb(); 257 } else { 258 transport_slave(matrix + thatHand, matrix + thisHand); 259 260 matrix_slave_scan_user(); 261 } 262 263 return changed; 264 } 265 266 uint8_t matrix_scan(void) { 267 bool local_changed = false; 268 static matrix_row_t temp_raw_matrix[MATRIX_ROWS]; // temp raw values 269 270 // Set row, read cols 271 for (uint8_t current_row = 0; current_row < ROWS_PER_HAND / 2; current_row++) { 272 local_changed |= read_cols_on_row(raw_matrix, current_row); 273 } 274 275 // Set col, read rows 276 for (uint8_t current_col = 0; current_col < MATRIX_COLS; current_col++) { 277 local_changed |= read_rows_on_col(temp_raw_matrix, current_col); 278 // Updated key matrix on lines 6-10 (or lines 16-20) 279 if (local_changed) { 280 for (uint8_t i = ROWS_PER_HAND / 2; i < ROWS_PER_HAND; i++) { 281 raw_matrix[i] = temp_raw_matrix[i]; 282 } 283 } 284 } 285 286 debounce(raw_matrix, matrix + thisHand, local_changed); 287 288 bool remote_changed = matrix_post_scan(); 289 return (uint8_t)(local_changed || remote_changed); 290 }