楽天Kobo Touchをディスプレイにする
汎用e-inkデバイスとして8000円で売ったら売れるかもね。
というわけで、Kobo Touchで動くVNCビューアをコンパイルしてみた。本来は意地でも一行もコードを書かないという企画だったのだけど、諸般の事情(後述)で十数行のコードが必要になってしまった。。
手持ちの撮影なのでへろへろになってしまった。。三脚的な奴を買ったほうが良いに違いない。
接近版。
ツールチェインの準備
ここを読むような人には説明不要だと思うけど、linuxのツールチェインはcrosstool-ngで簡単に準備することができる。ただし、Koboに使用されているlibcは微妙に古く、最近のgcc + makeの組み合わせでは正常にビルドできない。
今回はeglibc 2_15をビルドした。これはKoboに使用されているglibc 2.11.1とABI互換を保っている。ついでに言うとLinuxもマッチするバージョンが無いが、近いバージョンを適当に選べばOK。
ヘッダファイルの準備
KoboはカーネルソースコードをGitHubのリポジトリに置いている。これに、必要なヘッダファイルも含まれている。
Linuxを展開し、include/linuxを生成したツールチェインのsysroot/usr/include/linuxと置き換える。
ドキュメントの準備
Freescaleに登録していれば、
から"i.MX50 EVK Linux Documentation Bundle" をダウンロードできる。mx50_linux.pdfに必要な情報は載っている。
まぁ実際にはドキュメントを読まなくても必要な情報はソースコードに十分書かれている。
他の記述も興味深い。地味にOpenVGをサポートしているが、Koboでは使用されていないように見える。
SDLとlibvncclientの準備
SDLは最新のSDL2でなく、SDL 1.2を使う必要がある。というのも、SDL2からは通常のフレームバッファコンソール(fbcon)のサポートが無くなってしまったため。Koboのe-inkディスプレイはカーネルフレームバッファ(/dev/fb0)に見える。
libvncclientは普通にビルドできる。添付のCMakeLists.txtを適当に修正し、vncclientだけがビルドされるようにする。
両方をビルドできたら、libvncclientのSDLvncviewerサンプルをビルドする。
罠への対処
ここからが重要なポイント。。
- export SDL_NOMOUSE=1 する
まず、SDLのfbconドライバはマウスがopenできないとクラッシュするという伝統的なバグがある。これを避けるために環境変数SDL_NOMOUSEを指定する必要がある。
- VNCサーバのサイズは800 x 600にする
今回のシステムでは誰もフレームバッファの縮小を実装していないので、最初から800 x 600にしてく必要がある。
他のサイズだと失敗する。
- 手動でフレームバッファをアップデートする
今回最大の罠。Koboのカーネルはe-inkフレームバッファに書き込んでも自動的にアップデートを行わない。なので、毎回手動でioctlして画面を更新する必要がある。
#include <fcntl.h> #include <sys/types.h> #include <linux/mxcfb.h> #include <sys/ioctl.h> int mxcfb = -1; static void mxc_damage(int x, int y, int w, int h){ struct mxcfb_update_data param; const int MARKER = 999; int r; if(mxcfb<0){ mxcfb = open("/dev/fb0", O_RDWR); } if(mxcfb<0){ printf("mxcfb open error!\n"); } param.update_region.left = x; param.update_region.top = y; param.update_region.width = w; param.update_region.height = h; param.waveform_mode = WAVEFORM_MODE_AUTO; param.update_mode = UPDATE_MODE_PARTIAL; param.update_marker = MARKER; param.temp = 0; param.flags = 0; /* alt_buffer_data */ r = ioctl(mxcfb, MXCFB_SEND_UPDATE, ¶m); printf("send update = %d\n",r); #if 0 r = ioctl(mxcfb, MXCFB_WAIT_FOR_UPDATE_COMPLETE, &MARKER); printf("wait = %d\n",r); #endif }
興味深いのはflagsで、ここの設定によって白黒2値の高速アップデート(PDFやブラウザでスクロールすると発生するアレ)やアップデート時の反転を制御することができる。
今回はflagsにゼロを入れているので、反転無しの16段階グレースケールアップデートになる。なので残像が残って汚い。
あと、今回waitは外している。アップデートにはそれなりに時間が掛かるので、本来はwaitを入れる必要がある。