0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Raspberry Pi Pico WでWebMiteを使う〜Webサーバ

Posted at

はじめに

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サーバのプログラムは次の処理を実行します。

  1. クライアントから要求文字列を受信バッファに格納する
  2. 適切なHTTPヘッダかを確認する
  3. 適切なHTTPヘッダならばクライアントが要求しているリソースが存在するかを確認する
  4. 要求されたリソースが存在する場合はそれをクライアントに返信する

変数宣言など

変数宣言部を以下に示します。行番号は全体の通し番号です。
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を設定してファイル内容をクライアントに返信

すべてのコード

以下が完全なコードです。

WebSvr.bas
     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$}です。

index.html
     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/ になります。

スクリーンショット 2025-05-30 20.19.07.png

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よりもメモリ容量が大きいので上記のようなエラーメッセージは試した限りでは表示されなかった。

参考サイト

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?