🎵

MSX0でHTTP通信

2023/10/11に公開

MSX0は、BASICからHTTP通信が出来るようになっているようですので試してみました。

事前準備

MSX0をシステムメニューからWi-fiの設定します。設定方法は、付属SDカードのDOC/manualフォルダにあるマニュアル(1_MSX0Stack利用方法.pdf)に書かれています。M5 Stackは、2.4GHz(b)に対応しているようです。
設定が出来ていると、画面下に、MSX0に割り当てられたIPアドレスが表示されます。

私のところのネットワーク環境では192.168.10.123になりました。このIPアドレスはそれほど重要ではないので表示されていればOKです。

HTTPサーバの準備

MSX0からHTTP通信をする相手、つまりHTTPサーバが必要になります。サーバの用意方法は色々ありますが、ここでは手軽な方法としてWindowsかMac上で動作するVisual Studio Code(以降はVSC)を使ってみます。VSCはテキストエディタですが、お手軽にHTTPサーバとして機能させることが出来ます。

Visual Studio CodeをHTTPサーバとして動かす

機能拡張のLive Serverを使います。

VSCの画面左端のブロックぽいアイコンを選んで検索枠にLive Serverと入力してInstallボタンを押します。

そのまま歯車アイコンをクリックして、Extension Settingsを選びます。

設定画面を下へとスクロールして、Use Local IP as hostにチェックを入れます。
Live ServerはデフォルトではLocalHost(127.0.0.1)を使ってHTTPサーバを起動します。VSCが動作しているPC上でHTTP通信をするのであればLocalHostで充分なのですが、今回はMSX0からPCへとアクセスさせるため、PCに割り当てられているIPアドレスを使ってHTTPサーバを起動させるようにします。

MSX0に送るファイルを用意する

MSX0からHTTP要求があった時に、送り返す中身を用意します。一般的にはHTMLですね。これはテキストファイルとして作成します。

VSCの左上アイコンをクリックして、Open Folderボタンを押します。

適当な場所にフォルダを作成して、そのフォルダを選択します。Live Serverはこのフォルダを基点にして、HTTP通信のやり取りをします。

新規ファイルを作成します。

ファイル名はindex.htmlにしておきましょう。

適当に文章を入力して保存します。

VSCの右下にあるGo Liveという箇所をクリックすると、HTTPサーバが起動します。

それと同時に、デフォルトのWebブラウザが起動して、先ほど作成したindex.htmlを表示してくれます。

ちなみにHTMLを書けばちゃんと動作します。ここではただのテキストにしておきましょう。

ここでWebブラウザに表示されたIPアドレスとポート番号(5500)が、MSX0からアクセスする時のIPアドレスになります。

これでHTTPサーバの準備は完了です。

MSX0からアクセステストしてみる

MSX0からHTTPを使う方法ですが、MSX0の付属SDに収録されているDSKフォルダのSAMPLE.DSKに、HTTP通信用のコード(SEND2NET.BAS)がありましたので、これを参考にしてみました。

まずは通信自体が出来るかどうかの疎通確認をしてみますので、以下のコードをMSX0に入力して実行してみます。入力方法は、マニュアルに書かれているUSBリモート接続でも、ディスクイメージ経由でも、実機のキーボードポチポチ入力のどれでも構いません。
2010行目のIPアドレスは、先ほどのPC側のIPアドレスに置き換えてください。MSX0のIPアドレスではないです。

1010 CLS
1020 CLEAR 800
2010 SV$="192.168.10.108"
2020 PA$="msx/me/if/NET0/"
3010 _IOTPUT(PA$+ "conf/addr",SV$)
3020 _IOTPUT(PA$+ "conf/port",5500)
3030 _IOTPUT(PA$+ "connect",1)
3510 FOR T=0 TO 100:NEXT
3520 _IOTGET(PA$+ "connect",S)
3530 PRINT S
3530 IF S<>1 THEN PRINT "connect fail":GOTO 8010
3540 PRINT "connect success"
8010 _IOTPUT(PA$+ "connect",0)

実行して、画面上にconnect successと表示されたら成功です。

失敗する時の理由はいくつか考えられます。

  • IPアドレスかポート番号が間違っている
  • 外部からアクセスできないを使っている(仮想通信デバイスにありがちです)
  • PC側でセキュリティソフト(ファイヤウォール)が働いていて、外部からのアクセスをブロックしている
    などなどです。

上記プログラムの説明

MSX0からHTTP通信の設定をするには_IOTPUT命令を使うようです。この命令の第一引数はDOC/manualフォルダにある、2_IoT_BASICノード情報.pdfに書かれている文字列を使うようです。

HTTP通信だけでなく、他のセンサーの情報を受け取ったり、MSX0自身をリブートしたりシャットダウンしたりすることも出来るようになっています。
HTTP通信の場合、msx/me/if/NET0/ に加えて、/conf/addr, /conf/port, /connect, /msgという文字列を使います。
_IOTPUTが設定、_IOTGETが読み取りのようです。

3010,3020行目は、IPアドレスとポート番号を指定しています。
3030行目のconnectは詳しい説明がないのですが、1を指定することで通信準備になるようですね。
3510行目はMSX0がHTTPの準備をするための待ち時間でしょうか。サンプルコードがそのようになっていたのでコピペしました。
3520行目は、通信可否状態の読み取りです。読み取った結果は変数Sに代入され、1の時は成功となるようです。

HTTPサーバのindex.htmlを読み取る

上記のプログラムに加えて以下のプログラムを入力します。

4010 NL$=CHR$(13)+CHR$(10)
4020 _IOTPUT(PA$+"msg", "GET /index.html HTTP/1.1"+NL$)
4030 _IOTPUT(PA$+"msg", NL$)
4040 FOR T=0 TO 100:NEXT
4050 _IOTGET(PA$+"msg", RV$)
4060 IF RV$="" THEN 8010
4070 PRINT RV$;
4080 GOTO 4050

補足:HTTP1.1でGETする時はHost情報も送る必要があるので、VSC LiveServerではなく、ngnixやApacheといったHTTPサーバに対して通信をする時は以下の行も追加してください。

4025 _IOTPUT(PA$+"Host:"+SV$+NL$)

実行結果

追加プログラムの説明

HTTP通信の改行コードは送受信共にCR+LF(0x0D, 0x0A)ですので、4010行目で定義しています。

4020行目は、HTTPでクライアント(MSX0)からHTTPサーバに対して要求する時のお約束(プロトコル)です。サーバから受け取りたいファイル名を指定しています。ここのページの最初にVSCで作成したindex.htmlになります。
4030行目もHTTPのお約束で、クライアント(MSX0)からHTTPサーバに対して、これ以上、クライアントから送るものはありませんよという区切り情報です。空行を送るというお約束になっています。
この辺はHTTP通信などのキーワードで検索すると出てきますし、MSX0とはあまり関係がない話なので省略します。

4050行目は受信処理で、HTTPサーバから送られてくるデータを受け取ります。受け取ったデータは、RV$に文字列として格納されます。受信した文字列が空であれば終了へとジャンプし、そうでなければPRINTで表示して繰り返します。

4050行目で受け取る文字列ですが、HTTPサーバから送られてくるデータの1行ではありません。色々と調べてみたところ、_IOTGET()では、最大で63文字分のデータを受け取ることができる(63文字しか受け取れない)ようです。
ですので、長いデータの場合は63文字毎に区切られて受信することになりますから、4070行目のPRINT文は行末にセミコロン(;)を付けて表示する必要があります。また、このデータには改行コード(0x0D,0x0A)も含まれています。

受信したデータの中身

先ほどのプログラムを実行すると、以下の内容が画面に表示されます。

HTTP/1.1 200 OK
Vary: Origin
Access-Control-Allow-Credentials: true
Accept-Ranges: bytes
Cache-Control: public, max-age=0
Last-Modified: Mon, 09 Oct 2023 11:59:54 GMT
ETag: W/"d-18b144edc3f"
Content-Type: text/html; charset=UTF-8
Content-Length: 13
Date: Tue, 10 Oct 2023 13:45:08 GMT
Connection: keep-alive
Keep-Alive: timeout=5

HELLO MSX0!

VisualStudioCodeで作成したindex.htmlの中身は HELLO MSX0! だけでしたが、その前に長々とテキストが送られてきています。
この辺もHTTPのお約束で、1行目のHTTP/1.1 200 OKがステータスライン、2行目以降がレスポンスヘッダ、続いて空行があり、そこからのHELLO MSX0!がレスポンスボディという構成になります。

MSX0を使ってHTTPサーバからデータを受け取る場合、レスポンスヘッダの中身を使うことはあまりなさそうですので、レスポンスボディだけを使えた方が便利そうですが、BASICを使ってレスポンスボディを切り分けるのはちょっと重そうですね。

理想的には、HTTPサーバがステータスラインとレスポンスヘッダを送らないようになっていればよいのですが、残念ながらVisualStudioCodeのLive Serverでは出来ません。
他の手としては、HTTP/1.1で要求している箇所をHTTP/0.9にすることでレスポンスボディだけを受取るという手段もあるのですが、サーバ側がHTTP/0.9に対応している必要があり、VisualStudioCodeのLive Server機能では出来ないようです。

レスポンスボディだけを根性で切り出す

受け取ったデータからステータスラインとレスポンスヘッダを読み捨てればいいわけです。レスポンスヘッダとレスポンスボディの区切りは空行(0x0D,0x0A)ですから、前の行の改行コードからの並びが0x0A,0x0D,0x0A(10進数だと10,13,10)になっていれば、そこがレスポンスヘッダの最後ということになります。その次からがレスポンスボディですね。

1010 CLS
1020 CLEAR 800
2010 SV$="192.168.10.108"
2020 PA$="msx/me/if/NET0/"
3010 _IOTPUT(PA$+ "conf/addr",SV$)
3020 _IOTPUT(PA$+ "conf/port",5500)
3030 _IOTPUT(PA$+ "connect",1)
3510 FOR T=0 TO 100:NEXT
3520 _IOTGET(PA$+ "connect",S)
3530 PRINT S
3530 IF S<>1 THEN PRINT "connect fail":GOTO 8010

4010 NL$=CHR$(13)+CHR$(10)
4020 _IOTPUT(PA$+"msg", "GET /index.html HTTP/1.1"+NL$)
4030 _IOTPUT(PA$+"msg", NL$)
4040 FOR T=0 TO 100:NEXT

5000 DIM CK$[3]
5010 CK$[0]=CHR$(10):CK$[1]=CHR$(13):CK$[2]=CHR$(10)
5020 IX=0

5100 _IOTGET(PA$+"msg", RV$)
5110 IF RV$="" THEN 8010
5120 LN=LEN(RV$)
5130 FOR I=1 TO LN
5131 PRINT "#";
5140 C$=MID$(RV$,I,1)
5150 if C$=CK$[IX] THEN IX=IX+1 ELSE IX=0
5160 IF IX<>3 THEN NEXT
5170 IF IX=3 THEN GOTO 5200
5180 GOTO 5100

5200 'BODY
5210 MS$=RIGHT$(RV$,LN-I)
5220 _IOTGET(PA$+"msg", RV$)
5230 MS$=MS$+RV$

8010 _IOTPUT(PA$+ "connect",0)
8020 PRINT
8030 PRINT MS$

5000から5180行目がステータスラインとレスポンスヘッダの読み捨て処理です。5200行目からが目当てのレスポンスボディです。5210行目は読み捨て処理後の残りデータで、5220行目で続きを1度だけ読み取っています。ちゃんとやるのであれば、ここでもループ処理で受け取り処理を書いた方がいいでしょう。
8030行目の時点でMS$にはレスポンスボディ、つまり、index.htmlに書いた*HELLO MSX0!*が入ってきます。
5131行目は、ヘッダの読み捨て経過を表示するものです。なんで経過を表示しているかというと、このプログラムを実行してから結果を受け取るまで7秒くらい待たされるからです。遅いですね!
たぶん、MID$で1文字単位で文字を切り出すのが遅いのではないかなと思うのですが、BASICにやらせる処理ではないような気がします。他にもっと良い書き方があるかもしれません。

ちょっとだけ?実用的な使い方

index.htmlの中身を以下のように書き換えます。

VisualStudioCodeは、テキストファイルを保存する時に勝手に改行コードを付けてしまうので、設定項目のinsertFinalNewlineをOffにしてください。

それから先ほどのBASICプログラムに以下の行を追加してRUNすると、ドレミ~と曲が再生されます。

8040 PLAY MS$

その他にも、VisualStudioCodeでOpen Folderで指定したフォルダ内にバイナリファイルを置いておけば、MSX0で受け取ることも出来るようです(GET /index.htmlのファイル名のところを変える)。

動作速度の問題は、やはりマシン語ということになってしまうと思いますが、VisualStudioCodeではなく、ちゃんとしたHTTPサーバを用意して、送信データを工夫する事でも改善の余地はありそうです。やっぱりBASICは手軽でいいですよね。

Discussion