瀏覽代碼

Eager Per Row Debouncing added (added to Ergodox) (#5498)

* Implemented Eager Per Row debouncing algorithm.

Good for when fingers can only press one row at a time (e.g. when keyboard is wired so that "rows" are vertical)

* Added documentation for eager_pr

* Ported ergodox_ez to eager_pr debouncing.

* Removed check for changes in matrix_scan.

* Added further clarification in docs.

* Accidental merge with ergodox_ez

* Small cleanup in eager_pr

* Forgot to debounce_init - this would probably cause seg-faults.
Alex Ong 6 年之前
父節點
當前提交
17e7762de7
共有 5 個文件被更改,包括 302 次插入264 次删除
  1. 4 1
      docs/feature_debounce_type.md
  2. 196 262
      keyboards/ergodox_ez/matrix.c
  3. 1 0
      keyboards/ergodox_ez/rules.mk
  4. 100 0
      quantum/debounce/eager_pr.c
  5. 1 1
      quantum/debounce/readme.md

+ 4 - 1
docs/feature_debounce_type.md

@@ -33,7 +33,10 @@ The debounce code is compatible with split keyboards.
 # Changing between included debouncing methods
 # Changing between included debouncing methods
 You can either use your own code, by including your own debounce.c, or switch to another included one.
 You can either use your own code, by including your own debounce.c, or switch to another included one.
 Included debounce methods are:
 Included debounce methods are:
-* eager_pk - debouncing per key. On any state change, response is immediate, followed by ```DEBOUNCE_DELAY``` millseconds of no further input for that key
+* eager_pr - debouncing per row. On any state change, response is immediate, followed by locking the row ```DEBOUNCE_DELAY``` milliseconds of no further input for that row. 
+For use in keyboards where refreshing ```NUM_KEYS``` 8-bit counters is computationally expensive / low scan rate, and fingers usually only hit one row at a time. This could be
+appropriate for the ErgoDox models; the matrix is rotated 90°, and hence its "rows" are really columns, and each finger only hits a single "row" at a time in normal use.
+* eager_pk - debouncing per key. On any state change, response is immediate, followed by ```DEBOUNCE_DELAY``` milliseconds of no further input for that key
 * sym_g - debouncing per keyboard. On any state change, a global timer is set. When ```DEBOUNCE_DELAY``` milliseconds of no changes has occured, all input changes are pushed.
 * sym_g - debouncing per keyboard. On any state change, a global timer is set. When ```DEBOUNCE_DELAY``` milliseconds of no changes has occured, all input changes are pushed.
 
 
 
 

+ 196 - 262
keyboards/ergodox_ez/matrix.c

@@ -33,14 +33,14 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #include "debug.h"
 #include "debug.h"
 #include "util.h"
 #include "util.h"
 #include "matrix.h"
 #include "matrix.h"
+#include "debounce.h"
 #include QMK_KEYBOARD_H
 #include QMK_KEYBOARD_H
 #ifdef DEBUG_MATRIX_SCAN_RATE
 #ifdef DEBUG_MATRIX_SCAN_RATE
-#include  "timer.h"
+#  include "timer.h"
 #endif
 #endif
 
 
 /*
 /*
- * This constant define not debouncing time in msecs, but amount of matrix
- * scan loops which should be made to get stable debounced results.
+ * This constant define not debouncing time in msecs, assuming eager_pr.
  *
  *
  * On Ergodox matrix scan rate is relatively low, because of slow I2C.
  * On Ergodox matrix scan rate is relatively low, because of slow I2C.
  * Now it's only 317 scans/second, or about 3.15 msec/scan.
  * Now it's only 317 scans/second, or about 3.15 msec/scan.
@@ -52,26 +52,17 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
  */
 
 
 #ifndef DEBOUNCE
 #ifndef DEBOUNCE
-#   define DEBOUNCE	5
+#  define DEBOUNCE 5
 #endif
 #endif
 
 
 /* matrix state(1:on, 0:off) */
 /* matrix state(1:on, 0:off) */
-static matrix_row_t matrix[MATRIX_ROWS];
-/*
- * matrix state(1:on, 0:off)
- * contains the raw values without debounce filtering of the last read cycle.
- */
-static matrix_row_t raw_matrix[MATRIX_ROWS];
-
-// Debouncing: store for each key the number of scans until it's eligible to
-// change.  When scanning the matrix, ignore any changes in keys that have
-// already changed in the last DEBOUNCE scans.
-static uint8_t debounce_matrix[MATRIX_ROWS * MATRIX_COLS];
+static matrix_row_t raw_matrix[MATRIX_ROWS];  // raw values
+static matrix_row_t matrix[MATRIX_ROWS];      // debounced values
 
 
 static matrix_row_t read_cols(uint8_t row);
 static matrix_row_t read_cols(uint8_t row);
-static void init_cols(void);
-static void unselect_rows(void);
-static void select_row(uint8_t row);
+static void         init_cols(void);
+static void         unselect_rows(void);
+static void         select_row(uint8_t row);
 
 
 static uint8_t mcp23018_reset_loop;
 static uint8_t mcp23018_reset_loop;
 // static uint16_t mcp23018_reset_loop;
 // static uint16_t mcp23018_reset_loop;
@@ -81,197 +72,137 @@ uint32_t matrix_timer;
 uint32_t matrix_scan_count;
 uint32_t matrix_scan_count;
 #endif
 #endif
 
 
+__attribute__((weak)) void matrix_init_user(void) {}
 
 
-__attribute__ ((weak))
-void matrix_init_user(void) {}
+__attribute__((weak)) void matrix_scan_user(void) {}
 
 
-__attribute__ ((weak))
-void matrix_scan_user(void) {}
+__attribute__((weak)) void matrix_init_kb(void) { matrix_init_user(); }
 
 
-__attribute__ ((weak))
-void matrix_init_kb(void) {
-  matrix_init_user();
-}
+__attribute__((weak)) void matrix_scan_kb(void) { matrix_scan_user(); }
 
 
-__attribute__ ((weak))
-void matrix_scan_kb(void) {
-  matrix_scan_user();
-}
-
-inline
-uint8_t matrix_rows(void)
-{
-    return MATRIX_ROWS;
-}
+inline uint8_t matrix_rows(void) { return MATRIX_ROWS; }
 
 
-inline
-uint8_t matrix_cols(void)
-{
-    return MATRIX_COLS;
-}
+inline uint8_t matrix_cols(void) { return MATRIX_COLS; }
 
 
-void matrix_init(void)
-{
-    // initialize row and col
+void matrix_init(void) {
+  // initialize row and col
 
 
-    mcp23018_status = init_mcp23018();
+  mcp23018_status = init_mcp23018();
 
 
+  unselect_rows();
+  init_cols();
 
 
-    unselect_rows();
-    init_cols();
-
-    // initialize matrix state: all keys off
-    for (uint8_t i=0; i < MATRIX_ROWS; i++) {
-        matrix[i] = 0;
-        raw_matrix[i] = 0;
-        for (uint8_t j=0; j < MATRIX_COLS; ++j) {
-            debounce_matrix[i * MATRIX_COLS + j] = 0;
-        }
-    }
+  // initialize matrix state: all keys off
+  for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
+    matrix[i]     = 0;
+    raw_matrix[i] = 0;    
+  }
 
 
 #ifdef DEBUG_MATRIX_SCAN_RATE
 #ifdef DEBUG_MATRIX_SCAN_RATE
-    matrix_timer = timer_read32();
-    matrix_scan_count = 0;
+  matrix_timer      = timer_read32();
+  matrix_scan_count = 0;
 #endif
 #endif
-
-    matrix_init_quantum();
-
+  debounce_init(MATRIX_ROWS);
+  matrix_init_quantum();
 }
 }
 
 
 void matrix_power_up(void) {
 void matrix_power_up(void) {
-    mcp23018_status = init_mcp23018();
+  mcp23018_status = init_mcp23018();
 
 
-    unselect_rows();
-    init_cols();
+  unselect_rows();
+  init_cols();
 
 
-    // initialize matrix state: all keys off
-    for (uint8_t i=0; i < MATRIX_ROWS; i++) {
-        matrix[i] = 0;
-    }
+  // initialize matrix state: all keys off
+  for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
+    matrix[i] = 0;
+  }
 
 
 #ifdef DEBUG_MATRIX_SCAN_RATE
 #ifdef DEBUG_MATRIX_SCAN_RATE
-    matrix_timer = timer_read32();
-    matrix_scan_count = 0;
+  matrix_timer      = timer_read32();
+  matrix_scan_count = 0;
 #endif
 #endif
 }
 }
 
 
-// Returns a matrix_row_t whose bits are set if the corresponding key should be
-// eligible to change in this scan.
-matrix_row_t debounce_mask(matrix_row_t rawcols, uint8_t row) {
-  matrix_row_t result = 0;
-  matrix_row_t change = rawcols ^ raw_matrix[row];
-  raw_matrix[row] = rawcols;
-  for (uint8_t i = 0; i < MATRIX_COLS; ++i) {
-    if (debounce_matrix[row * MATRIX_COLS + i]) {
-      --debounce_matrix[row * MATRIX_COLS + i];
-    } else {
-      result |= (1 << i);
-    }
-    if (change & (1 << i)) {
-      debounce_matrix[row * MATRIX_COLS + i] = DEBOUNCE;
+uint8_t matrix_scan(void) {
+  if (mcp23018_status) {  // if there was an error
+    if (++mcp23018_reset_loop == 0) {
+      // if (++mcp23018_reset_loop >= 1300) {
+      // since mcp23018_reset_loop is 8 bit - we'll try to reset once in 255 matrix scans
+      // this will be approx bit more frequent than once per second
+      print("trying to reset mcp23018\n");
+      mcp23018_status = init_mcp23018();
+      if (mcp23018_status) {
+        print("left side not responding\n");
+      } else {
+        print("left side attached\n");
+        ergodox_blink_all_leds();
+      }
     }
     }
   }
   }
-  return result;
-}
-
-matrix_row_t debounce_read_cols(uint8_t row) {
-  // Read the row without debouncing filtering and store it for later usage.
-  matrix_row_t cols = read_cols(row);
-  // Get the Debounce mask.
-  matrix_row_t mask = debounce_mask(cols, row);
-  // debounce the row and return the result.
-  return (cols & mask) | (matrix[row] & ~mask);;
-}
-
-uint8_t matrix_scan(void)
-{
-    if (mcp23018_status) { // if there was an error
-        if (++mcp23018_reset_loop == 0) {
-        // if (++mcp23018_reset_loop >= 1300) {
-            // since mcp23018_reset_loop is 8 bit - we'll try to reset once in 255 matrix scans
-            // this will be approx bit more frequent than once per second
-            print("trying to reset mcp23018\n");
-            mcp23018_status = init_mcp23018();
-            if (mcp23018_status) {
-                print("left side not responding\n");
-            } else {
-                print("left side attached\n");
-                ergodox_blink_all_leds();
-            }
-        }
-    }
 
 
 #ifdef DEBUG_MATRIX_SCAN_RATE
 #ifdef DEBUG_MATRIX_SCAN_RATE
-    matrix_scan_count++;
+  matrix_scan_count++;
 
 
-    uint32_t timer_now = timer_read32();
-    if (TIMER_DIFF_32(timer_now, matrix_timer)>1000) {
-        print("matrix scan frequency: ");
-        pdec(matrix_scan_count);
-        print("\n");
+  uint32_t timer_now = timer_read32();
+  if (TIMER_DIFF_32(timer_now, matrix_timer) > 1000) {
+    print("matrix scan frequency: ");
+    pdec(matrix_scan_count);
+    print("\n");
 
 
-        matrix_timer = timer_now;
-        matrix_scan_count = 0;
-    }
+    matrix_timer      = timer_now;
+    matrix_scan_count = 0;
+  }
 #endif
 #endif
 
 
 #ifdef LEFT_LEDS
 #ifdef LEFT_LEDS
-    mcp23018_status = ergodox_left_leds_update();
-#endif // LEFT_LEDS
-    for (uint8_t i = 0; i < MATRIX_ROWS_PER_SIDE; i++) {
-        select_row(i);
-        // and select on left hand
-        select_row(i + MATRIX_ROWS_PER_SIDE);
-        // we don't need a 30us delay anymore, because selecting a
-        // left-hand row requires more than 30us for i2c.
-
-        // grab cols from left hand
-        matrix[i] = debounce_read_cols(i);
-        // grab cols from right hand
-        matrix[i + MATRIX_ROWS_PER_SIDE] = debounce_read_cols(i + MATRIX_ROWS_PER_SIDE);
-
-        unselect_rows();
-    }
-
-    matrix_scan_quantum();
+  mcp23018_status = ergodox_left_leds_update();
+#endif  // LEFT_LEDS
+  for (uint8_t i = 0; i < MATRIX_ROWS_PER_SIDE; i++) {
+    // select rows from left and right hands
+    select_row(i);
+    select_row(i + MATRIX_ROWS_PER_SIDE);
+
+    // we don't need a 30us delay anymore, because selecting a
+    // left-hand row requires more than 30us for i2c.
+
+    // grab left + right cols.
+    raw_matrix[i] = read_cols(i);    
+    raw_matrix[i+MATRIX_ROWS_PER_SIDE] = read_cols(i+MATRIX_ROWS_PER_SIDE);
+    
+    unselect_rows();
+  }
+  
+  debounce(raw_matrix, matrix, MATRIX_ROWS, true);
+  matrix_scan_quantum();
 
 
-    return 1;
+  return 1;
 }
 }
 
 
-bool matrix_is_modified(void) // deprecated and evidently not called.
+bool matrix_is_modified(void)  // deprecated and evidently not called.
 {
 {
-    return true;
+  return true;
 }
 }
 
 
-inline
-bool matrix_is_on(uint8_t row, uint8_t col)
-{
-    return (matrix[row] & ((matrix_row_t)1<<col));
-}
+inline bool matrix_is_on(uint8_t row, uint8_t col) { return (matrix[row] & ((matrix_row_t)1 << col)); }
 
 
-inline
-matrix_row_t matrix_get_row(uint8_t row)
-{
-    return matrix[row];
-}
+inline matrix_row_t matrix_get_row(uint8_t row) { return matrix[row]; }
 
 
-void matrix_print(void)
-{
-    print("\nr/c 0123456789ABCDEF\n");
-    for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
-        phex(row); print(": ");
-        pbin_reverse16(matrix_get_row(row));
-        print("\n");
-    }
+void matrix_print(void) {
+  print("\nr/c 0123456789ABCDEF\n");
+  for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
+    phex(row);
+    print(": ");
+    pbin_reverse16(matrix_get_row(row));
+    print("\n");
+  }
 }
 }
 
 
-uint8_t matrix_key_count(void)
-{
-    uint8_t count = 0;
-    for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
-        count += bitpop16(matrix[i]);
-    }
-    return count;
+uint8_t matrix_key_count(void) {
+  uint8_t count = 0;
+  for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
+    count += bitpop16(matrix[i]);
+  }
+  return count;
 }
 }
 
 
 /* Column pin configuration
 /* Column pin configuration
@@ -284,43 +215,45 @@ uint8_t matrix_key_count(void)
  * col: 0   1   2   3   4   5
  * col: 0   1   2   3   4   5
  * pin: B5  B4  B3  B2  B1  B0
  * pin: B5  B4  B3  B2  B1  B0
  */
  */
-static void  init_cols(void)
-{
-    // init on mcp23018
-    // not needed, already done as part of init_mcp23018()
-
-    // init on teensy
-    // Input with pull-up(DDR:0, PORT:1)
-    DDRF  &= ~(1<<7 | 1<<6 | 1<<5 | 1<<4 | 1<<1 | 1<<0);
-    PORTF |=  (1<<7 | 1<<6 | 1<<5 | 1<<4 | 1<<1 | 1<<0);
+static void init_cols(void) {
+  // init on mcp23018
+  // not needed, already done as part of init_mcp23018()
+
+  // init on teensy
+  // Input with pull-up(DDR:0, PORT:1)
+  DDRF &= ~(1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 1 | 1 << 0);
+  PORTF |= (1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 1 | 1 << 0);
 }
 }
 
 
-static matrix_row_t read_cols(uint8_t row)
-{
-    if (row < 7) {
-        if (mcp23018_status) { // if there was an error
-            return 0;
-        } else {
-            uint8_t data = 0;
-            mcp23018_status = i2c_start(I2C_ADDR_WRITE, ERGODOX_EZ_I2C_TIMEOUT);    if (mcp23018_status) goto out;
-            mcp23018_status = i2c_write(GPIOB, ERGODOX_EZ_I2C_TIMEOUT);             if (mcp23018_status) goto out;
-            mcp23018_status = i2c_start(I2C_ADDR_READ, ERGODOX_EZ_I2C_TIMEOUT);     if (mcp23018_status) goto out;
-            mcp23018_status = i2c_read_nack(ERGODOX_EZ_I2C_TIMEOUT);                if (mcp23018_status < 0) goto out;
-            data = ~((uint8_t)mcp23018_status);
-            mcp23018_status = I2C_STATUS_SUCCESS;
-        out:
-            i2c_stop();
-            return data;
-        }
+static matrix_row_t read_cols(uint8_t row) {
+  if (row < 7) {
+    if (mcp23018_status) {  // if there was an error
+      return 0;
     } else {
     } else {
-        /* read from teensy
-	 * bitmask is 0b11110011, but we want those all
-	 * in the lower six bits.
-	 * we'll return 1s for the top two, but that's harmless.
-	 */
-
-        return ~((PINF & 0x03) | ((PINF & 0xF0) >> 2));
+      uint8_t data    = 0;
+      mcp23018_status = i2c_start(I2C_ADDR_WRITE, ERGODOX_EZ_I2C_TIMEOUT);
+      if (mcp23018_status) goto out;
+      mcp23018_status = i2c_write(GPIOB, ERGODOX_EZ_I2C_TIMEOUT);
+      if (mcp23018_status) goto out;
+      mcp23018_status = i2c_start(I2C_ADDR_READ, ERGODOX_EZ_I2C_TIMEOUT);
+      if (mcp23018_status) goto out;
+      mcp23018_status = i2c_read_nack(ERGODOX_EZ_I2C_TIMEOUT);
+      if (mcp23018_status < 0) goto out;
+      data            = ~((uint8_t)mcp23018_status);
+      mcp23018_status = I2C_STATUS_SUCCESS;
+    out:
+      i2c_stop();
+      return data;
     }
     }
+  } else {
+    /* read from teensy
+     * bitmask is 0b11110011, but we want those all
+     * in the lower six bits.
+     * we'll return 1s for the top two, but that's harmless.
+     */
+
+    return ~((PINF & 0x03) | ((PINF & 0xF0) >> 2));
+  }
 }
 }
 
 
 /* Row pin configuration
 /* Row pin configuration
@@ -333,69 +266,70 @@ static matrix_row_t read_cols(uint8_t row)
  * row: 0   1   2   3   4   5   6
  * row: 0   1   2   3   4   5   6
  * pin: A0  A1  A2  A3  A4  A5  A6
  * pin: A0  A1  A2  A3  A4  A5  A6
  */
  */
-static void unselect_rows(void)
-{
-    // no need to unselect on mcp23018, because the select step sets all
-    // the other row bits high, and it's not changing to a different
-    // direction
-
-    // unselect on teensy
-    // Hi-Z(DDR:0, PORT:0) to unselect
-    DDRB  &= ~(1<<0 | 1<<1 | 1<<2 | 1<<3);
-    PORTB &= ~(1<<0 | 1<<1 | 1<<2 | 1<<3);
-    DDRD  &= ~(1<<2 | 1<<3);
-    PORTD &= ~(1<<2 | 1<<3);
-    DDRC  &= ~(1<<6);
-    PORTC &= ~(1<<6);
+static void unselect_rows(void) {
+  // no need to unselect on mcp23018, because the select step sets all
+  // the other row bits high, and it's not changing to a different
+  // direction
+
+  // unselect on teensy
+  // Hi-Z(DDR:0, PORT:0) to unselect
+  DDRB &= ~(1 << 0 | 1 << 1 | 1 << 2 | 1 << 3);
+  PORTB &= ~(1 << 0 | 1 << 1 | 1 << 2 | 1 << 3);
+  DDRD &= ~(1 << 2 | 1 << 3);
+  PORTD &= ~(1 << 2 | 1 << 3);
+  DDRC &= ~(1 << 6);
+  PORTC &= ~(1 << 6);
 }
 }
 
 
-static void select_row(uint8_t row)
-{
-    if (row < 7) {
-        // select on mcp23018
-        if (mcp23018_status) { // if there was an error
-            // do nothing
-        } else {
-            // set active row low  : 0
-            // set other rows hi-Z : 1
-            mcp23018_status = i2c_start(I2C_ADDR_WRITE, ERGODOX_EZ_I2C_TIMEOUT);        if (mcp23018_status) goto out;
-            mcp23018_status = i2c_write(GPIOA, ERGODOX_EZ_I2C_TIMEOUT);                 if (mcp23018_status) goto out;
-            mcp23018_status = i2c_write(0xFF & ~(1<<row), ERGODOX_EZ_I2C_TIMEOUT);      if (mcp23018_status) goto out;
-        out:
-            i2c_stop();
-        }
+static void select_row(uint8_t row) {
+  if (row < 7) {
+    // select on mcp23018
+    if (mcp23018_status) {  // if there was an error
+                            // do nothing
     } else {
     } else {
-        // select on teensy
-        // Output low(DDR:1, PORT:0) to select
-        switch (row) {
-            case 7:
-                DDRB  |= (1<<0);
-                PORTB &= ~(1<<0);
-                break;
-            case 8:
-                DDRB  |= (1<<1);
-                PORTB &= ~(1<<1);
-                break;
-            case 9:
-                DDRB  |= (1<<2);
-                PORTB &= ~(1<<2);
-                break;
-            case 10:
-                DDRB  |= (1<<3);
-                PORTB &= ~(1<<3);
-                break;
-            case 11:
-                DDRD  |= (1<<2);
-                PORTD &= ~(1<<2);
-                break;
-            case 12:
-                DDRD  |= (1<<3);
-                PORTD &= ~(1<<3);
-                break;
-            case 13:
-                DDRC  |= (1<<6);
-                PORTC &= ~(1<<6);
-                break;
-        }
+      // set active row low  : 0
+      // set other rows hi-Z : 1
+      mcp23018_status = i2c_start(I2C_ADDR_WRITE, ERGODOX_EZ_I2C_TIMEOUT);
+      if (mcp23018_status) goto out;
+      mcp23018_status = i2c_write(GPIOA, ERGODOX_EZ_I2C_TIMEOUT);
+      if (mcp23018_status) goto out;
+      mcp23018_status = i2c_write(0xFF & ~(1 << row), ERGODOX_EZ_I2C_TIMEOUT);
+      if (mcp23018_status) goto out;
+    out:
+      i2c_stop();
+    }
+  } else {
+    // select on teensy
+    // Output low(DDR:1, PORT:0) to select
+    switch (row) {
+      case 7:
+        DDRB |= (1 << 0);
+        PORTB &= ~(1 << 0);
+        break;
+      case 8:
+        DDRB |= (1 << 1);
+        PORTB &= ~(1 << 1);
+        break;
+      case 9:
+        DDRB |= (1 << 2);
+        PORTB &= ~(1 << 2);
+        break;
+      case 10:
+        DDRB |= (1 << 3);
+        PORTB &= ~(1 << 3);
+        break;
+      case 11:
+        DDRD |= (1 << 2);
+        PORTD &= ~(1 << 2);
+        break;
+      case 12:
+        DDRD |= (1 << 3);
+        PORTD &= ~(1 << 3);
+        break;
+      case 13:
+        DDRC |= (1 << 6);
+        PORTC &= ~(1 << 6);
+        break;
     }
     }
+  }
 }
 }

+ 1 - 0
keyboards/ergodox_ez/rules.mk

@@ -83,6 +83,7 @@ SLEEP_LED_ENABLE = no
 API_SYSEX_ENABLE = no
 API_SYSEX_ENABLE = no
 RGBLIGHT_ENABLE = yes
 RGBLIGHT_ENABLE = yes
 RGB_MATRIX_ENABLE = no # enable later
 RGB_MATRIX_ENABLE = no # enable later
+DEBOUNCE_TYPE = eager_pr
 
 
 ifeq ($(strip $(RGB_MATRIX_ENABLE)), no)
 ifeq ($(strip $(RGB_MATRIX_ENABLE)), no)
   SRC += i2c_master.c
   SRC += i2c_master.c

+ 100 - 0
quantum/debounce/eager_pr.c

@@ -0,0 +1,100 @@
+/*
+Copyright 2019 Alex Ong<the.onga@gmail.com>
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+Basic per-row algorithm. Uses an 8-bit counter per row.
+After pressing a key, it immediately changes state, and sets a counter.
+No further inputs are accepted until DEBOUNCE milliseconds have occurred.
+*/
+
+#include "matrix.h"
+#include "timer.h"
+#include "quantum.h"
+#include <stdlib.h>
+
+#ifndef DEBOUNCE
+  #define DEBOUNCE 5
+#endif
+
+
+#define debounce_counter_t uint8_t
+
+static debounce_counter_t *debounce_counters;
+
+#define DEBOUNCE_ELAPSED 251
+#define MAX_DEBOUNCE (DEBOUNCE_ELAPSED - 1)
+
+void update_debounce_counters(uint8_t num_rows, uint8_t current_time);
+void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, uint8_t current_time);
+
+//we use num_rows rather than MATRIX_ROWS to support split keyboards
+void debounce_init(uint8_t num_rows)
+{
+  debounce_counters = (debounce_counter_t*)malloc(num_rows*sizeof(debounce_counter_t));  
+  for (uint8_t r = 0; r < num_rows; r++)
+  {    
+    debounce_counters[r] = DEBOUNCE_ELAPSED;
+  }
+}
+
+void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed)
+{
+  uint8_t current_time = timer_read() % MAX_DEBOUNCE;
+  update_debounce_counters(num_rows, current_time);
+  transfer_matrix_values(raw, cooked, num_rows, current_time);
+}
+
+//If the current time is > debounce counter, set the counter to enable input.
+void update_debounce_counters(uint8_t num_rows, uint8_t current_time)
+{
+  debounce_counter_t *debounce_pointer = debounce_counters;
+  for (uint8_t row = 0; row < num_rows; row++)
+  {    
+    if (*debounce_pointer != DEBOUNCE_ELAPSED)
+    {
+      if (TIMER_DIFF(current_time, *debounce_pointer, MAX_DEBOUNCE) >= DEBOUNCE) {
+        *debounce_pointer = DEBOUNCE_ELAPSED;
+      }
+    }
+    debounce_pointer++;
+  }
+}
+
+// upload from raw_matrix to final matrix;
+void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, uint8_t current_time)
+{
+  debounce_counter_t *debounce_pointer = debounce_counters;
+  for (uint8_t row = 0; row < num_rows; row++)
+  {
+    matrix_row_t existing_row = cooked[row]; 
+    matrix_row_t raw_row = raw[row];
+    
+    //determine new value basd on debounce pointer + raw value
+    if (*debounce_pointer == DEBOUNCE_ELAPSED &&
+      (existing_row != raw_row))
+    {
+      *debounce_pointer = current_time;
+      existing_row = raw_row; 
+    }
+    cooked[row] = existing_row;
+    
+    debounce_pointer++;
+  }  
+}
+
+bool debounce_active(void)
+{
+  return true;
+}
+

+ 1 - 1
quantum/debounce/readme.md

@@ -22,7 +22,7 @@ Here are a few that could be implemented:
 sym_g.c
 sym_g.c
 sym_pk.c
 sym_pk.c
 sym_pr.c
 sym_pr.c
-sym_pr_cycles.c //currently used in ergo-dox
+sym_pr_cycles.c 
 eager_g.c
 eager_g.c
 eager_pk.c
 eager_pk.c
 eager_pr.c //could be used in ergo-dox!
 eager_pr.c //could be used in ergo-dox!