MicroPythonのosモジュールにはduptermという機能があり、これを使うとREPLで使われている標準の入出力チャネルをUART以外のデバイスへ複製することができます。
duptermのパラメータにオブジェクトを与えると、そのオブジェクトでREPLへの入出力ができるようになります。
オブジェクトはwriteとreadintoの2つのメソッドだけ持っていれば、duptermに使用できます。
writeでフレームバッファに描画するオブジェクトを作れば、フレームバッファ互換のOLEDやRaspberry Piの画面などのデバイスをREPLの出力先として使えそうです。
そこで、Raspberry PiのMicroPythonにduptermのサポートを追加し、duptermでフレームバッファに出力するためのクラスを作成してみました。
dupterm自体はMicroPythonに実装が含まれています(extmod/uos_dupterm.c)。ヘッダファイルはextmod/misc.hです。
出力については、標準の文字列出力関数(mp_hal_stdout_tx_strn)の内部で、duptermへ送りたい文字列をmp_uos_dupterm_tx_strnで送れば動作します。
入力を受け付ける場合は、入力側の処理(mp_uos_dupterm_rx_chr)も行う必要がありますが、今回はとりあえず省略しました。
次に、フレームバッファをduptermの出力先にするためのクラスですが、これはMicroPythonで作成しました。
I2C接続のOLED(SSD1306)を出力先にする場合の使い方はこんな感じです。
I2Cのクロックがデフォルトの100KHzだとかなり遅いので、1MHzに設定しています。
FBConsoleというのが今回作成したクラスです。
さすがに、128×64ドットの画面ではコンソールに使うにはちょっと狭いですが、たとえば
console.cls();console.x=10;console.y=5;print("Hey!")
こんな感じでOLEDの好きな場所にprint文で出力することもできます。
duptermをやめる場合は
os.dupterm(None)
を実行します。
FBConsoleクラスの中身は以下の通りです。
必須のメソッドはwrite(buf)とreadinto(buf, nbytes)の2つですが、readintoは何もせずNoneを返すのみです。
(7/4追記:uio.IOBaseのサブクラスとなるよう変更しました。uio.IOBaseはmpconfigport.hでMICROPY_PY_IO_IOBASEを有効にすることで使えるようになります。)
(11/11追記:改良版を作成しました。)
writeはバイト列を受け取ってフレームバッファへ文字として描画します。
基本的に1文字ずつ出力し、画面がいっぱいになったら1行分スクロールするだけです。
そのほか、エスケープシーケンスやバックスペースの処理を行っています。
フレームバッファに汎用的に使えるようにしようとしましたが、OLEDは
- show()を呼ばないと表示されない
- widthとheightが属性としてアクセスできる
といったあたりがフレームバッファとは異なるので、OLED専用の処理をtry~exceptで行うようにしています。
コメント