aboutsummaryrefslogtreecommitdiff
path: root/quantum/split_common
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 /quantum/split_common
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.
Diffstat (limited to 'quantum/split_common')
-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
9 files changed, 494 insertions, 595 deletions
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[]);