summary refs log tree commit diff
path: root/quantum/matrix.c
diff options
context:
space:
mode:
authorNick Brassel <nick@tzarc.org>2021-08-29 08:20:25 +1000
committerNick Brassel <nick@tzarc.org>2021-08-29 08:20:25 +1000
commitf061ca497464fe85284906fb163a33eaee7a91ef (patch)
tree33ef1bfb529aed382e8526c607c4e18717f92571 /quantum/matrix.c
parentff65185dec6f97be1eb49f17cea526a0d0bbf3d6 (diff)
parent4bad375d7c09d949a9dcdd4feba147c9c7a67ec6 (diff)
Breaking changes develop merge to master, 2021Q3 edition. (#14196)
Diffstat (limited to 'quantum/matrix.c')
-rw-r--r--quantum/matrix.c277
1 files changed, 211 insertions, 66 deletions
diff --git a/quantum/matrix.c b/quantum/matrix.c
index 34d6af2e6d..33586c431b 100644
--- a/quantum/matrix.c
+++ b/quantum/matrix.c
@@ -16,22 +16,65 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 #include <stdint.h>
 #include <stdbool.h>
+#include <string.h>
 #include "util.h"
 #include "matrix.h"
 #include "debounce.h"
 #include "quantum.h"
+#ifdef SPLIT_KEYBOARD
+#    include "split_common/split_util.h"
+#    include "split_common/transactions.h"
+
+#    define ROWS_PER_HAND (MATRIX_ROWS / 2)
+#else
+#    define ROWS_PER_HAND (MATRIX_ROWS)
+#endif
+
+#ifdef DIRECT_PINS_RIGHT
+#    define SPLIT_MUTABLE
+#else
+#    define SPLIT_MUTABLE const
+#endif
+#ifdef MATRIX_ROW_PINS_RIGHT
+#    define SPLIT_MUTABLE_ROW
+#else
+#    define SPLIT_MUTABLE_ROW const
+#endif
+#ifdef MATRIX_COL_PINS_RIGHT
+#    define SPLIT_MUTABLE_COL
+#else
+#    define SPLIT_MUTABLE_COL const
+#endif
 
 #ifdef DIRECT_PINS
-static pin_t direct_pins[MATRIX_ROWS][MATRIX_COLS] = DIRECT_PINS;
+static SPLIT_MUTABLE pin_t direct_pins[MATRIX_ROWS][MATRIX_COLS] = DIRECT_PINS;
 #elif (DIODE_DIRECTION == ROW2COL) || (DIODE_DIRECTION == COL2ROW)
-static const pin_t row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS;
-static const pin_t col_pins[MATRIX_COLS] = MATRIX_COL_PINS;
+#    ifdef MATRIX_ROW_PINS
+static SPLIT_MUTABLE_ROW pin_t row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS;
+#    endif  // MATRIX_ROW_PINS
+#    ifdef MATRIX_COL_PINS
+static SPLIT_MUTABLE_COL pin_t col_pins[MATRIX_COLS] = MATRIX_COL_PINS;
+#    endif  // MATRIX_COL_PINS
 #endif
 
 /* matrix state(1:on, 0:off) */
 extern matrix_row_t raw_matrix[MATRIX_ROWS];  // raw values
 extern matrix_row_t matrix[MATRIX_ROWS];      // debounced values
 
+#ifdef SPLIT_KEYBOARD
+// row offsets for each hand
+uint8_t thisHand, thatHand;
+#endif
+
+// user-defined overridable functions
+__attribute__((weak)) void matrix_init_pins(void);
+__attribute__((weak)) void matrix_read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row);
+__attribute__((weak)) void matrix_read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col);
+#ifdef SPLIT_KEYBOARD
+__attribute__((weak)) void matrix_slave_scan_kb(void) { matrix_slave_scan_user(); }
+__attribute__((weak)) void matrix_slave_scan_user(void) {}
+#endif
+
 static inline void setPinOutput_writeLow(pin_t pin) {
     ATOMIC_BLOCK_FORCEON {
         setPinOutput(pin);
@@ -43,11 +86,19 @@ static inline void setPinInputHigh_atomic(pin_t pin) {
     ATOMIC_BLOCK_FORCEON { setPinInputHigh(pin); }
 }
 
+static inline uint8_t readMatrixPin(pin_t pin) {
+    if (pin != NO_PIN) {
+        return readPin(pin);
+    } else {
+        return 1;
+    }
+}
+
 // matrix code
 
 #ifdef DIRECT_PINS
 
-static void init_pins(void) {
+__attribute__((weak)) void matrix_init_pins(void) {
     for (int row = 0; row < MATRIX_ROWS; row++) {
         for (int col = 0; col < MATRIX_COLS; col++) {
             pin_t pin = direct_pins[row][col];
@@ -58,7 +109,7 @@ static void init_pins(void) {
     }
 }
 
-static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row) {
+__attribute__((weak)) void matrix_read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row) {
     // Start with a clear matrix row
     matrix_row_t current_row_value = 0;
 
@@ -69,46 +120,57 @@ static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row)
         }
     }
 
-    // If the row has changed, store the row and return the changed flag.
-    if (current_matrix[current_row] != current_row_value) {
-        current_matrix[current_row] = current_row_value;
-        return true;
-    }
-    return false;
+    // Update the matrix
+    current_matrix[current_row] = current_row_value;
 }
 
 #elif defined(DIODE_DIRECTION)
-#    if (DIODE_DIRECTION == COL2ROW)
+#    if defined(MATRIX_ROW_PINS) && defined(MATRIX_COL_PINS)
+#        if (DIODE_DIRECTION == COL2ROW)
 
-static void select_row(uint8_t row) { setPinOutput_writeLow(row_pins[row]); }
+static bool select_row(uint8_t row) {
+    pin_t pin = row_pins[row];
+    if (pin != NO_PIN) {
+        setPinOutput_writeLow(pin);
+        return true;
+    }
+    return false;
+}
 
-static void unselect_row(uint8_t row) { setPinInputHigh_atomic(row_pins[row]); }
+static void unselect_row(uint8_t row) {
+    pin_t pin = row_pins[row];
+    if (pin != NO_PIN) {
+        setPinInputHigh_atomic(pin);
+    }
+}
 
 static void unselect_rows(void) {
-    for (uint8_t x = 0; x < MATRIX_ROWS; x++) {
-        setPinInputHigh_atomic(row_pins[x]);
+    for (uint8_t x = 0; x < ROWS_PER_HAND; x++) {
+        unselect_row(x);
     }
 }
 
-static void init_pins(void) {
+__attribute__((weak)) void matrix_init_pins(void) {
     unselect_rows();
     for (uint8_t x = 0; x < MATRIX_COLS; x++) {
-        setPinInputHigh_atomic(col_pins[x]);
+        if (col_pins[x] != NO_PIN) {
+            setPinInputHigh_atomic(col_pins[x]);
+        }
     }
 }
 
-static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row) {
+__attribute__((weak)) void matrix_read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row) {
     // Start with a clear matrix row
     matrix_row_t current_row_value = 0;
 
-    // Select row
-    select_row(current_row);
+    if (!select_row(current_row)) {  // Select row
+        return;                      // skip NO_PIN row
+    }
     matrix_output_select_delay();
 
     // For each col...
     for (uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++) {
-        // Select the col pin to read (active low)
-        uint8_t pin_state = readPin(col_pins[col_index]);
+        uint8_t pin_state = readMatrixPin(col_pins[col_index]);
 
         // Populate the matrix row with the state of the col pin
         current_row_value |= pin_state ? 0 : (MATRIX_ROW_SHIFTER << col_index);
@@ -116,81 +178,114 @@ static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row)
 
     // Unselect row
     unselect_row(current_row);
-    matrix_output_unselect_delay();  // wait for all Col signals to go HIGH
+    matrix_output_unselect_delay(current_row, current_row_value != 0);  // wait for all Col signals to go HIGH
 
-    // If the row has changed, store the row and return the changed flag.
-    if (current_matrix[current_row] != current_row_value) {
-        current_matrix[current_row] = current_row_value;
+    // Update the matrix
+    current_matrix[current_row] = current_row_value;
+}
+
+#        elif (DIODE_DIRECTION == ROW2COL)
+
+static bool select_col(uint8_t col) {
+    pin_t pin = col_pins[col];
+    if (pin != NO_PIN) {
+        setPinOutput_writeLow(pin);
         return true;
     }
     return false;
 }
 
-#    elif (DIODE_DIRECTION == ROW2COL)
-
-static void select_col(uint8_t col) { setPinOutput_writeLow(col_pins[col]); }
-
-static void unselect_col(uint8_t col) { setPinInputHigh_atomic(col_pins[col]); }
+static void unselect_col(uint8_t col) {
+    pin_t pin = col_pins[col];
+    if (pin != NO_PIN) {
+        setPinInputHigh_atomic(pin);
+    }
+}
 
 static void unselect_cols(void) {
     for (uint8_t x = 0; x < MATRIX_COLS; x++) {
-        setPinInputHigh_atomic(col_pins[x]);
+        unselect_col(x);
     }
 }
 
-static void init_pins(void) {
+__attribute__((weak)) void matrix_init_pins(void) {
     unselect_cols();
-    for (uint8_t x = 0; x < MATRIX_ROWS; x++) {
-        setPinInputHigh_atomic(row_pins[x]);
+    for (uint8_t x = 0; x < ROWS_PER_HAND; x++) {
+        if (row_pins[x] != NO_PIN) {
+            setPinInputHigh_atomic(row_pins[x]);
+        }
     }
 }
 
-static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col) {
-    bool matrix_changed = false;
+__attribute__((weak)) void matrix_read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col) {
+    bool key_pressed = false;
 
     // Select col
-    select_col(current_col);
+    if (!select_col(current_col)) {  // select col
+        return;                      // skip NO_PIN col
+    }
     matrix_output_select_delay();
 
     // For each row...
-    for (uint8_t row_index = 0; row_index < MATRIX_ROWS; row_index++) {
-        // Store last value of row prior to reading
-        matrix_row_t last_row_value    = current_matrix[row_index];
-        matrix_row_t current_row_value = last_row_value;
-
+    for (uint8_t row_index = 0; row_index < ROWS_PER_HAND; row_index++) {
         // Check row pin state
-        if (readPin(row_pins[row_index]) == 0) {
+        if (readMatrixPin(row_pins[row_index]) == 0) {
             // Pin LO, set col bit
-            current_row_value |= (MATRIX_ROW_SHIFTER << current_col);
+            current_matrix[row_index] |= (MATRIX_ROW_SHIFTER << current_col);
+            key_pressed = true;
         } else {
             // Pin HI, clear col bit
-            current_row_value &= ~(MATRIX_ROW_SHIFTER << current_col);
-        }
-
-        // Determine if the matrix changed state
-        if ((last_row_value != current_row_value)) {
-            matrix_changed |= true;
-            current_matrix[row_index] = current_row_value;
+            current_matrix[row_index] &= ~(MATRIX_ROW_SHIFTER << current_col);
         }
     }
 
     // Unselect col
     unselect_col(current_col);
-    matrix_output_unselect_delay();  // wait for all Row signals to go HIGH
-
-    return matrix_changed;
+    matrix_output_unselect_delay(current_col, key_pressed);  // wait for all Row signals to go HIGH
 }
 
-#    else
-#        error DIODE_DIRECTION must be one of COL2ROW or ROW2COL!
-#    endif
+#        else
+#            error DIODE_DIRECTION must be one of COL2ROW or ROW2COL!
+#        endif
+#    endif  // defined(MATRIX_ROW_PINS) && defined(MATRIX_COL_PINS)
 #else
 #    error DIODE_DIRECTION is not defined!
 #endif
 
 void matrix_init(void) {
+#ifdef SPLIT_KEYBOARD
+    split_pre_init();
+
+    // Set pinout for right half if pinout for that half is defined
+    if (!isLeftHand) {
+#    ifdef DIRECT_PINS_RIGHT
+        const pin_t direct_pins_right[MATRIX_ROWS][MATRIX_COLS] = DIRECT_PINS_RIGHT;
+        for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
+            for (uint8_t j = 0; j < MATRIX_COLS; j++) {
+                direct_pins[i][j] = direct_pins_right[i][j];
+            }
+        }
+#    endif
+#    ifdef MATRIX_ROW_PINS_RIGHT
+        const pin_t row_pins_right[MATRIX_ROWS] = MATRIX_ROW_PINS_RIGHT;
+        for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
+            row_pins[i] = row_pins_right[i];
+        }
+#    endif
+#    ifdef MATRIX_COL_PINS_RIGHT
+        const pin_t col_pins_right[MATRIX_COLS] = MATRIX_COL_PINS_RIGHT;
+        for (uint8_t i = 0; i < MATRIX_COLS; i++) {
+            col_pins[i] = col_pins_right[i];
+        }
+#    endif
+    }
+
+    thisHand = isLeftHand ? 0 : (ROWS_PER_HAND);
+    thatHand = ROWS_PER_HAND - thisHand;
+#endif
+
     // initialize key pins
-    init_pins();
+    matrix_init_pins();
 
     // initialize matrix state: all keys off
     for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
@@ -198,28 +293,78 @@ void matrix_init(void) {
         matrix[i]     = 0;
     }
 
-    debounce_init(MATRIX_ROWS);
+    debounce_init(ROWS_PER_HAND);
 
     matrix_init_quantum();
+
+#ifdef SPLIT_KEYBOARD
+    split_post_init();
+#endif
 }
 
-uint8_t matrix_scan(void) {
+#ifdef SPLIT_KEYBOARD
+// Fallback implementation for keyboards not using the standard split_util.c
+__attribute__((weak)) bool transport_master_if_connected(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
+    transport_master(master_matrix, slave_matrix);
+    return true;  // Treat the transport as always connected
+}
+
+bool matrix_post_scan(void) {
     bool changed = false;
+    if (is_keyboard_master()) {
+        matrix_row_t slave_matrix[ROWS_PER_HAND] = {0};
+        if (transport_master_if_connected(matrix + thisHand, slave_matrix)) {
+            for (int i = 0; i < ROWS_PER_HAND; ++i) {
+                if (matrix[thatHand + i] != slave_matrix[i]) {
+                    matrix[thatHand + i] = slave_matrix[i];
+                    changed              = true;
+                }
+            }
+        } else {
+            // reset other half if disconnected
+            for (int i = 0; i < ROWS_PER_HAND; ++i) {
+                matrix[thatHand + i] = 0;
+                slave_matrix[i]      = 0;
+            }
+
+            changed = true;
+        }
+
+        matrix_scan_quantum();
+    } else {
+        transport_slave(matrix + thatHand, matrix + thisHand);
+
+        matrix_slave_scan_kb();
+    }
+
+    return changed;
+}
+#endif
+
+uint8_t matrix_scan(void) {
+    matrix_row_t curr_matrix[MATRIX_ROWS] = {0};
 
 #if defined(DIRECT_PINS) || (DIODE_DIRECTION == COL2ROW)
     // Set row, read cols
-    for (uint8_t current_row = 0; current_row < MATRIX_ROWS; current_row++) {
-        changed |= read_cols_on_row(raw_matrix, current_row);
+    for (uint8_t current_row = 0; current_row < ROWS_PER_HAND; current_row++) {
+        matrix_read_cols_on_row(curr_matrix, current_row);
     }
 #elif (DIODE_DIRECTION == ROW2COL)
     // Set col, read rows
     for (uint8_t current_col = 0; current_col < MATRIX_COLS; current_col++) {
-        changed |= read_rows_on_col(raw_matrix, current_col);
+        matrix_read_rows_on_col(curr_matrix, current_col);
     }
 #endif
 
-    debounce(raw_matrix, matrix, MATRIX_ROWS, changed);
+    bool changed = memcmp(raw_matrix, curr_matrix, sizeof(curr_matrix)) != 0;
+    if (changed) memcpy(raw_matrix, curr_matrix, sizeof(curr_matrix));
 
+#ifdef SPLIT_KEYBOARD
+    debounce(raw_matrix, matrix + thisHand, ROWS_PER_HAND, changed);
+    changed = (changed || matrix_post_scan());
+#else
+    debounce(raw_matrix, matrix, ROWS_PER_HAND, changed);
     matrix_scan_quantum();
+#endif
     return (uint8_t)changed;
 }