Skip to content

Commit d1806a2

Browse files
authored
Split transport mirror (qmk#11046)
* Split transport mirror support * Updated RGB Matrix to respond to electrical events instead of key events * split matrix slave fix
1 parent 1bc8a6e commit d1806a2

12 files changed

+93
-59
lines changed

docs/feature_split_keyboard.md

+6
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,12 @@ communication protocol and may impact the matrix scan speed when enabled.
191191
The purpose of this feature is to support cosmetic use of modifer state (e.g.
192192
displaying status on an OLED screen).
193193
194+
```c
195+
#define SPLIT_TRANSPORT_MIRROR
196+
```
197+
198+
This mirrors the master side matrix to the slave side for features that react or require knowledge of master side key presses on the slave side. This adds a few bytes of data to the split communication protocol and may impact the matrix scan speed when enabled. The purpose of this feature is to support cosmetic use of key events (e.g. RGB reacting to Keypresses).
199+
194200
### Hardware Configuration Options
195201
196202
There are some settings that you may need to configure, based on how the hardware is set up.

docs/ja/understanding_qmk.md

-1
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,6 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
147147
* [`bool process_haptic(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/2cee371bf125a6ec541dd7c5a809573facc7c456/drivers/haptic/haptic.c#L216)
148148
* [`bool process_record_kb(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/keyboards/clueboard/card/card.c#L20)
149149
* [`bool process_record_user(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/keyboards/clueboard/card/keymaps/default/keymap.c#L58)
150-
* [`bool process_rgb_matrix(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/quantum/rgb_matrix.c#L139)
151150
* [`bool process_midi(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/quantum/process_keycode/process_midi.c#L81)
152151
* [`bool process_audio(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/quantum/process_keycode/process_audio.c#L19)
153152
* [`bool process_steno(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/quantum/process_keycode/process_steno.c#L160)

docs/understanding_qmk.md

-1
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,6 @@ The `process_record()` function itself is deceptively simple, but hidden within
142142
* [`bool process_haptic(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/2cee371bf125a6ec541dd7c5a809573facc7c456/drivers/haptic/haptic.c#L216)
143143
* [`bool process_record_kb(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/keyboards/clueboard/card/card.c#L20)
144144
* [`bool process_record_user(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/keyboards/clueboard/card/keymaps/default/keymap.c#L58)
145-
* [`bool process_rgb_matrix(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/quantum/rgb_matrix.c#L139)
146145
* [`bool process_midi(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/quantum/process_keycode/process_midi.c#L81)
147146
* [`bool process_audio(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/quantum/process_keycode/process_audio.c#L19)
148147
* [`bool process_steno(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/quantum/process_keycode/process_steno.c#L160)

quantum/quantum.c

-10
Original file line numberDiff line numberDiff line change
@@ -221,9 +221,6 @@ bool process_record_quantum(keyrecord_t *record) {
221221
#ifdef HAPTIC_ENABLE
222222
process_haptic(keycode, record) &&
223223
#endif // HAPTIC_ENABLE
224-
#if defined(RGB_MATRIX_ENABLE)
225-
process_rgb_matrix(keycode, record) &&
226-
#endif
227224
#if defined(VIA_ENABLE)
228225
process_record_via(keycode, record) &&
229226
#endif
@@ -624,9 +621,6 @@ void matrix_init_quantum() {
624621
#ifdef AUDIO_ENABLE
625622
audio_init();
626623
#endif
627-
#ifdef RGB_MATRIX_ENABLE
628-
rgb_matrix_init();
629-
#endif
630624
#if defined(UNICODE_ENABLE) || defined(UNICODEMAP_ENABLE) || defined(UCIS_ENABLE)
631625
unicode_input_mode_init();
632626
#endif
@@ -681,10 +675,6 @@ void matrix_scan_quantum() {
681675
led_matrix_task();
682676
#endif
683677

684-
#ifdef RGB_MATRIX_ENABLE
685-
rgb_matrix_task();
686-
#endif
687-
688678
#ifdef WPM_ENABLE
689679
decay_wpm();
690680
#endif

quantum/rgb_matrix.c

+9-10
Original file line numberDiff line numberDiff line change
@@ -184,24 +184,25 @@ void rgb_matrix_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) {
184184

185185
void rgb_matrix_set_color_all(uint8_t red, uint8_t green, uint8_t blue) { rgb_matrix_driver.set_color_all(red, green, blue); }
186186

187-
bool process_rgb_matrix(uint16_t keycode, keyrecord_t *record) {
187+
void process_rgb_matrix(uint8_t row, uint8_t col, bool pressed) {
188+
#ifndef RGB_MATRIX_SPLIT
189+
if (!is_keyboard_master()) return;
190+
#endif
188191
#if RGB_DISABLE_TIMEOUT > 0
189-
if (record->event.pressed) {
190-
rgb_anykey_timer = 0;
191-
}
192+
rgb_anykey_timer = 0;
192193
#endif // RGB_DISABLE_TIMEOUT > 0
193194

194195
#ifdef RGB_MATRIX_KEYREACTIVE_ENABLED
195196
uint8_t led[LED_HITS_TO_REMEMBER];
196197
uint8_t led_count = 0;
197198

198199
# if defined(RGB_MATRIX_KEYRELEASES)
199-
if (!record->event.pressed)
200+
if (!pressed)
200201
# elif defined(RGB_MATRIX_KEYPRESSES)
201-
if (record->event.pressed)
202+
if (pressed)
202203
# endif // defined(RGB_MATRIX_KEYRELEASES)
203204
{
204-
led_count = rgb_matrix_map_row_column_to_led(record->event.key.row, record->event.key.col, led);
205+
led_count = rgb_matrix_map_row_column_to_led(row, col, led);
205206
}
206207

207208
if (last_hit_buffer.count + led_count > LED_HITS_TO_REMEMBER) {
@@ -224,11 +225,9 @@ bool process_rgb_matrix(uint16_t keycode, keyrecord_t *record) {
224225

225226
#if defined(RGB_MATRIX_FRAMEBUFFER_EFFECTS) && !defined(DISABLE_RGB_MATRIX_TYPING_HEATMAP)
226227
if (rgb_matrix_config.mode == RGB_MATRIX_TYPING_HEATMAP) {
227-
process_rgb_matrix_typing_heatmap(record);
228+
process_rgb_matrix_typing_heatmap(row, col);
228229
}
229230
#endif // defined(RGB_MATRIX_FRAMEBUFFER_EFFECTS) && !defined(DISABLE_RGB_MATRIX_TYPING_HEATMAP)
230-
231-
return true;
232231
}
233232

234233
void rgb_matrix_test(void) {

quantum/rgb_matrix.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ uint8_t rgb_matrix_map_row_column_to_led(uint8_t row, uint8_t column, uint8_t *l
9898
void rgb_matrix_set_color(int index, uint8_t red, uint8_t green, uint8_t blue);
9999
void rgb_matrix_set_color_all(uint8_t red, uint8_t green, uint8_t blue);
100100

101-
bool process_rgb_matrix(uint16_t keycode, keyrecord_t *record);
101+
void process_rgb_matrix(uint8_t row, uint8_t col, bool pressed);
102102

103103
void rgb_matrix_task(void);
104104

quantum/rgb_matrix_animations/typing_heatmap_anim.h

+1-3
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,7 @@ RGB_MATRIX_EFFECT(TYPING_HEATMAP)
66
# define RGB_MATRIX_TYPING_HEATMAP_DECREASE_DELAY_MS 25
77
# endif
88

9-
void process_rgb_matrix_typing_heatmap(keyrecord_t* record) {
10-
uint8_t row = record->event.key.row;
11-
uint8_t col = record->event.key.col;
9+
void process_rgb_matrix_typing_heatmap(uint8_t row, uint8_t col) {
1210
uint8_t m_row = row - 1;
1311
uint8_t p_row = row + 1;
1412
uint8_t m_col = col - 1;

quantum/split_common/matrix.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ bool matrix_post_scan(void) {
257257
static uint8_t error_count;
258258

259259
matrix_row_t slave_matrix[ROWS_PER_HAND] = {0};
260-
if (!transport_master(slave_matrix)) {
260+
if (!transport_master(matrix + thisHand, slave_matrix)) {
261261
error_count++;
262262

263263
if (error_count > ERROR_DISCONNECT_COUNT) {
@@ -282,7 +282,7 @@ bool matrix_post_scan(void) {
282282

283283
matrix_scan_quantum();
284284
} else {
285-
transport_slave(matrix + thisHand);
285+
transport_slave(matrix + thatHand, matrix + thisHand);
286286

287287
matrix_slave_scan_user();
288288
}

quantum/split_common/transport.c

+28-9
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ static pin_t encoders_pad[] = ENCODERS_PAD_A;
3030
typedef struct _I2C_slave_buffer_t {
3131
# ifndef DISABLE_SYNC_TIMER
3232
uint32_t sync_timer;
33+
# endif
34+
# ifdef SPLIT_TRANSPORT_MIRROR
35+
matrix_row_t mmatrix[ROWS_PER_HAND];
3336
# endif
3437
matrix_row_t smatrix[ROWS_PER_HAND];
3538
# ifdef SPLIT_MODS_ENABLE
@@ -56,7 +59,8 @@ typedef struct _I2C_slave_buffer_t {
5659
static I2C_slave_buffer_t *const i2c_buffer = (I2C_slave_buffer_t *)i2c_slave_reg;
5760

5861
# define I2C_SYNC_TIME_START offsetof(I2C_slave_buffer_t, sync_timer)
59-
# define I2C_KEYMAP_START offsetof(I2C_slave_buffer_t, smatrix)
62+
# define I2C_KEYMAP_MASTER_START offsetof(I2C_slave_buffer_t, mmatrix)
63+
# define I2C_KEYMAP_SLAVE_START offsetof(I2C_slave_buffer_t, smatrix)
6064
# define I2C_REAL_MODS_START offsetof(I2C_slave_buffer_t, real_mods)
6165
# define I2C_WEAK_MODS_START offsetof(I2C_slave_buffer_t, weak_mods)
6266
# define I2C_ONESHOT_MODS_START offsetof(I2C_slave_buffer_t, oneshot_mods)
@@ -72,8 +76,11 @@ static I2C_slave_buffer_t *const i2c_buffer = (I2C_slave_buffer_t *)i2c_slave_re
7276
# endif
7377

7478
// Get rows from other half over i2c
75-
bool transport_master(matrix_row_t matrix[]) {
76-
i2c_readReg(SLAVE_I2C_ADDRESS, I2C_KEYMAP_START, (void *)matrix, sizeof(i2c_buffer->smatrix), TIMEOUT);
79+
bool transport_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
80+
i2c_readReg(SLAVE_I2C_ADDRESS, I2C_KEYMAP_SLAVE_START, (void *)slave_matrix, sizeof(i2c_buffer->smatrix), TIMEOUT);
81+
#ifdef SPLIT_TRANSPORT_MIRROR
82+
i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_KEYMAP_MASTER_START, (void *)master_matrix, sizeof(i2c_buffer->mmatrix), TIMEOUT);
83+
#endif
7784

7885
// write backlight info
7986
# ifdef BACKLIGHT_ENABLE
@@ -141,12 +148,15 @@ bool transport_master(matrix_row_t matrix[]) {
141148
return true;
142149
}
143150

144-
void transport_slave(matrix_row_t matrix[]) {
151+
void transport_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
145152
# ifndef DISABLE_SYNC_TIMER
146153
sync_timer_update(i2c_buffer->sync_timer);
147154
# endif
148155
// Copy matrix to I2C buffer
149-
memcpy((void *)i2c_buffer->smatrix, (void *)matrix, sizeof(i2c_buffer->smatrix));
156+
memcpy((void*)i2c_buffer->smatrix, (void *)slave_matrix, sizeof(i2c_buffer->smatrix));
157+
#ifdef SPLIT_TRANSPORT_MIRROR
158+
memcpy((void*)master_matrix, (void *)i2c_buffer->mmatrix, sizeof(i2c_buffer->mmatrix));
159+
#endif
150160

151161
// Read Backlight Info
152162
# ifdef BACKLIGHT_ENABLE
@@ -207,6 +217,9 @@ typedef struct _Serial_m2s_buffer_t {
207217
# ifndef DISABLE_SYNC_TIMER
208218
uint32_t sync_timer;
209219
# endif
220+
# ifdef SPLIT_TRANSPORT_MIRROR
221+
matrix_row_t mmatrix[ROWS_PER_HAND];
222+
# endif
210223
# ifdef BACKLIGHT_ENABLE
211224
uint8_t backlight_level;
212225
# endif
@@ -289,7 +302,7 @@ void transport_rgblight_slave(void) {
289302
# define transport_rgblight_slave()
290303
# endif
291304

292-
bool transport_master(matrix_row_t matrix[]) {
305+
bool transport_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
293306
# ifndef SERIAL_USE_MULTI_TRANSACTION
294307
if (soft_serial_transaction() != TRANSACTION_END) {
295308
return false;
@@ -303,7 +316,10 @@ bool transport_master(matrix_row_t matrix[]) {
303316

304317
// TODO: if MATRIX_COLS > 8 change to unpack()
305318
for (int i = 0; i < ROWS_PER_HAND; ++i) {
306-
matrix[i] = serial_s2m_buffer.smatrix[i];
319+
slave_matrix[i] = serial_s2m_buffer.smatrix[i];
320+
#ifdef SPLIT_TRANSPORT_MIRROR
321+
serial_m2s_buffer.mmatrix[i] = master_matrix[i];
322+
#endif
307323
}
308324

309325
# ifdef BACKLIGHT_ENABLE
@@ -333,15 +349,18 @@ bool transport_master(matrix_row_t matrix[]) {
333349
return true;
334350
}
335351

336-
void transport_slave(matrix_row_t matrix[]) {
352+
void transport_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
337353
transport_rgblight_slave();
338354
# ifndef DISABLE_SYNC_TIMER
339355
sync_timer_update(serial_m2s_buffer.sync_timer);
340356
# endif
341357

342358
// TODO: if MATRIX_COLS > 8 change to pack()
343359
for (int i = 0; i < ROWS_PER_HAND; ++i) {
344-
serial_s2m_buffer.smatrix[i] = matrix[i];
360+
serial_s2m_buffer.smatrix[i] = slave_matrix[i];
361+
#ifdef SPLIT_TRANSPORT_MIRROR
362+
master_matrix[i] = serial_m2s_buffer.mmatrix[i];
363+
#endif
345364
}
346365
# ifdef BACKLIGHT_ENABLE
347366
backlight_set(serial_m2s_buffer.backlight_level);

quantum/split_common/transport.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,5 @@ void transport_master_init(void);
66
void transport_slave_init(void);
77

88
// returns false if valid data not received from slave
9-
bool transport_master(matrix_row_t matrix[]);
10-
void transport_slave(matrix_row_t matrix[]);
9+
bool transport_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]);
10+
void transport_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]);

tmk_core/common/eeconfig.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
2121
#include <stdbool.h>
2222

2323
#ifndef EECONFIG_MAGIC_NUMBER
24-
# define EECONFIG_MAGIC_NUMBER (uint16_t)0xFEEC
24+
# define EECONFIG_MAGIC_NUMBER (uint16_t)0xFEEB // When changing, decrement this value to avoid future re-init issues
2525
#endif
2626
#define EECONFIG_MAGIC_NUMBER_OFF (uint16_t)0xFFFF
2727

tmk_core/common/keyboard.c

+43-19
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
5454
#ifdef RGBLIGHT_ENABLE
5555
# include "rgblight.h"
5656
#endif
57+
#ifdef RGB_MATRIX_ENABLE
58+
# include "rgb_matrix.h"
59+
#endif
5760
#ifdef ENCODER_ENABLE
5861
# include "encoder.h"
5962
#endif
@@ -304,6 +307,9 @@ void keyboard_init(void) {
304307
#ifdef RGBLIGHT_ENABLE
305308
rgblight_init();
306309
#endif
310+
#ifdef RGB_MATRIX_ENABLE
311+
rgb_matrix_init();
312+
#endif
307313
#ifdef ENCODER_ENABLE
308314
encoder_init();
309315
#endif
@@ -328,6 +334,17 @@ void keyboard_init(void) {
328334
keyboard_post_init_kb(); /* Always keep this last */
329335
}
330336

337+
/** \brief key_event_task
338+
*
339+
* This function is responsible for calling into other systems when they need to respond to electrical switch press events.
340+
* This is differnet than keycode events as no layer processing, or filtering occurs.
341+
*/
342+
void switch_events(uint8_t row, uint8_t col, bool pressed) {
343+
#if defined(RGB_MATRIX_ENABLE)
344+
process_rgb_matrix(row, col, pressed);
345+
#endif
346+
}
347+
331348
/** \brief Keyboard task: Do keyboard routine jobs
332349
*
333350
* Do routine keyboard jobs:
@@ -358,32 +375,35 @@ void keyboard_task(void) {
358375
uint8_t matrix_changed = matrix_scan();
359376
if (matrix_changed) last_matrix_activity_trigger();
360377

361-
if (should_process_keypress()) {
362-
for (uint8_t r = 0; r < MATRIX_ROWS; r++) {
363-
matrix_row = matrix_get_row(r);
364-
matrix_change = matrix_row ^ matrix_prev[r];
365-
if (matrix_change) {
378+
for (uint8_t r = 0; r < MATRIX_ROWS; r++) {
379+
matrix_row = matrix_get_row(r);
380+
matrix_change = matrix_row ^ matrix_prev[r];
381+
if (matrix_change) {
366382
#ifdef MATRIX_HAS_GHOST
367-
if (has_ghost_in_row(r, matrix_row)) {
368-
continue;
369-
}
383+
if (has_ghost_in_row(r, matrix_row)) {
384+
continue;
385+
}
370386
#endif
371-
if (debug_matrix) matrix_print();
372-
matrix_row_t col_mask = 1;
373-
for (uint8_t c = 0; c < MATRIX_COLS; c++, col_mask <<= 1) {
374-
if (matrix_change & col_mask) {
387+
if (debug_matrix) matrix_print();
388+
matrix_row_t col_mask = 1;
389+
for (uint8_t c = 0; c < MATRIX_COLS; c++, col_mask <<= 1) {
390+
if (matrix_change & col_mask) {
391+
if (should_process_keypress()) {
375392
action_exec((keyevent_t){
376393
.key = (keypos_t){.row = r, .col = c}, .pressed = (matrix_row & col_mask), .time = (timer_read() | 1) /* time should not be 0 */
377394
});
378-
// record a processed key
379-
matrix_prev[r] ^= col_mask;
395+
}
396+
// record a processed key
397+
matrix_prev[r] ^= col_mask;
398+
399+
switch_events(r, c, (matrix_row & col_mask));
400+
380401
#ifdef QMK_KEYS_PER_SCAN
381-
// only jump out if we have processed "enough" keys.
382-
if (++keys_processed >= QMK_KEYS_PER_SCAN)
402+
// only jump out if we have processed "enough" keys.
403+
if (++keys_processed >= QMK_KEYS_PER_SCAN)
383404
#endif
384-
// process a key per task call
385-
goto MATRIX_LOOP_END;
386-
}
405+
// process a key per task call
406+
goto MATRIX_LOOP_END;
387407
}
388408
}
389409
}
@@ -405,6 +425,10 @@ void keyboard_task(void) {
405425
rgblight_task();
406426
#endif
407427

428+
#ifdef RGB_MATRIX_ENABLE
429+
rgb_matrix_task();
430+
#endif
431+
408432
#if defined(BACKLIGHT_ENABLE)
409433
# if defined(BACKLIGHT_PIN) || defined(BACKLIGHT_PINS)
410434
backlight_task();

0 commit comments

Comments
 (0)