Browse Source

Add modifier state to the split keyboard transport (#10400)

* Add modifier state to the split transport

This adds modifier state to the i2c and serial transport for split
keyboards.  The purpose of this is to allow e.g. displaying modifier
state on the slave side of a split keyboard on an oled.  This adds one
byte to the data transferred between halves.

This also fixes a missing ifdef guard for BLACKLIGHT_ENABLE.

Break modifiers into real/weak/oneshot

Fix incorrect slave serial mod setting

Fix typo in serial weal mod setter

Fix build errors for the I2C code that I introduced

Code cleanup and formatting per project preferences

Correctly get oneshot mods

Fix missing braces

Remove unneeded ifdef guard

Make the added state transport optional

Add documentation for the new define to enable this feature

Fix stray grave mark

* Fix error introduced in conflict resolution
Casey Webster 4 years ago
parent
commit
5e2b53541b
2 changed files with 78 additions and 0 deletions
  1. 10 0
      docs/feature_split_keyboard.md
  2. 68 0
      quantum/split_common/transport.c

+ 10 - 0
docs/feature_split_keyboard.md

@@ -181,6 +181,16 @@ If you're having issues with serial communication, you can change this value, as
 * **`4`**: about 26kbps
 * **`5`**: about 20kbps
 
+```c
+#define SPLIT_MODS_ENABLE
+```
+
+This enables transmitting modifier state (normal, weak and oneshot) to the non
+primary side of the split keyboard.  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 modifer state (e.g.
+displaying status on an OLED screen).
+
 ###  Hardware Configuration Options
 
 There are some settings that you may need to configure, based on how the hardware is set up. 

+ 68 - 0
quantum/split_common/transport.c

@@ -32,7 +32,16 @@ typedef struct _I2C_slave_buffer_t {
     uint32_t sync_timer;
 #    endif
     matrix_row_t smatrix[ROWS_PER_HAND];
+#    ifdef SPLIT_MODS_ENABLE
+    uint8_t real_mods;
+    uint8_t weak_mods;
+#        ifndef NO_ACTION_ONESHOT
+    uint8_t oneshot_mods;
+#        endif
+#    endif
+#    ifdef BACKLIGHT_ENABLE
     uint8_t      backlight_level;
+#    endif
 #    if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
     rgblight_syncinfo_t rgblight_sync;
 #    endif
@@ -46,6 +55,10 @@ typedef struct _I2C_slave_buffer_t {
 
 static I2C_slave_buffer_t *const i2c_buffer = (I2C_slave_buffer_t *)i2c_slave_reg;
 
+#    define I2C_KEYMAP_START offsetof(I2C_slave_buffer_t, smatrix)
+#    define I2C_REAL_MODS_START offsetof(I2C_slave_buffer_t, real_mods)
+#    define I2C_WEAK_MODS_START offsetof(I2C_slave_buffer_t, weak_mods)
+#    define I2C_ONESHOT_MODS_START offsetof(I2C_slave_buffer_t, oneshot_mods)
 #    define I2C_BACKLIGHT_START offsetof(I2C_slave_buffer_t, backlight_level)
 #    define I2C_RGB_START offsetof(I2C_slave_buffer_t, rgblight_sync)
 #    define I2C_SYNC_TIME_START offsetof(I2C_slave_buffer_t, sync_timer)
@@ -97,6 +110,31 @@ bool transport_master(matrix_row_t matrix[]) {
     }
 #    endif
 
+#    ifdef SPLIT_MODS_ENABLE
+    uint8_t real_mods = get_mods();
+    if (real_mods != i2c_buffer->real_mods) {
+        if (i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_REAL_MODS_START, (void *)&real_mods, sizeof(real_mods), TIMEOUT) >= 0) {
+            i2c_buffer->real_mods = real_mods;
+        }
+    }
+
+    uint8_t weak_mods = get_weak_mods();
+    if (weak_mods != i2c_buffer->weak_mods) {
+        if (i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_WEAK_MODS_START, (void *)&weak_mods, sizeof(weak_mods), TIMEOUT) >= 0) {
+            i2c_buffer->weak_mods = weak_mods;
+        }
+    }
+
+#        ifndef NO_ACTION_ONESHOT
+    uint8_t oneshot_mods = get_oneshot_mods();
+    if (oneshot_mods != i2c_buffer->oneshot_mods) {
+        if (i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_ONESHOT_MODS_START, (void *)&oneshot_mods, sizeof(oneshot_mods), TIMEOUT) >= 0) {
+            i2c_buffer->oneshot_mods = oneshot_mods;
+        }
+    }
+#        endif
+#    endif
+
 #    ifndef DISABLE_SYNC_TIMER
     i2c_buffer->sync_timer = sync_timer_read32() + SYNC_TIMER_OFFSET;
     i2c_writeReg(SLAVE_I2C_ADDRESS, I2C_SYNC_TIME_START, (void *)&i2c_buffer->sync_timer, sizeof(i2c_buffer->sync_timer), TIMEOUT);
@@ -131,6 +169,14 @@ void transport_slave(matrix_row_t matrix[]) {
 #    ifdef WPM_ENABLE
     set_current_wpm(i2c_buffer->current_wpm);
 #    endif
+
+#    ifdef SPLIT_MODS_ENABLE
+    set_mods(i2c_buffer->real_mods);
+    set_weak_mods(i2c_buffer->weak_mods);
+#       ifndef NO_ACTION_ONESHOT
+    set_oneshot_mods(i2c_buffer->oneshot_mods);
+#       endif
+#    endif
 }
 
 void transport_master_init(void) { i2c_init(); }
@@ -152,6 +198,13 @@ typedef struct _Serial_s2m_buffer_t {
 } Serial_s2m_buffer_t;
 
 typedef struct _Serial_m2s_buffer_t {
+#    ifdef SPLIT_MODS_ENABLE
+    uint8_t real_mods;
+    uint8_t weak_mods;
+#        ifndef NO_ACTION_ONESHOT
+    uint8_t oneshot_mods;
+#        endif
+#    endif
 #    ifndef DISABLE_SYNC_TIMER
     uint32_t sync_timer;
 #    endif
@@ -268,6 +321,13 @@ bool transport_master(matrix_row_t matrix[]) {
     serial_m2s_buffer.current_wpm = get_current_wpm();
 #    endif
 
+#    ifdef SPLIT_MODS_ENABLE
+    serial_m2s_buffer.real_mods = get_mods();
+    serial_m2s_buffer.weak_mods = get_weak_mods();
+#        ifndef NO_ACTION_ONESHOT
+    serial_m2s_buffer.oneshot_mods = get_oneshot_mods();
+#        endif
+#    endif
 #    ifndef DISABLE_SYNC_TIMER
     serial_m2s_buffer.sync_timer = sync_timer_read32() + SYNC_TIMER_OFFSET;
 #    endif
@@ -295,6 +355,14 @@ void transport_slave(matrix_row_t matrix[]) {
 #    ifdef WPM_ENABLE
     set_current_wpm(serial_m2s_buffer.current_wpm);
 #    endif
+
+#    ifdef SPLIT_MODS_ENABLE
+    set_mods(serial_m2s_buffer.real_mods);
+    set_weak_mods(serial_m2s_buffer.weak_mods);
+#        ifndef NO_ACTION_ONESHOT
+    set_oneshot_mods(serial_m2s_buffer.oneshot_mods);
+#        endif
+#    endif
 }
 
 #endif