Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Split Keyboard RGB Matrix Support #5998

Closed
wants to merge 8 commits into from
Closed
4 changes: 4 additions & 0 deletions common_features.mk
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,10 @@ ifeq ($(strip $(SPLIT_KEYBOARD)), yes)
QUANTUM_SRC += $(QUANTUM_DIR)/split_common/transport.c
# Functions added via QUANTUM_LIB_SRC are only included in the final binary if they're called.
# Unused functions are pruned away, which is why we can add multiple drivers here without bloat.
ifeq ($(strip $(SPLIT_TRANSPORT)), mirror)
OPT_DEFS += -DSPLIT_TRANSPORT_MIRROR
endef
drashna marked this conversation as resolved.
Show resolved Hide resolved

ifeq ($(PLATFORM),AVR)
QUANTUM_LIB_SRC += i2c_master.c \
i2c_slave.c
Expand Down
12 changes: 8 additions & 4 deletions keyboards/rgbkb/zygomorph/keymaps/xulkal/rules.mk
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@ 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.
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
Expand Down Expand Up @@ -40,3 +41,6 @@ endif
ifeq ($(strip $(RGBLIGHT_SPLIT_ENABLE)), yes)
OPT_DEFS += -DRGBLIGHT_SPLIT_ENABLE
endif

# Xulkal user feature
OPT_DEFS += -DRGB_MATRIX_EXTRAS
4 changes: 3 additions & 1 deletion keyboards/rgbkb/zygomorph/rev1/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,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
Expand Down
102 changes: 36 additions & 66 deletions keyboards/rgbkb/zygomorph/rev1/rev1.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
3 changes: 3 additions & 0 deletions quantum/quantum.c
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,9 @@ bool process_record_quantum(keyrecord_t *record) {
switch (keycode) {
#ifndef NO_RESET
case RESET:
#ifdef SPLIT_TRANSPORT_MIRROR
if (is_keyboard_master())
#endif
reset_keyboard();
return false;
#endif
Expand Down
1 change: 1 addition & 0 deletions quantum/quantum.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
31 changes: 26 additions & 5 deletions quantum/rgb_matrix.c
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,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)); }
Expand Down Expand Up @@ -164,9 +171,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
Expand Down Expand Up @@ -255,8 +276,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;
Expand All @@ -280,7 +301,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) {
Expand Down
2 changes: 0 additions & 2 deletions quantum/rgb_matrix.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
12 changes: 8 additions & 4 deletions quantum/split_common/matrix.c
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,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) {
Expand All @@ -254,11 +254,15 @@ void matrix_post_scan(void) {

matrix_scan_quantum();
} else {
transport_slave(matrix + thisHand);
#ifdef ENCODER_ENABLE
transport_slave(matrix + thatHand, matrix + thisHand);
#ifdef SPLIT_TRANSPORT_MIRROR
matrix_scan_quantum();
#else
# ifdef ENCODER_ENABLE
encoder_read();
#endif
# endif
matrix_slave_scan_user();
XScorpion2 marked this conversation as resolved.
Show resolved Hide resolved
#endif
}
}

Expand Down
56 changes: 47 additions & 9 deletions quantum/split_common/transport.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ static pin_t encoders_pad[] = ENCODERS_PAD_A;
# include "i2c_slave.h"

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)
Expand All @@ -44,7 +48,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 I2C_WPM_START offsetof(I2C_slave_buffer_t, current_wpm)

Expand All @@ -55,8 +61,11 @@ 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);
#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
Expand Down Expand Up @@ -91,12 +100,21 @@ bool transport_master(matrix_row_t matrix[]) {
}
}
# 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));
#ifdef SPLIT_TRANSPORT_MIRROR
memcpy((void*)master_matrix, (void *)i2c_buffer->mmatrix, sizeof(i2c_buffer->mmatrix));
#endif

// Read Backlight Info
# ifdef BACKLIGHT_ENABLE
Expand Down Expand Up @@ -139,6 +157,11 @@ 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];
XScorpion2 marked this conversation as resolved.
Show resolved Hide resolved
#endif
uint32_t sync_timer;

# ifdef BACKLIGHT_ENABLE
uint8_t backlight_level;
# endif
Expand Down Expand Up @@ -221,7 +244,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;
Expand All @@ -235,7 +259,10 @@ 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];
#ifdef SPLIT_TRANSPORT_MIRROR
serial_m2s_buffer.mmatrix[i] = master_matrix[i];
XScorpion2 marked this conversation as resolved.
Show resolved Hide resolved
#endif
}

# ifdef BACKLIGHT_ENABLE
Expand All @@ -247,19 +274,30 @@ bool transport_master(matrix_row_t matrix[]) {
encoder_update_raw((uint8_t *)serial_s2m_buffer.encoder_state);
# endif


# ifdef WPM_ENABLE
// Write wpm to slave
serial_m2s_buffer.current_wpm = get_current_wpm();
# 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];
#ifdef SPLIT_TRANSPORT_MIRROR
master_matrix[i] = serial_m2s_buffer.mmatrix[i];
XScorpion2 marked this conversation as resolved.
Show resolved Hide resolved
#endif
}

# ifdef BACKLIGHT_ENABLE
backlight_set(serial_m2s_buffer.backlight_level);
# endif
Expand Down
Loading