QMKでArduino用キーボードを作る (2/4 protocol改造編)

最終更新日

I/Fのチェックに利用するテスターはできた。

QMKでArduino用キーボードを作る (1/4 テスター編)

QMKでArduino用キーボードを作る (1/4 テスター編)

2020.11.22

ということで、 su120 の split_keyboard用である GPIO D2 からシリアル(8N1)のTXを送信するように改造する。

su120 のシリアル通信

su120 のPCBデータをみて、オシロスコープで確認すると、下図の配線になっていることがわかる。

QMKのcodeを読むと、スプリット対応のキーボードをつなぐと、defaultでUSB ケーブルに刺さっている方が Master となり、もう一方を Slave として独自のシリアル通信が始まる。

transport 層

codeの該当箇所は、以下の辺り。

qmk_firmware/quantum/split_common/transport.c

void transport_rgblight_slave(void) {
    if (status_rgblight == TRANSACTION_ACCEPTED) {
        rgblight_update_sync((rgblight_syncinfo_t *)&serial_rgblight.rgblight_sync, false);
        status_rgblight = TRANSACTION_END;
    }
}

#    else
#        define transport_rgblight_master()
#        define transport_rgblight_slave()
#    endif

bool transport_master(matrix_row_t matrix[]) {
#    ifndef SERIAL_USE_MULTI_TRANSACTION
    if (soft_serial_transaction() != TRANSACTION_END) {
        return false;
    }
#    else
    transport_rgblight_master();
    if (soft_serial_transaction(GET_SLAVE_MATRIX) != TRANSACTION_END) {
        return false;
    }
#    endif

    // TODO:  if MATRIX_COLS > 8 change to unpack()
    for (int i = 0; i < ROWS_PER_HAND; ++i) {
        matrix[i] = serial_s2m_buffer.smatrix[i];
    }

上記のcode から、 protocol GET_SLAVE_MATRIX によって、Master 発で、Slave の状態を取得しているとわかる。

Slaveが送ってきたキーのMatrix情報をMaster自身のMatrix情報に上書きして右手分を補完している。

オリジナルprotocol の詳細

Master からSlave に送る情報(request)は、こんな感じ。

SERIAL_USE_MULTI_TRANSACTION は、シリアル通信で複数のprotocolをサポートできるようになっている。

  • GET_SLAVE_MATRIX …SlaveのキーMatrixを取得
  • PUT_RGBLIGHT … RGBの発光制御

自分でオリジナルのprotcol を追加することも簡単。

typedef struct _Serial_m2s_buffer_t {
#    ifdef BACKLIGHT_ENABLE
    uint8_t backlight_level;
#    endif
#    ifdef WPM_ENABLE
    uint8_t current_wpm;
#    endif
} Serial_m2s_buffer_t;

もし、backlight のlevel 指示、あるいは wpm 情報を利用しない場合、Master -> Slave は、実質 0byte.

それに答えるSlave の情報(reply)は、こんな感じ。

typedef struct _Serial_s2m_buffer_t {
    // TODO: if MATRIX_COLS > 8 change to uint8_t packed_matrix[] for pack/unpack
    matrix_row_t smatrix[ROWS_PER_HAND];

#    ifdef ENCODER_ENABLE
    uint8_t      encoder_state[NUMBER_OF_ENCODERS];
#    endif

} Serial_s2m_buffer_t;

SlaveのキーのMatrix(どのキーが押されているかの状態)と、ロータリーエンcodeの状態。

改造後のprotocol

MasterからだらだらとキーのMatrix情報を流したい(isochronous)。

また、お互いお行儀良くしゃべる必要はなく、Master->Slave の方向のみでよい。
下記のデータ(キーMatrix)をだらだら流す。

typedef struct _Serial_m2s_buffer_t {
    matrix_row_t smatrix[ROWS_PER_HAND]; // 追加!
#    ifdef BACKLIGHT_ENABLE
    uint8_t backlight_level;
#    endif
#    ifdef WPM_ENABLE
    uint8_t current_wpm;
#    endif
    uint8_t stop;
} Serial_m2s_buffer_t;

network 層

code の該当箇所は、以下の辺り。

qmk_firmware/drivers/avr/serial.c

ムリムリと読んでいくと、シリアルPINを LOW/HIGH 切り換えながら、Master <-> Slave のデータをお行儀良くやり取りしている。

データを送信する serial_write_chunk を 8N1 に書き換える。

void serial_write_chunk(uint8_t data, uint8_t bit) {

    uint8_t b;

    /* start bit */
    serial_low();
    serial_delay();

    for (b = 1, c = 0; c < bit; b <<= 1) {
        if(data & b) {
            serial_high();
        } else {
            serial_lowx();
        }
        serial_delay();
    }

    /* stop bit */
    serial_high();
    serial_delay();
}

だらだらのためには、transaction も書き換える。

int  soft_serial_transaction(int sstd_index) {
  if( sstd_index > Transaction_table_size )
      return TRANSACTION_TYPE_ERROR;
  SSTD_t *trans = &Transaction_table[sstd_index];
  cli();

  // initiator send phase
  if( trans->initiator2target_buffer_size > 0 ) {
      serial_send_packet((uint8_t *)trans->initiator2target_buffer,
                         trans->initiator2target_buffer_size);
  }

    // no wait slave

  // always ok
  *trans->status = TRANSACTION_END;
  sei();
  return TRANSACTION_END;
}

こういう改造をすれば、シリアルTXとしてだらだらとデータを流してくれるはず。

code の組み込み

追加ファイル

上記の `transport.c` と `serial.c` をkeymapの自分のdirectory に作成

rules.mk

makefile(rules.mk) に設定

# CONSOLE_ENABLE = yes

ENCODER_ENABLE = yes

SPLIT_KEYBOARD = yes
SPLIT_TRANSPORT = custom

SRC += transport.c serial.c

config.h

software serialの設定など

#pragma once

#define SOFT_SERIAL_PIN D2  // or D1, D2, D3, E6
#define SELECT_SOFT_SERIAL_SPEED 5 // 20kbps
#define MASTER_RIGHT 1

code

qmk_firmware の repository は、ここ。

ここからforkして、自分用のbranchを切るのがお作法みたいだけど、そもそも @e3w2q さんのpatchみたいなものなので、さて。。

とりあえず、 @e3w2q さんの fork repository に修正を加えたものを公開しておく。

https://github.com/kurosuke/qmk_firmware/tree/kurosuke_arudino_patch/keyboards/e3w2q/su120/rev1_4knob/keymaps/arduino

続き

QMKでArduino用キーボードを作る (3/4 配線編)

QMKでArduino用キーボードを作る (3/4 配線編)

2020.11.23

シェアする