diff --git a/common_features.mk b/common_features.mk index 572a6db54..8c3361732 100644 --- a/common_features.mk +++ b/common_features.mk @@ -254,20 +254,34 @@ QUANTUM_SRC:= \ $(QUANTUM_DIR)/keymap_common.c \ $(QUANTUM_DIR)/keycode_config.c -ifeq ($(strip $(SPLIT_KEYBOARD)), yes) - ifneq ($(strip $(CUSTOM_MATRIX)), yes) - QUANTUM_SRC += $(QUANTUM_DIR)/split_common/matrix.c - # Do not use $(QUANTUM_DIR)/matrix.c. - CUSTOM_MATRIX=yes +# Include the standard or split matrix code if needed +ifneq ($(strip $(CUSTOM_MATRIX)), yes) + ifeq ($(strip $(SPLIT_KEYBOARD)), yes) + QUANTUM_SRC += $(QUANTUM_DIR)/split_common/matrix.c + else + QUANTUM_SRC += $(QUANTUM_DIR)/matrix.c endif - OPT_DEFS += -DSPLIT_KEYBOARD - QUANTUM_SRC += $(QUANTUM_DIR)/split_common/split_flags.c \ - $(QUANTUM_DIR)/split_common/split_util.c - QUANTUM_LIB_SRC += $(QUANTUM_DIR)/split_common/i2c.c - QUANTUM_LIB_SRC += $(QUANTUM_DIR)/split_common/serial.c - COMMON_VPATH += $(QUANTUM_PATH)/split_common endif -ifneq ($(strip $(CUSTOM_MATRIX)), yes) - QUANTUM_SRC += $(QUANTUM_DIR)/matrix.c +# Include the standard debounce code if needed +ifneq ($(strip $(CUSTOM_DEBOUNCE)), yes) + QUANTUM_SRC += $(QUANTUM_DIR)/debounce.c +endif + +ifeq ($(strip $(SPLIT_KEYBOARD)), yes) + OPT_DEFS += -DSPLIT_KEYBOARD + + # Include files used by all split keyboards + QUANTUM_SRC += $(QUANTUM_DIR)/split_common/split_flags.c \ + $(QUANTUM_DIR)/split_common/split_util.c + + # Determine which (if any) transport files are required + ifneq ($(strip $(SPLIT_TRANSPORT)), custom) + QUANTUM_SRC += $(QUANTUM_DIR)/split_common/transport.c + # Functions added via QUANTUM_LIB_SRC are only included in the final binary if they're called. + # Unused functions are pruned away, which is why we can add both drivers here without bloat. + QUANTUM_LIB_SRC += $(QUANTUM_DIR)/split_common/i2c.c \ + $(QUANTUM_DIR)/split_common/serial.c + endif + COMMON_VPATH += $(QUANTUM_PATH)/split_common endif diff --git a/docs/config_options.md b/docs/config_options.md index 63bcc41d0..f5c2e76e7 100644 --- a/docs/config_options.md +++ b/docs/config_options.md @@ -143,7 +143,7 @@ If you define these options you will enable the associated feature, which may in * Breaks any Tap Toggle functionality (`TT` or the One Shot Tap Toggle) * `#define LEADER_TIMEOUT 300` * how long before the leader key times out - * If you're having issues finishing the sequence before it times out, you may need to increase the timeout setting. Or you may want to enable the `LEADER_PER_KEY_TIMING` option, which resets the timeout after each key is tapped. + * If you're having issues finishing the sequence before it times out, you may need to increase the timeout setting. Or you may want to enable the `LEADER_PER_KEY_TIMING` option, which resets the timeout after each key is tapped. * `#define LEADER_PER_KEY_TIMING` * sets the timer for leader key chords to run on each key press rather than overall * `#define LEADER_KEY_STRICT_KEY_PROCESSING` @@ -197,6 +197,9 @@ If you define these options you will enable the associated feature, which may in Split Keyboard specific options, make sure you have 'SPLIT_KEYBOARD = yes' in your rules.mk +* `SPLIT_TRANSPORT = custom` + * Allows replacing the standard split communication routines with a custom one. ARM based split keyboards must use this at present. + ### Setting Handedness One thing to remember, the side that the USB port is plugged into is always the master half. The side not plugged into USB is the slave. @@ -208,7 +211,7 @@ There are a few different ways to set handedness for split keyboards (listed in 3. Set `MASTER_RIGHT`: Half that is plugged into the USB port is determined to be the master and right half (inverse of the default) 4. Default: The side that is plugged into the USB port is the master half and is assumed to be the left half. The slave side is the right half -* `#define SPLIT_HAND_PIN B7` +* `#define SPLIT_HAND_PIN B7` * For using high/low pin to determine handedness, low = right hand, high = left hand. Replace `B7` with the pin you are using. This is optional, and if you leave `SPLIT_HAND_PIN` undefined, then you can still use the EE_HANDS method or MASTER_LEFT / MASTER_RIGHT defines like the stock Let's Split uses. * `#define EE_HANDS` (only works if `SPLIT_HAND_PIN` is not defined) @@ -302,6 +305,10 @@ Use these to enable or disable building certain features. The more you have enab * Current options are AdafruitEzKey, AdafruitBLE, RN42 * `SPLIT_KEYBOARD` * Enables split keyboard support (dual MCU like the let's split and bakingpy's boards) and includes all necessary files located at quantum/split_common +* `CUSTOM_MATRIX` + * Allows replacing the standard matrix scanning routine with a custom one. +* `CUSTOM_DEBOUNCE` + * Allows replacing the standard key debouncing routine with a custom one. * `WAIT_FOR_USB` * Forces the keyboard to wait for a USB connection to be established before it starts up * `NO_USB_STARTUP_CHECK` diff --git a/docs/getting_started_make_guide.md b/docs/getting_started_make_guide.md index adc1aed75..bb7e1e7e3 100644 --- a/docs/getting_started_make_guide.md +++ b/docs/getting_started_make_guide.md @@ -97,7 +97,7 @@ This allows you to send Unicode characters using `UC()` in your keym `UNICODEMAP_ENABLE` -This allows you to send Unicode characters using `X()` in your keymap. You will need to maintain a mapping table in your keymap file. All possible code points (up to `0x10FFFF`) are supported. +This allows you to send Unicode characters using `X()` in your keymap. You will need to maintain a mapping table in your keymap file. All possible code points (up to `0x10FFFF`) are supported. `UCIS_ENABLE` @@ -135,6 +135,18 @@ This enables [key lock](feature_key_lock.md). This consumes an additional 260 by This enables split keyboard support (dual MCU like the let's split and bakingpy's boards) and includes all necessary files located at quantum/split_common +`SPLIT_TRANSPORT` + +As there is no standard split communication driver for ARM-based split keyboards yet, `SPLIT_TRANSPORT = custom` must be used for these. It will prevent the standard split keyboard communication code (which is AVR-specific) from being included, allowing a custom implementation to be used. + +`CUSTOM_MATRIX` + +Lets you replace the default matrix scanning routine with your own code. You will need to provide your own implementations of matrix_init() and matrix_scan(). + +`CUSTOM_DEBOUNCE` + +Lets you replace the default key debouncing routine with your own code. You will need to provide your own implementation of debounce(). + ## Customizing Makefile Options on a Per-Keymap Basis If your keymap directory has a file called `rules.mk` any options you set in that file will take precedence over other `rules.mk` options for your particular keyboard. diff --git a/keyboards/handwired/xealous/debounce.c b/keyboards/handwired/xealous/debounce.c new file mode 100644 index 000000000..65a99f27f --- /dev/null +++ b/keyboards/handwired/xealous/debounce.c @@ -0,0 +1,63 @@ +#include +#include "config.h" +#include "matrix.h" +#include "timer.h" +#include "quantum.h" + +#ifndef DEBOUNCING_DELAY +# define DEBOUNCING_DELAY 5 +#endif + +//Debouncing counters +typedef uint8_t debounce_counter_t; +#define DEBOUNCE_COUNTER_MODULO 250 +#define DEBOUNCE_COUNTER_INACTIVE 251 + +static debounce_counter_t *debounce_counters; + +void debounce_init(uint8_t num_rows) +{ + debounce_counters = malloc(num_rows*MATRIX_COLS); + memset(debounce_counters, DEBOUNCE_COUNTER_INACTIVE, num_rows*MATRIX_COLS); +} + +void update_debounce_counters(uint8_t num_rows, uint8_t current_time) +{ + for (uint8_t row = 0; row < num_rows; row++) + { + for (uint8_t col = 0; col < MATRIX_COLS; col++) + { + if (debounce_counters[row*MATRIX_COLS + col] != DEBOUNCE_COUNTER_INACTIVE) + { + if (TIMER_DIFF(current_time, debounce_counters[row*MATRIX_COLS + col], DEBOUNCE_COUNTER_MODULO) >= DEBOUNCING_DELAY) { + debounce_counters[row*MATRIX_COLS + col] = DEBOUNCE_COUNTER_INACTIVE; + } + } + } + } +} + +void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, uint8_t current_time) +{ + for (uint8_t row = 0; row < num_rows; row++) + { + matrix_row_t delta = raw[row] ^ cooked[row]; + + for (uint8_t col = 0; col < MATRIX_COLS; col++) + { + if (debounce_counters[row*MATRIX_COLS + col] == DEBOUNCE_COUNTER_INACTIVE && (delta & (1<. //#define NO_ACTION_ONESHOT //#define NO_ACTION_MACRO //#define NO_ACTION_FUNCTION + +#ifdef USE_Link_Time_Optimization + // LTO has issues with macros (action_get_macro) and "functions" (fn_actions), + // so just disable them + #define NO_ACTION_MACRO + #define NO_ACTION_FUNCTION + + #define DISABLE_LEADER +#endif // USE_Link_Time_Optimization \ No newline at end of file diff --git a/keyboards/lets_split/sockets/rules.mk b/keyboards/lets_split/sockets/rules.mk index e14d18d8d..da04decf4 100644 --- a/keyboards/lets_split/sockets/rules.mk +++ b/keyboards/lets_split/sockets/rules.mk @@ -1,3 +1,5 @@ BACKLIGHT_ENABLE = no AUDIO_ENABLE = yes RGBLIGHT_ENABLE = yes #Don't enable this along with I2C + +EXTRAFLAGS += -flto -DUSE_Link_Time_Optimization diff --git a/keyboards/miniaxe/config.h b/keyboards/miniaxe/config.h index 2b732ca16..7a68476a5 100644 --- a/keyboards/miniaxe/config.h +++ b/keyboards/miniaxe/config.h @@ -44,8 +44,7 @@ along with this program. If not, see . */ // #define MATRIX_ROW_PINS { D0, D5 } // #define MATRIX_COL_PINS { F1, F0, B0 } -#define NO_PIN 0xFF -#define MATRIX_ROW_COL_PINS { \ +#define DIRECT_PINS { \ { F1, E6, B0, B2, B3 }, \ { F5, F0, B1, B7, D2 }, \ { F6, F7, C7, D5, D3 }, \ @@ -54,7 +53,7 @@ along with this program. If not, see . #define UNUSED_PINS /* COL2ROW, ROW2COL, or CUSTOM_MATRIX */ -#define DIODE_DIRECTION CUSTOM_MATRIX +//#define DIODE_DIRECTION CUSTOM_MATRIX // #define BACKLIGHT_PIN B7 // #define BACKLIGHT_BREATHING diff --git a/keyboards/miniaxe/matrix.c b/keyboards/miniaxe/matrix.c deleted file mode 100644 index 5fec1281d..000000000 --- a/keyboards/miniaxe/matrix.c +++ /dev/null @@ -1,641 +0,0 @@ -/* -Copyright 2012 Jun Wako - -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 . -*/ - -/* - * scan matrix - */ -#include -#include -#include -#include "wait.h" -#include "print.h" -#include "debug.h" -#include "util.h" -#include "matrix.h" -#include "split_util.h" -#include "pro_micro.h" -#include "config.h" -#include "timer.h" -#include "split_flags.h" - -#ifdef BACKLIGHT_ENABLE -# include "backlight.h" - extern backlight_config_t backlight_config; -#endif - -#if defined(USE_I2C) || defined(EH) -# include "i2c.h" -#else // USE_SERIAL -# include "serial.h" -#endif - -#ifndef DEBOUNCING_DELAY -# define DEBOUNCING_DELAY 5 -#endif - -#if (DEBOUNCING_DELAY > 0) - static uint16_t debouncing_time; - static bool debouncing = false; -#endif - -#if defined(USE_I2C) || defined(EH) - -#if (MATRIX_COLS <= 8) -# define print_matrix_header() print("\nr/c 01234567\n") -# define print_matrix_row(row) print_bin_reverse8(matrix_get_row(row)) -# define matrix_bitpop(i) bitpop(matrix[i]) -# define ROW_SHIFTER ((uint8_t)1) -#else -# error "Currently only supports 8 COLS" -#endif - -#else // USE_SERIAL - -#if (MATRIX_COLS <= 8) -# define print_matrix_header() print("\nr/c 01234567\n") -# define print_matrix_row(row) print_bin_reverse8(matrix_get_row(row)) -# define matrix_bitpop(i) bitpop(matrix[i]) -# define ROW_SHIFTER ((uint8_t)1) -#elif (MATRIX_COLS <= 16) -# define print_matrix_header() print("\nr/c 0123456789ABCDEF\n") -# define print_matrix_row(row) print_bin_reverse16(matrix_get_row(row)) -# define matrix_bitpop(i) bitpop16(matrix[i]) -# define ROW_SHIFTER ((uint16_t)1) -#elif (MATRIX_COLS <= 32) -# define print_matrix_header() print("\nr/c 0123456789ABCDEF0123456789ABCDEF\n") -# define print_matrix_row(row) print_bin_reverse32(matrix_get_row(row)) -# define matrix_bitpop(i) bitpop32(matrix[i]) -# define ROW_SHIFTER ((uint32_t)1) -#endif - -#endif -static matrix_row_t matrix_debouncing[MATRIX_ROWS]; - -#define ERROR_DISCONNECT_COUNT 5 - -#define ROWS_PER_HAND (MATRIX_ROWS/2) - -static uint8_t error_count = 0; - -#if ((DIODE_DIRECTION == COL2ROW) || (DIODE_DIRECTION == ROW2COL)) -static uint8_t row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS; -static uint8_t col_pins[MATRIX_COLS] = MATRIX_COL_PINS; -#elif (DIODE_DIRECTION == CUSTOM_MATRIX) -static uint8_t row_col_pins[MATRIX_ROWS][MATRIX_COLS] = MATRIX_ROW_COL_PINS; -#endif - -/* matrix state(1:on, 0:off) */ -static matrix_row_t matrix[MATRIX_ROWS]; -static matrix_row_t matrix_debouncing[MATRIX_ROWS]; - -#if (DIODE_DIRECTION == COL2ROW) - static void init_cols(void); - static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row); - static void unselect_rows(void); - static void select_row(uint8_t row); - static void unselect_row(uint8_t row); -#elif (DIODE_DIRECTION == ROW2COL) - static void init_rows(void); - static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col); - static void unselect_cols(void); - static void unselect_col(uint8_t col); - static void select_col(uint8_t col); -#elif (DIODE_DIRECTION == CUSTOM_MATRIX) - static void init_cols_rows(void); - static bool read_cols(matrix_row_t current_matrix[], uint8_t current_row); -#endif - -__attribute__ ((weak)) -void matrix_init_kb(void) { - matrix_init_user(); -} - -__attribute__ ((weak)) -void matrix_scan_kb(void) { - matrix_scan_user(); -} - -__attribute__ ((weak)) -void matrix_init_user(void) { -} - -__attribute__ ((weak)) -void matrix_scan_user(void) { -} - -__attribute__ ((weak)) -void matrix_slave_scan_user(void) { -} - -inline -uint8_t matrix_rows(void) -{ - return MATRIX_ROWS; -} - -inline -uint8_t matrix_cols(void) -{ - return MATRIX_COLS; -} - -void matrix_init(void) -{ -#ifdef DISABLE_JTAG - // JTAG disable for PORT F. write JTD bit twice within four cycles. - MCUCR |= (1< 0) - bool matrix_changed = read_cols_on_row(matrix_debouncing+offset, current_row); - - if (matrix_changed) { - debouncing = true; - debouncing_time = timer_read(); - } - -# else - read_cols_on_row(matrix+offset, current_row); -# endif - - } - -#elif (DIODE_DIRECTION == ROW2COL) - // Set col, read rows - for (uint8_t current_col = 0; current_col < MATRIX_COLS; current_col++) { -# if (DEBOUNCING_DELAY > 0) - bool matrix_changed = read_rows_on_col(matrix_debouncing+offset, current_col); - if (matrix_changed) { - debouncing = true; - debouncing_time = timer_read(); - } -# else - read_rows_on_col(matrix+offset, current_col); -# endif - - } - -#elif (DIODE_DIRECTION == CUSTOM_MATRIX) - // Set row, read cols - for (uint8_t current_row = 0; current_row < ROWS_PER_HAND; current_row++) { -# if (DEBOUNCING_DELAY > 0) - bool matrix_changed = read_cols(matrix_debouncing+offset, current_row); - if (matrix_changed) { - debouncing = true; - debouncing_time = timer_read(); - } -# else - read_cols(matrix+offset, current_row); -# endif - } -#endif - -# if (DEBOUNCING_DELAY > 0) - if (debouncing && (timer_elapsed(debouncing_time) > DEBOUNCING_DELAY)) { - for (uint8_t i = 0; i < ROWS_PER_HAND; i++) { - matrix[i+offset] = matrix_debouncing[i+offset]; - } - debouncing = false; - } -# endif - - return 1; -} - -#if defined(USE_I2C) || defined(EH) - -// Get rows from other half over i2c -int i2c_transaction(void) { - int slaveOffset = (isLeftHand) ? (ROWS_PER_HAND) : 0; - int err = 0; - - // write backlight info - #ifdef BACKLIGHT_ENABLE - if (BACKLIT_DIRTY) { - err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_WRITE); - if (err) goto i2c_error; - - // Backlight location - err = i2c_master_write(I2C_BACKLIT_START); - if (err) goto i2c_error; - - // Write backlight - i2c_master_write(get_backlight_level()); - - BACKLIT_DIRTY = false; - } - #endif - - err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_WRITE); - if (err) goto i2c_error; - - // start of matrix stored at I2C_KEYMAP_START - err = i2c_master_write(I2C_KEYMAP_START); - if (err) goto i2c_error; - - // Start read - err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_READ); - if (err) goto i2c_error; - - if (!err) { - int i; - for (i = 0; i < ROWS_PER_HAND-1; ++i) { - matrix[slaveOffset+i] = i2c_master_read(I2C_ACK); - } - matrix[slaveOffset+i] = i2c_master_read(I2C_NACK); - i2c_master_stop(); - } else { -i2c_error: // the cable is disconnceted, or something else went wrong - i2c_reset_state(); - return err; - } - - #ifdef RGBLIGHT_ENABLE - if (RGB_DIRTY) { - err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_WRITE); - if (err) goto i2c_error; - - // RGB Location - err = i2c_master_write(I2C_RGB_START); - if (err) goto i2c_error; - - uint32_t dword = eeconfig_read_rgblight(); - - // Write RGB - err = i2c_master_write_data(&dword, 4); - if (err) goto i2c_error; - - RGB_DIRTY = false; - i2c_master_stop(); - } - #endif - - return 0; -} - -#else // USE_SERIAL - - -typedef struct _Serial_s2m_buffer_t { - // TODO: if MATRIX_COLS > 8 change to uint8_t packed_matrix[] for pack/unpack - matrix_row_t smatrix[ROWS_PER_HAND]; -} Serial_s2m_buffer_t; - -volatile Serial_s2m_buffer_t serial_s2m_buffer = {}; -volatile Serial_m2s_buffer_t serial_m2s_buffer = {}; -uint8_t volatile status0 = 0; - -SSTD_t transactions[] = { - { (uint8_t *)&status0, - sizeof(serial_m2s_buffer), (uint8_t *)&serial_m2s_buffer, - sizeof(serial_s2m_buffer), (uint8_t *)&serial_s2m_buffer - } -}; - -void serial_master_init(void) -{ soft_serial_initiator_init(transactions, TID_LIMIT(transactions)); } - -void serial_slave_init(void) -{ soft_serial_target_init(transactions, TID_LIMIT(transactions)); } - -int serial_transaction(void) { - int slaveOffset = (isLeftHand) ? (ROWS_PER_HAND) : 0; - - if (soft_serial_transaction()) { - return 1; - } - - // TODO: if MATRIX_COLS > 8 change to unpack() - for (int i = 0; i < ROWS_PER_HAND; ++i) { - matrix[slaveOffset+i] = serial_s2m_buffer.smatrix[i]; - } - - #ifdef RGBLIGHT_ENABLE - // Code to send RGB over serial goes here (not implemented yet) - #endif - - #ifdef BACKLIGHT_ENABLE - // Write backlight level for slave to read - serial_m2s_buffer.backlight_level = backlight_config.enable ? backlight_config.level : 0; - #endif - - return 0; -} -#endif - -uint8_t matrix_scan(void) -{ - uint8_t ret = _matrix_scan(); - -#if defined(USE_I2C) || defined(EH) - if( i2c_transaction() ) { -#else // USE_SERIAL - if( serial_transaction() ) { -#endif - - error_count++; - - if (error_count > ERROR_DISCONNECT_COUNT) { - // reset other half if disconnected - int slaveOffset = (isLeftHand) ? (ROWS_PER_HAND) : 0; - for (int i = 0; i < ROWS_PER_HAND; ++i) { - matrix[slaveOffset+i] = 0; - } - } - } else { - error_count = 0; - } - matrix_scan_quantum(); - return ret; -} - -void matrix_slave_scan(void) { - _matrix_scan(); - - int offset = (isLeftHand) ? 0 : ROWS_PER_HAND; - -#if defined(USE_I2C) || defined(EH) - for (int i = 0; i < ROWS_PER_HAND; ++i) { - i2c_slave_buffer[I2C_KEYMAP_START+i] = matrix[offset+i]; - } -#else // USE_SERIAL - // TODO: if MATRIX_COLS > 8 change to pack() - for (int i = 0; i < ROWS_PER_HAND; ++i) { - serial_s2m_buffer.smatrix[i] = matrix[offset+i]; - } -#endif - matrix_slave_scan_user(); -} - -bool matrix_is_modified(void) -{ - if (debouncing) return false; - return true; -} - -inline -bool matrix_is_on(uint8_t row, uint8_t col) -{ - return (matrix[row] & ((matrix_row_t)1<> 4) + 1) &= ~_BV(pin & 0xF); // IN - _SFR_IO8((pin >> 4) + 2) |= _BV(pin & 0xF); // HI - } -} - -static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row) -{ - // Store last value of row prior to reading - matrix_row_t last_row_value = current_matrix[current_row]; - - // Clear data in matrix row - current_matrix[current_row] = 0; - - // Select row and wait for row selecton to stabilize - select_row(current_row); - wait_us(30); - - // 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 = col_pins[col_index]; - uint8_t pin_state = (_SFR_IO8(pin >> 4) & _BV(pin & 0xF)); - - // Populate the matrix row with the state of the col pin - current_matrix[current_row] |= pin_state ? 0 : (ROW_SHIFTER << col_index); - } - - // Unselect row - unselect_row(current_row); - - return (last_row_value != current_matrix[current_row]); -} - -static void select_row(uint8_t row) -{ - uint8_t pin = row_pins[row]; - _SFR_IO8((pin >> 4) + 1) |= _BV(pin & 0xF); // OUT - _SFR_IO8((pin >> 4) + 2) &= ~_BV(pin & 0xF); // LOW -} - -static void unselect_row(uint8_t row) -{ - uint8_t pin = row_pins[row]; - _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN - _SFR_IO8((pin >> 4) + 2) |= _BV(pin & 0xF); // HI -} - -static void unselect_rows(void) -{ - for(uint8_t x = 0; x < ROWS_PER_HAND; x++) { - uint8_t pin = row_pins[x]; - _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN - _SFR_IO8((pin >> 4) + 2) |= _BV(pin & 0xF); // HI - } -} - -#elif (DIODE_DIRECTION == ROW2COL) - -static void init_rows(void) -{ - for(uint8_t x = 0; x < ROWS_PER_HAND; x++) { - uint8_t pin = row_pins[x]; - _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN - _SFR_IO8((pin >> 4) + 2) |= _BV(pin & 0xF); // HI - } -} - -static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col) -{ - bool matrix_changed = false; - - // Select col and wait for col selecton to stabilize - select_col(current_col); - wait_us(30); - - // For each row... - for(uint8_t row_index = 0; row_index < ROWS_PER_HAND; row_index++) - { - - // Store last value of row prior to reading - matrix_row_t last_row_value = current_matrix[row_index]; - - // Check row pin state - if ((_SFR_IO8(row_pins[row_index] >> 4) & _BV(row_pins[row_index] & 0xF)) == 0) - { - // Pin LO, set col bit - current_matrix[row_index] |= (ROW_SHIFTER << current_col); - } - else - { - // Pin HI, clear col bit - current_matrix[row_index] &= ~(ROW_SHIFTER << current_col); - } - - // Determine if the matrix changed state - if ((last_row_value != current_matrix[row_index]) && !(matrix_changed)) - { - matrix_changed = true; - } - } - - // Unselect col - unselect_col(current_col); - - return matrix_changed; -} - -static void select_col(uint8_t col) -{ - uint8_t pin = col_pins[col]; - _SFR_IO8((pin >> 4) + 1) |= _BV(pin & 0xF); // OUT - _SFR_IO8((pin >> 4) + 2) &= ~_BV(pin & 0xF); // LOW -} - -static void unselect_col(uint8_t col) -{ - uint8_t pin = col_pins[col]; - _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN - _SFR_IO8((pin >> 4) + 2) |= _BV(pin & 0xF); // HI -} - -static void unselect_cols(void) -{ - for(uint8_t x = 0; x < MATRIX_COLS; x++) { - uint8_t pin = col_pins[x]; - _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN - _SFR_IO8((pin >> 4) + 2) |= _BV(pin & 0xF); // HI - } -} - -#elif (DIODE_DIRECTION == CUSTOM_MATRIX) - -static void init_cols_rows(void) -{ - for(int row = 0; row < MATRIX_ROWS; row++) { - for(int col = 0; col < MATRIX_COLS; col++) { - uint8_t pin = row_col_pins[row][col]; - if(pin == NO_PIN) { - continue; - } - // DDxn set 0 for input - _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); - // PORTxn set 1 for input/pullup - _SFR_IO8((pin >> 4) + 2) |= _BV(pin & 0xF); - } - } -} - -static bool read_cols(matrix_row_t current_matrix[], uint8_t current_row) -{ - matrix_row_t last_row_value = current_matrix[current_row]; - current_matrix[current_row] = 0; - - for(uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++) { - uint8_t pin = row_col_pins[current_row][col_index]; - if(pin == NO_PIN) { - current_matrix[current_row] |= 0; - } - else { - uint8_t pin_state = (_SFR_IO8(pin >> 4) & _BV(pin & 0xF)); - current_matrix[current_row] |= pin_state ? 0 : (ROW_SHIFTER << col_index); - } - } - - return (last_row_value != current_matrix[current_row]); -} - -#endif diff --git a/keyboards/miniaxe/rules.mk b/keyboards/miniaxe/rules.mk index 96e27686b..2f56a907b 100644 --- a/keyboards/miniaxe/rules.mk +++ b/keyboards/miniaxe/rules.mk @@ -1,4 +1,3 @@ -SRC += matrix.c # MCU name #MCU = at90usb1286 @@ -83,6 +82,6 @@ FAUXCLICKY_ENABLE = no # Use buzzer to emulate clicky switches HD44780_ENABLE = no # Enable support for HD44780 based LCDs (+400) DEBUG_ENABLE = no -CUSTOM_MATRIX = yes # Use custom matrix code +CUSTOM_MATRIX = no # Use custom matrix code SPLIT_KEYBOARD = yes # Use shared split_common code diff --git a/quantum/config_common.h b/quantum/config_common.h index 606cd9381..0b2e408a4 100644 --- a/quantum/config_common.h +++ b/quantum/config_common.h @@ -21,6 +21,9 @@ #define ROW2COL 1 #define CUSTOM_MATRIX 2 /* Disables built-in matrix scanning code */ +// useful for direct pin mapping +#define NO_PIN (~0) + #ifdef __AVR__ #ifndef __ASSEMBLER__ #include diff --git a/quantum/debounce.c b/quantum/debounce.c new file mode 100644 index 000000000..929023ab2 --- /dev/null +++ b/quantum/debounce.c @@ -0,0 +1,52 @@ + +#include "matrix.h" +#include "timer.h" +#include "quantum.h" + +#ifndef DEBOUNCING_DELAY +# define DEBOUNCING_DELAY 5 +#endif + +void debounce_init(uint8_t num_rows) { +} + +#if DEBOUNCING_DELAY > 0 + +static bool debouncing = false; + +void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) { + static uint16_t debouncing_time; + + if (changed) { + debouncing = true; + debouncing_time = timer_read(); + } + + if (debouncing && (timer_elapsed(debouncing_time) > DEBOUNCING_DELAY)) { + for (uint8_t i = 0; i < num_rows; i++) { + cooked[i] = raw[i]; + } + debouncing = false; + } +} + +bool debounce_active(void) { + return debouncing; +} + +#else + +// no debounce +void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) { + if (changed) + { + for (uint8_t i = 0; i < num_rows; i++) { + cooked[i] = raw[i]; + } + } +} + +bool debounce_active(void) { + return false; +} +#endif diff --git a/quantum/debounce.h b/quantum/debounce.h new file mode 100644 index 000000000..360af77e7 --- /dev/null +++ b/quantum/debounce.h @@ -0,0 +1,11 @@ +#pragma once + +// raw is the current key state +// on entry cooked is the previous debounced state +// on exit cooked is the current debounced state +// changed is true if raw has changed since the last call +void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed); + +bool debounce_active(void); + +void debounce_init(uint8_t num_rows); \ No newline at end of file diff --git a/quantum/matrix.c b/quantum/matrix.c index 9b5ce33d2..49a184569 100644 --- a/quantum/matrix.c +++ b/quantum/matrix.c @@ -21,21 +21,9 @@ along with this program. If not, see . #include "debug.h" #include "util.h" #include "matrix.h" -#include "timer.h" +#include "debounce.h" #include "quantum.h" - -/* Set 0 if debouncing isn't needed */ - -#ifndef DEBOUNCING_DELAY -# define DEBOUNCING_DELAY 5 -#endif - -#if (DEBOUNCING_DELAY > 0) - static uint16_t debouncing_time; - static bool debouncing = false; -#endif - #if (MATRIX_COLS <= 8) # define print_matrix_header() print("\nr/c 01234567\n") # define print_matrix_row(row) print_bin_reverse8(matrix_get_row(row)) @@ -63,9 +51,9 @@ static const pin_t col_pins[MATRIX_COLS] = MATRIX_COL_PINS; #endif /* matrix state(1:on, 0:off) */ -static matrix_row_t matrix[MATRIX_ROWS]; +static matrix_row_t raw_matrix[MATRIX_ROWS]; -static matrix_row_t matrix_debouncing[MATRIX_ROWS]; +static matrix_row_t matrix[MATRIX_ROWS]; #if (DIODE_DIRECTION == COL2ROW) @@ -157,70 +145,39 @@ void matrix_init(void) { // initialize matrix state: all keys off for (uint8_t i=0; i < MATRIX_ROWS; i++) { + raw_matrix[i] = 0; matrix[i] = 0; - matrix_debouncing[i] = 0; } + debounce_init(MATRIX_ROWS); matrix_init_quantum(); } uint8_t matrix_scan(void) { + bool changed = false; #if (DIODE_DIRECTION == COL2ROW) - - // Set row, read cols - for (uint8_t current_row = 0; current_row < MATRIX_ROWS; current_row++) { -# if (DEBOUNCING_DELAY > 0) - bool matrix_changed = read_cols_on_row(matrix_debouncing, current_row); - - if (matrix_changed) { - debouncing = true; - debouncing_time = timer_read(); - } - -# else - read_cols_on_row(matrix, current_row); -# endif - - } - + // 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); + } #elif (DIODE_DIRECTION == ROW2COL) - - // Set col, read rows - for (uint8_t current_col = 0; current_col < MATRIX_COLS; current_col++) { -# if (DEBOUNCING_DELAY > 0) - bool matrix_changed = read_rows_on_col(matrix_debouncing, current_col); - if (matrix_changed) { - debouncing = true; - debouncing_time = timer_read(); - } -# else - read_rows_on_col(matrix, current_col); -# endif - - } - + // 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); + } #endif -# if (DEBOUNCING_DELAY > 0) - if (debouncing && (timer_elapsed(debouncing_time) > DEBOUNCING_DELAY)) { - for (uint8_t i = 0; i < MATRIX_ROWS; i++) { - matrix[i] = matrix_debouncing[i]; - } - debouncing = false; - } -# endif + debounce(raw_matrix, matrix, MATRIX_ROWS, changed); - matrix_scan_quantum(); - return 1; + matrix_scan_quantum(); + return 1; } bool matrix_is_modified(void) { -#if (DEBOUNCING_DELAY > 0) - if (debouncing) return false; -#endif + if (debounce_active()) return false; return true; } diff --git a/quantum/split_common/i2c.h b/quantum/split_common/i2c.h index b3cbe8c82..91e8e96f4 100644 --- a/quantum/split_common/i2c.h +++ b/quantum/split_common/i2c.h @@ -1,5 +1,4 @@ -#ifndef I2C_H -#define I2C_H +#pragma once #include @@ -58,5 +57,3 @@ extern unsigned char i2c_readNak(void); extern unsigned char i2c_read(unsigned char ack); #define i2c_read(ack) (ack) ? i2c_readAck() : i2c_readNak(); - -#endif diff --git a/quantum/split_common/matrix.c b/quantum/split_common/matrix.c index 2c37053f8..c3d2857ed 100644 --- a/quantum/split_common/matrix.c +++ b/quantum/split_common/matrix.c @@ -25,529 +25,304 @@ along with this program. If not, see . #include "matrix.h" #include "split_util.h" #include "config.h" -#include "timer.h" #include "split_flags.h" #include "quantum.h" - -#ifdef BACKLIGHT_ENABLE -# include "backlight.h" - extern backlight_config_t backlight_config; -#endif - -#if defined(USE_I2C) || defined(EH) -# include "i2c.h" -#else // USE_SERIAL -# include "serial.h" -#endif - -#ifndef DEBOUNCING_DELAY -# define DEBOUNCING_DELAY 5 -#endif - -#if (DEBOUNCING_DELAY > 0) - static uint16_t debouncing_time; - static bool debouncing = false; -#endif - -#if defined(USE_I2C) || defined(EH) +#include "debounce.h" +#include "transport.h" #if (MATRIX_COLS <= 8) -# define print_matrix_header() print("\nr/c 01234567\n") -# define print_matrix_row(row) print_bin_reverse8(matrix_get_row(row)) -# define matrix_bitpop(i) bitpop(matrix[i]) -# define ROW_SHIFTER ((uint8_t)1) -#else -# error "Currently only supports 8 COLS" -#endif - -#else // USE_SERIAL - -#if (MATRIX_COLS <= 8) -# define print_matrix_header() print("\nr/c 01234567\n") -# define print_matrix_row(row) print_bin_reverse8(matrix_get_row(row)) -# define matrix_bitpop(i) bitpop(matrix[i]) -# define ROW_SHIFTER ((uint8_t)1) +# define print_matrix_header() print("\nr/c 01234567\n") +# define print_matrix_row(row) print_bin_reverse8(matrix_get_row(row)) +# define matrix_bitpop(i) bitpop(matrix[i]) +# define ROW_SHIFTER ((uint8_t)1) #elif (MATRIX_COLS <= 16) -# define print_matrix_header() print("\nr/c 0123456789ABCDEF\n") -# define print_matrix_row(row) print_bin_reverse16(matrix_get_row(row)) -# define matrix_bitpop(i) bitpop16(matrix[i]) -# define ROW_SHIFTER ((uint16_t)1) +# define print_matrix_header() print("\nr/c 0123456789ABCDEF\n") +# define print_matrix_row(row) print_bin_reverse16(matrix_get_row(row)) +# define matrix_bitpop(i) bitpop16(matrix[i]) +# define ROW_SHIFTER ((uint16_t)1) #elif (MATRIX_COLS <= 32) -# define print_matrix_header() print("\nr/c 0123456789ABCDEF0123456789ABCDEF\n") -# define print_matrix_row(row) print_bin_reverse32(matrix_get_row(row)) -# define matrix_bitpop(i) bitpop32(matrix[i]) -# define ROW_SHIFTER ((uint32_t)1) +# define print_matrix_header() print("\nr/c 0123456789ABCDEF0123456789ABCDEF\n") +# define print_matrix_row(row) print_bin_reverse32(matrix_get_row(row)) +# define matrix_bitpop(i) bitpop32(matrix[i]) +# define ROW_SHIFTER ((uint32_t)1) #endif -#endif -static matrix_row_t matrix_debouncing[MATRIX_ROWS]; - #define ERROR_DISCONNECT_COUNT 5 -#define ROWS_PER_HAND (MATRIX_ROWS/2) - -static uint8_t error_count = 0; +#define ROWS_PER_HAND (MATRIX_ROWS / 2) +#ifdef DIRECT_PINS +static pin_t direct_pins[MATRIX_ROWS][MATRIX_COLS] = DIRECT_PINS; +#else static pin_t row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS; static pin_t col_pins[MATRIX_COLS] = MATRIX_COL_PINS; +#endif /* matrix state(1:on, 0:off) */ static matrix_row_t matrix[MATRIX_ROWS]; -static matrix_row_t matrix_debouncing[MATRIX_ROWS]; +static matrix_row_t raw_matrix[ROWS_PER_HAND]; + +// row offsets for each hand +uint8_t thisHand, thatHand; + +// user-defined overridable functions + +__attribute__((weak)) void matrix_init_kb(void) { matrix_init_user(); } + +__attribute__((weak)) void matrix_scan_kb(void) { matrix_scan_user(); } + +__attribute__((weak)) void matrix_init_user(void) {} + +__attribute__((weak)) void matrix_scan_user(void) {} + +__attribute__((weak)) void matrix_slave_scan_user(void) {} + +// helper functions + +inline uint8_t matrix_rows(void) { return MATRIX_ROWS; } + +inline uint8_t matrix_cols(void) { return MATRIX_COLS; } + +bool matrix_is_modified(void) { + if (debounce_active()) return false; + return true; +} + +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]; } + +void matrix_print(void) { + print_matrix_header(); + + for (uint8_t row = 0; row < MATRIX_ROWS; row++) { + phex(row); + print(": "); + print_matrix_row(row); + print("\n"); + } +} + +uint8_t matrix_key_count(void) { + uint8_t count = 0; + for (uint8_t i = 0; i < MATRIX_ROWS; i++) { + count += matrix_bitpop(i); + } + return count; +} + +// matrix code + +#ifdef DIRECT_PINS + +static void 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]; + if (pin != NO_PIN) { + setPinInputHigh(pin); + } + } + } +} + +static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row) { + matrix_row_t last_row_value = current_matrix[current_row]; + current_matrix[current_row] = 0; + + for (uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++) { + pin_t pin = direct_pins[current_row][col_index]; + if (pin != NO_PIN) { + current_matrix[current_row] |= readPin(pin) ? 0 : (ROW_SHIFTER << col_index); + } + } + + return (last_row_value != current_matrix[current_row]); +} + +#elif (DIODE_DIRECTION == COL2ROW) + +static void select_row(uint8_t row) { + writePinLow(row_pins[row]); + setPinOutput(row_pins[row]); +} + +static void unselect_row(uint8_t row) { setPinInputHigh(row_pins[row]); } + +static void unselect_rows(void) { + for (uint8_t x = 0; x < ROWS_PER_HAND; x++) { + setPinInputHigh(row_pins[x]); + } +} + +static void init_pins(void) { + unselect_rows(); + for (uint8_t x = 0; x < MATRIX_COLS; x++) { + setPinInputHigh(col_pins[x]); + } +} + +static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row) { + // Store last value of row prior to reading + matrix_row_t last_row_value = current_matrix[current_row]; + + // Clear data in matrix row + current_matrix[current_row] = 0; + + // Select row and wait for row selecton to stabilize + select_row(current_row); + wait_us(30); + + // For each col... + for (uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++) { + // Populate the matrix row with the state of the col pin + current_matrix[current_row] |= readPin(col_pins[col_index]) ? 0 : (ROW_SHIFTER << col_index); + } + + // Unselect row + unselect_row(current_row); + + return (last_row_value != current_matrix[current_row]); +} -#if (DIODE_DIRECTION == COL2ROW) - static void init_cols(void); - static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row); - static void unselect_rows(void); - static void select_row(uint8_t row); - static void unselect_row(uint8_t row); #elif (DIODE_DIRECTION == ROW2COL) - static void init_rows(void); - static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col); - static void unselect_cols(void); - static void unselect_col(uint8_t col); - static void select_col(uint8_t col); + +static void select_col(uint8_t col) { + writePinLow(col_pins[col]); + setPinOutput(col_pins[col]); +} + +static void unselect_col(uint8_t col) { setPinInputHigh(col_pins[col]); } + +static void unselect_cols(void) { + for (uint8_t x = 0; x < MATRIX_COLS; x++) { + setPinInputHigh(col_pins[x]); + } +} + +static void init_pins(void) { + unselect_cols(); + for (uint8_t x = 0; x < ROWS_PER_HAND; x++) { + setPinInputHigh(row_pins[x]); + } +} + +static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col) { + bool matrix_changed = false; + + // Select col and wait for col selecton to stabilize + select_col(current_col); + wait_us(30); + + // For each row... + for (uint8_t row_index = 0; row_index < ROWS_PER_HAND; row_index++) { + // Store last value of row prior to reading + matrix_row_t last_row_value = current_matrix[row_index]; + + // Check row pin state + if (readPin(row_pins[row_index])) { + // Pin HI, clear col bit + current_matrix[row_index] &= ~(ROW_SHIFTER << current_col); + } else { + // Pin LO, set col bit + current_matrix[row_index] |= (ROW_SHIFTER << current_col); + } + + // Determine if the matrix changed state + if ((last_row_value != current_matrix[row_index]) && !(matrix_changed)) { + matrix_changed = true; + } + } + + // Unselect col + unselect_col(current_col); + + return matrix_changed; +} + #endif -__attribute__ ((weak)) -void matrix_init_kb(void) { - matrix_init_user(); -} +void matrix_init(void) { + debug_enable = true; + debug_matrix = true; + debug_mouse = true; -__attribute__ ((weak)) -void matrix_scan_kb(void) { - matrix_scan_user(); -} - -__attribute__ ((weak)) -void matrix_init_user(void) { -} - -__attribute__ ((weak)) -void matrix_scan_user(void) { -} - -__attribute__ ((weak)) -void matrix_slave_scan_user(void) { -} - -inline -uint8_t matrix_rows(void) -{ - return MATRIX_ROWS; -} - -inline -uint8_t matrix_cols(void) -{ - return MATRIX_COLS; -} - -void matrix_init(void) -{ - debug_enable = true; - debug_matrix = true; - debug_mouse = true; - - // Set pinout for right half if pinout for that half is defined - if (!isLeftHand) { + // Set pinout for right half if pinout for that half is defined + if (!isLeftHand) { #ifdef MATRIX_ROW_PINS_RIGHT - const uint8_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]; + const uint8_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 uint8_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 - } - - // initialize row and col -#if (DIODE_DIRECTION == COL2ROW) - unselect_rows(); - init_cols(); -#elif (DIODE_DIRECTION == ROW2COL) - unselect_cols(); - init_rows(); -#endif - - // initialize matrix state: all keys off - for (uint8_t i=0; i < MATRIX_ROWS; i++) { - matrix[i] = 0; - matrix_debouncing[i] = 0; - } - - matrix_init_quantum(); - -} - -uint8_t _matrix_scan(void) -{ - int offset = isLeftHand ? 0 : (ROWS_PER_HAND); -#if (DIODE_DIRECTION == COL2ROW) - // Set row, read cols - for (uint8_t current_row = 0; current_row < ROWS_PER_HAND; current_row++) { -# if (DEBOUNCING_DELAY > 0) - bool matrix_changed = read_cols_on_row(matrix_debouncing+offset, current_row); - - if (matrix_changed) { - debouncing = true; - debouncing_time = timer_read(); - } - -# else - read_cols_on_row(matrix+offset, current_row); -# endif - - } - -#elif (DIODE_DIRECTION == ROW2COL) - // Set col, read rows - for (uint8_t current_col = 0; current_col < MATRIX_COLS; current_col++) { -# if (DEBOUNCING_DELAY > 0) - bool matrix_changed = read_rows_on_col(matrix_debouncing+offset, current_col); - if (matrix_changed) { - debouncing = true; - debouncing_time = timer_read(); - } -# else - read_rows_on_col(matrix+offset, current_col); -# endif - + const uint8_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 - -# if (DEBOUNCING_DELAY > 0) - if (debouncing && (timer_elapsed(debouncing_time) > DEBOUNCING_DELAY)) { - for (uint8_t i = 0; i < ROWS_PER_HAND; i++) { - matrix[i+offset] = matrix_debouncing[i+offset]; - } - debouncing = false; - } -# endif - - return 1; -} - -#if defined(USE_I2C) || defined(EH) - -// Get rows from other half over i2c -int i2c_transaction(void) { - int slaveOffset = (isLeftHand) ? (ROWS_PER_HAND) : 0; - int err = 0; - - // write backlight info - #ifdef BACKLIGHT_ENABLE - if (BACKLIT_DIRTY) { - err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_WRITE); - if (err) goto i2c_error; - - // Backlight location - err = i2c_master_write(I2C_BACKLIT_START); - if (err) goto i2c_error; - - // Write backlight - i2c_master_write(get_backlight_level()); - - BACKLIT_DIRTY = false; - } - #endif - - err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_WRITE); - if (err) goto i2c_error; - - // start of matrix stored at I2C_KEYMAP_START - err = i2c_master_write(I2C_KEYMAP_START); - if (err) goto i2c_error; - - // Start read - err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_READ); - if (err) goto i2c_error; - - if (!err) { - int i; - for (i = 0; i < ROWS_PER_HAND-1; ++i) { - matrix[slaveOffset+i] = i2c_master_read(I2C_ACK); - } - matrix[slaveOffset+i] = i2c_master_read(I2C_NACK); - i2c_master_stop(); - } else { -i2c_error: // the cable is disconnceted, or something else went wrong - i2c_reset_state(); - return err; - } - - #ifdef RGBLIGHT_ENABLE - if (RGB_DIRTY) { - err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_WRITE); - if (err) goto i2c_error; - - // RGB Location - err = i2c_master_write(I2C_RGB_START); - if (err) goto i2c_error; - - uint32_t dword = eeconfig_read_rgblight(); - - // Write RGB - err = i2c_master_write_data(&dword, 4); - if (err) goto i2c_error; - - RGB_DIRTY = false; - i2c_master_stop(); - } - #endif - - return 0; -} - -#else // USE_SERIAL - - -typedef struct _Serial_s2m_buffer_t { - // TODO: if MATRIX_COLS > 8 change to uint8_t packed_matrix[] for pack/unpack - matrix_row_t smatrix[ROWS_PER_HAND]; -} Serial_s2m_buffer_t; - -volatile Serial_s2m_buffer_t serial_s2m_buffer = {}; -volatile Serial_m2s_buffer_t serial_m2s_buffer = {}; -uint8_t volatile status0 = 0; - -SSTD_t transactions[] = { - { (uint8_t *)&status0, - sizeof(serial_m2s_buffer), (uint8_t *)&serial_m2s_buffer, - sizeof(serial_s2m_buffer), (uint8_t *)&serial_s2m_buffer } -}; -void serial_master_init(void) -{ soft_serial_initiator_init(transactions, TID_LIMIT(transactions)); } + thisHand = isLeftHand ? 0 : (ROWS_PER_HAND); + thatHand = ROWS_PER_HAND - thisHand; -void serial_slave_init(void) -{ soft_serial_target_init(transactions, TID_LIMIT(transactions)); } + // initialize key pins + init_pins(); -int serial_transaction(void) { - int slaveOffset = (isLeftHand) ? (ROWS_PER_HAND) : 0; + // initialize matrix state: all keys off + for (uint8_t i = 0; i < MATRIX_ROWS; i++) { + matrix[i] = 0; + } - if (soft_serial_transaction()) { - return 1; - } + debounce_init(ROWS_PER_HAND); - // TODO: if MATRIX_COLS > 8 change to unpack() - for (int i = 0; i < ROWS_PER_HAND; ++i) { - matrix[slaveOffset+i] = serial_s2m_buffer.smatrix[i]; - } - - #if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT) - // Code to send RGB over serial goes here (not implemented yet) - #endif - - #ifdef BACKLIGHT_ENABLE - // Write backlight level for slave to read - serial_m2s_buffer.backlight_level = backlight_config.enable ? backlight_config.level : 0; - #endif - - return 0; -} -#endif - -uint8_t matrix_scan(void) -{ - uint8_t ret = _matrix_scan(); - -#if defined(USE_I2C) || defined(EH) - if( i2c_transaction() ) { -#else // USE_SERIAL - if( serial_transaction() ) { -#endif - - error_count++; - - if (error_count > ERROR_DISCONNECT_COUNT) { - // reset other half if disconnected - int slaveOffset = (isLeftHand) ? (ROWS_PER_HAND) : 0; - for (int i = 0; i < ROWS_PER_HAND; ++i) { - matrix[slaveOffset+i] = 0; - } - } - } else { - error_count = 0; - } - matrix_scan_quantum(); - return ret; + matrix_init_quantum(); } -void matrix_slave_scan(void) { - _matrix_scan(); - - int offset = (isLeftHand) ? 0 : ROWS_PER_HAND; - -#if defined(USE_I2C) || defined(EH) - for (int i = 0; i < ROWS_PER_HAND; ++i) { - i2c_slave_buffer[I2C_KEYMAP_START+i] = matrix[offset+i]; - } -#else // USE_SERIAL - // TODO: if MATRIX_COLS > 8 change to pack() - for (int i = 0; i < ROWS_PER_HAND; ++i) { - serial_s2m_buffer.smatrix[i] = matrix[offset+i]; - } -#endif - matrix_slave_scan_user(); -} - -bool matrix_is_modified(void) -{ - if (debouncing) return false; - return true; -} - -inline -bool matrix_is_on(uint8_t row, uint8_t col) -{ - return (matrix[row] & ((matrix_row_t)1< ERROR_DISCONNECT_COUNT) { + // reset other half if disconnected + for (int i = 0; i < ROWS_PER_HAND; ++i) { + matrix[thatHand + i] = 0; + } + } + } else { + error_count = 0; + } + + matrix_scan_quantum(); + } else { + transport_slave(matrix + thisHand); + matrix_slave_scan_user(); + } + + return ret; +} diff --git a/quantum/split_common/matrix.h b/quantum/split_common/matrix.h index b5cb45bae..c2bdd3098 100644 --- a/quantum/split_common/matrix.h +++ b/quantum/split_common/matrix.h @@ -1,31 +1,3 @@ -#ifndef SPLIT_COMMON_MATRIX_H -#define SPLIT_COMMON_MATRIX_H +#pragma once #include - -#ifdef RGBLIGHT_ENABLE -# include "rgblight.h" -#endif - -typedef struct _Serial_m2s_buffer_t { -#ifdef BACKLIGHT_ENABLE - uint8_t backlight_level; -#endif -#if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT) - rgblight_config_t rgblight_config; //not yet use - // - // When MCUs on both sides drive their respective RGB LED chains, - // it is necessary to synchronize, so it is necessary to communicate RGB information. - // In that case, define the RGBLIGHT_SPLIT macro. - // - // Otherwise, if the master side MCU drives both sides RGB LED chains, - // there is no need to communicate. -#endif -} Serial_m2s_buffer_t; - -extern volatile Serial_m2s_buffer_t serial_m2s_buffer; - -void serial_master_init(void); -void serial_slave_init(void); - -#endif diff --git a/quantum/split_common/serial.h b/quantum/split_common/serial.h index b6638b3bd..1c1e64006 100644 --- a/quantum/split_common/serial.h +++ b/quantum/split_common/serial.h @@ -1,5 +1,4 @@ -#ifndef SOFT_SERIAL_H -#define SOFT_SERIAL_H +#pragma once #include @@ -61,5 +60,3 @@ int soft_serial_transaction(int sstd_index); #ifdef SERIAL_USE_MULTI_TRANSACTION int soft_serial_get_and_clean_status(int sstd_index); #endif - -#endif /* SOFT_SERIAL_H */ diff --git a/quantum/split_common/split_flags.h b/quantum/split_common/split_flags.h index f101fff5b..aaac474a7 100644 --- a/quantum/split_common/split_flags.h +++ b/quantum/split_common/split_flags.h @@ -1,10 +1,9 @@ -#ifndef SPLIT_FLAGS_H -#define SPLIT_FLAGS_H +#pragma once #include #include -/** +/** * Global Flags **/ @@ -14,7 +13,3 @@ extern volatile bool RGB_DIRTY; //Backlight Stuff extern volatile bool BACKLIT_DIRTY; - - - -#endif \ No newline at end of file diff --git a/quantum/split_common/split_util.c b/quantum/split_common/split_util.c index e41b6f638..5095cb8fd 100644 --- a/quantum/split_common/split_util.c +++ b/quantum/split_common/split_util.c @@ -4,142 +4,84 @@ #include "config.h" #include "timer.h" #include "split_flags.h" +#include "transport.h" #include "quantum.h" #ifdef EE_HANDS # include "tmk_core/common/eeprom.h" -#endif - -#ifdef BACKLIGHT_ENABLE -# include "backlight.h" -#endif - -#if defined(USE_I2C) || defined(EH) -# include "i2c.h" +# include "eeconfig.h" #endif volatile bool isLeftHand = true; -volatile uint8_t setTries = 0; - -static void setup_handedness(void) { +__attribute__((weak)) +bool is_keyboard_left(void) { #ifdef SPLIT_HAND_PIN // Test pin SPLIT_HAND_PIN for High/Low, if low it's right hand setPinInput(SPLIT_HAND_PIN); - isLeftHand = readPin(SPLIT_HAND_PIN); + return readPin(SPLIT_HAND_PIN); #else #ifdef EE_HANDS - isLeftHand = eeprom_read_byte(EECONFIG_HANDEDNESS); + return eeprom_read_byte(EECONFIG_HANDEDNESS); #else #ifdef MASTER_RIGHT - isLeftHand = !has_usb(); + return !is_keyboard_master(); #else - isLeftHand = has_usb(); + return is_keyboard_master(); #endif #endif #endif } +bool is_keyboard_master(void) +{ +#ifdef __AVR__ + static enum { UNKNOWN, MASTER, SLAVE } usbstate = UNKNOWN; + + // only check once, as this is called often + if (usbstate == UNKNOWN) + { + USBCON |= (1 << OTGPADE); // enables VBUS pad + wait_us(5); + + usbstate = (USBSTA & (1 << VBUS)) ? MASTER : SLAVE; // checks state of VBUS + } + + return (usbstate == MASTER); +#else + return true; +#endif +} + static void keyboard_master_setup(void) { #if defined(USE_I2C) || defined(EH) - i2c_master_init(); #ifdef SSD1306OLED matrix_master_OLED_init (); #endif -#else - serial_master_init(); #endif + transport_master_init(); - // For master the Backlight info needs to be sent on startup - // Otherwise the salve won't start with the proper info until an update - BACKLIT_DIRTY = true; + // For master the Backlight info needs to be sent on startup + // Otherwise the salve won't start with the proper info until an update + BACKLIT_DIRTY = true; } -static void keyboard_slave_setup(void) { - timer_init(); -#if defined(USE_I2C) || defined(EH) - i2c_slave_init(SLAVE_I2C_ADDRESS); -#else - serial_slave_init(); -#endif -} - -bool has_usb(void) { - USBCON |= (1 << OTGPADE); //enables VBUS pad - _delay_us(5); - return (USBSTA & (1< #include #include #include -#include "eeconfig.h" - -#define SLAVE_I2C_ADDRESS 0x32 extern volatile bool isLeftHand; -// slave version of matix scan, defined in matrix.c -void matrix_slave_scan(void); - -void split_keyboard_setup(void); -bool has_usb(void); -void keyboard_slave_loop(void); - void matrix_master_OLED_init (void); - -#endif diff --git a/quantum/split_common/transport.c b/quantum/split_common/transport.c new file mode 100644 index 000000000..95738530e --- /dev/null +++ b/quantum/split_common/transport.c @@ -0,0 +1,224 @@ + +#include "config.h" +#include "matrix.h" +#include "quantum.h" + +#define ROWS_PER_HAND (MATRIX_ROWS/2) + +#ifdef RGBLIGHT_ENABLE +# include "rgblight.h" +#endif + +#ifdef BACKLIGHT_ENABLE +# include "backlight.h" + extern backlight_config_t backlight_config; +#endif + +#if defined(USE_I2C) || defined(EH) + +#include "i2c.h" + +#ifndef SLAVE_I2C_ADDRESS +# define SLAVE_I2C_ADDRESS 0x32 +#endif + +#if (MATRIX_COLS > 8) +# error "Currently only supports 8 COLS" +#endif + +// Get rows from other half over i2c +bool transport_master(matrix_row_t matrix[]) { + int err = 0; + + // write backlight info +#ifdef BACKLIGHT_ENABLE + if (BACKLIT_DIRTY) { + err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_WRITE); + if (err) { goto i2c_error; } + + // Backlight location + err = i2c_master_write(I2C_BACKLIT_START); + if (err) { goto i2c_error; } + + // Write backlight + i2c_master_write(get_backlight_level()); + + BACKLIT_DIRTY = false; + } +#endif + + err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_WRITE); + if (err) { goto i2c_error; } + + // start of matrix stored at I2C_KEYMAP_START + err = i2c_master_write(I2C_KEYMAP_START); + if (err) { goto i2c_error; } + + // Start read + err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_READ); + if (err) { goto i2c_error; } + + if (!err) { + int i; + for (i = 0; i < ROWS_PER_HAND-1; ++i) { + matrix[i] = i2c_master_read(I2C_ACK); + } + matrix[i] = i2c_master_read(I2C_NACK); + i2c_master_stop(); + } else { +i2c_error: // the cable is disconnceted, or something else went wrong + i2c_reset_state(); + return false; + } + +#ifdef RGBLIGHT_ENABLE + if (RGB_DIRTY) { + err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_WRITE); + if (err) { goto i2c_error; } + + // RGB Location + err = i2c_master_write(I2C_RGB_START); + if (err) { goto i2c_error; } + + uint32_t dword = eeconfig_read_rgblight(); + + // Write RGB + err = i2c_master_write_data(&dword, 4); + if (err) { goto i2c_error; } + + RGB_DIRTY = false; + i2c_master_stop(); + } +#endif + + return true; +} + +void transport_slave(matrix_row_t matrix[]) { + + for (int i = 0; i < ROWS_PER_HAND; ++i) + { + i2c_slave_buffer[I2C_KEYMAP_START + i] = matrix[i]; + } + // Read Backlight Info + #ifdef BACKLIGHT_ENABLE + if (BACKLIT_DIRTY) + { + backlight_set(i2c_slave_buffer[I2C_BACKLIT_START]); + BACKLIT_DIRTY = false; + } + #endif + #ifdef RGBLIGHT_ENABLE + if (RGB_DIRTY) + { + // Disable interupts (RGB data is big) + cli(); + // Create new DWORD for RGB data + uint32_t dword; + + // Fill the new DWORD with the data that was sent over + uint8_t * dword_dat = (uint8_t *)(&dword); + for (int i = 0; i < 4; i++) + { + dword_dat[i] = i2c_slave_buffer[I2C_RGB_START + i]; + } + + // Update the RGB now with the new data and set RGB_DIRTY to false + rgblight_update_dword(dword); + RGB_DIRTY = false; + // Re-enable interupts now that RGB is set + sei(); + } + #endif +} + +void transport_master_init(void) { + i2c_master_init(); +} + +void transport_slave_init(void) { + i2c_slave_init(SLAVE_I2C_ADDRESS); +} + +#else // USE_SERIAL + +#include "serial.h" + +typedef struct _Serial_s2m_buffer_t { + // TODO: if MATRIX_COLS > 8 change to uint8_t packed_matrix[] for pack/unpack + matrix_row_t smatrix[ROWS_PER_HAND]; +} Serial_s2m_buffer_t; + +typedef struct _Serial_m2s_buffer_t { +#ifdef BACKLIGHT_ENABLE + uint8_t backlight_level; +#endif +#if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT) + rgblight_config_t rgblight_config; //not yet use + // + // When MCUs on both sides drive their respective RGB LED chains, + // it is necessary to synchronize, so it is necessary to communicate RGB information. + // In that case, define the RGBLIGHT_SPLIT macro. + // + // Otherwise, if the master side MCU drives both sides RGB LED chains, + // there is no need to communicate. +#endif +} Serial_m2s_buffer_t; + +volatile Serial_s2m_buffer_t serial_s2m_buffer = {}; +volatile Serial_m2s_buffer_t serial_m2s_buffer = {}; +uint8_t volatile status0 = 0; + +SSTD_t transactions[] = { + { (uint8_t *)&status0, + sizeof(serial_m2s_buffer), (uint8_t *)&serial_m2s_buffer, + sizeof(serial_s2m_buffer), (uint8_t *)&serial_s2m_buffer + } +}; + +void transport_master_init(void) +{ soft_serial_initiator_init(transactions, TID_LIMIT(transactions)); } + +void transport_slave_init(void) +{ soft_serial_target_init(transactions, TID_LIMIT(transactions)); } + +bool transport_master(matrix_row_t matrix[]) { + + if (soft_serial_transaction()) { + return false; + } + + // TODO: if MATRIX_COLS > 8 change to unpack() + for (int i = 0; i < ROWS_PER_HAND; ++i) { + matrix[i] = serial_s2m_buffer.smatrix[i]; + } + + #if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT) + // Code to send RGB over serial goes here (not implemented yet) + #endif + + #ifdef BACKLIGHT_ENABLE + // Write backlight level for slave to read + serial_m2s_buffer.backlight_level = backlight_config.enable ? backlight_config.level : 0; + #endif + + return true; +} + +void transport_slave(matrix_row_t matrix[]) { + + // TODO: if MATRIX_COLS > 8 change to pack() + for (int i = 0; i < ROWS_PER_HAND; ++i) + { + serial_s2m_buffer.smatrix[i] = matrix[i]; + } + #ifdef BACKLIGHT_ENABLE + backlight_set(serial_m2s_buffer.backlight_level); + #endif + #if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT) + // Add serial implementation for RGB here + #endif + +} + +#endif diff --git a/quantum/split_common/transport.h b/quantum/split_common/transport.h new file mode 100644 index 000000000..ccce57e44 --- /dev/null +++ b/quantum/split_common/transport.h @@ -0,0 +1,10 @@ +#pragma once + +#include + +void transport_master_init(void); +void transport_slave_init(void); + +// returns false if valid data not received from slave +bool transport_master(matrix_row_t matrix[]); +void transport_slave(matrix_row_t matrix[]); diff --git a/tmk_core/common/keyboard.h b/tmk_core/common/keyboard.h index 71e594a89..ea2f336e9 100644 --- a/tmk_core/common/keyboard.h +++ b/tmk_core/common/keyboard.h @@ -67,6 +67,8 @@ void keyboard_init(void); void keyboard_task(void); /* it runs when host LED status is updated */ void keyboard_set_leds(uint8_t leds); +/* it runs whenever code has to behave differently on a slave */ +bool is_keyboard_master(void); #ifdef __cplusplus }