何をしたか#
DCS Worldとは#
DCS World、通称DCSっていう超リアルな戦闘機のシミュレーターがあります。
Digital Combat Simulator | DCS World | Combat Simulator
なぜ外部から操作したいか#
このシミュレーター、本物の戦闘機を可能な限り忠実に再現しているのでただ離陸するだけでもクソみたいな数の操作をしないといけません。まぁそう言うのが好きでやってるんですが、ともかく操作が多いのでマウスでポチポチやるのはしんどいわけです。ましてや戦闘中にいちいちマウスを触る余裕はありません。特にVRだと視点が動くとカーソルも動くのでめっちゃ操作しづらいです。というわけで手元に物理的なボタンが欲しくなったので試行錯誤の記録です。なお未完成で、後述するソフトから送られてくるデータの読み取りには成功していますが書き込みはまだできていません。
なぜラズピコなのか#
たまたま手元にあったから
使用技術#
- DCS-BIOS
- Rust
- Embassy-rp
- Raspberry Pi Pico W
- Tauri
DCS-BIOSはDCSにデータを送ったりDCSからデータを取得したりすることができるツール群です。Arduinoライブラリとかもあります。
Embassyは組み込みRustの非同期ランタイムとかです。それのrp2040用がEmbassy-rp
今回はWiFiに接続してデータを受け取るのでPico Wでやりますが、最終的に通信できたら何でも良いです。
残念ながらラズピコからデータを読んだり書き込んだりする部分は完成してないので、TauriでGUI作ってライブラリが正しく動くことを確認しました。ボタンが多すぎてIOエキスパンダやらなんやらが必要なんですけど基板に収まらなくて発注しないといけない。そんな金は無いので停滞中。
DCS-BIOSについて#
DCS-Skunkworks/dcs-bios: Data export tool for DCS.
もとはGolangで書かれてたみたいですがフォークされてLuaに書き直されたみたいです。LuaはDCSのプラグインの言語なんでわかるんですけどなんでGolangで書かれてたんだろう…。
DCS-BIOSのプロトコル#
日本語での解説は皆無だと思うのでここに書いておきます。DCS-BIOSはメモリの変化の情報をそのまま抜き出してきたような感じのプロトコルで、アドレスとかはありますがアドレスに1対1で対応したデータが送られてくるわけではありません。例えば0x00というアドレスで8バイト分のデータが送られてきたとします。このときデータを見ただけでは0x00からのデータが文字列なのか数値なのかの判断をすることはおろか、データ間の区切りすらわかりません。データを受け取る側は欲しいデータの型と長さとアドレスを知っておく必要があります。あと場合によってはビットマスクの値とビットシフトの値も必要です。
で、それがこんな感じ。なんとなく書いたけどいらんなこれ…
Data Address以降は何回も繰り返される可能性があります。全ての数値はリトルエンディアンなので読むときは注意する必要があります。
データを受け取る側、クライアントは受け取ったデータの内必要な部分を保持しておく必要があります。もちろん全てのデータを保持する必要はないので、65kbもメモリを持っていかれるわけじゃないんですが、いまいちどこが必要なのか探すのが面倒なので私は全部保持してます。PCだとなんとも無いけど組み込みだとちょっと辛い。
実装時の注意点として、DCS-BIOSから送られてくるアドレスはあくまでもメモリに変化があった箇所の始点のアドレスなのでそのまま使ってはいけないです。もちろんそのまま使うこともできますが、データが歯抜けになります。(1敗)
機体のスピードなんかは同時に変化し続けるのでまとめてデータが送られてきます。例えば0x0050から10バイトぐらいが機体のスピードに関するデータが書き込まれている場所だとします。DCS-BIOSは0x0050から10バイトの長さで変更があったよ~と教えてくれるわけです。このとき変化するアドレスは0x0050、0x0051、0x0052…となるわけですが、0x0052のデータが欲しいからと言って0x0052とDCS-BIOSのプロトコルのData Address(今回は0x0050)を直接比較してしまうと当然falseになります。するとこれも当然ながら0x0050以外の箇所はデータがない事になってしまいます。DCS-BIOSはデータを纏めて送ってくるという知識があればすぐに気づく当然のことなんですが、全然気づかなかったのでここに書いておきます。
Embassyについて#
I2Cについて#
まだ全然分からん感じなので大したことかけないんですが、Embassyを使いながらでもEmbedded HALのライブラリは使えることに気づくのに時間がかかったので、これもここに書いておきます。
Embassy-rpのHALもEmbedded HALといい感じに互換性があるみたいです。詳しいことはよくわからないのでそのうちちゃんと読みます。
外部入力割り込みについて#
これもさっぱり分からんのですが、どうやらTaskを起動して中でinputのwait_for_high().await
とかを呼ぶことで実現している…?みたいです。
よくわからんのでExample
Tauriについて#
すごい簡単でいいですねこれ Electronが流行るのもわかる
Tauriを選んだ理由とかは特に無いんですけど、ラズピコで動くコードがそのままデスクトップでも動くのでバグが入り込む場所が少なくなっていいかなと思って採用しました。
なんか書きたいんですけどGitHubがクソ重たくて全然コード見れないので今日はこの辺にしておきます。
その他#
ハード側は3Dプリンターの記事でも書いた通りある程度できてきていますが、大量のボタンをまとめてラズピコに送る部分ができてません。
次に向けて#
とりあえず基板設計し終えたい。ソフト側もこちらからの書き込みに対応したい。