From 216fedae21d4eb1bba37af54af59150ebf722e6b Mon Sep 17 00:00:00 2001
From: Ryan Caltabiano <rcalt2vt@gmail.com>
Date: Mon, 27 May 2019 11:23:21 -0500
Subject: [PATCH 1/5] Test split common changes for split rgb matrix support.

Update quantum/split_common/transport.c

Co-Authored-By: Drashna Jaelre <drashna@live.com>

Update sync time before bailing

Update quantum/split_common/transport.c

Co-Authored-By: Drashna Jaelre <drashna@live.com>
---
 .../rgbkb/zygomorph/keymaps/xulkal/rules.mk   |  11 +-
 keyboards/rgbkb/zygomorph/rev1/config.h       |   4 +-
 keyboards/rgbkb/zygomorph/rev1/rev1.c         | 102 +++++++-----------
 quantum/quantum.c                             |   3 +
 quantum/quantum.h                             |   1 +
 quantum/rgb_matrix.c                          |  31 +++++-
 quantum/rgb_matrix.h                          |   2 -
 quantum/split_common/matrix.c                 |   9 +-
 quantum/split_common/transport.c              |  42 ++++++--
 quantum/split_common/transport.h              |   4 +-
 tmk_core/common.mk                            |   1 +
 tmk_core/common/keyboard.c                    |  15 ++-
 tmk_core/common/keyboard.h                    |   2 +
 tmk_core/common/sync_timer.c                  |  68 ++++++++++++
 tmk_core/common/sync_timer.h                  |  44 ++++++++
 users/xulkal/config.h                         |   2 +-
 16 files changed, 243 insertions(+), 98 deletions(-)
 create mode 100644 tmk_core/common/sync_timer.c
 create mode 100644 tmk_core/common/sync_timer.h

diff --git a/keyboards/rgbkb/zygomorph/keymaps/xulkal/rules.mk b/keyboards/rgbkb/zygomorph/keymaps/xulkal/rules.mk
index dc687cbbd348..9982b3d4e96f 100644
--- a/keyboards/rgbkb/zygomorph/keymaps/xulkal/rules.mk
+++ b/keyboards/rgbkb/zygomorph/keymaps/xulkal/rules.mk
@@ -8,10 +8,10 @@ EXTRAKEY_ENABLE = yes       # Audio control and System control
 CONSOLE_ENABLE = no         # Console for debug
 COMMAND_ENABLE = no         # Commands for debug and configuration
 NKRO_ENABLE = no            # Nkey Rollover - if this doesn't work, see here: https://github.com/tmk/tmk_keyboard/wiki/FAQ#nkro-doesnt-work
-RGBLIGHT_ENABLE = yes       # Enable global lighting effects. Do not enable with RGB Matrix
-RGBLIGHT_ANIMATIONS = yes   # LED animations
-RGBLIGHT_SPLIT_ENABLE = yes # Split RGBLight Support
-RGB_MATRIX_ENABLE = no      # Enable per-key coordinate based RGB effects. Do not enable with RGBlight
+RGBLIGHT_ENABLE = no        # Enable global lighting effects. Do not enable with RGB Matrix
+RGBLIGHT_ANIMATIONS = no    # LED animations
+RGBLIGHT_SPLIT_ENABLE = no  # Split RGBLight Support
+RGB_MATRIX_ENABLE = WS2812  # Enable per-key coordinate based RGB effects. Do not enable with RGBlight
 RGB_MATRIX_KEYPRESSES = no  # Enable reactive per-key effects.
 RGBLIGHT_FULL_POWER = yes   # Allow maximum RGB brightness. Otherwise, limited to a safe level for a normal USB-A port
 UNICODE_ENABLE = no         # Unicode
@@ -40,3 +40,6 @@ endif
 ifeq ($(strip $(RGBLIGHT_SPLIT_ENABLE)), yes)
     OPT_DEFS += -DRGBLIGHT_SPLIT_ENABLE
 endif
+
+# Xulkal user feature
+OPT_DEFS += -DRGB_MATRIX_EXTRAS
diff --git a/keyboards/rgbkb/zygomorph/rev1/config.h b/keyboards/rgbkb/zygomorph/rev1/config.h
index 6e55a6a5f5dd..5c25ccb05a77 100644
--- a/keyboards/rgbkb/zygomorph/rev1/config.h
+++ b/keyboards/rgbkb/zygomorph/rev1/config.h
@@ -54,7 +54,9 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
     #define RGBLED_NUM 60
     #define RGBLED_SPLIT { 30, 30 }
 #endif
-#define DRIVER_LED_TOTAL 30
+
+#define DRIVER_LED_TOTAL 60
+#define RGB_MATRIX_SPLIT { 30, 30 }
 
 #ifdef IOS_DEVICE_ENABLE
   #define RGBLIGHT_LIMIT_VAL 40
diff --git a/keyboards/rgbkb/zygomorph/rev1/rev1.c b/keyboards/rgbkb/zygomorph/rev1/rev1.c
index 3edf48c5d541..1fb1716a0936 100644
--- a/keyboards/rgbkb/zygomorph/rev1/rev1.c
+++ b/keyboards/rgbkb/zygomorph/rev1/rev1.c
@@ -2,72 +2,42 @@
 
 
 #ifdef RGB_MATRIX_ENABLE
-#define RGB_LEFT_HAND    { { 0 | ( 5 << 4) }, { 102,  0 }, 4}, \
-    { { 0 | ( 4 << 4) }, {  81,  0 }, 4}, \
-    { { 0 | ( 3 << 4) }, {  61,  0 }, 4}, \
-    { { 0 | ( 2 << 4) }, {  41,  0 }, 4}, \
-    { { 0 | ( 1 << 4) }, {  20,  0 }, 4}, \
-    { { 0 | ( 0 << 4) }, {   0,  0 }, 1}, \
-    { { 1 | ( 5 << 4) }, { 102, 16 }, 4}, \
-    { { 1 | ( 4 << 4) }, {  81, 16 }, 4}, \
-    { { 1 | ( 3 << 4) }, {  61, 16 }, 4}, \
-    { { 1 | ( 2 << 4) }, {  41, 16 }, 4}, \
-    { { 1 | ( 1 << 4) }, {  20, 16 }, 4}, \
-    { { 1 | ( 0 << 4) }, {   0, 16 }, 1}, \
-    { { 2 | ( 5 << 4) }, { 102, 32 }, 4}, \
-    { { 2 | ( 4 << 4) }, {  81, 32 }, 4}, \
-    { { 2 | ( 3 << 4) }, {  61, 32 }, 4}, \
-    { { 2 | ( 2 << 4) }, {  41, 32 }, 4}, \
-    { { 2 | ( 1 << 4) }, {  20, 32 }, 4}, \
-    { { 2 | ( 0 << 4) }, {   0, 32 }, 1}, \
-    { { 3 | ( 5 << 4) }, { 102, 48 }, 4}, \
-    { { 3 | ( 4 << 4) }, {  81, 48 }, 4}, \
-    { { 3 | ( 3 << 4) }, {  61, 48 }, 4}, \
-    { { 3 | ( 2 << 4) }, {  41, 48 }, 4}, \
-    { { 3 | ( 1 << 4) }, {  20, 48 }, 4}, \
-    { { 3 | ( 0 << 4) }, {   0, 48 }, 1}, \
-    { { 4 | ( 5 << 4) }, { 102, 64 }, 1}, \
-    { { 4 | ( 4 << 4) }, {  81, 64 }, 1}, \
-    { { 4 | ( 3 << 4) }, {  61, 64 }, 1}, \
-    { { 4 | ( 2 << 4) }, {  41, 64 }, 1}, \
-    { { 4 | ( 1 << 4) }, {  20, 64 }, 1}, \
-    { { 4 | ( 0 << 4) }, {   0, 64 }, 1}
-
-#define RGB_RIGHT_HAND    { { 0 | (11 << 4) }, { 224,  0 }, 1}, \
-    { { 0 | (10 << 4) }, { 204,  0 }, 4}, \
-    { { 0 | ( 9 << 4) }, { 183,  0 }, 4}, \
-    { { 0 | ( 8 << 4) }, { 163,  0 }, 4}, \
-    { { 0 | ( 7 << 4) }, { 143,  0 }, 4}, \
-    { { 0 | ( 6 << 4) }, { 122,  0 }, 4}, \
-    { { 1 | (11 << 4) }, { 224, 16 }, 1}, \
-    { { 1 | (10 << 4) }, { 204, 16 }, 4}, \
-    { { 1 | ( 9 << 4) }, { 183, 16 }, 4}, \
-    { { 1 | ( 8 << 4) }, { 163, 16 }, 4}, \
-    { { 1 | ( 7 << 4) }, { 143, 16 }, 4}, \
-    { { 1 | ( 6 << 4) }, { 122, 16 }, 4}, \
-    { { 2 | (11 << 4) }, { 224, 32 }, 1}, \
-    { { 2 | (10 << 4) }, { 204, 32 }, 4}, \
-    { { 2 | ( 9 << 4) }, { 183, 32 }, 4}, \
-    { { 2 | ( 8 << 4) }, { 163, 32 }, 4}, \
-    { { 2 | ( 7 << 4) }, { 143, 32 }, 4}, \
-    { { 2 | ( 6 << 4) }, { 122, 32 }, 4}, \
-    { { 3 | (11 << 4) }, { 224, 48 }, 1}, \
-    { { 3 | (10 << 4) }, { 204, 48 }, 4}, \
-    { { 3 | ( 9 << 4) }, { 183, 48 }, 4}, \
-    { { 3 | ( 8 << 4) }, { 163, 48 }, 4}, \
-    { { 3 | ( 7 << 4) }, { 143, 48 }, 4}, \
-    { { 3 | ( 6 << 4) }, { 122, 48 }, 4}, \
-    { { 4 | (11 << 4) }, { 224, 64 }, 1}, \
-    { { 4 | (10 << 4) }, { 204, 64 }, 1}, \
-    { { 4 | ( 9 << 4) }, { 183, 64 }, 1}, \
-    { { 4 | ( 8 << 4) }, { 163, 64 }, 1}, \
-    { { 4 | ( 7 << 4) }, { 143, 64 }, 1}, \
-    { { 4 | ( 6 << 4) }, { 122, 64 }, 1}
-
-rgb_led g_rgb_leds[DRIVER_LED_TOTAL] = {
+led_config_t g_led_config = { {
+    {      5,      4,      3,      2,      1,      0 },
+    {     11,     10,      9,      8,      7,      6 },
+    {     17,     16,     15,     14,     13,     12 },
+    {     23,     22,     21,     20,     19,     18 },
+    {     29,     28,     27,     26,     25,     24 },
+    {     35,     34,     33,     32,     31,     30 },
+    {     41,     40,     39,     38,     37,     36 },
+    {     47,     46,     45,     44,     43,     42 },
+    {     53,     52,     51,     50,     49,     48 },
+    {     59,     58,     57,     56,     55,     54 }
+}, {
+// Left Hand
+    { 102,   0 }, {  81,   0 }, {  61,   0 }, {  41,   0 }, {  20,   0 }, {   0,   0 },
+    { 102,  16 }, {  81,  16 }, {  61,  16 }, {  41,  16 }, {  20,  16 }, {   0,  16 },
+    { 102,  32 }, {  81,  32 }, {  61,  32 }, {  41,  32 }, {  20,  32 }, {   0,  32 },
+    { 102,  48 }, {  81,  48 }, {  61,  48 }, {  41,  48 }, {  20,  48 }, {   0,  48 },
+    { 102,  64 }, {  81,  64 }, {  61,  64 }, {  41,  64 }, {  20,  64 }, {   0,  64 },
+// Right Hand
+    { 224,   0 }, { 204,   0 }, { 183,   0 }, { 163,   0 }, { 143,   0 }, { 122,   0 },
+    { 224,  16 }, { 204,  16 }, { 183,  16 }, { 163,  16 }, { 143,  16 }, { 122,  16 },
+    { 224,  32 }, { 204,  32 }, { 183,  32 }, { 163,  32 }, { 143,  32 }, { 122,  32 },
+    { 224,  48 }, { 204,  48 }, { 183,  48 }, { 163,  48 }, { 143,  48 }, { 122,  48 },
+    { 224,  64 }, { 204,  64 }, { 183,  64 }, { 163,  64 }, { 143,  64 }, { 122,  64 }
+}, {
 // Left Hand
-RGB_LEFT_HAND
+    4, 4, 4, 4, 4, 1,
+    4, 4, 4, 4, 4, 1,
+    4, 4, 4, 4, 4, 1,
+    4, 4, 4, 4, 4, 1,
+    1, 1, 1, 1, 1, 1,
 // Right Hand
-//RGB_RIGHT_HAND
-};
+    4, 4, 4, 4, 4, 4,
+    1, 4, 4, 4, 4, 4,
+    1, 4, 4, 4, 4, 4,
+    1, 4, 4, 4, 4, 4,
+    1, 1, 1, 1, 1, 1
+} };
 #endif
diff --git a/quantum/quantum.c b/quantum/quantum.c
index bf159644ab6d..f93cad584008 100644
--- a/quantum/quantum.c
+++ b/quantum/quantum.c
@@ -266,6 +266,9 @@ bool process_record_quantum(keyrecord_t *record) {
     if (record->event.pressed) {
         switch (keycode) {
             case RESET:
+#ifdef SPLIT_KEYBOARD
+                if (is_keyboard_master())
+#endif
                 reset_keyboard();
                 return false;
 #ifndef NO_DEBUG
diff --git a/quantum/quantum.h b/quantum/quantum.h
index 9758374f64ca..d9385f025dba 100644
--- a/quantum/quantum.h
+++ b/quantum/quantum.h
@@ -53,6 +53,7 @@
 #include "eeconfig.h"
 #include "bootloader.h"
 #include "timer.h"
+#include "sync_timer.h"
 #include "config_common.h"
 #include "led.h"
 #include "action_util.h"
diff --git a/quantum/rgb_matrix.c b/quantum/rgb_matrix.c
index 9bbeff833269..6e276bb7c6a0 100644
--- a/quantum/rgb_matrix.c
+++ b/quantum/rgb_matrix.c
@@ -111,6 +111,13 @@ last_hit_t        g_last_hit_tracker;
 static last_hit_t last_hit_buffer;
 #endif  // RGB_MATRIX_KEYREACTIVE_ENABLED
 
+// Extern driver internally, driver should not be used directly
+extern const rgb_matrix_driver_t rgb_matrix_driver;
+
+#ifdef RGB_MATRIX_SPLIT
+const uint8_t k_rgb_matrix_split[2] = RGB_MATRIX_SPLIT;
+#endif
+
 void eeconfig_read_rgb_matrix(void) { eeprom_read_block(&rgb_matrix_config, EECONFIG_RGB_MATRIX, sizeof(rgb_matrix_config)); }
 
 void eeconfig_update_rgb_matrix(void) { eeprom_update_block(&rgb_matrix_config, EECONFIG_RGB_MATRIX, sizeof(rgb_matrix_config)); }
@@ -148,9 +155,23 @@ uint8_t rgb_matrix_map_row_column_to_led(uint8_t row, uint8_t column, uint8_t *l
 
 void rgb_matrix_update_pwm_buffers(void) { rgb_matrix_driver.flush(); }
 
-void rgb_matrix_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) { rgb_matrix_driver.set_color(index, red, green, blue); }
+void rgb_matrix_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) {
+#ifdef RGB_MATRIX_SPLIT
+    if (!is_keyboard_left() && index >= k_rgb_matrix_split[0])
+        rgb_matrix_driver.set_color(index - k_rgb_matrix_split[0], red, green, blue);
+    else if (is_keyboard_left() && index < k_rgb_matrix_split[0])
+#endif
+    rgb_matrix_driver.set_color(index, red, green, blue);
+}
 
-void rgb_matrix_set_color_all(uint8_t red, uint8_t green, uint8_t blue) { rgb_matrix_driver.set_color_all(red, green, blue); }
+void rgb_matrix_set_color_all(uint8_t red, uint8_t green, uint8_t blue) {
+#ifdef RGB_MATRIX_SPLIT
+    for (uint8_t i = 0; i < DRIVER_LED_TOTAL; i++)
+        rgb_matrix_set_color(i, red, green, blue);
+#else
+    rgb_matrix_driver.set_color_all(red, green, blue);
+#endif
+}
 
 bool process_rgb_matrix(uint16_t keycode, keyrecord_t *record) {
 #ifdef RGB_MATRIX_KEYREACTIVE_ENABLED
@@ -239,8 +260,8 @@ static rgb_task_states rgb_task_state    = SYNCING;
 
 static void rgb_task_timers(void) {
     // Update double buffer timers
-    uint16_t deltaTime  = timer_elapsed32(rgb_counters_buffer);
-    rgb_counters_buffer = timer_read32();
+    uint16_t deltaTime  = sync_timer_elapsed32(rgb_counters_buffer);
+    rgb_counters_buffer = sync_timer_read32();
     if (g_rgb_counters.any_key_hit < UINT32_MAX) {
         if (UINT32_MAX - deltaTime < g_rgb_counters.any_key_hit) {
             g_rgb_counters.any_key_hit = UINT32_MAX;
@@ -264,7 +285,7 @@ static void rgb_task_timers(void) {
 
 static void rgb_task_sync(void) {
     // next task
-    if (timer_elapsed32(g_rgb_counters.tick) >= RGB_MATRIX_LED_FLUSH_LIMIT) rgb_task_state = STARTING;
+    if (sync_timer_elapsed32(g_rgb_counters.tick) >= RGB_MATRIX_LED_FLUSH_LIMIT) rgb_task_state = STARTING;
 }
 
 static void rgb_task_start(void) {
diff --git a/quantum/rgb_matrix.h b/quantum/rgb_matrix.h
index 96494836ee42..0fa29308755a 100644
--- a/quantum/rgb_matrix.h
+++ b/quantum/rgb_matrix.h
@@ -161,8 +161,6 @@ typedef struct {
     void (*flush)(void);
 } rgb_matrix_driver_t;
 
-extern const rgb_matrix_driver_t rgb_matrix_driver;
-
 extern rgb_config_t rgb_matrix_config;
 
 extern bool           g_suspend_state;
diff --git a/quantum/split_common/matrix.c b/quantum/split_common/matrix.c
index 58602af859dc..06f7ddcaa1a4 100644
--- a/quantum/split_common/matrix.c
+++ b/quantum/split_common/matrix.c
@@ -235,7 +235,7 @@ void matrix_post_scan(void) {
     if (is_keyboard_master()) {
         static uint8_t error_count;
 
-        if (!transport_master(matrix + thatHand)) {
+        if (!transport_master(matrix + thisHand, matrix + thatHand)) {
             error_count++;
 
             if (error_count > ERROR_DISCONNECT_COUNT) {
@@ -250,11 +250,8 @@ void matrix_post_scan(void) {
 
         matrix_scan_quantum();
     } else {
-        transport_slave(matrix + thisHand);
-#ifdef ENCODER_ENABLE
-        encoder_read();
-#endif
-        matrix_slave_scan_user();
+        transport_slave(matrix + thatHand, matrix + thisHand);
+        matrix_scan_quantum();
     }
 }
 
diff --git a/quantum/split_common/transport.c b/quantum/split_common/transport.c
index ab421adc4a48..12d48cfff897 100644
--- a/quantum/split_common/transport.c
+++ b/quantum/split_common/transport.c
@@ -27,6 +27,8 @@ static pin_t encoders_pad[] = ENCODERS_PAD_A;
 #    include "i2c_slave.h"
 
 typedef struct _I2C_slave_buffer_t {
+    uint32_t     sync_time;
+    matrix_row_t mmatrix[ROWS_PER_HAND];
     matrix_row_t smatrix[ROWS_PER_HAND];
     uint8_t      backlight_level;
 #    if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
@@ -41,7 +43,9 @@ static I2C_slave_buffer_t *const i2c_buffer = (I2C_slave_buffer_t *)i2c_slave_re
 
 #    define I2C_BACKLIGHT_START offsetof(I2C_slave_buffer_t, backlight_level)
 #    define I2C_RGB_START offsetof(I2C_slave_buffer_t, rgblight_sync)
-#    define I2C_KEYMAP_START offsetof(I2C_slave_buffer_t, smatrix)
+#    define I2C_SYNC_TIME_START offsetof(I2C_slave_buffer_t, sync_time)
+#    define I2C_KEYMAP_MASTER_START offsetof(I2C_slave_buffer_t, mmatrix)
+#    define I2C_KEYMAP_SLAVE_START offsetof(I2C_slave_buffer_t, smatrix)
 #    define I2C_ENCODER_START offsetof(I2C_slave_buffer_t, encoder_state)
 
 #    define TIMEOUT 100
@@ -51,8 +55,9 @@ static I2C_slave_buffer_t *const i2c_buffer = (I2C_slave_buffer_t *)i2c_slave_re
 #    endif
 
 // Get rows from other half over i2c
-bool transport_master(matrix_row_t matrix[]) {
-    i2c_readReg(SLAVE_I2C_ADDRESS, I2C_KEYMAP_START, (void *)matrix, sizeof(i2c_buffer->smatrix), TIMEOUT);
+bool transport_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
+    i2c_readReg(SLAVE_I2C_ADDRESS, I2C_KEYMAP_SLAVE_START, (void *)slave_matrix, sizeof(i2c_buffer->smatrix), TIMEOUT);
+    i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_KEYMAP_MASTER_START, (void *)master_matrix, sizeof(i2c_buffer->mmatrix), TIMEOUT);
 
     // write backlight info
 #    ifdef BACKLIGHT_ENABLE
@@ -79,12 +84,18 @@ bool transport_master(matrix_row_t matrix[]) {
     encoder_update_raw(i2c_buffer->encoder_state);
 #    endif
 
+    i2c_buffer->sync_time = timer_read32();
+    sync_timer_update(i2c_buffer->sync_time);
+    i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_SYNC_TIME_START, (void *)&i2c_buffer->sync_time, sizeof(i2c_buffer->sync_time), TIMEOUT);
     return true;
 }
 
-void transport_slave(matrix_row_t matrix[]) {
+void transport_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
+    sync_timer_update(i2c_buffer->sync_time + 1); // 1ms offset to account for tansfer speed
+
     // Copy matrix to I2C buffer
-    memcpy((void *)i2c_buffer->smatrix, (void *)matrix, sizeof(i2c_buffer->smatrix));
+    memcpy((void*)i2c_buffer->smatrix, (void *)slave_matrix, sizeof(i2c_buffer->smatrix));
+    memcpy((void*)master_matrix, (void *)i2c_buffer->mmatrix, sizeof(i2c_buffer->mmatrix));
 
 // Read Backlight Info
 #    ifdef BACKLIGHT_ENABLE
@@ -123,6 +134,10 @@ typedef struct _Serial_s2m_buffer_t {
 } Serial_s2m_buffer_t;
 
 typedef struct _Serial_m2s_buffer_t {
+    matrix_row_t mmatrix[ROWS_PER_HAND];
+
+    uint32_t sync_timer;
+
 #    ifdef BACKLIGHT_ENABLE
     uint8_t backlight_level;
 #    endif
@@ -202,7 +217,8 @@ void transport_rgblight_slave(void) {
 #        define transport_rgblight_slave()
 #    endif
 
-bool transport_master(matrix_row_t matrix[]) {
+bool transport_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
+    sync_timer_update(timer_read32());
 #    ifndef SERIAL_USE_MULTI_TRANSACTION
     if (soft_serial_transaction() != TRANSACTION_END) {
         return false;
@@ -216,7 +232,8 @@ bool transport_master(matrix_row_t matrix[]) {
 
     // TODO:  if MATRIX_COLS > 8 change to unpack()
     for (int i = 0; i < ROWS_PER_HAND; ++i) {
-        matrix[i] = serial_s2m_buffer.smatrix[i];
+        slave_matrix[i] = serial_s2m_buffer.smatrix[i];
+        serial_m2s_buffer.mmatrix[i] = master_matrix[i];
     }
 
 #    ifdef BACKLIGHT_ENABLE
@@ -228,15 +245,22 @@ bool transport_master(matrix_row_t matrix[]) {
     encoder_update_raw((uint8_t *)serial_s2m_buffer.encoder_state);
 #    endif
 
+    sync_timer_update(timer_read32());
+    serial_m2s_buffer.sync_timer = sync_timer_read32();
     return true;
 }
 
-void transport_slave(matrix_row_t matrix[]) {
+void transport_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
     transport_rgblight_slave();
+
+    sync_timer_update(serial_m2s_buffer.sync_timer + 2);  // 2ms offset to account for tansfer speed
+
     // TODO: if MATRIX_COLS > 8 change to pack()
     for (int i = 0; i < ROWS_PER_HAND; ++i) {
-        serial_s2m_buffer.smatrix[i] = matrix[i];
+        serial_s2m_buffer.smatrix[i] = slave_matrix[i];
+        master_matrix[i] = serial_m2s_buffer.mmatrix[i];
     }
+
 #    ifdef BACKLIGHT_ENABLE
     backlight_set(serial_m2s_buffer.backlight_level);
 #    endif
diff --git a/quantum/split_common/transport.h b/quantum/split_common/transport.h
index ccce57e444d5..230787a80194 100644
--- a/quantum/split_common/transport.h
+++ b/quantum/split_common/transport.h
@@ -6,5 +6,5 @@ void transport_master_init(void);
 void transport_slave_init(void);
 
 // returns false if valid data not received from slave
-bool transport_master(matrix_row_t matrix[]);
-void transport_slave(matrix_row_t matrix[]);
+bool transport_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]);
+void transport_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]);
diff --git a/tmk_core/common.mk b/tmk_core/common.mk
index d43950299b1b..8211b2fd8046 100644
--- a/tmk_core/common.mk
+++ b/tmk_core/common.mk
@@ -23,6 +23,7 @@ TMK_COMMON_SRC +=	$(COMMON_DIR)/host.c \
 	$(COMMON_DIR)/report.c \
 	$(PLATFORM_COMMON_DIR)/suspend.c \
 	$(PLATFORM_COMMON_DIR)/timer.c \
+	$(COMMON_DIR)/sync_timer.c \
 	$(PLATFORM_COMMON_DIR)/bootloader.c \
 
 ifeq ($(PLATFORM),AVR)
diff --git a/tmk_core/common/keyboard.c b/tmk_core/common/keyboard.c
index 794a9152fbeb..491db3884b0e 100644
--- a/tmk_core/common/keyboard.c
+++ b/tmk_core/common/keyboard.c
@@ -23,6 +23,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #include "led.h"
 #include "keycode.h"
 #include "timer.h"
+#include "sync_timer.h"
 #include "print.h"
 #include "debug.h"
 #include "command.h"
@@ -213,12 +214,22 @@ void keyboard_setup(void) {
  */
 __attribute__((weak)) bool is_keyboard_master(void) { return true; }
 
+/** \brief is_keyboard_left
+ *
+ * FIXME: needs doc
+ */
+__attribute__((weak))
+bool is_keyboard_left(void) {
+    return true;
+}
+
 /** \brief keyboard_init
  *
  * FIXME: needs doc
  */
 void keyboard_init(void) {
     timer_init();
+    sync_timer_init();
     matrix_init();
 #ifdef VIA_ENABLE
     via_init();
@@ -292,7 +303,7 @@ void keyboard_task(void) {
     matrix_scan();
 #endif
 
-    if (is_keyboard_master()) {
+    //if (is_keyboard_master()) {
         for (uint8_t r = 0; r < MATRIX_ROWS; r++) {
             matrix_row    = matrix_get_row(r);
             matrix_change = matrix_row ^ matrix_prev[r];
@@ -321,7 +332,7 @@ void keyboard_task(void) {
                 }
             }
         }
-    }
+    //}
     // call with pseudo tick event when no real key event.
 #ifdef QMK_KEYS_PER_SCAN
     // we can get here with some keys processed now.
diff --git a/tmk_core/common/keyboard.h b/tmk_core/common/keyboard.h
index 98ceca49b1a6..79d9490898fa 100644
--- a/tmk_core/common/keyboard.h
+++ b/tmk_core/common/keyboard.h
@@ -63,6 +63,8 @@ void keyboard_task(void);
 void keyboard_set_leds(uint8_t leds);
 /* it runs whenever code has to behave differently on a slave */
 bool is_keyboard_master(void);
+/* it runs whenever code has to behave differently on left vs right split */
+bool is_keyboard_left(void);
 
 void keyboard_pre_init_kb(void);
 void keyboard_pre_init_user(void);
diff --git a/tmk_core/common/sync_timer.c b/tmk_core/common/sync_timer.c
new file mode 100644
index 000000000000..fb130557b28f
--- /dev/null
+++ b/tmk_core/common/sync_timer.c
@@ -0,0 +1,68 @@
+#include "sync_timer.h"
+
+#ifdef SPLIT_KEYBOARD
+volatile uint32_t sync_timer_ms;
+
+void sync_timer_init(void) {
+    sync_timer_ms = timer_read32();
+}
+
+void sync_timer_clear(void) {
+    sync_timer_ms = 0;
+}
+
+void sync_timer_update(uint32_t time) {
+    sync_timer_ms = time;
+}
+
+uint16_t sync_timer_read(void) {
+    return sync_timer_ms;
+}
+
+uint32_t sync_timer_read32(void) {
+    return sync_timer_ms;
+}
+
+#else
+
+void sync_timer_init(void) {
+    // Already handled
+}
+
+void sync_timer_clear(void) {
+    // Already handled
+}
+
+void sync_timer_update(uint32_t time) {
+    // Unused
+}
+
+uint16_t sync_timer_read(void) {
+    return timer_read();
+}
+
+uint32_t sync_timer_read32(void) {
+    return timer_read32();
+}
+
+#endif
+
+uint16_t sync_timer_elapsed(uint16_t last) {
+    return TIMER_DIFF_16(sync_timer_read(), last);
+}
+
+uint32_t sync_timer_elapsed32(uint32_t last) {
+    return TIMER_DIFF_32(sync_timer_read32(), last);
+}
+
+// TODO: should be moved into timer.h
+// Useful for automatically handling wrapping when called more frequently than 32768ms
+bool sync_timer_expired(uint16_t future) {
+    return sync_timer_read() - future < 0x8000;
+}
+
+// TODO: should be moved into timer.h
+// Useful for automatically handling wrapping when called more frequently than 2147483648ms
+bool sync_timer_expired32(uint32_t future) {
+    return sync_timer_read32() - future < 0x80000000;
+}
diff --git a/tmk_core/common/sync_timer.h b/tmk_core/common/sync_timer.h
new file mode 100644
index 000000000000..4170b974aa6d
--- /dev/null
+++ b/tmk_core/common/sync_timer.h
@@ -0,0 +1,44 @@
+/*
+Copyright 2011 Jun Wako <wakojun@gmail.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef SYNC_TIMER_H
+#define SYNC_TIMER_H
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "timer.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void sync_timer_init(void);
+void sync_timer_clear(void);
+void sync_timer_update(uint32_t time);
+uint16_t sync_timer_read(void);
+uint32_t sync_timer_read32(void);
+uint16_t sync_timer_elapsed(uint16_t last);
+uint32_t sync_timer_elapsed32(uint32_t last);
+bool sync_timer_expired(uint16_t future);
+bool sync_timer_expired32(uint32_t future);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/users/xulkal/config.h b/users/xulkal/config.h
index 4b05ea4ec4de..4400d3a2d7d9 100644
--- a/users/xulkal/config.h
+++ b/users/xulkal/config.h
@@ -12,7 +12,7 @@
 #define RCPC_KEYS KC_RCTL, KC_TRNS, KC_EQL
 
 // Running out of firmware space
-#if defined(__AVR__)
+#if defined(__AVR__) && !defined(RGB_MATRIX_EXTRAS)
 #undef RGB_MATRIX_KEYPRESSES
 #undef RGB_MATRIX_KEYRELEASES
 #undef RGB_MATRIX_FRAMEBUFFER_EFFECTS

From 1bd126837599a428b40fb5a86a57009e8068466f Mon Sep 17 00:00:00 2001
From: Ryan Caltabiano <rcalt2vt@gmail.com>
Date: Sat, 9 Nov 2019 12:00:00 -0600
Subject: [PATCH 2/5] Added mirror option to split transport

---
 common_features.mk                                |  3 +++
 keyboards/rgbkb/zygomorph/keymaps/xulkal/rules.mk |  1 +
 quantum/quantum.c                                 |  2 +-
 quantum/split_common/transport.c                  | 13 ++++++++++++-
 4 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/common_features.mk b/common_features.mk
index 67c64b425f68..ead78bc94514 100644
--- a/common_features.mk
+++ b/common_features.mk
@@ -421,6 +421,9 @@ ifeq ($(strip $(SPLIT_KEYBOARD)), yes)
         QUANTUM_LIB_SRC += $(QUANTUM_DIR)/split_common/serial.c \
                            i2c_master.c \
                            i2c_slave.c
+        ifeq ($(strip $(SPLIT_TRANSPORT)), mirror)
+            OPT_DEFS += -DSPLIT_TRANSPORT_MIRROR
+        endif
     endif
     COMMON_VPATH += $(QUANTUM_PATH)/split_common
 endif
diff --git a/keyboards/rgbkb/zygomorph/keymaps/xulkal/rules.mk b/keyboards/rgbkb/zygomorph/keymaps/xulkal/rules.mk
index 9982b3d4e96f..e3446927e34c 100644
--- a/keyboards/rgbkb/zygomorph/keymaps/xulkal/rules.mk
+++ b/keyboards/rgbkb/zygomorph/keymaps/xulkal/rules.mk
@@ -13,6 +13,7 @@ RGBLIGHT_ANIMATIONS = no    # LED animations
 RGBLIGHT_SPLIT_ENABLE = no  # Split RGBLight Support
 RGB_MATRIX_ENABLE = WS2812  # Enable per-key coordinate based RGB effects. Do not enable with RGBlight
 RGB_MATRIX_KEYPRESSES = no  # Enable reactive per-key effects.
+SPLIT_TRANSPORT = mirror    # For split RGB Matrix support
 RGBLIGHT_FULL_POWER = yes   # Allow maximum RGB brightness. Otherwise, limited to a safe level for a normal USB-A port
 UNICODE_ENABLE = no         # Unicode
 SWAP_HANDS_ENABLE = no      # Enable one-hand typing
diff --git a/quantum/quantum.c b/quantum/quantum.c
index f93cad584008..3c24d13bec08 100644
--- a/quantum/quantum.c
+++ b/quantum/quantum.c
@@ -266,7 +266,7 @@ bool process_record_quantum(keyrecord_t *record) {
     if (record->event.pressed) {
         switch (keycode) {
             case RESET:
-#ifdef SPLIT_KEYBOARD
+#ifdef SPLIT_TRANSPORT_MIRROR
                 if (is_keyboard_master())
 #endif
                 reset_keyboard();
diff --git a/quantum/split_common/transport.c b/quantum/split_common/transport.c
index 12d48cfff897..fc1c64e2ca11 100644
--- a/quantum/split_common/transport.c
+++ b/quantum/split_common/transport.c
@@ -28,7 +28,9 @@ static pin_t encoders_pad[] = ENCODERS_PAD_A;
 
 typedef struct _I2C_slave_buffer_t {
     uint32_t     sync_time;
+#ifdef SPLIT_TRANSPORT_MIRROR
     matrix_row_t mmatrix[ROWS_PER_HAND];
+#endif
     matrix_row_t smatrix[ROWS_PER_HAND];
     uint8_t      backlight_level;
 #    if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
@@ -57,7 +59,9 @@ static I2C_slave_buffer_t *const i2c_buffer = (I2C_slave_buffer_t *)i2c_slave_re
 // Get rows from other half over i2c
 bool transport_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[]) {
     i2c_readReg(SLAVE_I2C_ADDRESS, I2C_KEYMAP_SLAVE_START, (void *)slave_matrix, sizeof(i2c_buffer->smatrix), TIMEOUT);
+#ifdef SPLIT_TRANSPORT_MIRROR
     i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_KEYMAP_MASTER_START, (void *)master_matrix, sizeof(i2c_buffer->mmatrix), TIMEOUT);
+#endif
 
     // write backlight info
 #    ifdef BACKLIGHT_ENABLE
@@ -95,7 +99,9 @@ void transport_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[])
 
     // Copy matrix to I2C buffer
     memcpy((void*)i2c_buffer->smatrix, (void *)slave_matrix, sizeof(i2c_buffer->smatrix));
+#ifdef SPLIT_TRANSPORT_MIRROR
     memcpy((void*)master_matrix, (void *)i2c_buffer->mmatrix, sizeof(i2c_buffer->mmatrix));
+#endif
 
 // Read Backlight Info
 #    ifdef BACKLIGHT_ENABLE
@@ -134,8 +140,9 @@ typedef struct _Serial_s2m_buffer_t {
 } Serial_s2m_buffer_t;
 
 typedef struct _Serial_m2s_buffer_t {
+#ifdef SPLIT_TRANSPORT_MIRROR
     matrix_row_t mmatrix[ROWS_PER_HAND];
-
+#endif
     uint32_t sync_timer;
 
 #    ifdef BACKLIGHT_ENABLE
@@ -233,7 +240,9 @@ bool transport_master(matrix_row_t master_matrix[], matrix_row_t slave_matrix[])
     // TODO:  if MATRIX_COLS > 8 change to unpack()
     for (int i = 0; i < ROWS_PER_HAND; ++i) {
         slave_matrix[i] = serial_s2m_buffer.smatrix[i];
+#ifdef SPLIT_TRANSPORT_MIRROR
         serial_m2s_buffer.mmatrix[i] = master_matrix[i];
+#endif
     }
 
 #    ifdef BACKLIGHT_ENABLE
@@ -258,7 +267,9 @@ void transport_slave(matrix_row_t master_matrix[], matrix_row_t slave_matrix[])
     // TODO: if MATRIX_COLS > 8 change to pack()
     for (int i = 0; i < ROWS_PER_HAND; ++i) {
         serial_s2m_buffer.smatrix[i] = slave_matrix[i];
+#ifdef SPLIT_TRANSPORT_MIRROR
         master_matrix[i] = serial_m2s_buffer.mmatrix[i];
+#endif
     }
 
 #    ifdef BACKLIGHT_ENABLE

From 1ca9a445e34b6ce275eedf1b57f124889ce45397 Mon Sep 17 00:00:00 2001
From: Ryan Caltabiano <rcalt2vt@gmail.com>
Date: Sat, 9 Nov 2019 12:05:25 -0600
Subject: [PATCH 3/5] Updated slave matrix scanning based on mirror define

---
 quantum/split_common/matrix.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/quantum/split_common/matrix.c b/quantum/split_common/matrix.c
index 06f7ddcaa1a4..44354c6f6da4 100644
--- a/quantum/split_common/matrix.c
+++ b/quantum/split_common/matrix.c
@@ -251,7 +251,14 @@ void matrix_post_scan(void) {
         matrix_scan_quantum();
     } else {
         transport_slave(matrix + thatHand, matrix + thisHand);
+#ifdef SPLIT_TRANSPORT_MIRROR
         matrix_scan_quantum();
+#else
+#    ifdef ENCODER_ENABLE
+        encoder_read();
+#    endif
+        matrix_slave_scan_user();
+#endif
     }
 }
 

From ca64bdf2d1ba820214b3cd0e3974402ae3880f52 Mon Sep 17 00:00:00 2001
From: Ryan Caltabiano <rcalt2vt@gmail.com>
Date: Thu, 14 Nov 2019 08:58:38 -0600
Subject: [PATCH 4/5] Updated keyboard.c for split mirroring

---
 tmk_core/common/keyboard.c | 13 ++++++-------
 1 file changed, 6 insertions(+), 7 deletions(-)

diff --git a/tmk_core/common/keyboard.c b/tmk_core/common/keyboard.c
index 491db3884b0e..78b13041bda7 100644
--- a/tmk_core/common/keyboard.c
+++ b/tmk_core/common/keyboard.c
@@ -218,10 +218,7 @@ __attribute__((weak)) bool is_keyboard_master(void) { return true; }
  *
  * FIXME: needs doc
  */
-__attribute__((weak))
-bool is_keyboard_left(void) {
-    return true;
-}
+__attribute__((weak)) bool is_keyboard_left(void) { return true; }
 
 /** \brief keyboard_init
  *
@@ -302,8 +299,10 @@ void keyboard_task(void) {
 #else
     matrix_scan();
 #endif
-
-    //if (is_keyboard_master()) {
+#ifndef SPLIT_TRANSPORT_MIRROR
+    if (is_keyboard_master())
+#endif
+    {
         for (uint8_t r = 0; r < MATRIX_ROWS; r++) {
             matrix_row    = matrix_get_row(r);
             matrix_change = matrix_row ^ matrix_prev[r];
@@ -332,7 +331,7 @@ void keyboard_task(void) {
                 }
             }
         }
-    //}
+    }
     // call with pseudo tick event when no real key event.
 #ifdef QMK_KEYS_PER_SCAN
     // we can get here with some keys processed now.

From c6c234dea8add585f3c748c4a72b50988ee3c3b4 Mon Sep 17 00:00:00 2001
From: Drashna Jaelre <drashna@live.com>
Date: Sat, 2 May 2020 18:08:28 -0700
Subject: [PATCH 5/5] fix typo in common_features.mk
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Co-authored-by: Hoàng Vương <shadowprogr@gmail.com>
---
 common_features.mk | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/common_features.mk b/common_features.mk
index c1a5fc37ba9d..1c36dfe991ae 100644
--- a/common_features.mk
+++ b/common_features.mk
@@ -399,7 +399,7 @@ ifeq ($(strip $(SPLIT_KEYBOARD)), yes)
         # Unused functions are pruned away, which is why we can add multiple drivers here without bloat.
         ifeq ($(strip $(SPLIT_TRANSPORT)), mirror)
             OPT_DEFS += -DSPLIT_TRANSPORT_MIRROR
-        endef 
+        endif 
         
         ifeq ($(PLATFORM),AVR)
             QUANTUM_LIB_SRC += i2c_master.c \