脱獄したKindleにRustとSlintを導入する
多くの開発者にとって、古いハードウェアを再利用したいという衝動は抗いがたいものです。忘れ去られたタブレットをスマートホームのダッシュボードに変えたり、専用の電子書籍リーダーをナイトスタンド用の時計に変えたりするなど、その目的は最終的な製品の有用性よりも、プロセスそのものの挑戦にあることが多いものです。
最近、RustとSlint GUIフレームワークを活用することで、第7世代Kindle Paperwhiteの制限されたエコシステムから脱却する方法を示すプロジェクトが登場しました。この取り組みは、ロックダウンされたE-inkデバイスをプログラマブルなキャンバスへと変貌させ、レガシーなARMv7ハードウェア上でモダンでメモリ安全なコードを実行したいと考えているすべての人にロードマップを提供します。
クロスコンパイルの課題
Kindleのような低電力デバイスでRustを実行するには、コンパイルツールチェーンという主要なハードルがあります。リソースが限られているため、デバイス上で直接コンパイルを試みることは現実的ではありません。解決策は、armv7-unknown-linux-musleabihfをターゲットとしたクロスコンパイルです。
これを実現する方法はいくつかありますが、この特定のタスクにおいてはcargo-zigbuildが非常に効率的なツールとして浮上しています。Zigコンパイラは、サポートされているすべてのアーキテクチャ用のmusl libcソースとヘッダーを同梱しており、独自のリンカーも備えているため、完全なクロスコンパイルツールチェーンとして機能することができます。プロセスは、以下の3つの基本的なステップに簡略化されます。
- Zigをインストールする。
cargo-zigbuildをインストールする。cargo zigbuild --release --target armv7-unknown-linux-musleabihfを実行する。
コミュニティ内の他の開発者は、rust-lldと特定の.cargo/config.toml設定を使用して自己完結型のバイナリを作成することでも同様の成功を収めていますが、このアプローチではC言語の依存関係の使用が制限される可能性があります。
デバイスへのアクセス確立
バイナリがコンパイルされたら、デプロイして実行する必要があります。脱獄プロセス中にKUAL (Kindle Unified Application Launcher)のようなツールが利用可能ですが、これらはデバッグ用のstdoutへのアクセスを提供しないため、開発には不十分です。
これを解決するために、USBNetworkツールを使用して、USBまたはWi-Fi経由でSSHアクセスを設定できます。これにより、公開鍵の転送が可能になり、シェルでアプリケーションを実行できるため、コードの反復的な改善に必要なリアルタイムのフィードバックが得られます。
E-ink上でのGUIの実装
「Hello World」アプリはツールチェーンが動作することを証明しますが、Kindleの真の可能性は画面にあります。視覚的なインターフェースを作成するために、ARMv7のサポートと軽量なソフトウェアレンダラーを備えたSlint GUIライブラリが選ばれました。
フレームバッファへのレンダリング
「すべてはファイルである」というLinuxの哲学に従い、Kindleのディスプレイは/dev/fb0のフレームバッファを介してアクセス可能です。SlintでLineBufferProviderを実装することで、アプリケーションはラスタライズされた視覚的出力を一行ずつ取得し、それをグレースケールに変換して、メモリマップされたフレームバッファに直接書き込むことができます。
しかし、フレームバッファへの書き込みだけでは不十分です。E-ink画面は、物理的なディスプレイを更新するために明示的なトリガーを必要とします。これは、libcクレートとioctl() (input/output control)を使用して、ドライバに画面の「dirty region」を更新するように通知することで処理されます。
タッチ入力の処理
入力の処理は出力と同様です。タッチコントローラーは/dev/input/event1のファイルとして公開されています。このファイルから読み取ることで、アプリケーションはLinuxカーネルのマルチタッチ・プロトコル・タイプBに従ったデータのストリームを受け取ります。
このプロトコルは、座標(XおよびY)とトラッキングIDのシーケンスとしてイベントを配信し、SYNC_REPORTで終了します。これをSlintと統合するためのロジックは以下の通りです。
- PointerPressed: タッチダウン後の最初の同期によってトリガートされる。
- PointerMoved: その後の同期レポートによってトリガートされる。
- PointerReleased: トラッキングIDが
-1であることを示し、指が離れたことを示すときにトリガートされる。
結論とコミュニティへの影響
このロジックをスタンドアロンのクレート、slint-backend-kindleとして抽出することで、Kindle向けのGUI構築プロセスが民主化されました。単純なナイトスタンド用の時計を作りたいという欲求から始まったものが、機能的なGUIバックエンドへと進化し、他の開発者がE-inkダッシュボードやカスタムアプリケーションを実験できる環境を提供しています。
コミュニティが指摘するように、E-inkの「レトロな感覚」は、これらのプロジェクトを独特の満足感を与えてくれます。セルフホスト型のライブラリサーバーや、RISC-V上で動作するポータブルオーディオプレイヤーを構築するなど、RustやZigのようなモダンな言語とレガシーなハードウェアの交差点は、技術的な探求の肥沃な領域であり続けています。