matrix.c (7076B)
1 /* 2 Copyright 2021 mtei 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 // clang-format off 18 #ifndef readPort 19 # include "gpio_extr.h" 20 #endif 21 #include "atomic_util.h" 22 #include "util.h" 23 #include "matrix.h" 24 #include "matrix_extr.h" 25 #include "debounce.h" 26 27 #define ALWAYS_INLINE inline __attribute__((always_inline)) 28 #define NO_INLINE __attribute__((noinline)) 29 #define LOCAL_FUNC static 30 #define LOCAL_DATA static 31 32 #ifndef _BV 33 # define _BV(bit) (1 << (bit)) 34 #endif 35 36 #ifndef MATRIX_DEBUG_PIN 37 # define MATRIX_DEBUG_PIN_INIT() 38 # define MATRIX_DEBUG_SCAN_START() 39 # define MATRIX_DEBUG_SCAN_END() 40 # define MATRIX_DEBUG_DELAY_START() 41 # define MATRIX_DEBUG_DELAY_END() 42 # define MATRIX_DEBUG_GAP() 43 #else 44 # define MATRIX_DEBUG_GAP() asm volatile("nop \n nop":::"memory") 45 #endif 46 47 typedef uint16_t port_width_t; 48 #if MATRIX_TYPE == DIRECT_SWITCH || MATRIX_TYPE == DIODE_COL2ROW 49 # define MATRIX_LINES MATRIX_ROWS 50 typedef matrix_row_t matrix_line_t; 51 #endif 52 #if MATRIX_TYPE == DIODE_ROW2COL 53 # define MATRIX_LINES MATRIX_COLS 54 typedef matrix_col_t matrix_line_t; 55 #endif 56 typedef struct _port_descriptor { 57 int device; 58 pin_t port; 59 } port_descriptor; 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 #define setPortBitOutput_writeLow(port, bit) \ 66 do { setPortBitOutput(port, bit); writePortBitLow(port, bit); } while(0) 67 #define setPortBitOutput_writeLow_atomic(port, bit) \ 68 do { ATOMIC_BLOCK_FORCEON { setPortBitOutput_writeLow(port, bit); } } while(0) 69 #define setPortBitInputHigh_atomic(port, bit) \ 70 do { ATOMIC_BLOCK_FORCEON { setPortBitInputHigh(port, bit); } } while(0) 71 72 #if defined(MATRIX_IN_PORTS) && defined(MATRIX_IN_PINS) 73 # include "matrix_config_expand.c" 74 #else 75 # error matrix.c need defined MATRIX_IN_PORTS and MATRIX_IN_PINS 76 #endif 77 78 LOCAL_FUNC 79 void unselect_output(uint8_t out_index) { 80 unselect_output_inline(out_index); 81 } 82 83 LOCAL_FUNC 84 void init_output_ports(void) { 85 for (int i = 0; i < END_outpin_index; i++) { 86 unselect_output(i); 87 } 88 } 89 90 LOCAL_FUNC 91 void init_all_ports(void) { 92 init_input_ports(); 93 init_output_ports(); 94 init_inport_mask(); 95 init_extension(); 96 } 97 98 LOCAL_FUNC ALWAYS_INLINE void select_line_and_read_input_ports(uint8_t current_line, port_width_t port_buffer[NUM_OF_INPUT_PORTS]); 99 LOCAL_FUNC void select_line_and_read_input_ports(uint8_t current_line, port_width_t port_buffer[NUM_OF_INPUT_PORTS]) { 100 // Select row (or col) 101 select_output(current_line); 102 matrix_output_select_delay(); 103 104 // Read ports 105 read_all_input_ports(port_buffer, false); 106 107 // Unselect row (or col) 108 unselect_output_inline(current_line); 109 } 110 111 LOCAL_FUNC ALWAYS_INLINE void read_matrix_line(matrix_line_t phy_matrix[], uint8_t current_line); 112 113 #if MATRIX_TYPE == DIODE_ROW2COL || MATRIX_TYPE == DIODE_COL2ROW 114 LOCAL_FUNC void read_matrix_line(matrix_line_t phy_matrix[], uint8_t current_line) { 115 // Start with a clear matrix row 116 matrix_line_t current_line_value = 0; 117 port_width_t port_buffer[NUM_OF_INPUT_PORTS]; 118 119 #ifdef MATRIX_GPIO_NEED_SEPARATE_ATOMIC 120 select_line_and_read_input_ports(current_line, port_buffer); 121 #else 122 ATOMIC_BLOCK_FORCEON { 123 select_line_and_read_input_ports(current_line, port_buffer); 124 } 125 #endif 126 127 // Build row (or col) 128 current_line_value = build_matrix_line(port_buffer); 129 130 // Wait signal raise up 131 if (current_line_value) { 132 MATRIX_DEBUG_DELAY_START(); 133 wait_unselect_done(); 134 MATRIX_DEBUG_DELAY_END(); 135 } 136 phy_matrix[current_line] = current_line_value; 137 } 138 #endif // MATRIX_TYPE == DIODE_ROW2COL || MATRIX_TYPE == DIODE_COL2ROW 139 140 #if MATRIX_TYPE == DIRECT_SWITCH 141 LOCAL_FUNC void read_matrix_line(matrix_line_t phy_matrix[], uint8_t current_line) { 142 port_width_t port_buffer[NUM_OF_INPUT_PORTS]; 143 144 if (current_line != 0) { 145 return; 146 } 147 148 for (uint8_t i = 0; i < MATRIX_LINES; i++) { 149 phy_matrix[i] = 0; 150 } 151 152 read_all_input_ports(port_buffer, false); 153 154 // Build matrix 155 build_matrix_direct(port_buffer, phy_matrix); 156 } 157 #endif // MATRIX_TYPE == DIRECT_SWITCH 158 159 void matrix_init(void) { 160 // initialize key pins 161 init_all_ports(); 162 163 // initialize matrix state: all keys off 164 for (uint8_t i = 0; i < MATRIX_ROWS; i++) { 165 raw_matrix[i] = 0; 166 matrix[i] = 0; 167 } 168 169 debounce_init(); 170 171 matrix_init_kb(); 172 } 173 174 uint8_t matrix_scan(void) { 175 matrix_line_t phy_matrix[MATRIX_LINES]; 176 177 MATRIX_DEBUG_PIN_INIT(); 178 179 MATRIX_DEBUG_SCAN_START(); 180 181 // read I/O port to phy_matrix[] (physical matrix) 182 //select line, read inputs 183 for (uint8_t current_line = 0; current_line < MATRIX_LINES; current_line++) { 184 read_matrix_line(phy_matrix, current_line); 185 } 186 MATRIX_DEBUG_SCAN_END(); MATRIX_DEBUG_GAP(); MATRIX_DEBUG_SCAN_START(); 187 188 bool changed = false; 189 #if MATRIX_TYPE == DIRECT_SWITCH || MATRIX_TYPE == DIODE_COL2ROW 190 // copy phy_matrix[] to raw_matrix[] 191 for (uint8_t current_line = 0; current_line < MATRIX_ROWS; current_line++) { 192 if (raw_matrix[current_line] != phy_matrix[current_line]) { 193 changed = true; 194 raw_matrix[current_line] = phy_matrix[current_line]; 195 } 196 } 197 #endif 198 #if MATRIX_TYPE == DIODE_ROW2COL 199 // transpose phy_matrix[] to raw_matrix[] 200 matrix_row_t trans_matrix[MATRIX_ROWS]; 201 for (uint8_t i = 0; i < MATRIX_ROWS; i++ ) { 202 trans_matrix[i] = 0; 203 } 204 for (uint8_t src_line = 0; src_line < MATRIX_LINES; src_line++) { 205 matrix_line_t src_line_data = phy_matrix[src_line]; 206 matrix_row_t dist_bit = MATRIX_ROW_SHIFTER << src_line; 207 for (uint8_t dist_rows = 0; dist_rows < MATRIX_ROWS; dist_rows++) { 208 if ((src_line_data & 1) == 1) { 209 trans_matrix[dist_rows] |= dist_bit; 210 } 211 src_line_data >>= 1; 212 } 213 } 214 for (uint8_t current_row = 0; current_row < MATRIX_ROWS; current_row++) { 215 if (raw_matrix[current_row] != trans_matrix[current_row]) { 216 changed = true; 217 raw_matrix[current_row] = trans_matrix[current_row]; 218 } 219 } 220 #endif 221 MATRIX_DEBUG_SCAN_END(); MATRIX_DEBUG_GAP(); MATRIX_DEBUG_SCAN_START(); 222 223 // debounce raw_matrix[] to matrix[] 224 debounce(raw_matrix, matrix, changed); 225 MATRIX_DEBUG_SCAN_END(); MATRIX_DEBUG_GAP(); 226 227 MATRIX_DEBUG_SCAN_START(); 228 matrix_scan_kb(); 229 MATRIX_DEBUG_SCAN_END(); 230 return (uint8_t)changed; 231 }