aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Churchill <pelrun@gmail.com>2019-01-18 04:08:14 +1000
committerDrashna Jaelre <drashna@live.com>2019-01-17 10:08:14 -0800
commit28929ad0174bdcb38e09f6d272a23b9be6aa430c (patch)
tree3d3568df6a3f7292ccfcedd616cb1bbc8839804c
parent5fcca9a226b2ab0b1335396e25c37e4b2a261a06 (diff)
downloadqmk_firmware-28929ad0174bdcb38e09f6d272a23b9be6aa430c.tar.gz
qmk_firmware-28929ad0174bdcb38e09f6d272a23b9be6aa430c.zip
Simplify split_common Code significantly (#4772)
* Eliminate separate slave loop Both master and slave run the standard keyboard_task main loop now. * Refactor i2c/serial specific code Simplify some of the preprocessor mess by using common function names. * Fix missing #endif * Move direct pin mapping support from miniaxe to split_common For boards with more pins than sense--sorry, switches. * Reordering and reformatting only * Don't run matrix_scan_quantum on slave side * Clean up the offset/slaveOffset calculations * Cut undebounced matrix size in half * Refactor debouncing * Minor fixups * Split split_common transport and debounce code into their own files Can now be replaced with custom versions per keyboard using CUSTOM_TRANSPORT = yes and CUSTOM_DEBOUNCE = yes * Refactor debounce for non-split keyboards too * Update handwired/xealous to build using new split_common * Fix debounce breaking basic test * Dodgy method to allow a split kb to only include one of i2c/serial SPLIT_TRANSPORT = serial or SPLIT_TRANSPORT = i2c will include only that driver code in the binary. SPLIT_TRANSPORT = custom (or anything else) will include neither, the keyboard must supply it's own code if SPLIT_TRANSPORT is not defined then the original behaviour (include both avr i2c and serial code) is maintained. This could be better but it would require explicitly updating all the existing split keyboards. * Enable LTO to get lets_split/sockets under the line * Add docs for SPLIT_TRANSPORT, CUSTOM_MATRIX, CUSTOM_DEBOUNCE * Remove avr-specific sei() from split matrix_setup Not needed now that slave doesn't have a separate main loop. Both sides (on avr) call sei() in lufa's main() after exiting keyboard_setup(). * Fix QUANTUM_LIB_SRC references and simplify SPLIT_TRANSPORT. * Add comments and fix formatting.
-rw-r--r--common_features.mk38
-rw-r--r--docs/config_options.md11
-rw-r--r--docs/getting_started_make_guide.md14
-rw-r--r--keyboards/handwired/xealous/debounce.c63
-rw-r--r--keyboards/handwired/xealous/rules.mk10
-rw-r--r--keyboards/lets_split/sockets/config.h9
-rw-r--r--keyboards/lets_split/sockets/rules.mk2
-rw-r--r--keyboards/miniaxe/config.h5
-rw-r--r--keyboards/miniaxe/matrix.c641
-rw-r--r--keyboards/miniaxe/rules.mk3
-rw-r--r--quantum/config_common.h3
-rw-r--r--quantum/debounce.c52
-rw-r--r--quantum/debounce.h11
-rw-r--r--quantum/matrix.c79
-rw-r--r--quantum/split_common/i2c.h5
-rw-r--r--quantum/split_common/matrix.c639
-rw-r--r--quantum/split_common/matrix.h30
-rw-r--r--quantum/split_common/serial.h5
-rw-r--r--quantum/split_common/split_flags.h9
-rw-r--r--quantum/split_common/split_util.c152
-rw-r--r--quantum/split_common/split_util.h15
-rw-r--r--quantum/split_common/transport.c224
-rw-r--r--quantum/split_common/transport.h10
-rw-r--r--tmk_core/common/keyboard.h2
24 files changed, 711 insertions, 1321 deletions
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:= \
254 $(QUANTUM_DIR)/keymap_common.c \ 254 $(QUANTUM_DIR)/keymap_common.c \
255 $(QUANTUM_DIR)/keycode_config.c 255 $(QUANTUM_DIR)/keycode_config.c
256 256
257ifeq ($(strip $(SPLIT_KEYBOARD)), yes) 257# Include the standard or split matrix code if needed
258 ifneq ($(strip $(CUSTOM_MATRIX)), yes) 258ifneq ($(strip $(CUSTOM_MATRIX)), yes)
259 QUANTUM_SRC += $(QUANTUM_DIR)/split_common/matrix.c 259 ifeq ($(strip $(SPLIT_KEYBOARD)), yes)
260 # Do not use $(QUANTUM_DIR)/matrix.c. 260 QUANTUM_SRC += $(QUANTUM_DIR)/split_common/matrix.c
261 CUSTOM_MATRIX=yes 261 else
262 QUANTUM_SRC += $(QUANTUM_DIR)/matrix.c
262 endif 263 endif
264endif
265
266# Include the standard debounce code if needed
267ifneq ($(strip $(CUSTOM_DEBOUNCE)), yes)
268 QUANTUM_SRC += $(QUANTUM_DIR)/debounce.c
269endif
270
271ifeq ($(strip $(SPLIT_KEYBOARD)), yes)
263 OPT_DEFS += -DSPLIT_KEYBOARD 272 OPT_DEFS += -DSPLIT_KEYBOARD
273
274 # Include files used by all split keyboards
264 QUANTUM_SRC += $(QUANTUM_DIR)/split_common/split_flags.c \ 275 QUANTUM_SRC += $(QUANTUM_DIR)/split_common/split_flags.c \
265 $(QUANTUM_DIR)/split_common/split_util.c 276 $(QUANTUM_DIR)/split_common/split_util.c
266 QUANTUM_LIB_SRC += $(QUANTUM_DIR)/split_common/i2c.c 277
267 QUANTUM_LIB_SRC += $(QUANTUM_DIR)/split_common/serial.c 278 # Determine which (if any) transport files are required
279 ifneq ($(strip $(SPLIT_TRANSPORT)), custom)
280 QUANTUM_SRC += $(QUANTUM_DIR)/split_common/transport.c
281 # Functions added via QUANTUM_LIB_SRC are only included in the final binary if they're called.
282 # Unused functions are pruned away, which is why we can add both drivers here without bloat.
283 QUANTUM_LIB_SRC += $(QUANTUM_DIR)/split_common/i2c.c \
284 $(QUANTUM_DIR)/split_common/serial.c
285 endif
268 COMMON_VPATH += $(QUANTUM_PATH)/split_common 286 COMMON_VPATH += $(QUANTUM_PATH)/split_common
269endif 287endif
270
271ifneq ($(strip $(CUSTOM_MATRIX)), yes)
272 QUANTUM_SRC += $(QUANTUM_DIR)/matrix.c
273endif
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
143 * Breaks any Tap Toggle functionality (`TT` or the One Shot Tap Toggle) 143 * Breaks any Tap Toggle functionality (`TT` or the One Shot Tap Toggle)
144* `#define LEADER_TIMEOUT 300` 144* `#define LEADER_TIMEOUT 300`
145 * how long before the leader key times out 145 * how long before the leader key times out
146 * 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. 146 * 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.
147* `#define LEADER_PER_KEY_TIMING` 147* `#define LEADER_PER_KEY_TIMING`
148 * sets the timer for leader key chords to run on each key press rather than overall 148 * sets the timer for leader key chords to run on each key press rather than overall
149* `#define LEADER_KEY_STRICT_KEY_PROCESSING` 149* `#define LEADER_KEY_STRICT_KEY_PROCESSING`
@@ -197,6 +197,9 @@ If you define these options you will enable the associated feature, which may in
197 197
198Split Keyboard specific options, make sure you have 'SPLIT_KEYBOARD = yes' in your rules.mk 198Split Keyboard specific options, make sure you have 'SPLIT_KEYBOARD = yes' in your rules.mk
199 199
200* `SPLIT_TRANSPORT = custom`
201 * Allows replacing the standard split communication routines with a custom one. ARM based split keyboards must use this at present.
202
200### Setting Handedness 203### Setting Handedness
201 204
202One 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. 205One 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
2083. Set `MASTER_RIGHT`: Half that is plugged into the USB port is determined to be the master and right half (inverse of the default) 2113. Set `MASTER_RIGHT`: Half that is plugged into the USB port is determined to be the master and right half (inverse of the default)
2094. 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 2124. 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
210 213
211* `#define SPLIT_HAND_PIN B7` 214* `#define SPLIT_HAND_PIN B7`
212 * 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. 215 * 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.
213 216
214* `#define EE_HANDS` (only works if `SPLIT_HAND_PIN` is not defined) 217* `#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
302 * Current options are AdafruitEzKey, AdafruitBLE, RN42 305 * Current options are AdafruitEzKey, AdafruitBLE, RN42
303* `SPLIT_KEYBOARD` 306* `SPLIT_KEYBOARD`
304 * 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 307 * 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
308* `CUSTOM_MATRIX`
309 * Allows replacing the standard matrix scanning routine with a custom one.
310* `CUSTOM_DEBOUNCE`
311 * Allows replacing the standard key debouncing routine with a custom one.
305* `WAIT_FOR_USB` 312* `WAIT_FOR_USB`
306 * Forces the keyboard to wait for a USB connection to be established before it starts up 313 * Forces the keyboard to wait for a USB connection to be established before it starts up
307* `NO_USB_STARTUP_CHECK` 314* `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(<code point>)` in your keym
97 97
98`UNICODEMAP_ENABLE` 98`UNICODEMAP_ENABLE`
99 99
100This allows you to send Unicode characters using `X(<map index>)` in your keymap. You will need to maintain a mapping table in your keymap file. All possible code points (up to `0x10FFFF`) are supported. 100This allows you to send Unicode characters using `X(<map index>)` in your keymap. You will need to maintain a mapping table in your keymap file. All possible code points (up to `0x10FFFF`) are supported.
101 101
102`UCIS_ENABLE` 102`UCIS_ENABLE`
103 103
@@ -135,6 +135,18 @@ This enables [key lock](feature_key_lock.md). This consumes an additional 260 by
135 135
136This 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 136This 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
137 137
138`SPLIT_TRANSPORT`
139
140As 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.
141
142`CUSTOM_MATRIX`
143
144Lets 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().
145
146`CUSTOM_DEBOUNCE`
147
148Lets you replace the default key debouncing routine with your own code. You will need to provide your own implementation of debounce().
149
138## Customizing Makefile Options on a Per-Keymap Basis 150## Customizing Makefile Options on a Per-Keymap Basis
139 151
140If 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. 152If 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 @@
1#include <string.h>
2#include "config.h"
3#include "matrix.h"
4#include "timer.h"
5#include "quantum.h"
6
7#ifndef DEBOUNCING_DELAY
8# define DEBOUNCING_DELAY 5
9#endif
10
11//Debouncing counters
12typedef uint8_t debounce_counter_t;
13#define DEBOUNCE_COUNTER_MODULO 250
14#define DEBOUNCE_COUNTER_INACTIVE 251
15
16static debounce_counter_t *debounce_counters;
17
18void debounce_init(uint8_t num_rows)
19{
20 debounce_counters = malloc(num_rows*MATRIX_COLS);
21 memset(debounce_counters, DEBOUNCE_COUNTER_INACTIVE, num_rows*MATRIX_COLS);
22}
23
24void update_debounce_counters(uint8_t num_rows, uint8_t current_time)
25{
26 for (uint8_t row = 0; row < num_rows; row++)
27 {
28 for (uint8_t col = 0; col < MATRIX_COLS; col++)
29 {
30 if (debounce_counters[row*MATRIX_COLS + col] != DEBOUNCE_COUNTER_INACTIVE)
31 {
32 if (TIMER_DIFF(current_time, debounce_counters[row*MATRIX_COLS + col], DEBOUNCE_COUNTER_MODULO) >= DEBOUNCING_DELAY) {
33 debounce_counters[row*MATRIX_COLS + col] = DEBOUNCE_COUNTER_INACTIVE;
34 }
35 }
36 }
37 }
38}
39
40void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, uint8_t current_time)
41{
42 for (uint8_t row = 0; row < num_rows; row++)
43 {
44 matrix_row_t delta = raw[row] ^ cooked[row];
45
46 for (uint8_t col = 0; col < MATRIX_COLS; col++)
47 {
48 if (debounce_counters[row*MATRIX_COLS + col] == DEBOUNCE_COUNTER_INACTIVE && (delta & (1<<col)))
49 {
50 debounce_counters[row*MATRIX_COLS + col] = current_time;
51 cooked[row] ^= (1 << col);
52 }
53 }
54 }
55}
56
57void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed)
58{
59 uint8_t current_time = timer_read() % DEBOUNCE_COUNTER_MODULO;
60
61 update_debounce_counters(num_rows, current_time);
62 transfer_matrix_values(raw, cooked, num_rows, current_time);
63} \ No newline at end of file
diff --git a/keyboards/handwired/xealous/rules.mk b/keyboards/handwired/xealous/rules.mk
index eebd11d86..07e1c875e 100644
--- a/keyboards/handwired/xealous/rules.mk
+++ b/keyboards/handwired/xealous/rules.mk
@@ -1,4 +1,5 @@
1SRC += matrix_scanrate.c matrix.c 1#SRC += matrix_scanrate.c matrix.c
2SRC += debounce.c
2 3
3# MCU name 4# MCU name
4MCU = atmega32u4 5MCU = atmega32u4
@@ -37,7 +38,7 @@ F_USB = $(F_CPU)
37 38
38# Bootloader 39# Bootloader
39# This definition is optional, and if your keyboard supports multiple bootloaders of 40# This definition is optional, and if your keyboard supports multiple bootloaders of
40# different sizes, comment this out, and the correct address will be loaded 41# different sizes, comment this out, and the correct address will be loaded
41# automatically (+60). See bootloader.mk for all options. 42# automatically (+60). See bootloader.mk for all options.
42BOOTLOADER = caterina 43BOOTLOADER = caterina
43 44
@@ -59,14 +60,15 @@ MIDI_ENABLE = no # MIDI controls
59AUDIO_ENABLE = yes # Audio output on port C6 60AUDIO_ENABLE = yes # Audio output on port C6
60UNICODE_ENABLE = no # Unicode 61UNICODE_ENABLE = no # Unicode
61BLUETOOTH_ENABLE = no # Enable Bluetooth with the Adafruit EZ-Key HID 62BLUETOOTH_ENABLE = no # Enable Bluetooth with the Adafruit EZ-Key HID
62RGBLIGHT_ENABLE = no # Enable WS2812 RGB underlight. 63RGBLIGHT_ENABLE = no # Enable WS2812 RGB underlight.
63SPLIT_KEYBOARD = yes # Use shared split_common code 64SPLIT_KEYBOARD = yes # Use shared split_common code
64SUBPROJECT_rev1 = yes 65SUBPROJECT_rev1 = yes
65 66
66# Do not enable SLEEP_LED_ENABLE. it uses the same timer as BACKLIGHT_ENABLE 67# Do not enable SLEEP_LED_ENABLE. it uses the same timer as BACKLIGHT_ENABLE
67SLEEP_LED_ENABLE = no # Breathing sleep LED during USB suspend 68SLEEP_LED_ENABLE = no # Breathing sleep LED during USB suspend
68 69
69CUSTOM_MATRIX = yes 70CUSTOM_MATRIX = no
71CUSTOM_DEBOUNCE = yes
70 72
71LAYOUTS = split60 73LAYOUTS = split60
72 74
diff --git a/keyboards/lets_split/sockets/config.h b/keyboards/lets_split/sockets/config.h
index 6939d37dc..e73c45722 100644
--- a/keyboards/lets_split/sockets/config.h
+++ b/keyboards/lets_split/sockets/config.h
@@ -85,3 +85,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
85//#define NO_ACTION_ONESHOT 85//#define NO_ACTION_ONESHOT
86//#define NO_ACTION_MACRO 86//#define NO_ACTION_MACRO
87//#define NO_ACTION_FUNCTION 87//#define NO_ACTION_FUNCTION
88
89#ifdef USE_Link_Time_Optimization
90 // LTO has issues with macros (action_get_macro) and "functions" (fn_actions),
91 // so just disable them
92 #define NO_ACTION_MACRO
93 #define NO_ACTION_FUNCTION
94
95 #define DISABLE_LEADER
96#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 @@
1BACKLIGHT_ENABLE = no 1BACKLIGHT_ENABLE = no
2AUDIO_ENABLE = yes 2AUDIO_ENABLE = yes
3RGBLIGHT_ENABLE = yes #Don't enable this along with I2C 3RGBLIGHT_ENABLE = yes #Don't enable this along with I2C
4
5EXTRAFLAGS += -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 <http://www.gnu.org/licenses/>.
44*/ 44*/
45// #define MATRIX_ROW_PINS { D0, D5 } 45// #define MATRIX_ROW_PINS { D0, D5 }
46// #define MATRIX_COL_PINS { F1, F0, B0 } 46// #define MATRIX_COL_PINS { F1, F0, B0 }
47#define NO_PIN 0xFF 47#define DIRECT_PINS { \
48#define MATRIX_ROW_COL_PINS { \
49 { F1, E6, B0, B2, B3 }, \ 48 { F1, E6, B0, B2, B3 }, \
50 { F5, F0, B1, B7, D2 }, \ 49 { F5, F0, B1, B7, D2 }, \
51 { F6, F7, C7, D5, D3 }, \ 50 { F6, F7, C7, D5, D3 }, \
@@ -54,7 +53,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
54#define UNUSED_PINS 53#define UNUSED_PINS
55 54
56/* COL2ROW, ROW2COL, or CUSTOM_MATRIX */ 55/* COL2ROW, ROW2COL, or CUSTOM_MATRIX */
57#define DIODE_DIRECTION CUSTOM_MATRIX 56//#define DIODE_DIRECTION CUSTOM_MATRIX
58 57
59// #define BACKLIGHT_PIN B7 58// #define BACKLIGHT_PIN B7
60// #define BACKLIGHT_BREATHING 59// #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 @@
1/*
2Copyright 2012 Jun Wako <wakojun@gmail.com>
3
4This program is free software: you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation, either version 2 of the License, or
7(at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program. If not, see <http://www.gnu.org/licenses/>.
16*/
17
18/*
19 * scan matrix
20 */
21#include <stdint.h>
22#include <stdbool.h>
23#include <avr/io.h>
24#include "wait.h"
25#include "print.h"
26#include "debug.h"
27#include "util.h"
28#include "matrix.h"
29#include "split_util.h"
30#include "pro_micro.h"
31#include "config.h"
32#include "timer.h"
33#include "split_flags.h"
34
35#ifdef BACKLIGHT_ENABLE
36# include "backlight.h"
37 extern backlight_config_t backlight_config;
38#endif
39
40#if defined(USE_I2C) || defined(EH)
41# include "i2c.h"
42#else // USE_SERIAL
43# include "serial.h"
44#endif
45
46#ifndef DEBOUNCING_DELAY
47# define DEBOUNCING_DELAY 5
48#endif
49
50#if (DEBOUNCING_DELAY > 0)
51 static uint16_t debouncing_time;
52 static bool debouncing = false;
53#endif
54
55#if defined(USE_I2C) || defined(EH)
56
57#if (MATRIX_COLS <= 8)
58# define print_matrix_header() print("\nr/c 01234567\n")
59# define print_matrix_row(row) print_bin_reverse8(matrix_get_row(row))
60# define matrix_bitpop(i) bitpop(matrix[i])
61# define ROW_SHIFTER ((uint8_t)1)
62#else
63# error "Currently only supports 8 COLS"
64#endif
65
66#else // USE_SERIAL
67
68#if (MATRIX_COLS <= 8)
69# define print_matrix_header() print("\nr/c 01234567\n")
70# define print_matrix_row(row) print_bin_reverse8(matrix_get_row(row))
71# define matrix_bitpop(i) bitpop(matrix[i])
72# define ROW_SHIFTER ((uint8_t)1)
73#elif (MATRIX_COLS <= 16)
74# define print_matrix_header() print("\nr/c 0123456789ABCDEF\n")
75# define print_matrix_row(row) print_bin_reverse16(matrix_get_row(row))
76# define matrix_bitpop(i) bitpop16(matrix[i])
77# define ROW_SHIFTER ((uint16_t)1)
78#elif (MATRIX_COLS <= 32)
79# define print_matrix_header() print("\nr/c 0123456789ABCDEF0123456789ABCDEF\n")
80# define print_matrix_row(row) print_bin_reverse32(matrix_get_row(row))
81# define matrix_bitpop(i) bitpop32(matrix[i])
82# define ROW_SHIFTER ((uint32_t)1)
83#endif
84
85#endif
86static matrix_row_t matrix_debouncing[MATRIX_ROWS];
87
88#define ERROR_DISCONNECT_COUNT 5
89
90#define ROWS_PER_HAND (MATRIX_ROWS/2)
91
92static uint8_t error_count = 0;
93
94#if ((DIODE_DIRECTION == COL2ROW) || (DIODE_DIRECTION == ROW2COL))
95static uint8_t row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS;
96static uint8_t col_pins[MATRIX_COLS] = MATRIX_COL_PINS;
97#elif (DIODE_DIRECTION == CUSTOM_MATRIX)
98static uint8_t row_col_pins[MATRIX_ROWS][MATRIX_COLS] = MATRIX_ROW_COL_PINS;
99#endif
100
101/* matrix state(1:on, 0:off) */
102static matrix_row_t matrix[MATRIX_ROWS];
103static matrix_row_t matrix_debouncing[MATRIX_ROWS];
104
105#if (DIODE_DIRECTION == COL2ROW)
106 static void init_cols(void);
107 static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row);
108 static void unselect_rows(void);
109 static void select_row(uint8_t row);
110 static void unselect_row(uint8_t row);
111#elif (DIODE_DIRECTION == ROW2COL)
112 static void init_rows(void);
113 static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col);
114 static void unselect_cols(void);
115 static void unselect_col(uint8_t col);
116 static void select_col(uint8_t col);
117#elif (DIODE_DIRECTION == CUSTOM_MATRIX)
118 static void init_cols_rows(void);
119 static bool read_cols(matrix_row_t current_matrix[], uint8_t current_row);
120#endif
121
122__attribute__ ((weak))
123void matrix_init_kb(void) {
124 matrix_init_user();
125}
126
127__attribute__ ((weak))
128void matrix_scan_kb(void) {
129 matrix_scan_user();
130}
131
132__attribute__ ((weak))
133void matrix_init_user(void) {
134}
135
136__attribute__ ((weak))
137void matrix_scan_user(void) {
138}
139
140__attribute__ ((weak))
141void matrix_slave_scan_user(void) {
142}
143
144inline
145uint8_t matrix_rows(void)
146{
147 return MATRIX_ROWS;
148}
149
150inline
151uint8_t matrix_cols(void)
152{
153 return MATRIX_COLS;
154}
155
156void matrix_init(void)
157{
158#ifdef DISABLE_JTAG
159 // JTAG disable for PORT F. write JTD bit twice within four cycles.
160 MCUCR |= (1<<JTD);
161 MCUCR |= (1<<JTD);
162#endif
163
164 debug_enable = true;
165 debug_matrix = true;
166 debug_mouse = true;
167
168 // Set pinout for right half if pinout for that half is defined
169 if (!isLeftHand) {
170#ifdef MATRIX_ROW_PINS_RIGHT
171 const uint8_t row_pins_right[MATRIX_ROWS] = MATRIX_ROW_PINS_RIGHT;
172 for (uint8_t i = 0; i < MATRIX_ROWS; i++)
173 row_pins[i] = row_pins_right[i];
174#endif
175#ifdef MATRIX_COL_PINS_RIGHT
176 const uint8_t col_pins_right[MATRIX_COLS] = MATRIX_COL_PINS_RIGHT;
177 for (uint8_t i = 0; i < MATRIX_COLS; i++)
178 col_pins[i] = col_pins_right[i];
179#endif
180 }
181
182 // initialize row and col
183#if (DIODE_DIRECTION == COL2ROW)
184 unselect_rows();
185 init_cols();
186#elif (DIODE_DIRECTION == ROW2COL)
187 unselect_cols();
188 init_rows();
189#elif (DIODE_DIRECTION == CUSTOM_MATRIX)
190 init_cols_rows();
191#endif
192
193 // initialize matrix state: all keys off
194 for (uint8_t i=0; i < MATRIX_ROWS; i++) {
195 matrix[i] = 0;
196 matrix_debouncing[i] = 0;
197 }
198
199 matrix_init_quantum();
200
201}
202
203uint8_t _matrix_scan(void)
204{
205 int offset = isLeftHand ? 0 : (ROWS_PER_HAND);
206#if (DIODE_DIRECTION == COL2ROW)
207 // Set row, read cols
208 for (uint8_t current_row = 0; current_row < ROWS_PER_HAND; current_row++) {
209# if (DEBOUNCING_DELAY > 0)
210 bool matrix_changed = read_cols_on_row(matrix_debouncing+offset, current_row);
211
212 if (matrix_changed) {
213 debouncing = true;
214 debouncing_time = timer_read();
215 }
216
217# else
218 read_cols_on_row(matrix+offset, current_row);
219# endif
220
221 }
222
223#elif (DIODE_DIRECTION == ROW2COL)
224 // Set col, read rows
225 for (uint8_t current_col = 0; current_col < MATRIX_COLS; current_col++) {
226# if (DEBOUNCING_DELAY > 0)
227 bool matrix_changed = read_rows_on_col(matrix_debouncing+offset, current_col);
228 if (matrix_changed) {
229 debouncing = true;
230 debouncing_time = timer_read();
231 }
232# else
233 read_rows_on_col(matrix+offset, current_col);
234# endif
235
236 }
237
238#elif (DIODE_DIRECTION == CUSTOM_MATRIX)
239 // Set row, read cols
240 for (uint8_t current_row = 0; current_row < ROWS_PER_HAND; current_row++) {
241# if (DEBOUNCING_DELAY > 0)
242 bool matrix_changed = read_cols(matrix_debouncing+offset, current_row);
243 if (matrix_changed) {
244 debouncing = true;
245 debouncing_time = timer_read();
246 }
247# else
248 read_cols(matrix+offset, current_row);
249# endif
250 }
251#endif
252
253# if (DEBOUNCING_DELAY > 0)
254 if (debouncing && (timer_elapsed(debouncing_time) > DEBOUNCING_DELAY)) {
255 for (uint8_t i = 0; i < ROWS_PER_HAND; i++) {
256 matrix[i+offset] = matrix_debouncing[i+offset];
257 }
258 debouncing = false;
259 }
260# endif
261
262 return 1;
263}
264
265#if defined(USE_I2C) || defined(EH)
266
267// Get rows from other half over i2c
268int i2c_transaction(void) {
269 int slaveOffset = (isLeftHand) ? (ROWS_PER_HAND) : 0;
270 int err = 0;
271
272 // write backlight info
273 #ifdef BACKLIGHT_ENABLE
274 if (BACKLIT_DIRTY) {
275 err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_WRITE);
276 if (err) goto i2c_error;
277
278 // Backlight location
279 err = i2c_master_write(I2C_BACKLIT_START);
280 if (err) goto i2c_error;
281
282 // Write backlight
283 i2c_master_write(get_backlight_level());
284
285 BACKLIT_DIRTY = false;
286 }
287 #endif
288
289 err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_WRITE);
290 if (err) goto i2c_error;
291
292 // start of matrix stored at I2C_KEYMAP_START
293 err = i2c_master_write(I2C_KEYMAP_START);
294 if (err) goto i2c_error;
295
296 // Start read
297 err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_READ);
298 if (err) goto i2c_error;
299
300 if (!err) {
301 int i;
302 for (i = 0; i < ROWS_PER_HAND-1; ++i) {
303 matrix[slaveOffset+i] = i2c_master_read(I2C_ACK);
304 }
305 matrix[slaveOffset+i] = i2c_master_read(I2C_NACK);
306 i2c_master_stop();
307 } else {
308i2c_error: // the cable is disconnceted, or something else went wrong
309 i2c_reset_state();
310 return err;
311 }
312
313 #ifdef RGBLIGHT_ENABLE
314 if (RGB_DIRTY) {
315 err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_WRITE);
316 if (err) goto i2c_error;
317
318 // RGB Location
319 err = i2c_master_write(I2C_RGB_START);
320 if (err) goto i2c_error;
321
322 uint32_t dword = eeconfig_read_rgblight();
323
324 // Write RGB
325 err = i2c_master_write_data(&dword, 4);
326 if (err) goto i2c_error;
327
328 RGB_DIRTY = false;
329 i2c_master_stop();
330 }
331 #endif
332
333 return 0;
334}
335
336#else // USE_SERIAL
337
338
339typedef struct _Serial_s2m_buffer_t {
340 // TODO: if MATRIX_COLS > 8 change to uint8_t packed_matrix[] for pack/unpack
341 matrix_row_t smatrix[ROWS_PER_HAND];
342} Serial_s2m_buffer_t;
343
344volatile Serial_s2m_buffer_t serial_s2m_buffer = {};
345volatile Serial_m2s_buffer_t serial_m2s_buffer = {};
346uint8_t volatile status0 = 0;
347
348SSTD_t transactions[] = {
349 { (uint8_t *)&status0,
350 sizeof(serial_m2s_buffer), (uint8_t *)&serial_m2s_buffer,
351 sizeof(serial_s2m_buffer), (uint8_t *)&serial_s2m_buffer
352 }
353};
354
355void serial_master_init(void)
356{ soft_serial_initiator_init(transactions, TID_LIMIT(transactions)); }
357
358void serial_slave_init(void)
359{ soft_serial_target_init(transactions, TID_LIMIT(transactions)); }
360
361int serial_transaction(void) {
362 int slaveOffset = (isLeftHand) ? (ROWS_PER_HAND) : 0;
363
364 if (soft_serial_transaction()) {
365 return 1;
366 }
367
368 // TODO: if MATRIX_COLS > 8 change to unpack()
369 for (int i = 0; i < ROWS_PER_HAND; ++i) {
370 matrix[slaveOffset+i] = serial_s2m_buffer.smatrix[i];
371 }
372
373 #ifdef RGBLIGHT_ENABLE
374 // Code to send RGB over serial goes here (not implemented yet)
375 #endif
376
377 #ifdef BACKLIGHT_ENABLE
378 // Write backlight level for slave to read
379 serial_m2s_buffer.backlight_level = backlight_config.enable ? backlight_config.level : 0;
380 #endif
381
382 return 0;
383}
384#endif
385
386uint8_t matrix_scan(void)
387{
388 uint8_t ret = _matrix_scan();
389
390#if defined(USE_I2C) || defined(EH)
391 if( i2c_transaction() ) {
392#else // USE_SERIAL
393 if( serial_transaction() ) {
394#endif
395
396 error_count++;
397
398 if (error_count > ERROR_DISCONNECT_COUNT) {
399 // reset other half if disconnected
400 int slaveOffset = (isLeftHand) ? (ROWS_PER_HAND) : 0;
401 for (int i = 0; i < ROWS_PER_HAND; ++i) {
402 matrix[slaveOffset+i] = 0;
403 }
404 }
405 } else {
406 error_count = 0;
407 }
408 matrix_scan_quantum();
409 return ret;
410}
411
412void matrix_slave_scan(void) {
413 _matrix_scan();
414
415 int offset = (isLeftHand) ? 0 : ROWS_PER_HAND;
416
417#if defined(USE_I2C) || defined(EH)
418 for (int i = 0; i < ROWS_PER_HAND; ++i) {
419 i2c_slave_buffer[I2C_KEYMAP_START+i] = matrix[offset+i];
420 }
421#else // USE_SERIAL
422 // TODO: if MATRIX_COLS > 8 change to pack()
423 for (int i = 0; i < ROWS_PER_HAND; ++i) {
424 serial_s2m_buffer.smatrix[i] = matrix[offset+i];
425 }
426#endif
427 matrix_slave_scan_user();
428}
429
430bool matrix_is_modified(void)
431{
432 if (debouncing) return false;
433 return true;
434}
435
436inline
437bool matrix_is_on(uint8_t row, uint8_t col)
438{
439 return (matrix[row] & ((matrix_row_t)1<<col));
440}
441
442inline
443matrix_row_t matrix_get_row(uint8_t row)
444{
445 return matrix[row];
446}
447
448void matrix_print(void)
449{
450 print("\nr/c 0123456789ABCDEF\n");
451 for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
452 phex(row); print(": ");
453 pbin_reverse16(matrix_get_row(row));
454 print("\n");
455 }
456}
457
458uint8_t matrix_key_count(void)
459{
460 uint8_t count = 0;
461 for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
462 count += bitpop16(matrix[i]);
463 }
464 return count;
465}
466
467#if (DIODE_DIRECTION == COL2ROW)
468
469static void init_cols(void)
470{
471 for(uint8_t x = 0; x < MATRIX_COLS; x++) {
472 uint8_t pin = col_pins[x];
473 _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN
474 _SFR_IO8((pin >> 4) + 2) |= _BV(pin & 0xF); // HI
475 }
476}
477
478static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row)
479{
480 // Store last value of row prior to reading
481 matrix_row_t last_row_value = current_matrix[current_row];
482
483 // Clear data in matrix row
484 current_matrix[current_row] = 0;
485
486 // Select row and wait for row selecton to stabilize
487 select_row(current_row);
488 wait_us(30);
489
490 // For each col...
491 for(uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++) {
492
493 // Select the col pin to read (active low)
494 uint8_t pin = col_pins[col_index];
495 uint8_t pin_state = (_SFR_IO8(pin >> 4) & _BV(pin & 0xF));
496
497 // Populate the matrix row with the state of the col pin
498 current_matrix[current_row] |= pin_state ? 0 : (ROW_SHIFTER << col_index);
499 }
500
501 // Unselect row
502 unselect_row(current_row);
503
504 return (last_row_value != current_matrix[current_row]);
505}
506
507static void select_row(uint8_t row)
508{
509 uint8_t pin = row_pins[row];
510 _SFR_IO8((pin >> 4) + 1) |= _BV(pin & 0xF); // OUT
511 _SFR_IO8((pin >> 4) + 2) &= ~_BV(pin & 0xF); // LOW
512}
513
514static void unselect_row(uint8_t row)
515{
516 uint8_t pin = row_pins[row];
517 _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN
518 _SFR_IO8((pin >> 4) + 2) |= _BV(pin & 0xF); // HI
519}
520
521static void unselect_rows(void)
522{
523 for(uint8_t x = 0; x < ROWS_PER_HAND; x++) {
524 uint8_t pin = row_pins[x];
525 _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN
526 _SFR_IO8((pin >> 4) + 2) |= _BV(pin & 0xF); // HI
527 }
528}
529
530#elif (DIODE_DIRECTION == ROW2COL)
531
532static void init_rows(void)
533{
534 for(uint8_t x = 0; x < ROWS_PER_HAND; x++) {
535 uint8_t pin = row_pins[x];
536 _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN
537 _SFR_IO8((pin >> 4) + 2) |= _BV(pin & 0xF); // HI
538 }
539}
540
541static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col)
542{
543 bool matrix_changed = false;
544
545 // Select col and wait for col selecton to stabilize
546 select_col(current_col);
547 wait_us(30);
548
549 // For each row...
550 for(uint8_t row_index = 0; row_index < ROWS_PER_HAND; row_index++)
551 {
552
553 // Store last value of row prior to reading
554 matrix_row_t last_row_value = current_matrix[row_index];
555
556 // Check row pin state
557 if ((_SFR_IO8(row_pins[row_index] >> 4) & _BV(row_pins[row_index] & 0xF)) == 0)
558 {
559 // Pin LO, set col bit
560 current_matrix[row_index] |= (ROW_SHIFTER << current_col);
561 }
562 else
563 {
564 // Pin HI, clear col bit
565 current_matrix[row_index] &= ~(ROW_SHIFTER << current_col);
566 }
567
568 // Determine if the matrix changed state
569 if ((last_row_value != current_matrix[row_index]) && !(matrix_changed))
570 {
571 matrix_changed = true;
572 }
573 }
574
575 // Unselect col
576 unselect_col(current_col);
577
578 return matrix_changed;
579}
580
581static void select_col(uint8_t col)
582{
583 uint8_t pin = col_pins[col];
584 _SFR_IO8((pin >> 4) + 1) |= _BV(pin & 0xF); // OUT
585 _SFR_IO8((pin >> 4) + 2) &= ~_BV(pin & 0xF); // LOW
586}
587
588static void unselect_col(uint8_t col)
589{
590 uint8_t pin = col_pins[col];
591 _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN
592 _SFR_IO8((pin >> 4) + 2) |= _BV(pin & 0xF); // HI
593}
594
595static void unselect_cols(void)
596{
597 for(uint8_t x = 0; x < MATRIX_COLS; x++) {
598 uint8_t pin = col_pins[x];
599 _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN
600 _SFR_IO8((pin >> 4) + 2) |= _BV(pin & 0xF); // HI
601 }
602}
603
604#elif (DIODE_DIRECTION == CUSTOM_MATRIX)
605
606static void init_cols_rows(void)
607{
608 for(int row = 0; row < MATRIX_ROWS; row++) {
609 for(int col = 0; col < MATRIX_COLS; col++) {
610 uint8_t pin = row_col_pins[row][col];
611 if(pin == NO_PIN) {
612 continue;
613 }
614 // DDxn set 0 for input
615 _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF);
616 // PORTxn set 1 for input/pullup
617 _SFR_IO8((pin >> 4) + 2) |= _BV(pin & 0xF);
618 }
619 }
620}
621
622static bool read_cols(matrix_row_t current_matrix[], uint8_t current_row)
623{
624 matrix_row_t last_row_value = current_matrix[current_row];
625 current_matrix[current_row] = 0;
626
627 for(uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++) {
628 uint8_t pin = row_col_pins[current_row][col_index];
629 if(pin == NO_PIN) {
630 current_matrix[current_row] |= 0;
631 }
632 else {
633 uint8_t pin_state = (_SFR_IO8(pin >> 4) & _BV(pin & 0xF));
634 current_matrix[current_row] |= pin_state ? 0 : (ROW_SHIFTER << col_index);
635 }
636 }
637
638 return (last_row_value != current_matrix[current_row]);
639}
640
641#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 @@
1SRC += matrix.c
2 1
3# MCU name 2# MCU name
4#MCU = at90usb1286 3#MCU = at90usb1286
@@ -83,6 +82,6 @@ FAUXCLICKY_ENABLE = no # Use buzzer to emulate clicky switches
83HD44780_ENABLE = no # Enable support for HD44780 based LCDs (+400) 82HD44780_ENABLE = no # Enable support for HD44780 based LCDs (+400)
84 83
85DEBUG_ENABLE = no 84DEBUG_ENABLE = no
86CUSTOM_MATRIX = yes # Use custom matrix code 85CUSTOM_MATRIX = no # Use custom matrix code
87SPLIT_KEYBOARD = yes # Use shared split_common code 86SPLIT_KEYBOARD = yes # Use shared split_common code
88 87
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 @@
21#define ROW2COL 1 21#define ROW2COL 1
22#define CUSTOM_MATRIX 2 /* Disables built-in matrix scanning code */ 22#define CUSTOM_MATRIX 2 /* Disables built-in matrix scanning code */
23 23
24// useful for direct pin mapping
25#define NO_PIN (~0)
26
24#ifdef __AVR__ 27#ifdef __AVR__
25 #ifndef __ASSEMBLER__ 28 #ifndef __ASSEMBLER__
26 #include <avr/io.h> 29 #include <avr/io.h>
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 @@
1
2#include "matrix.h"
3#include "timer.h"
4#include "quantum.h"
5
6#ifndef DEBOUNCING_DELAY
7# define DEBOUNCING_DELAY 5
8#endif
9
10void debounce_init(uint8_t num_rows) {
11}
12
13#if DEBOUNCING_DELAY > 0
14
15static bool debouncing = false;
16
17void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) {
18 static uint16_t debouncing_time;
19
20 if (changed) {
21 debouncing = true;
22 debouncing_time = timer_read();
23 }
24
25 if (debouncing && (timer_elapsed(debouncing_time) > DEBOUNCING_DELAY)) {
26 for (uint8_t i = 0; i < num_rows; i++) {
27 cooked[i] = raw[i];
28 }
29 debouncing = false;
30 }
31}
32
33bool debounce_active(void) {
34 return debouncing;
35}
36
37#else
38
39// no debounce
40void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) {
41 if (changed)
42 {
43 for (uint8_t i = 0; i < num_rows; i++) {
44 cooked[i] = raw[i];
45 }
46 }
47}
48
49bool debounce_active(void) {
50 return false;
51}
52#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 @@
1#pragma once
2
3// raw is the current key state
4// on entry cooked is the previous debounced state
5// on exit cooked is the current debounced state
6// changed is true if raw has changed since the last call
7void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed);
8
9bool debounce_active(void);
10
11void 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 <http://www.gnu.org/licenses/>.
21#include "debug.h" 21#include "debug.h"
22#include "util.h" 22#include "util.h"
23#include "matrix.h" 23#include "matrix.h"
24#include "timer.h" 24#include "debounce.h"
25#include "quantum.h" 25#include "quantum.h"
26 26
27
28/* Set 0 if debouncing isn't needed */
29
30#ifndef DEBOUNCING_DELAY
31# define DEBOUNCING_DELAY 5
32#endif
33
34#if (DEBOUNCING_DELAY > 0)
35 static uint16_t debouncing_time;
36 static bool debouncing = false;
37#endif
38
39#if (MATRIX_COLS <= 8) 27#if (MATRIX_COLS <= 8)
40# define print_matrix_header() print("\nr/c 01234567\n") 28# define print_matrix_header() print("\nr/c 01234567\n")
41# define print_matrix_row(row) print_bin_reverse8(matrix_get_row(row)) 29# 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;
63#endif 51#endif
64 52
65/* matrix state(1:on, 0:off) */ 53/* matrix state(1:on, 0:off) */
66static matrix_row_t matrix[MATRIX_ROWS]; 54static matrix_row_t raw_matrix[MATRIX_ROWS];
67 55
68static matrix_row_t matrix_debouncing[MATRIX_ROWS]; 56static matrix_row_t matrix[MATRIX_ROWS];
69 57
70 58
71#if (DIODE_DIRECTION == COL2ROW) 59#if (DIODE_DIRECTION == COL2ROW)
@@ -157,70 +145,39 @@ void matrix_init(void) {
157 145
158 // initialize matrix state: all keys off 146 // initialize matrix state: all keys off
159 for (uint8_t i=0; i < MATRIX_ROWS; i++) { 147 for (uint8_t i=0; i < MATRIX_ROWS; i++) {
148 raw_matrix[i] = 0;
160 matrix[i] = 0; 149 matrix[i] = 0;
161 matrix_debouncing[i] = 0;
162 } 150 }
151 debounce_init(MATRIX_ROWS);
163 152
164 matrix_init_quantum(); 153 matrix_init_quantum();
165} 154}
166 155
167uint8_t matrix_scan(void) 156uint8_t matrix_scan(void)
168{ 157{
158 bool changed = false;
169 159
170#if (DIODE_DIRECTION == COL2ROW) 160#if (DIODE_DIRECTION == COL2ROW)
171 161 // Set row, read cols
172 // Set row, read cols 162 for (uint8_t current_row = 0; current_row < MATRIX_ROWS; current_row++) {
173 for (uint8_t current_row = 0; current_row < MATRIX_ROWS; current_row++) { 163 changed |= read_cols_on_row(raw_matrix, current_row);
174# if (DEBOUNCING_DELAY > 0) 164 }
175 bool matrix_changed = read_cols_on_row(matrix_debouncing, current_row);
176
177 if (matrix_changed) {
178 debouncing = true;
179 debouncing_time = timer_read();
180 }
181
182# else
183 read_cols_on_row(matrix, current_row);
184# endif
185
186 }
187
188#elif (DIODE_DIRECTION == ROW2COL) 165#elif (DIODE_DIRECTION == ROW2COL)
189 166 // Set col, read rows
190 // Set col, read rows 167 for (uint8_t current_col = 0; current_col < MATRIX_COLS; current_col++) {
191 for (uint8_t current_col = 0; current_col < MATRIX_COLS; current_col++) { 168 changed |= read_rows_on_col(raw_matrix, current_col);
192# if (DEBOUNCING_DELAY > 0) 169 }
193 bool matrix_changed = read_rows_on_col(matrix_debouncing, current_col);
194 if (matrix_changed) {
195 debouncing = true;
196 debouncing_time = timer_read();
197 }
198# else
199 read_rows_on_col(matrix, current_col);
200# endif
201
202 }
203
204#endif 170#endif
205 171
206# if (DEBOUNCING_DELAY > 0) 172 debounce(raw_matrix, matrix, MATRIX_ROWS, changed);
207 if (debouncing && (timer_elapsed(debouncing_time) > DEBOUNCING_DELAY)) {
208 for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
209 matrix[i] = matrix_debouncing[i];
210 }
211 debouncing = false;
212 }
213# endif
214 173
215 matrix_scan_quantum(); 174 matrix_scan_quantum();
216 return 1; 175 return 1;
217} 176}
218 177
219bool matrix_is_modified(void) 178bool matrix_is_modified(void)
220{ 179{
221#if (DEBOUNCING_DELAY > 0) 180 if (debounce_active()) return false;
222 if (debouncing) return false;
223#endif
224 return true; 181 return true;
225} 182}
226 183
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 @@
1#ifndef I2C_H 1#pragma once
2#define I2C_H
3 2
4#include <stdint.h> 3#include <stdint.h>
5 4
@@ -58,5 +57,3 @@ extern unsigned char i2c_readNak(void);
58extern unsigned char i2c_read(unsigned char ack); 57extern unsigned char i2c_read(unsigned char ack);
59 58
60#define i2c_read(ack) (ack) ? i2c_readAck() : i2c_readNak(); 59#define i2c_read(ack) (ack) ? i2c_readAck() : i2c_readNak();
61
62#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 <http://www.gnu.org/licenses/>.
25#include "matrix.h" 25#include "matrix.h"
26#include "split_util.h" 26#include "split_util.h"
27#include "config.h" 27#include "config.h"
28#include "timer.h"
29#include "split_flags.h" 28#include "split_flags.h"
30#include "quantum.h" 29#include "quantum.h"
31 30#include "debounce.h"
32#ifdef BACKLIGHT_ENABLE 31#include "transport.h"
33# include "backlight.h"
34 extern backlight_config_t backlight_config;
35#endif
36
37#if defined(USE_I2C) || defined(EH)
38# include "i2c.h"
39#else // USE_SERIAL
40# include "serial.h"
41#endif
42
43#ifndef DEBOUNCING_DELAY
44# define DEBOUNCING_DELAY 5
45#endif
46
47#if (DEBOUNCING_DELAY > 0)
48 static uint16_t debouncing_time;
49 static bool debouncing = false;
50#endif
51
52#if defined(USE_I2C) || defined(EH)
53
54#if (MATRIX_COLS <= 8)
55# define print_matrix_header() print("\nr/c 01234567\n")
56# define print_matrix_row(row) print_bin_reverse8(matrix_get_row(row))
57# define matrix_bitpop(i) bitpop(matrix[i])
58# define ROW_SHIFTER ((uint8_t)1)
59#else
60# error "Currently only supports 8 COLS"
61#endif
62
63#else // USE_SERIAL
64 32
65#if (MATRIX_COLS <= 8) 33#if (MATRIX_COLS <= 8)
66# define print_matrix_header() print("\nr/c 01234567\n") 34# define print_matrix_header() print("\nr/c 01234567\n")
67# define print_matrix_row(row) print_bin_reverse8(matrix_get_row(row)) 35# define print_matrix_row(row) print_bin_reverse8(matrix_get_row(row))
68# define matrix_bitpop(i) bitpop(matrix[i]) 36# define matrix_bitpop(i) bitpop(matrix[i])
69# define ROW_SHIFTER ((uint8_t)1) 37# define ROW_SHIFTER ((uint8_t)1)
70#elif (MATRIX_COLS <= 16) 38#elif (MATRIX_COLS <= 16)
71# define print_matrix_header() print("\nr/c 0123456789ABCDEF\n") 39# define print_matrix_header() print("\nr/c 0123456789ABCDEF\n")
72# define print_matrix_row(row) print_bin_reverse16(matrix_get_row(row)) 40# define print_matrix_row(row) print_bin_reverse16(matrix_get_row(row))
73# define matrix_bitpop(i) bitpop16(matrix[i]) 41# define matrix_bitpop(i) bitpop16(matrix[i])
74# define ROW_SHIFTER ((uint16_t)1) 42# define ROW_SHIFTER ((uint16_t)1)
75#elif (MATRIX_COLS <= 32) 43#elif (MATRIX_COLS <= 32)
76# define print_matrix_header() print("\nr/c 0123456789ABCDEF0123456789ABCDEF\n") 44# define print_matrix_header() print("\nr/c 0123456789ABCDEF0123456789ABCDEF\n")
77# define print_matrix_row(row) print_bin_reverse32(matrix_get_row(row)) 45# define print_matrix_row(row) print_bin_reverse32(matrix_get_row(row))
78# define matrix_bitpop(i) bitpop32(matrix[i]) 46# define matrix_bitpop(i) bitpop32(matrix[i])
79# define ROW_SHIFTER ((uint32_t)1) 47# define ROW_SHIFTER ((uint32_t)1)
80#endif
81
82#endif 48#endif
83static matrix_row_t matrix_debouncing[MATRIX_ROWS];
84 49
85#define ERROR_DISCONNECT_COUNT 5 50#define ERROR_DISCONNECT_COUNT 5
86 51
87#define ROWS_PER_HAND (MATRIX_ROWS/2) 52#define ROWS_PER_HAND (MATRIX_ROWS / 2)
88
89static uint8_t error_count = 0;
90 53
54#ifdef DIRECT_PINS
55static pin_t direct_pins[MATRIX_ROWS][MATRIX_COLS] = DIRECT_PINS;
56#else
91static pin_t row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS; 57static pin_t row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS;
92static pin_t col_pins[MATRIX_COLS] = MATRIX_COL_PINS; 58static pin_t col_pins[MATRIX_COLS] = MATRIX_COL_PINS;
59#endif
93 60
94/* matrix state(1:on, 0:off) */ 61/* matrix state(1:on, 0:off) */
95static matrix_row_t matrix[MATRIX_ROWS]; 62static matrix_row_t matrix[MATRIX_ROWS];
96static matrix_row_t matrix_debouncing[MATRIX_ROWS]; 63static matrix_row_t raw_matrix[ROWS_PER_HAND];
97
98#if (DIODE_DIRECTION == COL2ROW)
99 static void init_cols(void);
100 static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row);
101 static void unselect_rows(void);
102 static void select_row(uint8_t row);
103 static void unselect_row(uint8_t row);
104#elif (DIODE_DIRECTION == ROW2COL)
105 static void init_rows(void);
106 static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col);
107 static void unselect_cols(void);
108 static void unselect_col(uint8_t col);
109 static void select_col(uint8_t col);
110#endif
111 64
112__attribute__ ((weak)) 65// row offsets for each hand
113void matrix_init_kb(void) { 66uint8_t thisHand, thatHand;
114 matrix_init_user();
115}
116 67
117__attribute__ ((weak)) 68// user-defined overridable functions
118void matrix_scan_kb(void) {
119 matrix_scan_user();
120}
121 69
122__attribute__ ((weak)) 70__attribute__((weak)) void matrix_init_kb(void) { matrix_init_user(); }
123void matrix_init_user(void) {
124}
125 71
126__attribute__ ((weak)) 72__attribute__((weak)) void matrix_scan_kb(void) { matrix_scan_user(); }
127void matrix_scan_user(void) {
128}
129 73
130__attribute__ ((weak)) 74__attribute__((weak)) void matrix_init_user(void) {}
131void matrix_slave_scan_user(void) {
132}
133 75
134inline 76__attribute__((weak)) void matrix_scan_user(void) {}
135uint8_t matrix_rows(void)
136{
137 return MATRIX_ROWS;
138}
139 77
140inline 78__attribute__((weak)) void matrix_slave_scan_user(void) {}
141uint8_t matrix_cols(void)
142{
143 return MATRIX_COLS;
144}
145 79
146void matrix_init(void) 80// helper functions
147{
148 debug_enable = true;
149 debug_matrix = true;
150 debug_mouse = true;
151 81
152 // Set pinout for right half if pinout for that half is defined 82inline uint8_t matrix_rows(void) { return MATRIX_ROWS; }
153 if (!isLeftHand) {
154#ifdef MATRIX_ROW_PINS_RIGHT
155 const uint8_t row_pins_right[MATRIX_ROWS] = MATRIX_ROW_PINS_RIGHT;
156 for (uint8_t i = 0; i < MATRIX_ROWS; i++)
157 row_pins[i] = row_pins_right[i];
158#endif
159#ifdef MATRIX_COL_PINS_RIGHT
160 const uint8_t col_pins_right[MATRIX_COLS] = MATRIX_COL_PINS_RIGHT;
161 for (uint8_t i = 0; i < MATRIX_COLS; i++)
162 col_pins[i] = col_pins_right[i];
163#endif
164 }
165 83
166 // initialize row and col 84inline uint8_t matrix_cols(void) { return MATRIX_COLS; }
167#if (DIODE_DIRECTION == COL2ROW)
168 unselect_rows();
169 init_cols();
170#elif (DIODE_DIRECTION == ROW2COL)
171 unselect_cols();
172 init_rows();
173#endif
174 85
175 // initialize matrix state: all keys off 86bool matrix_is_modified(void) {
176 for (uint8_t i=0; i < MATRIX_ROWS; i++) { 87 if (debounce_active()) return false;
177 matrix[i] = 0; 88 return true;
178 matrix_debouncing[i] = 0;
179 }
180
181 matrix_init_quantum();
182
183} 89}
184 90
185uint8_t _matrix_scan(void) 91inline bool matrix_is_on(uint8_t row, uint8_t col) { return (matrix[row] & ((matrix_row_t)1 << col)); }
186{
187 int offset = isLeftHand ? 0 : (ROWS_PER_HAND);
188#if (DIODE_DIRECTION == COL2ROW)
189 // Set row, read cols
190 for (uint8_t current_row = 0; current_row < ROWS_PER_HAND; current_row++) {
191# if (DEBOUNCING_DELAY > 0)
192 bool matrix_changed = read_cols_on_row(matrix_debouncing+offset, current_row);
193
194 if (matrix_changed) {
195 debouncing = true;
196 debouncing_time = timer_read();
197 }
198
199# else
200 read_cols_on_row(matrix+offset, current_row);
201# endif
202
203 }
204 92
205#elif (DIODE_DIRECTION == ROW2COL) 93inline matrix_row_t matrix_get_row(uint8_t row) { return matrix[row]; }
206 // Set col, read rows
207 for (uint8_t current_col = 0; current_col < MATRIX_COLS; current_col++) {
208# if (DEBOUNCING_DELAY > 0)
209 bool matrix_changed = read_rows_on_col(matrix_debouncing+offset, current_col);
210 if (matrix_changed) {
211 debouncing = true;
212 debouncing_time = timer_read();
213 }
214# else
215 read_rows_on_col(matrix+offset, current_col);
216# endif
217 94
218 } 95void matrix_print(void) {
219#endif 96 print_matrix_header();
220 97
221# if (DEBOUNCING_DELAY > 0) 98 for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
222 if (debouncing && (timer_elapsed(debouncing_time) > DEBOUNCING_DELAY)) { 99 phex(row);
223 for (uint8_t i = 0; i < ROWS_PER_HAND; i++) { 100 print(": ");
224 matrix[i+offset] = matrix_debouncing[i+offset]; 101 print_matrix_row(row);
225 } 102 print("\n");
226 debouncing = false; 103 }
227 } 104}
228# endif
229 105
230 return 1; 106uint8_t matrix_key_count(void) {
107 uint8_t count = 0;
108 for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
109 count += matrix_bitpop(i);
110 }
111 return count;
231} 112}
232 113
233#if defined(USE_I2C) || defined(EH) 114// matrix code
234
235// Get rows from other half over i2c
236int i2c_transaction(void) {
237 int slaveOffset = (isLeftHand) ? (ROWS_PER_HAND) : 0;
238 int err = 0;
239
240 // write backlight info
241 #ifdef BACKLIGHT_ENABLE
242 if (BACKLIT_DIRTY) {
243 err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_WRITE);
244 if (err) goto i2c_error;
245
246 // Backlight location
247 err = i2c_master_write(I2C_BACKLIT_START);
248 if (err) goto i2c_error;
249
250 // Write backlight
251 i2c_master_write(get_backlight_level());
252
253 BACKLIT_DIRTY = false;
254 }
255 #endif
256 115
257 err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_WRITE); 116#ifdef DIRECT_PINS
258 if (err) goto i2c_error;
259 117
260 // start of matrix stored at I2C_KEYMAP_START 118static void init_pins(void) {
261 err = i2c_master_write(I2C_KEYMAP_START); 119 for (int row = 0; row < MATRIX_ROWS; row++) {
262 if (err) goto i2c_error; 120 for (int col = 0; col < MATRIX_COLS; col++) {
121 pin_t pin = direct_pins[row][col];
122 if (pin != NO_PIN) {
123 setPinInputHigh(pin);
124 }
125 }
126 }
127}
263 128
264 // Start read 129static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row) {
265 err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_READ); 130 matrix_row_t last_row_value = current_matrix[current_row];
266 if (err) goto i2c_error; 131 current_matrix[current_row] = 0;
267 132
268 if (!err) { 133 for (uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++) {
269 int i; 134 pin_t pin = direct_pins[current_row][col_index];
270 for (i = 0; i < ROWS_PER_HAND-1; ++i) { 135 if (pin != NO_PIN) {
271 matrix[slaveOffset+i] = i2c_master_read(I2C_ACK); 136 current_matrix[current_row] |= readPin(pin) ? 0 : (ROW_SHIFTER << col_index);
272 }
273 matrix[slaveOffset+i] = i2c_master_read(I2C_NACK);
274 i2c_master_stop();
275 } else {
276i2c_error: // the cable is disconnceted, or something else went wrong
277 i2c_reset_state();
278 return err;
279 } 137 }
280 138 }
281 #ifdef RGBLIGHT_ENABLE
282 if (RGB_DIRTY) {
283 err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_WRITE);
284 if (err) goto i2c_error;
285
286 // RGB Location
287 err = i2c_master_write(I2C_RGB_START);
288 if (err) goto i2c_error;
289
290 uint32_t dword = eeconfig_read_rgblight();
291
292 // Write RGB
293 err = i2c_master_write_data(&dword, 4);
294 if (err) goto i2c_error;
295
296 RGB_DIRTY = false;
297 i2c_master_stop();
298 }
299 #endif
300 139
301 return 0; 140 return (last_row_value != current_matrix[current_row]);
302} 141}
303 142
304#else // USE_SERIAL 143#elif (DIODE_DIRECTION == COL2ROW)
305
306 144
307typedef struct _Serial_s2m_buffer_t { 145static void select_row(uint8_t row) {
308 // TODO: if MATRIX_COLS > 8 change to uint8_t packed_matrix[] for pack/unpack 146 writePinLow(row_pins[row]);
309 matrix_row_t smatrix[ROWS_PER_HAND]; 147 setPinOutput(row_pins[row]);
310} Serial_s2m_buffer_t; 148}
311 149
312volatile Serial_s2m_buffer_t serial_s2m_buffer = {}; 150static void unselect_row(uint8_t row) { setPinInputHigh(row_pins[row]); }
313volatile Serial_m2s_buffer_t serial_m2s_buffer = {};
314uint8_t volatile status0 = 0;
315 151
316SSTD_t transactions[] = { 152static void unselect_rows(void) {
317 { (uint8_t *)&status0, 153 for (uint8_t x = 0; x < ROWS_PER_HAND; x++) {
318 sizeof(serial_m2s_buffer), (uint8_t *)&serial_m2s_buffer, 154 setPinInputHigh(row_pins[x]);
319 sizeof(serial_s2m_buffer), (uint8_t *)&serial_s2m_buffer
320 } 155 }
321}; 156}
322 157
323void serial_master_init(void) 158static void init_pins(void) {
324{ soft_serial_initiator_init(transactions, TID_LIMIT(transactions)); } 159 unselect_rows();
160 for (uint8_t x = 0; x < MATRIX_COLS; x++) {
161 setPinInputHigh(col_pins[x]);
162 }
163}
325 164
326void serial_slave_init(void) 165static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row) {
327{ soft_serial_target_init(transactions, TID_LIMIT(transactions)); } 166 // Store last value of row prior to reading
167 matrix_row_t last_row_value = current_matrix[current_row];
328 168
329int serial_transaction(void) { 169 // Clear data in matrix row
330 int slaveOffset = (isLeftHand) ? (ROWS_PER_HAND) : 0; 170 current_matrix[current_row] = 0;
331 171
332 if (soft_serial_transaction()) { 172 // Select row and wait for row selecton to stabilize
333 return 1; 173 select_row(current_row);
334 } 174 wait_us(30);
335 175
336 // TODO: if MATRIX_COLS > 8 change to unpack() 176 // For each col...
337 for (int i = 0; i < ROWS_PER_HAND; ++i) { 177 for (uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++) {
338 matrix[slaveOffset+i] = serial_s2m_buffer.smatrix[i]; 178 // Populate the matrix row with the state of the col pin
339 } 179 current_matrix[current_row] |= readPin(col_pins[col_index]) ? 0 : (ROW_SHIFTER << col_index);
340 180 }
341 #if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
342 // Code to send RGB over serial goes here (not implemented yet)
343 #endif
344
345 #ifdef BACKLIGHT_ENABLE
346 // Write backlight level for slave to read
347 serial_m2s_buffer.backlight_level = backlight_config.enable ? backlight_config.level : 0;
348 #endif
349
350 return 0;
351}
352#endif
353 181
354uint8_t matrix_scan(void) 182 // Unselect row
355{ 183 unselect_row(current_row);
356 uint8_t ret = _matrix_scan();
357 184
358#if defined(USE_I2C) || defined(EH) 185 return (last_row_value != current_matrix[current_row]);
359 if( i2c_transaction() ) { 186}
360#else // USE_SERIAL
361 if( serial_transaction() ) {
362#endif
363 187
364 error_count++; 188#elif (DIODE_DIRECTION == ROW2COL)
365 189
366 if (error_count > ERROR_DISCONNECT_COUNT) { 190static void select_col(uint8_t col) {
367 // reset other half if disconnected 191 writePinLow(col_pins[col]);
368 int slaveOffset = (isLeftHand) ? (ROWS_PER_HAND) : 0; 192 setPinOutput(col_pins[col]);
369 for (int i = 0; i < ROWS_PER_HAND; ++i) {
370 matrix[slaveOffset+i] = 0;
371 }
372 }
373 } else {
374 error_count = 0;
375 }
376 matrix_scan_quantum();
377 return ret;
378} 193}
379 194
380void matrix_slave_scan(void) { 195static void unselect_col(uint8_t col) { setPinInputHigh(col_pins[col]); }
381 _matrix_scan();
382
383 int offset = (isLeftHand) ? 0 : ROWS_PER_HAND;
384 196
385#if defined(USE_I2C) || defined(EH) 197static void unselect_cols(void) {
386 for (int i = 0; i < ROWS_PER_HAND; ++i) { 198 for (uint8_t x = 0; x < MATRIX_COLS; x++) {
387 i2c_slave_buffer[I2C_KEYMAP_START+i] = matrix[offset+i]; 199 setPinInputHigh(col_pins[x]);
388 } 200 }
389#else // USE_SERIAL
390 // TODO: if MATRIX_COLS > 8 change to pack()
391 for (int i = 0; i < ROWS_PER_HAND; ++i) {
392 serial_s2m_buffer.smatrix[i] = matrix[offset+i];
393 }
394#endif
395 matrix_slave_scan_user();
396} 201}
397 202
398bool matrix_is_modified(void) 203static void init_pins(void) {
399{ 204 unselect_cols();
400 if (debouncing) return false; 205 for (uint8_t x = 0; x < ROWS_PER_HAND; x++) {
401 return true; 206 setPinInputHigh(row_pins[x]);
207 }
402} 208}
403 209
404inline 210static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col) {
405bool matrix_is_on(uint8_t row, uint8_t col) 211 bool matrix_changed = false;
406{
407 return (matrix[row] & ((matrix_row_t)1<<col));
408}
409 212
410inline 213 // Select col and wait for col selecton to stabilize
411matrix_row_t matrix_get_row(uint8_t row) 214 select_col(current_col);
412{ 215 wait_us(30);
413 return matrix[row]; 216
414} 217 // For each row...
218 for (uint8_t row_index = 0; row_index < ROWS_PER_HAND; row_index++) {
219 // Store last value of row prior to reading
220 matrix_row_t last_row_value = current_matrix[row_index];
415 221
416void matrix_print(void) 222 // Check row pin state
417{ 223 if (readPin(row_pins[row_index])) {
418 print("\nr/c 0123456789ABCDEF\n"); 224 // Pin HI, clear col bit
419 for (uint8_t row = 0; row < MATRIX_ROWS; row++) { 225 current_matrix[row_index] &= ~(ROW_SHIFTER << current_col);
420 phex(row); print(": "); 226 } else {
421 pbin_reverse16(matrix_get_row(row)); 227 // Pin LO, set col bit
422 print("\n"); 228 current_matrix[row_index] |= (ROW_SHIFTER << current_col);
423 } 229 }
424}
425 230
426uint8_t matrix_key_count(void) 231 // Determine if the matrix changed state
427{ 232 if ((last_row_value != current_matrix[row_index]) && !(matrix_changed)) {
428 uint8_t count = 0; 233 matrix_changed = true;
429 for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
430 count += bitpop16(matrix[i]);
431 } 234 }
432 return count; 235 }
433}
434 236
435#if (DIODE_DIRECTION == COL2ROW) 237 // Unselect col
238 unselect_col(current_col);
436 239
437static void init_cols(void) 240 return matrix_changed;
438{
439 for(uint8_t x = 0; x < MATRIX_COLS; x++) {
440 setPinInputHigh(col_pins[x]);
441 }
442} 241}
443 242
444static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row) 243#endif
445{
446 // Store last value of row prior to reading
447 matrix_row_t last_row_value = current_matrix[current_row];
448
449 // Clear data in matrix row
450 current_matrix[current_row] = 0;
451 244
452 // Select row and wait for row selecton to stabilize 245void matrix_init(void) {
453 select_row(current_row); 246 debug_enable = true;
454 wait_us(30); 247 debug_matrix = true;
248 debug_mouse = true;
455 249
456 // For each col... 250 // Set pinout for right half if pinout for that half is defined
457 for(uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++) { 251 if (!isLeftHand) {
458 // Populate the matrix row with the state of the col pin 252#ifdef MATRIX_ROW_PINS_RIGHT
459 current_matrix[current_row] |= readPin(col_pins[col_index]) ? 0 : (ROW_SHIFTER << col_index); 253 const uint8_t row_pins_right[MATRIX_ROWS] = MATRIX_ROW_PINS_RIGHT;
254 for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
255 row_pins[i] = row_pins_right[i];
460 } 256 }
257#endif
258#ifdef MATRIX_COL_PINS_RIGHT
259 const uint8_t col_pins_right[MATRIX_COLS] = MATRIX_COL_PINS_RIGHT;
260 for (uint8_t i = 0; i < MATRIX_COLS; i++) {
261 col_pins[i] = col_pins_right[i];
262 }
263#endif
264 }
461 265
462 // Unselect row 266 thisHand = isLeftHand ? 0 : (ROWS_PER_HAND);
463 unselect_row(current_row); 267 thatHand = ROWS_PER_HAND - thisHand;
464 268
465 return (last_row_value != current_matrix[current_row]); 269 // initialize key pins
466} 270 init_pins();
467 271
468static void select_row(uint8_t row) 272 // initialize matrix state: all keys off
469{ 273 for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
470 writePinLow(row_pins[row]); 274 matrix[i] = 0;
471 setPinOutput(row_pins[row]); 275 }
472}
473 276
474static void unselect_row(uint8_t row) 277 debounce_init(ROWS_PER_HAND);
475{
476 setPinInputHigh(row_pins[row]);
477}
478 278
479static void unselect_rows(void) 279 matrix_init_quantum();
480{
481 for(uint8_t x = 0; x < ROWS_PER_HAND; x++) {
482 setPinInputHigh(row_pins[x]);
483 }
484} 280}
485 281
282uint8_t _matrix_scan(void) {
283 bool changed = false;
284
285#if defined(DIRECT_PINS) || (DIODE_DIRECTION == COL2ROW)
286 // Set row, read cols
287 for (uint8_t current_row = 0; current_row < ROWS_PER_HAND; current_row++) {
288 changed |= read_cols_on_row(raw_matrix, current_row);
289 }
486#elif (DIODE_DIRECTION == ROW2COL) 290#elif (DIODE_DIRECTION == ROW2COL)
291 // Set col, read rows
292 for (uint8_t current_col = 0; current_col < MATRIX_COLS; current_col++) {
293 changed |= read_rows_on_col(raw_matrix, current_col);
294 }
295#endif
487 296
488static void init_rows(void) 297 debounce(raw_matrix, matrix + thisHand, ROWS_PER_HAND, changed);
489{
490 for(uint8_t x = 0; x < ROWS_PER_HAND; x++) {
491 setPinInputHigh(row_pins[x]);
492 }
493}
494 298
495static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col) 299 return 1;
496{ 300}
497 bool matrix_changed = false;
498 301
499 // Select col and wait for col selecton to stabilize 302uint8_t matrix_scan(void) {
500 select_col(current_col); 303 uint8_t ret = _matrix_scan();
501 wait_us(30);
502 304
503 // For each row... 305 if (is_keyboard_master()) {
504 for(uint8_t row_index = 0; row_index < ROWS_PER_HAND; row_index++) 306 static uint8_t error_count;
505 {
506 307
507 // Store last value of row prior to reading 308 if (!transport_master(matrix + thatHand)) {
508 matrix_row_t last_row_value = current_matrix[row_index]; 309 error_count++;
509 310
510 // Check row pin state 311 if (error_count > ERROR_DISCONNECT_COUNT) {
511 if (readPin(row_pins[row_index])) 312 // reset other half if disconnected
512 { 313 for (int i = 0; i < ROWS_PER_HAND; ++i) {
513 // Pin HI, clear col bit 314 matrix[thatHand + i] = 0;
514 current_matrix[row_index] &= ~(ROW_SHIFTER << current_col);
515 }
516 else
517 {
518 // Pin LO, set col bit
519 current_matrix[row_index] |= (ROW_SHIFTER << current_col);
520 }
521
522 // Determine if the matrix changed state
523 if ((last_row_value != current_matrix[row_index]) && !(matrix_changed))
524 {
525 matrix_changed = true;
526 } 315 }
316 }
317 } else {
318 error_count = 0;
527 } 319 }
528 320
529 // Unselect col 321 matrix_scan_quantum();
530 unselect_col(current_col); 322 } else {
531 323 transport_slave(matrix + thisHand);
532 return matrix_changed; 324 matrix_slave_scan_user();
533} 325 }
534
535static void select_col(uint8_t col)
536{
537 writePinLow(col_pins[col]);
538 setPinOutput(col_pins[col]);
539}
540
541static void unselect_col(uint8_t col)
542{
543 setPinInputHigh(col_pins[col]);
544}
545 326
546static void unselect_cols(void) 327 return ret;
547{
548 for(uint8_t x = 0; x < MATRIX_COLS; x++) {
549 setPinInputHigh(col_pins[x]);
550 }
551} 328}
552
553#endif
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 @@
1#ifndef SPLIT_COMMON_MATRIX_H 1#pragma once
2#define SPLIT_COMMON_MATRIX_H
3 2
4#include <common/matrix.h> 3#include <common/matrix.h>
5
6#ifdef RGBLIGHT_ENABLE
7# include "rgblight.h"
8#endif
9
10typedef struct _Serial_m2s_buffer_t {
11#ifdef BACKLIGHT_ENABLE
12 uint8_t backlight_level;
13#endif
14#if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
15 rgblight_config_t rgblight_config; //not yet use
16 //
17 // When MCUs on both sides drive their respective RGB LED chains,
18 // it is necessary to synchronize, so it is necessary to communicate RGB information.
19 // In that case, define the RGBLIGHT_SPLIT macro.
20 //
21 // Otherwise, if the master side MCU drives both sides RGB LED chains,
22 // there is no need to communicate.
23#endif
24} Serial_m2s_buffer_t;
25
26extern volatile Serial_m2s_buffer_t serial_m2s_buffer;
27
28void serial_master_init(void);
29void serial_slave_init(void);
30
31#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 @@
1#ifndef SOFT_SERIAL_H 1#pragma once
2#define SOFT_SERIAL_H
3 2
4#include <stdbool.h> 3#include <stdbool.h>
5 4
@@ -61,5 +60,3 @@ int soft_serial_transaction(int sstd_index);
61#ifdef SERIAL_USE_MULTI_TRANSACTION 60#ifdef SERIAL_USE_MULTI_TRANSACTION
62int soft_serial_get_and_clean_status(int sstd_index); 61int soft_serial_get_and_clean_status(int sstd_index);
63#endif 62#endif
64
65#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 @@
1#ifndef SPLIT_FLAGS_H 1#pragma once
2#define SPLIT_FLAGS_H
3 2
4#include <stdbool.h> 3#include <stdbool.h>
5#include <stdint.h> 4#include <stdint.h>
6 5
7/** 6/**
8* Global Flags 7* Global Flags
9**/ 8**/
10 9
@@ -14,7 +13,3 @@ extern volatile bool RGB_DIRTY;
14 13
15//Backlight Stuff 14//Backlight Stuff
16extern volatile bool BACKLIT_DIRTY; 15extern volatile bool BACKLIT_DIRTY;
17
18
19
20#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 @@
4#include "config.h" 4#include "config.h"
5#include "timer.h" 5#include "timer.h"
6#include "split_flags.h" 6#include "split_flags.h"
7#include "transport.h"
7#include "quantum.h" 8#include "quantum.h"
8 9
9#ifdef EE_HANDS 10#ifdef EE_HANDS
10# include "tmk_core/common/eeprom.h" 11# include "tmk_core/common/eeprom.h"
11#endif 12# include "eeconfig.h"
12
13#ifdef BACKLIGHT_ENABLE
14# include "backlight.h"
15#endif
16
17#if defined(USE_I2C) || defined(EH)
18# include "i2c.h"
19#endif 13#endif
20 14
21volatile bool isLeftHand = true; 15volatile bool isLeftHand = true;
22 16
23volatile uint8_t setTries = 0; 17__attribute__((weak))
24 18bool is_keyboard_left(void) {
25static void setup_handedness(void) {
26 #ifdef SPLIT_HAND_PIN 19 #ifdef SPLIT_HAND_PIN
27 // Test pin SPLIT_HAND_PIN for High/Low, if low it's right hand 20 // Test pin SPLIT_HAND_PIN for High/Low, if low it's right hand
28 setPinInput(SPLIT_HAND_PIN); 21 setPinInput(SPLIT_HAND_PIN);
29 isLeftHand = readPin(SPLIT_HAND_PIN); 22 return readPin(SPLIT_HAND_PIN);
30 #else 23 #else
31 #ifdef EE_HANDS 24 #ifdef EE_HANDS
32 isLeftHand = eeprom_read_byte(EECONFIG_HANDEDNESS); 25 return eeprom_read_byte(EECONFIG_HANDEDNESS);
33 #else 26 #else
34 #ifdef MASTER_RIGHT 27 #ifdef MASTER_RIGHT
35 isLeftHand = !has_usb(); 28 return !is_keyboard_master();
36 #else 29 #else
37 isLeftHand = has_usb(); 30 return is_keyboard_master();
38 #endif 31 #endif
39 #endif 32 #endif
40 #endif 33 #endif
41} 34}
42 35
43static void keyboard_master_setup(void) { 36bool is_keyboard_master(void)
44#if defined(USE_I2C) || defined(EH) 37{
45 i2c_master_init(); 38#ifdef __AVR__
46 #ifdef SSD1306OLED 39 static enum { UNKNOWN, MASTER, SLAVE } usbstate = UNKNOWN;
47 matrix_master_OLED_init ();
48 #endif
49#else
50 serial_master_init();
51#endif
52 40
53 // For master the Backlight info needs to be sent on startup 41 // only check once, as this is called often
54 // Otherwise the salve won't start with the proper info until an update 42 if (usbstate == UNKNOWN)
55 BACKLIT_DIRTY = true; 43 {
56} 44 USBCON |= (1 << OTGPADE); // enables VBUS pad
45 wait_us(5);
57 46
58static void keyboard_slave_setup(void) { 47 usbstate = (USBSTA & (1 << VBUS)) ? MASTER : SLAVE; // checks state of VBUS
59 timer_init(); 48 }
60#if defined(USE_I2C) || defined(EH) 49
61 i2c_slave_init(SLAVE_I2C_ADDRESS); 50 return (usbstate == MASTER);
62#else 51#else
63 serial_slave_init(); 52 return true;
64#endif 53#endif
65} 54}
66 55
67bool has_usb(void) { 56static void keyboard_master_setup(void) {
68 USBCON |= (1 << OTGPADE); //enables VBUS pad 57#if defined(USE_I2C) || defined(EH)
69 _delay_us(5); 58 #ifdef SSD1306OLED
70 return (USBSTA & (1<<VBUS)); //checks state of VBUS 59 matrix_master_OLED_init ();
71} 60 #endif
72 61#endif
73void split_keyboard_setup(void) { 62 transport_master_init();
74 setup_handedness();
75 63
76 if (has_usb()) { 64 // For master the Backlight info needs to be sent on startup
77 keyboard_master_setup(); 65 // Otherwise the salve won't start with the proper info until an update
78 } else { 66 BACKLIT_DIRTY = true;
79 keyboard_slave_setup();
80 }
81 sei();
82} 67}
83 68
84void keyboard_slave_loop(void) { 69static void keyboard_slave_setup(void)
85 matrix_init(); 70{
86 71 transport_slave_init();
87 //Init RGB
88 #ifdef RGBLIGHT_ENABLE
89 rgblight_init();
90 #endif
91
92 while (1) {
93 // Matrix Slave Scan
94 matrix_slave_scan();
95
96 // Read Backlight Info
97 #ifdef BACKLIGHT_ENABLE
98 #ifdef USE_I2C
99 if (BACKLIT_DIRTY) {
100 backlight_set(i2c_slave_buffer[I2C_BACKLIT_START]);
101 BACKLIT_DIRTY = false;
102 }
103 #else // USE_SERIAL
104 backlight_set(serial_m2s_buffer.backlight_level);
105 #endif
106 #endif
107 // Read RGB Info
108 #ifdef RGBLIGHT_ENABLE
109 #ifdef USE_I2C
110 if (RGB_DIRTY) {
111 // Disable interupts (RGB data is big)
112 cli();
113 // Create new DWORD for RGB data
114 uint32_t dword;
115
116 // Fill the new DWORD with the data that was sent over
117 uint8_t *dword_dat = (uint8_t *)(&dword);
118 for (int i = 0; i < 4; i++) {
119 dword_dat[i] = i2c_slave_buffer[I2C_RGB_START+i];
120 }
121
122 // Update the RGB now with the new data and set RGB_DIRTY to false
123 rgblight_update_dword(dword);
124 RGB_DIRTY = false;
125 // Re-enable interupts now that RGB is set
126 sei();
127 }
128 #else // USE_SERIAL
129 #ifdef RGBLIGHT_SPLIT
130 // Add serial implementation for RGB here
131 #endif
132 #endif
133 #endif
134 }
135} 72}
136 73
137// this code runs before the usb and keyboard is initialized 74// this code runs before the usb and keyboard is initialized
138void matrix_setup(void) { 75void matrix_setup(void)
139 split_keyboard_setup(); 76{
140 77 isLeftHand = is_keyboard_left();
141 if (!has_usb()) { 78
142 //rgblight_init(); 79 if (is_keyboard_master())
143 keyboard_slave_loop(); 80 {
144 } 81 keyboard_master_setup();
82 }
83 else
84 {
85 keyboard_slave_setup();
86 }
145} 87}
diff --git a/quantum/split_common/split_util.h b/quantum/split_common/split_util.h
index d6cf3e72a..20f7535bf 100644
--- a/quantum/split_common/split_util.h
+++ b/quantum/split_common/split_util.h
@@ -1,23 +1,10 @@
1#ifndef SPLIT_KEYBOARD_UTIL_H 1#pragma once
2#define SPLIT_KEYBOARD_UTIL_H
3 2
4#include <stdbool.h> 3#include <stdbool.h>
5#include <stdint.h> 4#include <stdint.h>
6#include <stdio.h> 5#include <stdio.h>
7#include <stdlib.h> 6#include <stdlib.h>
8#include "eeconfig.h"
9
10#define SLAVE_I2C_ADDRESS 0x32
11 7
12extern volatile bool isLeftHand; 8extern volatile bool isLeftHand;
13 9
14// slave version of matix scan, defined in matrix.c
15void matrix_slave_scan(void);
16
17void split_keyboard_setup(void);
18bool has_usb(void);
19void keyboard_slave_loop(void);
20
21void matrix_master_OLED_init (void); 10void matrix_master_OLED_init (void);
22
23#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 @@
1
2#include "config.h"
3#include "matrix.h"
4#include "quantum.h"
5
6#define ROWS_PER_HAND (MATRIX_ROWS/2)
7
8#ifdef RGBLIGHT_ENABLE
9# include "rgblight.h"
10#endif
11
12#ifdef BACKLIGHT_ENABLE
13# include "backlight.h"
14 extern backlight_config_t backlight_config;
15#endif
16
17#if defined(USE_I2C) || defined(EH)
18
19#include "i2c.h"
20
21#ifndef SLAVE_I2C_ADDRESS
22# define SLAVE_I2C_ADDRESS 0x32
23#endif
24
25#if (MATRIX_COLS > 8)
26# error "Currently only supports 8 COLS"
27#endif
28
29// Get rows from other half over i2c
30bool transport_master(matrix_row_t matrix[]) {
31 int err = 0;
32
33 // write backlight info
34#ifdef BACKLIGHT_ENABLE
35 if (BACKLIT_DIRTY) {
36 err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_WRITE);
37 if (err) { goto i2c_error; }
38
39 // Backlight location
40 err = i2c_master_write(I2C_BACKLIT_START);
41 if (err) { goto i2c_error; }
42
43 // Write backlight
44 i2c_master_write(get_backlight_level());
45
46 BACKLIT_DIRTY = false;
47 }
48#endif
49
50 err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_WRITE);
51 if (err) { goto i2c_error; }
52
53 // start of matrix stored at I2C_KEYMAP_START
54 err = i2c_master_write(I2C_KEYMAP_START);
55 if (err) { goto i2c_error; }
56
57 // Start read
58 err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_READ);
59 if (err) { goto i2c_error; }
60
61 if (!err) {
62 int i;
63 for (i = 0; i < ROWS_PER_HAND-1; ++i) {
64 matrix[i] = i2c_master_read(I2C_ACK);
65 }
66 matrix[i] = i2c_master_read(I2C_NACK);
67 i2c_master_stop();
68 } else {
69i2c_error: // the cable is disconnceted, or something else went wrong
70 i2c_reset_state();
71 return false;
72 }
73
74#ifdef RGBLIGHT_ENABLE
75 if (RGB_DIRTY) {
76 err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_WRITE);
77 if (err) { goto i2c_error; }
78
79 // RGB Location
80 err = i2c_master_write(I2C_RGB_START);
81 if (err) { goto i2c_error; }
82
83 uint32_t dword = eeconfig_read_rgblight();
84
85 // Write RGB
86 err = i2c_master_write_data(&dword, 4);
87 if (err) { goto i2c_error; }
88
89 RGB_DIRTY = false;
90 i2c_master_stop();
91 }
92#endif
93
94 return true;
95}
96
97void transport_slave(matrix_row_t matrix[]) {
98
99 for (int i = 0; i < ROWS_PER_HAND; ++i)
100 {
101 i2c_slave_buffer[I2C_KEYMAP_START + i] = matrix[i];
102 }
103 // Read Backlight Info
104 #ifdef BACKLIGHT_ENABLE
105 if (BACKLIT_DIRTY)
106 {
107 backlight_set(i2c_slave_buffer[I2C_BACKLIT_START]);
108 BACKLIT_DIRTY = false;
109 }
110 #endif
111 #ifdef RGBLIGHT_ENABLE
112 if (RGB_DIRTY)
113 {
114 // Disable interupts (RGB data is big)
115 cli();
116 // Create new DWORD for RGB data
117 uint32_t dword;
118
119 // Fill the new DWORD with the data that was sent over
120 uint8_t * dword_dat = (uint8_t *)(&dword);
121 for (int i = 0; i < 4; i++)
122 {
123 dword_dat[i] = i2c_slave_buffer[I2C_RGB_START + i];
124 }
125
126 // Update the RGB now with the new data and set RGB_DIRTY to false
127 rgblight_update_dword(dword);
128 RGB_DIRTY = false;
129 // Re-enable interupts now that RGB is set
130 sei();
131 }
132 #endif
133}
134
135void transport_master_init(void) {
136 i2c_master_init();
137}
138
139void transport_slave_init(void) {
140 i2c_slave_init(SLAVE_I2C_ADDRESS);
141}
142
143#else // USE_SERIAL
144
145#include "serial.h"
146
147typedef struct _Serial_s2m_buffer_t {
148 // TODO: if MATRIX_COLS > 8 change to uint8_t packed_matrix[] for pack/unpack
149 matrix_row_t smatrix[ROWS_PER_HAND];
150} Serial_s2m_buffer_t;
151
152typedef struct _Serial_m2s_buffer_t {
153#ifdef BACKLIGHT_ENABLE
154 uint8_t backlight_level;
155#endif
156#if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
157 rgblight_config_t rgblight_config; //not yet use
158 //
159 // When MCUs on both sides drive their respective RGB LED chains,
160 // it is necessary to synchronize, so it is necessary to communicate RGB information.
161 // In that case, define the RGBLIGHT_SPLIT macro.
162 //
163 // Otherwise, if the master side MCU drives both sides RGB LED chains,
164 // there is no need to communicate.
165#endif
166} Serial_m2s_buffer_t;
167
168volatile Serial_s2m_buffer_t serial_s2m_buffer = {};
169volatile Serial_m2s_buffer_t serial_m2s_buffer = {};
170uint8_t volatile status0 = 0;
171
172SSTD_t transactions[] = {
173 { (uint8_t *)&status0,
174 sizeof(serial_m2s_buffer), (uint8_t *)&serial_m2s_buffer,
175 sizeof(serial_s2m_buffer), (uint8_t *)&serial_s2m_buffer
176 }
177};
178
179void transport_master_init(void)
180{ soft_serial_initiator_init(transactions, TID_LIMIT(transactions)); }
181
182void transport_slave_init(void)
183{ soft_serial_target_init(transactions, TID_LIMIT(transactions)); }
184
185bool transport_master(matrix_row_t matrix[]) {
186
187 if (soft_serial_transaction()) {
188 return false;
189 }
190
191 // TODO: if MATRIX_COLS > 8 change to unpack()
192 for (int i = 0; i < ROWS_PER_HAND; ++i) {
193 matrix[i] = serial_s2m_buffer.smatrix[i];
194 }
195
196 #if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
197 // Code to send RGB over serial goes here (not implemented yet)
198 #endif
199
200 #ifdef BACKLIGHT_ENABLE
201 // Write backlight level for slave to read
202 serial_m2s_buffer.backlight_level = backlight_config.enable ? backlight_config.level : 0;
203 #endif
204
205 return true;
206}
207
208void transport_slave(matrix_row_t matrix[]) {
209
210 // TODO: if MATRIX_COLS > 8 change to pack()
211 for (int i = 0; i < ROWS_PER_HAND; ++i)
212 {
213 serial_s2m_buffer.smatrix[i] = matrix[i];
214 }
215 #ifdef BACKLIGHT_ENABLE
216 backlight_set(serial_m2s_buffer.backlight_level);
217 #endif
218 #if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
219 // Add serial implementation for RGB here
220 #endif
221
222}
223
224#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 @@
1#pragma once
2
3#include <common/matrix.h>
4
5void transport_master_init(void);
6void transport_slave_init(void);
7
8// returns false if valid data not received from slave
9bool transport_master(matrix_row_t matrix[]);
10void 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);
67void keyboard_task(void); 67void keyboard_task(void);
68/* it runs when host LED status is updated */ 68/* it runs when host LED status is updated */
69void keyboard_set_leds(uint8_t leds); 69void keyboard_set_leds(uint8_t leds);
70/* it runs whenever code has to behave differently on a slave */
71bool is_keyboard_master(void);
70 72
71#ifdef __cplusplus 73#ifdef __cplusplus
72} 74}