OBONO’s Diary

へっぽこプログラマの戯言

TJP Emulator

Android 端末で動作する Tiny Joypad のエミュレータ "TJP Emulator" について、

以前、Android 端末上で動く Arduboy エミュレーターを作って公開したことがあったので、それを流用すれば割とすぐに実現できるかな~とか思ってたんだけど、これがまた、いろいろと大変だったんだよね。エミュレーターの開発については、別の日に改めて記事を書く予定。

ってなことを先月書いたんだけど、そのままあっという間に半月経ってしまって、このままだと年を越してしまいそうなので、とりあえず記事を書く。

前述の通り、Arduboy エミュレーターのソースを流用すればすぐに作れるだろう…と思っていたのだが、なんだかんだで以下のような対応をする必要があった。

  • ネイティブ実装部分
    • SSD 1306 の I2C 通信の信号処理を自前で実装
    • arm64-v8a バイナリのビルド
  • Eclipse + ADT な環境から Android Studio への移行
  • Android 14 → 29 の対応
    • 廃止されたクラスの対応
    • ActionBar から Toolbar への移行
    • 各種アイコンの描き直し
    • アダプティブアイコン

どれもそれなりに骨が折れたのだが、中でも一番大変だったのは SSD 1306 との通信の部分。
simavrソースコード一式には、OLED ディスプレイ SSD 1306 をエミュレートするサンプルコードがあって、初期化用関数 ssd1306_connect() の引数に SPI 通信のための使用しているピンの情報を渡して呼び出せば、あとはよしなにエミュレートしてくれるようになっている。
Arduboy は SPI 通信なので、この関数をそのまま使えたのだが、Tiny Joypad は I2C 通信なので、同じ関数は使えない。一応、なんかそれっぽい ssd1306_connect_twi() という別の初期化関数もあるのだが、simavr のドキュメントによると、Tiny Joypad で使用している CPU ATtiny85 については、 TWI をサポートしていないとか書いてあって、こちらもダメそう。
simavr に関する情報がネット上でなかなか見つけられないのもあって、どんなに調べてもうまい方法が見つけられない。仕方が無いので、「無い物は作る」の精神で、SCL ピン / SDA ピンが H や L になるのを検出して、そこから I2C の仕様に基づいてバイトコードに変換し、その結果を1バイト受信するごとに処理する関数に直接流し込む…みたいなことを自前で実装することにした。
「うまく行った!」と思っても、別のスケッチだと動いてくれなかったり、SSD 1306 のサンプルコードが実機と微妙に違う挙動をすることが判明し、そのための小細工を入れてみたり。いろいろ試行錯誤して、最終的にはどうにか実現できたわけだが、一時は諦めかけたこともあって、なかなかの難産だったように思う。

他にも、最新の Android 事情に合わせる必要があり、それはそれで苦労したのだが、最終的にどうにかリリースすることができた。
f:id:OBONO:20201116154902j:plain
ただ、時間経過とともに動作が重くなる症状がみられるんだよね。どうもスケッチに依存するみたいで、少なくとも自分がリリースした Hollow Seeker だと確実に発生する。
アプリの CPU 負荷が上がっているのではなく、同じ処理をするのに必要なステップ数が、何故か時間経過とともに多くなっているような印象で、エミュレータが単位時間あたりに処理できるステップ数は維持できているのに、結果的にユーザ側には動作が重くなっているように見えてしまう。
原因は今のところサッパリわからないのだが、一体どうしたものか…