Rainy75 を ZMK Firmware で動かす
キーボードのファームウェアを触るのは久しぶりです。普段はQMK の keymap リポジトリを細々と更新している程度でしたが、今回は Wobkey の Rainy 75 Pro を OSS のZMKに載せ替えました。焼くだけのつもりが、clone してもビルドが通らなかったので、直して上流に PR を出すところまでやっています。
TL;DR:
- Wobkey Rainy 75 Pro にscholzri/rainy75-zmkの ZMK ファームウェアを焼いた
- clone 直後のビルドを止める問題が 4 つあったので、まとめて直してPR #2を出した。マージされた
- 手元の ANSI 配列では Enter キーが効かず、原因を突き止めてissue #1で報告した
- キーマップは QMK 時代と同じqmk-keymapsで管理する
Rainy 75 Pro と ZMK 移植プロジェクト
Rainy 75 Proは Wobkey の 75% メカニカルキーボードです。ガスケットマウントで打鍵感がよく、いわゆる中華ブランドですがビルドクオリティは高い。ただし MCU が Telink TLSR9511 (B91, RISC-V) というキーボードでは珍しいチップで、ファームウェアは Evision 系のクローズドなものです。キーマップはVIAで書き換えられますが、できるのはそこまで。
scholzri/rainy75-zmkは、この stock ファームウェアをGhidraでリバースエンジニアリングして ZMK を移植したプロジェクトです。ファームウェア内の 211 関数をすべて特定し、キーマトリクスや RGB の配線、OTA アップデートのプロトコルまで解読しています。おかげでケースを開けず、デバッガも使わずに、stock の OTA 経路をそのまま使って ZMK を焼けます。restore_stock.shで純正に戻す道も用意されています。docs/以下の解析記録だけでも読み物として面白いです。
ZMK はZephyr RTOSの上に乗ったキーボードファームウェアで、QMKと違ってビルドはmakeではなくwest、キーマップはkeymap.cではなく Devicetree 形式で書きます。BLE が標準で、ワイヤレス前提の設計です。
clone してもビルドが通らない
README のとおり clone → west update → west buildと進めたら、ビルドが通りませんでした。独立した問題が 4 つ重なっています。
.gitignoreのzephyr/パターンがルートだけでなくzmk/zephyr/にもマッチしていて、Zephyr module の manifest であるzmk/zephyr/module.ymlがコミットされていない。module が登録されないのでwest buildがNo board named 'rainy75'で落ちるzmk/west.ymlが pin している ZMK のコミットがzmkfirmware/zmkのどの ref からも辿れず、west updateが失敗する。push され忘れたコミットらしいCONFIG_ZMK_SLEEP=yが要求するHAS_POWEROFFをどこも select しておらず、Kconfig が abort する。poweroff.cの実装はすでにあるので、board の Kconfig に 1 行足りないだけconf/app.confが、pin されている ZMK には存在しないCONFIG_ZMK_USB_NO_VBUS_DETECTに代入していて、これも Kconfig が abort する
ほかに、README に書かれていないセットアップも 2 つ必要でした(pip install -r zephyr/scripts/requirements.txtとwest zephyr-export)。どれも直すのは 1〜2 行ですが、これだけ重なると clone からビルドまで一直線には進めません。
直して PR を出した
修正は、ビルドを止めている問題だけに絞ってPR #2を出しました。5 ファイル、+10/−3 です。いちばん効いた修正は.gitignoreの 1 文字でした。
# West workspace (fetched by west update)
zmk-src/
-zephyr/
+/zephyr/これでzmk/zephyr/module.ymlを commit できるようになり、board 定義が west に認識されます。残りは west.yml の pin を到達可能なコミットへ差し替え、Kconfig.rainy75にselect HAS_POWEROFFを追加、未定義シンボルの削除です。
PR の説明には原因と修正に加えて、./build.sh -paがクリーンに通ることと、実機で USB HID・BLE・deep sleep が動いていることを検証として書きました。マージされています。
ANSI の Enter が効かない
ビルドが通っても、もうひとつ問題が残っていました。この移植は作者の ISO DE 配列向けで、ANSI は「実験的・実機未検証」の扱いです。手元のユニットは ANSI で、そのまま焼くと物理の横長 Enter を押しても何も起きず、代わりに backslash の位置が Enter として効きます。
調べると原因は 2 段階でした。
1 つ目は、ANSI 用の#ifdef CONFIG_RAINY75_ANSIが構造的に効かないこと。keymap の overlay は Kconfig の処理より先に C プリプロセッサを通るので、-DCONFIG_RAINY75_ANSI=yを付けてビルドしてもこのマクロは未定義のまま、常に ISO 側の分岐が使われます。生成されたzephyr.dtsを確認すると、「ANSI ビルド」でも ISO のキーマップが出力されていました。
2 つ目は matrix transform です。ANSI の横長 Enter はマトリクスのRC(3,13)に配線されていますが、ISO 向けの transform はこの位置を飛ばしています。stock ファームウェアの VIA レイアウトと行を突き合わせると、home row が; ' → NUHS → ENTと並んでいて(3,13)が Enter だと確定できました。transform にRC(3,13)を足して&kp RETを割り当てれば直ります。
この 2 つは自分のforkで直して、経緯はissue #1にまとめて報告しました。ANSI/ISO の切り替えをどう設計するかは作者の判断が要るところなので、PR はビルド修正と切り離しています。
キーマップは QMK と同じリポジトリに置く
キーマップ本体は、これまでの QMK ボードと同じqmk-keymapsにkeyboards/wuque_studio/rainy75/zmk/rainy75.keymapとして置きました。リポジトリ名に反して ZMK ですが、キーマップの置き場は 1 箇所にまとめておきたい。
Space 両隣の英数・かなは、ほかの QMK ボードで使っている Mod-Tap をそのまま移しています。
| QMK (他のボード) | ZMK (Rainy75) | 動き |
|---|---|---|
CK_EISU | &mt LGUI LANG2 | tap で英数、hold で GUI |
CK_KANA | &mt RALT LANG1 | tap でかな、hold で Alt |
Fn レイヤーには Bluetooth のプロファイル切り替え (Fn+F1〜F3)、USB/BLE の出力切り替え (Fn+F4)、ZMK Studioのアンロック (Fn+Esc)、RGB の操作を割り当てています。
実機に焼いて、動いた
書き込んで、キーを押したら文字が届きました。自分の直したビルドで焼けているので、プロジェクトに参加できた感じがあります。OSS のファームウェアに PR を出してマージされるのは、キーボードの楽しみ方のひとつだと思います。
当面はこの構成をベースに、ほかのボードと同じようにキーマップを少しずつ更新していきます。scholzri/rainy75-zmk 自体もまだ動きのあるプロジェクトなので、fork も追従していくつもりです。