QMK Split キーボードのRGBLIGHTをUSBサスペンドで消灯する


# スレーブ側は光ったまま

QMKファームウェアで RGBLIGHT_ENABLE = yes, RGBLIGHT_SLEEP = yesの設定にすると、USBサスペンド時Splitキーボードのマスター側のみ消灯し、スレーブ側は光ったままになる。

tmk_core/common/avr/suspend.cに消灯するためのコードがあり、これは
tmk_core/protocol/lufa/lufa.cにある関数から呼ばれる。しかし、lufa.cはそもそもマスター側しかサスペンドへの対応がされていない。このため、マスター側がサスペンドに入ってもスレーブ側は点灯を続けることになる。

ハードウェアの修正が必要となるが、スレーブ側を消灯させることができたので記事を書いてみた。なお、#define USE_I2Cには物理的に対応できない。

# Splitキーボードのスレーブ側をサスペンドさせる
Corne Keyboardで修正しているが、他のSplitキーボードでも同じだと思う。
## ハードウェアの修正点
![DSC_0084.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274013/ea921fb8-c363-68cb-959e-ebda6fa725bb.jpeg)

マスター側とスレーブ側をTRSで接続する。このため、#define USE_I2Cは使えなくなる。

## ソースコードの修正点
keyboards/crkbd/rules.mkでRGBLIGHT_ENABLE = yesにする

```Diff:
diff --git a/keyboards/crkbd/rules.mk b/keyboards/crkbd/rules.mk
index 16d05b589..f4a639fea 100644
--- a/keyboards/crkbd/rules.mk
+++ b/keyboards/crkbd/rules.mk
@@ -26,7 +26,7 @@ MIDI_ENABLE = no            # MIDI controls
 AUDIO_ENABLE = no           # Audio output on port C6
 UNICODE_ENABLE = no         # Unicode
 BLUETOOTH_ENABLE = no       # Enable Bluetooth with the Adafruit EZ-Key HID
-RGBLIGHT_ENABLE = no       # Enable WS2812 RGB underlight.
+RGBLIGHT_ENABLE = yes       # Enable WS2812 RGB underlight.
 
 # Do not enable SLEEP_LED_ENABLE. it uses the same timer as BACKLIGHT_ENABLE
 SLEEP_LED_ENABLE = no    # Breathing sleep LED during USB suspend
```

keyboards/crkbd/keymaps/default/config.hでRGBLIGHT_SLEEPとSLAVE_SUSPEND_PINを定義する。SLAVE_SUSPEND_PINはハードウェアの修正で結線した端子を書く。

```Diff:
diff --git a/keyboards/crkbd/keymaps/default/config.h b/keyboards/crkbd/keymaps/default/config.h
index 899fde008..e14fe9745 100644
--- a/keyboards/crkbd/keymaps/default/config.h
+++ b/keyboards/crkbd/keymaps/default/config.h
@@ -35,9 +35,13 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #define TAPPING_FORCE_HOLD
 #define TAPPING_TERM 100
 
+#define SLAVE_SUSPEND_PIN B6
+
 #ifdef RGBLIGHT_ENABLE
     #undef RGBLED_NUM
     #define RGBLIGHT_ANIMATIONS
+    #define RGBLIGHT_SLEEP
+    #define RGBLED_SPLIT {27, 27}
     #define RGBLED_NUM 27
     #define RGBLIGHT_LIMIT_VAL 120
     #define RGBLIGHT_HUE_STEP 10
```

修正する関数はmatrix_init_user(), suspend_power_down_user(), suspend_wakeup_init_user(), matrix_scan_user()。

マスター側で端子出力のHigh/Lowを行い、スレーブ側で端子を読み取り、スレーブ側では呼び出されないsuspend_power_down(), suspend_wakeup_init()を呼び出す。

サスペンドのループ処理はtmk_core/protocol/lufa/lufa.cのmain()に書いたほうが良いが、すべてユーザ関数で対応するため、matrix_scan_user()に書いた。

```Diff:
diff --git a/keyboards/crkbd/keymaps/default/keymap.c b/keyboards/crkbd/keymaps/default/keymap.c
index 446e3281e..aecfed41b 100644
--- a/keyboards/crkbd/keymaps/default/keymap.c
+++ b/keyboards/crkbd/keymaps/default/keymap.c
@@ -105,6 +105,25 @@ void matrix_init_user(void) {
     #ifdef SSD1306OLED
         iota_gfx_init(!has_usb());   // turns on the display
     #endif
+      if(has_usb()) {
+        writePinHigh(SLAVE_SUSPEND_PIN);
+        setPinOutput(SLAVE_SUSPEND_PIN);
+      }
+}
+
+extern void suspend_power_down(void);
+extern void suspend_wakeup_init(void);
+
+void suspend_power_down_user(void) {
+    if(is_master) {
+        writePinLow(SLAVE_SUSPEND_PIN);
+    }
+}
+
+void suspend_wakeup_init_user(void) {
+    if(is_master) {
+        writePinHigh(SLAVE_SUSPEND_PIN);
+    }
 }
 
 //SSD1306 OLED update loop, make sure to add #define SSD1306OLED in config.h
@@ -123,6 +142,19 @@ const char *read_keylogs(void);
 // const char *read_timelog(void);
 
 void matrix_scan_user(void) {
+    static uint8_t recursive_call_guard = 0U;
+    if(!is_master && !recursive_call_guard) {
+        recursive_call_guard = 1U;
+        uint8_t need_suspend_wakeup_init = 0U;
+        while (readPin(SLAVE_SUSPEND_PIN) == 0x00 && !suspend_wakeup_condition()) {
+            suspend_power_down();
+            need_suspend_wakeup_init = 1U;
+        }
+        if (need_suspend_wakeup_init) {
+            suspend_wakeup_init();
+        }
+        recursive_call_guard = 0U;
+    }
    iota_gfx_task();
 }
 
```

これでマスター側の制御でスレーブ側がサスペンドに入るようになる。