qmk_firmware

QMK firmware for my keyboards (Corne, Sweep Ferris) and trackball (Ploopy Adept)
Log | Files | Refs | Submodules | LICENSE

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 }