はじめに
WebMiteを使うことでTCP/IPを利用できるようになります。PicoMite User Manualに記載されているWebサーバに関する記述をもとにWebMiteのWebサーバ機能を使ってみた。
TCPサーバの起動と停止
TCPサーバの起動
WebMiteでWebサーバを起動するにはOPTION TCP SERVER PORT nn
コマンドを使ってTCPのサーバを構成します。nnはサーバのポート番号です。Webサーバ、httpのポート番号は一般的に80なので次のようにコマンドプロンプトで実行します。コマンド実行後にWebMiteが再起動します。このコマンドは一度実行すれば保持されます。
> OPTION TCP SERVER PORT 80
PICO0123456789A connecting to WiFi...
Connected 192.168.10.24
Starting TCP server at 192.168.10.20 on port 80
試しにWebブラウザでOPTION
コマンドの出力したIPアドレスにアクセスしてもアクセスに対する応答のプログラムを実行していないので何も表示されない。Wiresharkで確認すると応答コード404を受信していました。
TCPサーバの停止
起動しているTCPサーバーを停止するときには起動時に使ったコマンドのポート番号を0にして実行します。実行後WebMiteは再起動します。
> OPTION TCP SERVER 0
サーバの最大接続数
TCPサーバが応答できる最大接続数はMM.INFO(MAX CONNECTIONS)
で確認できます。以下が実行結果で、最大8接続できることを示しています。
> PRINT MM.INFO(MAX CONNECTIONS)
8
Webサーバ機能の実装
OPTION TCP SERVER PORT 80
コマンドで80ポートを開きますがクライアントからの要求に応答するWebサーバーのプログラムはないため作成します。
80ポートへのアクセスが発生した場合に実行するサブルーチンは次のコマンドで指定します。これは割り込み処理になります。パラメータinterruptSub
に実行するサブルーチン名を指定します。
WEB TCP INTERRUPT interruptSub
サーバプログラム
PicoMite User Manualに掲載されたプログラムをもとにADT7410温度センサーで計測した温度をOLEDディスプレイに表示し、Webサーバーへアクセスすると温度を表示するプログラムを作成した。
Webサーバのプログラムは次の処理を実行します。
- クライアントから要求文字列を受信バッファに格納する
- 適切なHTTPヘッダかを確認する
- 適切なHTTPヘッダならばクライアントが要求しているリソースが存在するかを確認する
- 要求されたリソースが存在する場合はそれをクライアントに返信する
変数宣言など
変数宣言部を以下に示します。行番号は全体の通し番号です。
3行目に80番ポートへされたときに実行するサブルーチンWebInterrupt
を指定しています。
5〜9行目は温度センサーADT7410の温度データを格納する変数やI2C接続のピン番号を指定しています。
2 Option Explicit ' 変数宣言を強制する
3 WEB TCP INTERRUPT WebInterrupt ' Webアクセス時の処理サブルーチン指定
4 ' 変数宣言
5 Dim data%(1), raw%, temp! ' ADT7410空データ保存、温度データ用
6 Dim stemp$,datestr$ ' 表示用文字列保存用
7 Const TMP_ADDR = &H48 ' ADT7410のI2Cアドレス
8 SetPin GP16, GP17, I2C ' OLED I2C接続ピン
9 I2C OPEN 100, 100 ' I2Cチャンネル1を開く
ADT7410温度センサーのデータ処理
Raspberry Pi PicoでPicoMite(MMBasic)を使う〜OLEDディスプレイへの出力で作成したコードを流用している。
下記のコードを無限ループで実行している。
- 12、13行目:日時文字列の作成
ブラウザ上に表示する日時の文字列を作って変数datestr$
に格納しています。MMBasicで取得できる日付の形式がYYYY/MM/DDでないため、YYYY/MM/DD形式に変換しています。 - 14〜18行目:温度の取得
で温度センサADT7410からデータを読み取り、温度へ変換しています。 - 19行目:日時文字列をOLEDディスプレイに出力
- 20行目:温度を整数部2桁、小数部1桁の文字列に変換
- 21行目:温度文字列をOLEDディスプレイに出力
11 Do
12 datestr$ = Mid$(Date$, 7, 4) + "/" + Mid$(Date$, 4, 2) + "/" + Mid$(Date$, 1, 2)
13 datestr$ = datestr$ + " " + Time$
14 I2C READ TMP_ADDR, 0, 2, data%()
15 raw% = data%(0) << 8 Or data%(1)
16 raw% = raw% >> 3
17 If raw% >= 4096 Then raw% = raw% - 8192
18 temp! = raw% / 16.0
19 Text 0, 0, Time$,,3
20 stemp$ = Str$(temp!, 2, 1)
21 Text 0, 32, stemp$ + Chr$(&H60) + "C",,3
22 Pause 5000
23 Loop
Webアクセス時の処理ルーチン
25〜50行が80番ポートへのアクセス時に処理されるサブルーチンです。 PicoMite User Manualの75ページに記されているコードをそのまま使っています。
処理内容は下記のとおりです。
- 26行目:内部処理に必要なローカル変数、buff%()はクライアントから受信したメッセージを格納するバッファ
- 27〜49行目:複数接続に対応するためのループ
- 28行目:クライアントからのメッセージを読み取り、バッファに格納
- 29行目:バッファから文字列GETの位置を取得。
LINSTR
は長い文字列から指定された文字列の位置を返す関数です - 30行目:バッファから文字列HTTPの位置を取得。
- 31行目:HTTPのGETメソッドによるリソースの取得かの判定
HTTPでWebサーバーのリソースを取得するときはHTTPヘッダにGET / HTTP/1.1
という文字列が含まれるなずなので文字列GETがあり(p1% > 0)、かつHTTPがあり(p2% > 0)かつGET、HTTPの順(P2% > p1%)であるかを判定している。 - 32行目:クライアントが取得しようとしているファイル名を取得し、小文字に変換して変数
file$
に格納
LGetStr$
関数で長い文字列(buf%())のp1% + 4番目からp2% - p1% - 5文字分を取り出し、LCASE$
関数で小文字に変換している
GETメソッドがGET /Hello.html HTTP/1.1
の場合、/hello.html
が得られる - 33行目:ファイル名が
/
だけの場合は/index.html
に変更する - 34行目:35行目がエラーでも無視する
ON ERROR SKIP
は次の行のコマンドでエラーがあってもそれを無視します。読み取り専用変数MM.ERRNO
に0以外の値がセットされます - 35行目:変数file$のファイルを読み取りモードで開く。存在しない場合はエラーになるが、直前の
ON ERROR SKIP
でプログラムの実行は継続する - 36行目:エラーがあった場合(
MM.ERRNO
が0以外)は応答コード404を返す - 37行目:35行目で開いたファイルを閉じる
- 38〜47行目:ファイルの拡張子(ファイル名の末尾4文字
RGIHT$(file$, 4)
)により処理を分ける- HTMLやテキストファイル:ファイルの内容をクライアントに返信
- 画像(BMP、PNG、JPEG、ICO):Content-Typeを設定してファイル内容をクライアントに返信
すべてのコード
以下が完全なコードです。
1 CLS
2 Option Explicit ' 変数宣言を強制する
3 WEB TCP INTERRUPT WebInterrupt ' Webアクセス時の処理サブルーチン指定
4 ' 変数宣言
5 Dim data%(1), raw%, temp! ' ADT7410空データ保存、温度データ用
6 Dim stemp$,datestr$ ' 表示用文字列保存用
7 Const TMP_ADDR = &H48 ' ADT7410のI2Cアドレス
8 SetPin GP16, GP17, I2C ' OLED I2C接続ピン
9 I2C OPEN 100, 100 ' I2Cチャンネル1を開く
10
11 Do
12 datestr$ = Mid$(Date$, 7, 4) + "/" + Mid$(Date$, 4, 2) + "/" + Mid$(Date$, 1, 2)
13 datestr$ = datestr$ + " " + Time$
14 I2C READ TMP_ADDR, 0, 2, data%()
15 raw% = data%(0) << 8 Or data%(1)
16 raw% = raw% >> 3
17 If raw% >= 4096 Then raw% = raw% - 8192
18 temp! = raw% / 16.0
19 Text 0, 0, Time$,,3
20 stemp$ = Str$(temp!, 2, 1)
21 Text 0, 32, stemp$ + Chr$(&H60) + "C",,3
22 Pause 5000
23 Loop
24
25 SUB WebInterrupt
26 LOCAL a%, p1%, p2%, file$, buff%(4096)
27 FOR a% = 1 To MM.INFO(MAX CONNECTIONS)
28 WEB TCP READ a%, buff%()
29 P1% = LINSTR(buff%(),"GET")
30 P2% = LINSTR(buff%(),"HTTP")
31 If (p1% <> 0) And (p2% <> 0) And (p2% > p1%) Then
32 file$ = LCASE$(LGetStr$(buff%(), p1% + 4, p2% - p1% - 5))
33 IF file$ = "/" THEN file$ = "/index.html"
34 ON ERROR SKIP
35 OPEN file$ FOR INPUT AS #1 ' ファイルの存在をチェック
36 IF MM.ERRNO THEN WEB TRANSMIT CODE a%, 404 : CONTINUE FOR
37 CLOSE #1
38 SELECT CASE RIGHT$(file$, 4)
39 CASE "html", ".htm", ".txt"
40 WEB TRANSMIT PAGE a%, file$
41 CASE ".bmp", ".png", ".gif"
42 WEB TRANSMIT FILE a%, file$, "image/" + RIGHT$(file$, 3)
43 CASE ".jpg", "jpeg"
44 WEB TRANSMIT FILE a%, file$, "image/jpeg"
45 CASE ".ico"
46 WEB TRANSMIT FILE a%, file$, "image/vnd.microsoft.icon"
47 END SELECT
48 ENDIF
49 NEXT a%
50 END SUB
51
52 I2C CLOSE
53
54 End
HTMLファイル
サーバからクライアントへ転送するHTMLファイルにはサーバのプログラム(上記WebSvr.bas)で処理した結果、ここでは日時(datestr$
)と温度(sTemp$
)の2つの変数値をHTMLに含めています。
HTMLコード中に変数を含める場合は{
と}
で囲みます。下記のindex.htmlの10行目の{datestr$}
と{stenp$}
です。
1 <!DOCTYPE html>
2 <html lang="ja">
3 <head>
4 <meta charset="UTF-8">
5 <title>WebMite Test</title>
6 </head>
7 <body>
8 <h1>WebMite test</h1>
9 <h2>温度モニタ</h2>
10 <p>{datestr$}の温度は{stemp$}℃です</p>
11 </body>
12 </html>
実行結果
MMBasicのプログラム、HTMLファイルをアクティブドライブに配置し、MMBasicのプログラムを実行します。同一ネットワーク内のMacなどのブラウザを開き、Raspberry Pi Picoに割り当てられたIPアドレスでアクセスします。この例の場合はhttp://192.168.10.24/ になります。
WebMiteでの処理に時間がかかり、タイムアウトや応答しなくなることがあり、プログラムが停止することがあります。
[43] WEB TRANSMIT PAGE a%, file$
Error : No response to request from connection no. 7
> Warning: LWIP send data timeout
Error : No response to request from connection no. 1
>
Error : No response to request from connection no. 2
>
Error : No response to request from connection no. 3
> print MM.ERRNO
16
>
ユーザーズマニュアルには「インターネットプロトコルの実装にはプロセッサのリソース(特にRAM)が大量に使用されるため、WebMiteファームウェアは、WiFiとインターネット接続が重要で、標準のRaspberry Pi Picoと比較してパフォーマンスに多少の影響があっても許容できる場合にのみ使用してください。」とあり、特にRaspberry Pi Pico Wを使用する場合には注意が必要です。Raspberry Pi Pico 2 Wは Pico Wよりもメモリ容量が大きいので上記のようなエラーメッセージは試した限りでは表示されなかった。