From ebcd5457460553e8069e1e3d1b4d6dbe0a14193c Mon Sep 17 00:00:00 2001 From: Tim Crawford Date: Tue, 31 Mar 2020 12:38:50 -0600 Subject: [PATCH 1/2] kbscan: Add function to read row from matrix --- src/board/system76/darp5/kbscan.c | 60 +++++++++++++++-------------- src/board/system76/galp3-c/kbscan.c | 42 +++++++++++--------- src/board/system76/lemp9/kbscan.c | 42 +++++++++++--------- 3 files changed, 78 insertions(+), 66 deletions(-) diff --git a/src/board/system76/darp5/kbscan.c b/src/board/system76/darp5/kbscan.c index 67302bf..5a8f785 100644 --- a/src/board/system76/darp5/kbscan.c +++ b/src/board/system76/darp5/kbscan.c @@ -31,6 +31,37 @@ void kbscan_init(void) { // Debounce time in milliseconds #define DEBOUNCE_DELAY 20 +static uint8_t kbscan_get_row(int i) { + // Set current line as output + if (i < 8) { + KSOLGOEN = 1 << i; + KSOHGOEN = 0; + GPCRC3 = GPIO_IN; + GPCRC5 = GPIO_IN; + } else if (i < 16) { + KSOLGOEN = 0; + KSOHGOEN = 1 << (i - 8); + GPCRC3 = GPIO_IN; + GPCRC5 = GPIO_IN; + } else if (i == 16) { + KSOLGOEN = 0; + KSOHGOEN = 0; + GPCRC3 = GPIO_OUT; + GPCRC5 = GPIO_IN; + } else if (i == 17) { + KSOLGOEN = 0; + KSOHGOEN = 0; + GPCRC3 = GPIO_IN; + GPCRC5 = GPIO_OUT; + } + GPDRC &= ~((1 << 3) | (1 << 5)); + + // TODO: figure out optimal delay + delay_ticks(10); + + return ~KSI; +} + bool kbscan_press(uint16_t key, bool pressed, uint8_t * layer) { if (pressed && (power_state == POWER_STATE_S3 || power_state == POWER_STATE_DS3)) { @@ -142,34 +173,7 @@ void kbscan_event(void) { int i; for (i = 0; i < KM_OUT; i++) { - // Set current line as output - if (i < 8) { - KSOLGOEN = 1 << i; - KSOHGOEN = 0; - GPCRC3 = GPIO_IN; - GPCRC5 = GPIO_IN; - } else if (i < 16) { - KSOLGOEN = 0; - KSOHGOEN = 1 << (i - 8); - GPCRC3 = GPIO_IN; - GPCRC5 = GPIO_IN; - } else if (i == 16) { - KSOLGOEN = 0; - KSOHGOEN = 0; - GPCRC3 = GPIO_OUT; - GPCRC5 = GPIO_IN; - } else if (i == 17) { - KSOLGOEN = 0; - KSOHGOEN = 0; - GPCRC3 = GPIO_IN; - GPCRC5 = GPIO_OUT; - } - GPDRC &= ~((1 << 3) | (1 << 5)); - - // TODO: figure out optimal delay - delay_ticks(10); - - uint8_t new = ~KSI; + uint8_t new = kbscan_get_row(i); uint8_t last = kbscan_last[i]; if (new != last) { // A key was pressed or released diff --git a/src/board/system76/galp3-c/kbscan.c b/src/board/system76/galp3-c/kbscan.c index 41a5ddb..17caecf 100644 --- a/src/board/system76/galp3-c/kbscan.c +++ b/src/board/system76/galp3-c/kbscan.c @@ -32,6 +32,28 @@ void kbscan_init(void) { // Debounce time in milliseconds #define DEBOUNCE_DELAY 20 +static uint8_t kbscan_get_row(int i) { + // Set current line as output + if (i < 8) { + KSOLGOEN = 1 << i; + KSOHGOEN = 0; + } else if (i < 16) { + KSOLGOEN = 0; + KSOHGOEN = 1 << (i - 8); + } else if (i == 16) { + KSOLGOEN = 0; + KSOHGOEN = 0; + } else if (i == 17) { + KSOLGOEN = 0; + KSOHGOEN = 0; + } + + // TODO: figure out optimal delay + delay_ticks(10); + + return ~KSI; +} + bool kbscan_press(uint16_t key, bool pressed, uint8_t * layer) { if (pressed && (power_state == POWER_STATE_S3 || power_state == POWER_STATE_DS3)) { @@ -150,25 +172,7 @@ void kbscan_event(void) { int i; for (i = 0; i < KM_OUT; i++) { - // Set current line as output - if (i < 8) { - KSOLGOEN = 1 << i; - KSOHGOEN = 0; - } else if (i < 16) { - KSOLGOEN = 0; - KSOHGOEN = 1 << (i - 8); - } else if (i == 16) { - KSOLGOEN = 0; - KSOHGOEN = 0; - } else if (i == 17) { - KSOLGOEN = 0; - KSOHGOEN = 0; - } - - // TODO: figure out optimal delay - delay_ticks(10); - - uint8_t new = ~KSI; + uint8_t new = kbscan_get_row(i); uint8_t last = kbscan_last[i]; if (new != last) { // A key was pressed or released diff --git a/src/board/system76/lemp9/kbscan.c b/src/board/system76/lemp9/kbscan.c index 41a5ddb..efccc78 100644 --- a/src/board/system76/lemp9/kbscan.c +++ b/src/board/system76/lemp9/kbscan.c @@ -32,6 +32,28 @@ void kbscan_init(void) { // Debounce time in milliseconds #define DEBOUNCE_DELAY 20 +static uint8_t kbscan_get_row(int i) { + // Set current line as output + if (i < 8) { + KSOLGOEN = 1 << i; + KSOHGOEN = 0; + } else if (i < 16) { + KSOLGOEN = 0; + KSOHGOEN = 1 << (i - 8); + } else if (i == 16) { + KSOLGOEN = 0; + KSOHGOEN = 0; + } else if (i == 17) { + KSOLGOEN = 0; + KSOHGOEN = 0; + } + + // TODO: figure out optimal delay + delay_ticks(10); + + return ~KSI; +} + bool kbscan_press(uint16_t key, bool pressed, uint8_t * layer) { if (pressed && (power_state == POWER_STATE_S3 || power_state == POWER_STATE_DS3)) { @@ -150,25 +172,7 @@ void kbscan_event(void) { int i; for (i = 0; i < KM_OUT; i++) { - // Set current line as output - if (i < 8) { - KSOLGOEN = 1 << i; - KSOHGOEN = 0; - } else if (i < 16) { - KSOLGOEN = 0; - KSOHGOEN = 1 << (i - 8); - } else if (i == 16) { - KSOLGOEN = 0; - KSOHGOEN = 0; - } else if (i == 17) { - KSOLGOEN = 0; - KSOHGOEN = 0; - } - - // TODO: figure out optimal delay - delay_ticks(10); - - uint8_t new = ~KSI; + uint8_t new = kbscan_get_row(i); uint8_t last = kbscan_last[i]; if (new != last) { // A key was pressed or released From 9bf09e211ccf28744d16400e79b9f637d7d5fb74 Mon Sep 17 00:00:00 2001 From: Tim Crawford Date: Tue, 31 Mar 2020 13:40:31 -0600 Subject: [PATCH 2/2] kbscan: Ignore key presses with ghost keys --- src/board/system76/darp5/kbscan.c | 40 +++++++++++++++++++++++++++++ src/board/system76/galp3-c/kbscan.c | 40 +++++++++++++++++++++++++++++ src/board/system76/lemp9/kbscan.c | 40 +++++++++++++++++++++++++++++ 3 files changed, 120 insertions(+) diff --git a/src/board/system76/darp5/kbscan.c b/src/board/system76/darp5/kbscan.c index 5a8f785..fb11c9a 100644 --- a/src/board/system76/darp5/kbscan.c +++ b/src/board/system76/darp5/kbscan.c @@ -62,6 +62,41 @@ static uint8_t kbscan_get_row(int i) { return ~KSI; } +static inline bool popcount_more_than_one(uint8_t rowdata) { + return rowdata & (rowdata - 1); +} + +static uint8_t kbscan_get_real_keys(int row, uint8_t rowdata) { + // Remove any "active" blanks from the matrix. + uint8_t realdata = 0; + for (uint8_t col = 0; col < KM_IN; col++) { + if (KEYMAP[0][row][col] && (rowdata & (1 << col))) { + realdata |= 1 << col; + } + } + + return realdata; +} + +static bool kbscan_has_ghost_in_row(int row, uint8_t rowdata) { + rowdata = kbscan_get_real_keys(row, rowdata); + + // No ghosts exist when less than 2 keys in the row are active. + if (!popcount_more_than_one(rowdata)) { + return false; + } + + // Check against other rows to see if more than one column matches. + for (int i = 0; i < KM_OUT; i++) { + uint8_t otherrow = kbscan_get_real_keys(i, kbscan_get_row(i)); + if (i != row && popcount_more_than_one(otherrow & rowdata)) { + return true; + } + } + + return false; +} + bool kbscan_press(uint16_t key, bool pressed, uint8_t * layer) { if (pressed && (power_state == POWER_STATE_S3 || power_state == POWER_STATE_DS3)) { @@ -176,6 +211,11 @@ void kbscan_event(void) { uint8_t new = kbscan_get_row(i); uint8_t last = kbscan_last[i]; if (new != last) { + if (kbscan_has_ghost_in_row(i, new)) { + kbscan_last[i] = new; + continue; + } + // A key was pressed or released int j; for (j = 0; j < KM_IN; j++) { diff --git a/src/board/system76/galp3-c/kbscan.c b/src/board/system76/galp3-c/kbscan.c index 17caecf..048796e 100644 --- a/src/board/system76/galp3-c/kbscan.c +++ b/src/board/system76/galp3-c/kbscan.c @@ -54,6 +54,41 @@ static uint8_t kbscan_get_row(int i) { return ~KSI; } +static inline bool popcount_more_than_one(uint8_t rowdata) { + return rowdata & (rowdata - 1); +} + +static uint8_t kbscan_get_real_keys(int row, uint8_t rowdata) { + // Remove any "active" blanks from the matrix. + uint8_t realdata = 0; + for (uint8_t col = 0; col < KM_IN; col++) { + if (KEYMAP[0][row][col] && (rowdata & (1 << col))) { + realdata |= 1 << col; + } + } + + return realdata; +} + +static bool kbscan_has_ghost_in_row(int row, uint8_t rowdata) { + rowdata = kbscan_get_real_keys(row, rowdata); + + // No ghosts exist when less than 2 keys in the row are active. + if (!popcount_more_than_one(rowdata)) { + return false; + } + + // Check against other rows to see if more than one column matches. + for (int i = 0; i < KM_OUT; i++) { + uint8_t otherrow = kbscan_get_real_keys(i, kbscan_get_row(i)); + if (i != row && popcount_more_than_one(otherrow & rowdata)) { + return true; + } + } + + return false; +} + bool kbscan_press(uint16_t key, bool pressed, uint8_t * layer) { if (pressed && (power_state == POWER_STATE_S3 || power_state == POWER_STATE_DS3)) { @@ -175,6 +210,11 @@ void kbscan_event(void) { uint8_t new = kbscan_get_row(i); uint8_t last = kbscan_last[i]; if (new != last) { + if (kbscan_has_ghost_in_row(i, new)) { + kbscan_last[i] = new; + continue; + } + // A key was pressed or released int j; for (j = 0; j < KM_IN; j++) { diff --git a/src/board/system76/lemp9/kbscan.c b/src/board/system76/lemp9/kbscan.c index efccc78..a148aa0 100644 --- a/src/board/system76/lemp9/kbscan.c +++ b/src/board/system76/lemp9/kbscan.c @@ -54,6 +54,41 @@ static uint8_t kbscan_get_row(int i) { return ~KSI; } +static inline bool popcount_more_than_one(uint8_t rowdata) { + return rowdata & (rowdata - 1); +} + +static uint8_t kbscan_get_real_keys(int row, uint8_t rowdata) { + // Remove any "active" blanks from the matrix. + uint8_t realdata = 0; + for (uint8_t col = 0; col < KM_IN; col++) { + if (KEYMAP[0][row][col] && (rowdata & (1 << col))) { + realdata |= 1 << col; + } + } + + return realdata; +} + +static bool kbscan_has_ghost_in_row(int row, uint8_t rowdata) { + rowdata = kbscan_get_real_keys(row, rowdata); + + // No ghosts exist when less than 2 keys in the row are active. + if (!popcount_more_than_one(rowdata)) { + return false; + } + + // Check against other rows to see if more than one column matches. + for (int i = 0; i < KM_OUT; i++) { + uint8_t otherrow = kbscan_get_real_keys(i, kbscan_get_row(i)); + if (i != row && popcount_more_than_one(otherrow & rowdata)) { + return true; + } + } + + return false; +} + bool kbscan_press(uint16_t key, bool pressed, uint8_t * layer) { if (pressed && (power_state == POWER_STATE_S3 || power_state == POWER_STATE_DS3)) { @@ -175,6 +210,11 @@ void kbscan_event(void) { uint8_t new = kbscan_get_row(i); uint8_t last = kbscan_last[i]; if (new != last) { + if (kbscan_has_ghost_in_row(i, new)) { + kbscan_last[i] = new; + continue; + } + // A key was pressed or released int j; for (j = 0; j < KM_IN; j++) {