summaryrefslogtreecommitdiffstats
path: root/keyboards/hhkb/yang/matrix.c
diff options
context:
space:
mode:
Diffstat (limited to 'keyboards/hhkb/yang/matrix.c')
-rw-r--r--keyboards/hhkb/yang/matrix.c173
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;
+ }
+}