せっかなくので、やってみた。

日々のあんなこと、こんなこと、せっかくなのでやってみた

X68のレースゲーム OverTakeでネットワーク対戦してみた。(後編)

この記事は令和の時代もなお続くX68000用ディスクマガジン「ハリキリマガジン」の 38号(2019年7月)に収録していただいた内容に修正を加えたものです。文章が長くなったので、前編・後編に分割しています。

こちらの記事の続きです。
X68のレースゲーム OverTakeでネットワーク対戦してみた。(前編) - せっかなくので、やってみた。

ついにネット対戦

いよいよOverTakeの対戦を試します。手順は省略しますが、事前にSerial2Tcpなしの状態で通信対戦できることを確認済みです。
(XM6の完成度の高さに、改めて感動です!)
先ほどのSerial2Tcpを起動した構成でOverTakeを立ち上げ、2playersで対戦を行うと...
"not connected"が表示されて対向を認識してくれませんでした。

この後かなりの期間、Null-modem emulatorの設定やXM6の設定を変えては失敗を繰り返し、手詰まりの状態がしばらく続きました。
USBシリアルコンバータを購入し、x68実機(REDZONE)との接続も試してみましたが、繋がる事はありませんでした。
試している際中、Serial2Tcpのログ出力を見ると送受信しているデータの内容がボーレートによって変わるので、おそらくボーレートを合わせなければ 正しく通信できないだろうという事は分かったのですが、9600や19200、38400などの速度も試しても、どれもダメでした。
実際の通信設定はゲームプログラムを解析しない限り分かるはずもありません。
そもそもUSB-シリアルによってはDSR/DTRの信号が省略されている?とかの情報もあり、繋がらない原因がどこにあるのか つかめませんでした。(結局USBシリアルコンバータも3本購入することに...)

半ばあきらめかけているなかで、たまたまXM6のモニター機能でSCCの状態を表示したところ、 BaudRateの項目がx68起動直後の状態では1201、OverTakeが起動した状態では31250と表示が変わる事に気づきました。
(表示>デバイス>シリアルコミュニケーションコントローラ で表示できます。)

f:id:moneci:20191116174254p:plain:w300
ボーレート表示

どちらも見慣れない数値なので、実際のボーレートとは異なる値が表示されているのだろう思っていましたが、 試しに31250をSerial2Tcpのボーレートに設定してみたところ、なんと対戦モードが起動しました!!
どうもこの31250という値はMIDI機器を接続する時のスピードとしてよく使われるらしく、実際のボーレートである事に 気づきませんでした。
(ちなみにこの値はSWITCH.Xでは指定できませんし、9600を指定した時もSCCの表示では19531と表示されたり、値の関係性がよくわかりませんでした。)

しかしXM6のこの機能が無ければ、実際の通信設定を知る事はできませんでした。制作者様に感謝です!!
この後、実機とエミュレータでの接続も試し、

REDZONE - USBシリアルコンバータ - Windows10(Serial2TcpServer - Serial2TcpClient) - Null-modem(COM8) - TypeG(COM4)

の構成でも無事通信対戦する事ができました。 *1
(USBシリアルコンバータはラトックシステムのREX-USB60Fを使用しました。)

ラトックシステム USBシリアルコンバータ REX-USB60F

ラトックシステム USBシリアルコンバータ REX-USB60F

  • 発売日: 2005/06/20
  • メディア: Personal Computers

で、RasPiはどうなったの?

ここまででx68実機とx68エミュレータを、COMポートエミュレータ、USBシリアルコンバータを介してネットワーク対戦させることができました。
ただ、全てWindowsノートにつなげての確認だったので、当初の目的であるRasPiを使用していませんし、 ネットワークといいつつも、1台のPC内での動作なのでネットワーク感がありません。
RasPiでJava、USBシリアルコンバータが動作することはネットの情報で確認済みなので、後はインストールして試すだけです。

RasPiにログインし、以下でJava、シリアル通信ライブラリをインストールします。
ちなみにRasPiはRetroPiとして使用しているので、動作しているOSはRaspbian Stretch(RetroPi4.4)です。

# sudo apt-get install oracle-java8-jdk
# sudo apt-get install librxtx-java

USBシリアルコンバータのドライバも標準でサポートされているので、挿せば/dev/ttyUSB0として認識されました。

次にUSBシリアルコンバータのシリアル側とREDZONEをクロスケーブルで接続します。構成は以下のようになりました。

REDZONE - USBシリアルコンバータ - RasPi(Serial2TcpServer) - LAN - Windows10(Serial2TcpClient) - Null-modem(COM8) - TypeG(COM4)

RasPi側では以下でSerial2Tcpサーバを起動し、WindowsではSerial2TcpクライアントとTypeGを起動後、毎度のtype auxで疎通確認します。

# export LD_LIBRARY_PATH=/usr/lib/jni
# java -cp "./bin:/usr/share/java/RXTXcomm.jar" serial2tcp.Serial2TcpServer 9999 /dev/ttyUSB0 31250

ところが、実機からTypeGへの送信はできるものの、TypeGから実機への送信はできませんでした。(当然OverTakeも動作しませんでした)
REDZONE側のSWITHC.XとSerial2Tcpでボーレートを38400を設定しても、動作は変わりませんでした。
しかし、ボーレートを9600に変更すると、双方から送受信できたので、ここでも通信速度の問題の可能性があります。
WindowsとUSBシリアルコンバータの組み合わせでは31250でも動作していたので、RasPiとUSBシリアルコンバータ特有の問題かもしれません。

そこで"raspi 31250"で検索すると、midi関連の情報が出てきました。
どうもRasPiは31250というボーレートに標準では対応していない様で、みなさんmidi機器との接続で困っている感じです。
その中で有力そうな情報である、 /boot/config.txt の設定を変更する方法ではOSバージョンの違いの為か、成功しませんでした。 今度はLinuxのシリアルドライバである"ftdi_sio 設定"で検索すると大変参考になりそうな記事が。

qiita.com

qiita.com

なかなか難しい内容ですが、ボーレートを38400に設定し、RasPiのシリアルのベースボーレートを割り算して31250になる値(divisor)を setserialコマンドで指定するとよいみたいです。(カーネルの再コンパイルまでは手が出せないのでやっていません)
まずはsetserialをインストールして現在のベースクロックを確認。

# sudo apt-get install setserial
# sudo setserial -a /dev/ttyUSB0
/dev/ttyUSB0, Line 0, UART: unknown, Port: 0x0000, IRQ: 0
        Baud_base: 24000000, close_delay: 0, divisor: 0
        closing_wait: infinite
        Flags: spd_normal

Baud_base: 24000000と出ました。24000000÷31250=768で、divisorに設定する値がピッタリ整数で導きだせました。 もしかしたらいけるかもしれません。次のコマンドでttyUSB0にボーレートとdivisorを設定します。

# sudo stty -F /dev/ttyUSB0 38400
# sudo setserial /dev/ttyUSB0 spd_cust divisor 768

再度確認します。正しく反映された様です。

# sudo setserial -a /dev/ttyUSB0
/dev/ttyUSB0, Line 0, UART: unknown, Port: 0x0000, IRQ: 0
        Baud_base: 24000000, close_delay: 0, divisor: 768
        closing_wait: infinite
        Flags: spd_cust

それではOverTakeを起動して確認してみます。
すると...遂に動きました!!!とうとうRasPiを使ってのネットワーク対戦成功です!
こうして、かなり苦労したものの、RasPiでの対戦も何とか実現にたどり着く事ができました。

動作の様子はこちら
youtu.be

ちなみに、ネットワーク対戦の確認で、実機を16MHz、TypeGを10MHzで動かしたときに実機が先にゴールしたにも 関わらずTypeG側が勝利となった事がありました。
TCP変換も入っているし、実機とエミュレータの違いもあるので仕方ないかなーと思っていましたが、 OverTakeのシステムディスクに収録さていたREADME.DOCに以下の様な記述を発見しました。

『あと、通信プレイ時には必ず動作環境の統一(*)を、くれぐれもおねがいいたします。

(*)
 画面モード・BGMの有無等の設定の差で、画面上の見た目と内部的な処理との間にタイミング差が 生じて、実際の勝敗の内容が変わってしまう事があります。この場合は表示されているトータルタイム にて勝敗結果を判断して下さい。
 けんかしないでね。』

との事なので、CPUクロックの違いなどでレース結果が正しくなくなるかもしれません。
一応CPUクロックを合わせた場合は、抜きつ抜かれつの場面でも問題なく動作しているように見えました。 (何分一人で試しているので、あまり動作検証はできておりません...)
いずれにしても、Serial2Tcpを入れたことによって、挙動が変わっている可能性がありますので、ご了承ください。

最後に

以上の様な感じで、数年前から「もしかしたらできるんじゃないか」と考えていたことが、 やっと実現できました。技術的にできたというよりは、動作環境等を調べまくって(ググって)の成果なので あまり自慢はできませんが、あきらめずに粘り強くトライしての結果なので、本当に嬉しい限りです。

そしてここまで書いておきながらではありますが、この試みを始めた本当の理由は、ジオグラフシールの ネットワーク対戦をやってみたい為だったのです。
ジオグラフシールの方はSerial2Tcpを使わない状態でも接続する事ができず、この方法自体がだめだかと 考えていたのですが、代わりに試したOverTakeがエミュレータ上で動作したので、最後まで試した次第です。
(ジオグラフシールの場合は、本物のRS232C同士で接続しないと、通信できないのかもしれません。)

この仕組みをさらに発展させて、いつかはインターネット経由での「誰とでも対戦」が実現できればなーとか、 対戦以外でも、例えばMIDI機器のネットワーク化など他の用途にも応用もできるかもしれませんので、 暇を見て引き続きトライしてみたいと思います。

最後に、XM6本家のPI.氏、XM6TyepGのGIMONS氏、XM6iのisaki氏、Null-modem emulator (com0com)開発者様に 感謝申し上げます。これらの素晴らしいソフトウェアにより今回の試みを実現する事ができました。
ありがとうございました。

動作確認に使用した環境

[Windows環境]

  • Windows10 Pro 1803
  • Java 1.8.0_192-b12
  • rxtx-2.2pre2
  • com0com 3.0.0.0
  • XM6 TyepG version 3.30 L35
  • XM6i version 0.55

[Raspberry Pi環境]

  • Raspberry Pi 2 Model B
  • Retropie4.4(Linux retropie 4.14.52-v7+ / Raspbian Stretch)
  • Java 1.8.0_65-b17
  • rxtx-2.2pre2-13

[USBシリアルコンバータ(接続OKなもの)]

ラトックシステム USBシリアルコンバータ REX-USB60F

ラトックシステム USBシリアルコンバータ REX-USB60F

  • 発売日: 2005/06/20
  • メディア: Personal Computers

  • その2 FTDI社のチップを使用したケーブル (たしか秋月で購入したはずだが同じものか自信なし。)
    akizukidenshi.com

[USBシリアルコンバータ(接続NGなもの)]

https://www.amazon.co.jp/gp/product/B00QUZY4UG/ref=ppx_yo_dt_b_asin_title_o03_s00?ie=UTF8&psc=1

※Cannot set serial info: Inappropriate ioctl for deviceのエラーでsetserialコマンドが動作しない

*1:本文では説明を省略しておりましたが、USBシリアルコンバータはCOMポートを増設する趣旨のものなので、 x68実機への接続する際は、シリアルのクロスケーブルをはさむ必要があります。