diff options
Diffstat (limited to 'keyboards/hhkb/yang/matrix.c')
-rw-r--r-- | keyboards/hhkb/yang/matrix.c | 173 |
1 files changed, 173 insertions, 0 deletions
diff --git a/keyboards/hhkb/yang/matrix.c b/keyboards/hhkb/yang/matrix.c new file mode 100644 index 0000000000..f0eccc899d --- /dev/null +++ b/keyboards/hhkb/yang/matrix.c @@ -0,0 +1,173 @@ +/* +Copyright 2011 Jun Wako <wakojun@gmail.com> +Copyright 2020 Kan-Ru Chen <kanru@kanru.info> + +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/>. +*/ + +#include "quantum.h" + +#ifdef BLUETOOTH_ENABLE +# include "adafruit_ble.h" +#endif + +#define RELAX_TIME_US 5 +#define ADC_READ_TIME_US 5 + +uint8_t power_save_level; + +static uint32_t matrix_last_modified = 0; + +static inline void key_strobe_high(void) { writePinLow(B6); } +static inline void key_strobe_low(void) { writePinHigh(B6); } +static inline bool key_state(void) { return readPin(D7); } +static inline void key_prev_on(void) { writePinHigh(B7); } +static inline void key_prev_off(void) { writePinLow(B7); } +static inline bool key_power_state(void) { return !readPin(D6); } + +static inline void suspend_power_down_longer(void) { + uint8_t times = 60; + while (--times) suspend_power_down(); +} + +void matrix_power_up(void) { + dprint("[matrix_on]\n"); + // change pins output + DDRB = 0xFF; + PORTB = 0x40; + // switch MOS FET on + setPinOutput(D6); + writePinLow(D6); +} + +void matrix_power_down(void) { + dprint("[matrix_off]\n"); + // input with pull-up consumes less than without it when pin is open + DDRB = 0x00; + PORTB = 0xFF; + // switch MOS FET off + setPinOutput(D6); + writePinHigh(D6); +} + +static inline void key_select_row(uint8_t row) { PORTB = (PORTB & 0b11111000) | ((row)&0b111); } +static inline void key_select_col(uint8_t col) { PORTB = (PORTB & 0b11000111) | (((col)&0b111) << 3); } +static inline bool key_prev_was_on(matrix_row_t matrix[], uint8_t row, uint8_t col) { return matrix[row] & (1 << col); } + +void matrix_init_custom(void) { power_save_level = 0; } + +bool matrix_scan_custom(matrix_row_t current_matrix[]) { + bool matrix_has_changed = false; + + // power on + if (!key_power_state()) { + matrix_power_up(); + } + for (uint8_t row = 0; row < MATRIX_ROWS; row++) { + matrix_row_t last_row_value = current_matrix[row]; + + key_select_row(row); + wait_us(RELAX_TIME_US); + + for (uint8_t col = 0; col < MATRIX_COLS; col++) { + // Hysteresis control: assert(1) when previous key state is on + if (key_prev_was_on(current_matrix, row, col)) { + key_prev_on(); + } else { + key_prev_off(); + } + + // Disable interrupts to encure the ADC timing is correct + cli(); + + // strobe + key_select_col(col); + key_strobe_high(); + + // Wait for ADC to outputs its value. + // 1us was ok on one HHKB, but not worked on another. + // no wait doesn't work on Teensy++ with pro(1us works) + // no wait does work on tmk PCB(8MHz) with pro2 + // 1us wait does work on both of above + // 1us wait doesn't work on tmk(16MHz) + // 5us wait does work on tmk(16MHz) + // 5us wait does work on tmk(16MHz/2) + // 5us wait does work on tmk(8MHz) + // 10us wait does work on Teensy++ with pro + // 10us wait does work on 328p+iwrap with pro + // 10us wait doesn't work on tmk PCB(8MHz) with pro2(very lagged scan) + wait_us(ADC_READ_TIME_US); + + if (key_state()) { + current_matrix[row] &= ~(1 << col); + } else { + current_matrix[row] |= (1 << col); + } + + key_strobe_low(); + sei(); + + // Make sure enough time has elapsed since the last call + // This is to ensure the matrix voltages have relaxed + wait_us(RELAX_TIME_US); + } + if (current_matrix[row] ^ last_row_value) { + matrix_has_changed = true; + matrix_last_modified = timer_read32(); + } + } + + // Power saving + uint32_t time_diff = timer_elapsed32(matrix_last_modified); + if (time_diff > MATRIX_POWER_SAVE_TIMEOUT_L3_MS) { + power_save_level = 3; + suspend_power_down_longer(); + } else if (time_diff > MATRIX_POWER_SAVE_TIMEOUT_L2_MS) { + power_save_level = 2; +#ifdef BLUETOOTH_ENABLE + if (!adafruit_ble_is_connected()) { + power_save_level = 3; + } +#endif + suspend_power_down_longer(); + } else if (time_diff > MATRIX_POWER_SAVE_TIMEOUT_MS) { + power_save_level = 1; + suspend_power_down(); + } else { + if (power_save_level != 0) { + power_save_level = 0; + suspend_wakeup_init(); + } + } + + return matrix_has_changed; +} + +bool adafruit_ble_delbonds(void); +bool adafruit_ble_reconnect(void); + +bool command_extra(uint8_t code) { + switch (code) { +#ifdef BLUETOOTH_ENABLE + case KC_R: + adafruit_ble_delbonds(); + return true; + case KC_S: + adafruit_ble_reconnect(); + return true; +#endif + default: + return false; + } +} |