分割キーボードでデータの同期やデータ間通信をする

Data synchronization and communication for QMK split keyboard
これまでのQMKでは、分割キーボード間の同期のサポートが限定的で、データの取得ができなかったため、USBが繋がっていない方のキーボードのOLED画面には、常にロゴが表示されるような設計がほとんどでした。最新のQMKファームウェアでは、分割キーボード間の通信が標準でサポートされるようになったため、QMKのソースコードを改修することなくデータの同期ができるようになっています。

基本的な同期であれば、[config.h]にこれらの宣言を追加することで、両方のキーボードで変数が共有されるようになります。頻繁に同期通信を行うと、入力処理に影響するため、必要最低限の宣言だけにするのが望ましいでしょう。
config.h
#define SPLIT_TRANSPORT_MIRROR 		// マスターのマトリックス接続状況
#define SPLIT_LAYER_STATE_ENABLE	// レイヤー状態
#define SPLIT_LED_STATE_ENABLE		// CapsLockなどのLED点灯状態
#define SPLIT_MODS_ENABLE			// シフトキーなどのMODキーの状態
#define SPLIT_WPM_ENABLE			// キーボードWPMの状態
#define SPLIT_OLED_ENABLE			// OLEDのオン、オフの状態
これらに該当しない、独自の値を同期することもできます。データはトランザクションIDごとに設定でき、32byte(RPC_M2S_BUFFER_SIZE / RPC_S2M_BUFFER_SIZEの値を変更することで調整可)までの情報を送受信できます。

ユーザー定義によるトランザクションIDの宣言は[config.h]にて行います。
config_user.h
// この定義はコンパイラによって適時処理される
#define SPLIT_TRANSACTION_IDS_USER USER_DATA_SYNC

// 複数のIDを宣言したいときはカンマで区切る
#define SPLIT_TRANSACTION_IDS_USER USER_DATA_SYNC1, USER_DATA_SYNC2

QMKによって自動で気に呼び出されるkeyboard_post_init_user()関数内にて、このIDを実行プログラムへ登録します。
init.c
// キーボード初期化後に呼ばれる
void keyboard_post_init_user(void)
{
    transaction_register_rpc(USER_DATA_SYNC1, user_sync_sub1_handler);
}
データの更新が発生するなどで、データ通信を実行する必要が生じたなら、「transaction_rpc_send()」で、相手側のキーボードへデータを送ります。もう一方のキーボードでデータを受け取ると、登録したハンドラが呼び出されるので、ここで必要な同期処理を行います。
sync.c
// サブキーボードに同期したいデータ
typedef union {
  uint8_t raw;
  struct {
    bool swap_gui:1;
    bool mod_gui:1;
    bool caps_lock:1;
    bool num_lock:1;
    bool sc_lock:1;
  };
} key_state_r_t;
key_state_r_t key_state_r;

// サブ側で呼び出される同期ハンドラ
void user_sync_sub1_handler(uint8_t in_buflen, const void* in_data, uint8_t out_buflen, void* out_data)
{
	// データの同期処理
    const key_state_r_t *ks = (const key_state_r_t*)in_data;
    key_state_r.raw = ks->raw;
}

// メイン側から同期の実行
void sync(){
    if(is_keyboard_master()) {
        transaction_rpc_send(USER_DATA_SYNC1, 1, &key_state_r.raw);
    }
}
実行結果などの返り値が欲しいのであれば、transaction_rpc_send()の代わりにtransaction_rpc_exec()を使い、コールバックハンドラで参照されている「out_data」に送り返す情報を格納させます。
2021/10/04