qmk_firmware

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

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 }