Webページの取得

本チュートリアルでは、iSDIOコマンドでFlashAirを制御し、 インターネット上のファイルを取得してみます。


概要

iSDIOの無線LAN仕様には、HTTP (HyperText Transfer Protocol) 通信を利用したデータの送受信機能が含まれています。

通信に必要な HTTPや TCP/IP (Transmission Control Protocol/Internet Protocol) の処理を、 Arduino自身が行うことなくすべてFlashAirに任せることができます。 逆に言えば、それ以外のプロトコルを使うことはできませんが、 Arduinoの小さいRAMの上では、このトレードオフは多くの場合でメリットの方が大きいのではないでしょうか。

本チュートリアルでは、Webページの取得を行ってみましょう。


HTTP通信コマンドの種類

HTTP通信コマンドには、プロトコルやデータの渡し方の違いなどにより、いくつかのバージョンがあります。

コマンドID 名称 プロトコル 送信データの種類 コマンドにデータを渡す方法
21h SendHTTPMessageByRegister HTTP テキスト メモリ上から
22h SendHTTPFileByRegister HTTP ファイル メモリ上から
23h SendHTTPSSLMessageByRegister HTTP over SSL テキスト メモリ上から
24h SendHTTPSSLFileByRegister HTTP over SSL ファイル メモリ上から
25h SendHTTPMessageByFile HTTP テキスト ファイルから
26h SendHTTPFileByFile HTTP ファイル ファイルから
27h SendHTTPSSLMessageByFile HTTP over SSL テキスト ファイルから
28h SendHTTPSSLFileByFile HTTP over SSL ファイル ファイルから

いずれも Send から始まる名前ですが、送受信両方に使います。 HTTP通信は、クライアントからリクエストを送信し、サーバーが返信する、という仕組みだからです。 ファイルを返信してというリクエストであればサーバーからのファイル受信、 リクエストにファイルを付けて送るとサーバーへのファイル送信、となります。

HTTPに関しては Wikipediaをご覧ください。

なお、受信サイズは最大2048バイトとなっています。(iSDIOヘッダを除くと2024バイト。) 送信にはファイルを使う方法があるためサイズ制限は厳しくありません。


SendHTTPSSLMessageByRegisterコマンドの作成

この例では、FlashAir Developersのトップページのデータを取得することにします。

リクエストの送信

FlashAir Developersは、暗号化された通信を行うため HTTP over SSL (Secure Socket Layer) を使用しています。 データ取得には、HTTPの GETというコマンドを使います。 GETリクエストでは、リクエストヘッダのテキストデータのみが必要です。

以上の条件から、コマンドID 23hの、SendHTTPSSLMessageByRegisterコマンドを使います。

arduino_tutorial_6.ino (一部抜粋)
    boolean iSDIO_http(uint32_t sequenceId) {
      Serial.print(F("\nhttp command: \n"));
      memset(buffer, 0, 512);
      uint8_t* p = buffer;
      p = put_command_header(p, 1, 0);
      p = put_command_info_header(p, 0x23, sequenceId, 2);
      p = put_str_arg(p, "flashair-developers.com");  // Argument #1.
      p = put_str_arg(p,                              // Argument #2. 
          "GET /en/ HTTP/1.1\r\n"
          "Host: flashair-developers.com\r\n"
          "User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.125 Safari/537.36\r\n"
          "\r\n");
      put_command_header(buffer, 1, (p - buffer));
      printHex(buffer, (p - buffer));
      return card.writeExtDataPort(1, 1, 0x000, buffer) ? true : false;
    }
  • 7行目
    サーバーのドメイン名を指定します。IPアドレスも指定できます。
  • 9行目
    GETコマンドです。GET <取得したいデータのパス> <プロトコルとバージョン><改行> という書式です。 プロトコルとバージョンは通常HTTP/1.1でよいでしょう。改行は\r\nを使うのがHTTP通信のルールです。
  • 10行目
    ホスト名を指定します。
  • 11行目
    ユーザーエージェントを指定ています。FlashAir Developersは、ユーザーの使っているウェブブラウザを判別して 対応していないブラウザを使っている場合に警告を出しています。そのため、この例ではChromeのユーザーエージェント名を指定し(つまりChromeのふりをして)、 正しいデータが返ってくるようにしています。

  • 12行名
    最後に空行をつけます。

レスポンスの受信

コマンド完了を待機してから、取得したデータを読み取ります。 Response Dataに、サーバーから返されたデータが書かれています。 コマンド完了待機とデータの読み取り方法は、 APモードでの起動コマンド処理状況の確認 を参照してください。

今回はWebページのテキストデータが書かれていることを期待していますので、そのまま画面出力してみます。

iSDIO Command Response Data (SD Specifications Part E7 Wireless LAN Simplified Addendum Version 1.10より抜粋)

Wireless LAN SSID List

arduino_tutorial_6.ino (一部抜粋)
    boolean iSDIO_httpResponse() {
      // Read header and data.
      if (!card.readExtDataPort(1, 1, 0x200, buffer)) {
        return false;
      }
      uint32_t totalSize = get_u32(buffer + 20);
      uint32_t availableSize = totalSize > 488 ? 488 : totalSize;
      uint32_t pos = 24;
      for (;;) {
        for (uint32_t i = 0; i < availableSize; ++i) {
          Serial.print((char)buffer[pos + i]);
        }
        totalSize -= availableSize;

        // Have we read all data?
        if (totalSize == 0) break;

        // Read next data.
        if (!card.readExtDataPort(1, 1, 0x200, buffer)) {
          return false;
        }
        availableSize = totalSize > 512 ? 512 : totalSize;
        pos = 0;
      }
      return true;
    }
  • 3-8行目
    レスポンスの最初の部分を読み出します。先頭24バイト分はデータサイズなどの情報が書かれています。 必要な情報を保存しています。
  • 9-24行目
    サーバから受信したHTMLデータを画面に表示する部分です。 サイズが大きい場合は残りの部分を512バイトずつ読み取っています。

メインプログラム

メインプログラムに、追加します。

arduino_tutorial_06.ino (一部抜粋)
    void loop() {
        .. (snip) ..
      Serial.print(F("\n5. HTTP Get"));
        .. (snip) ..
        case 5 :
          if (iSDIO_http(nextSequenceId) &&
              iSDIO_waitResponse(nextSequenceId)) {
              iSDIO_httpResponse();
            Serial.println(F("\nSuccess."));
          } else {
            Serial.print(F("\nFailed or waiting. errorCode="));
            Serial.println(card.errorCode(), HEX);
          }
          nextSequenceId++;
          break;
        .. (snip) ..
      }
    }

実行結果

実行してみましょう。

Initializing SD card...OK
Waiting response 
  Process Succeeded
... (snip) ...
0. Show status
1. Disconnect
2. Establish
3. Connect
4. Scan
5. HTTP Get

Command? (next sequence id = 1)

Connectコマンドで、Internetの利用できる無線LANにつなぎます。 ここでは、iPhoneのインターネット共有(テザリング)を使ってみます。

シリアルターミナルのボックスに、 3、Enterと入力します。 つづいて、SSIDとパスワードを入力します。 (SSIDとパスワードの入力は、; (セミコロン) で終端することを忘れずに!)

SSID? iPhone
Network Key? 12345678

Connect command: 

00: 01010000300000000000000000000200
01: 0200000002000000060000006950686F
02: 6E650000080000003132333435363738

Waiting response 
  Command Processing.............
  Process Succeeded

Success.

ステータスで、IPアドレスが正しく得られていることを確認しましょう。

... (snip) ...
 [0550h] IP Address: 172.20.10.4
... (snip) ...

続いてHTTPによる受信です。 シリアルターミナルのボックスに、 5、Enterと入力します。

Command? (next sequence id = 2)

http command: 

00: 01010000E80000000000000000002300
01: 030000000200000017000000666C6173
02: 686169722D646576656C6F706572732E
03: 636F6D00AF000000474554202F656E2F
04: 20485454502F312E310D0A486F73743A
05: 20666C6173686169722D646576656C6F
06: 706572732E636F6D0D0A557365722D41
07: 67656E743A204D6F7A696C6C612F352E
08: 30202857696E646F7773204E5420362E
09: 333B20574F57363429204170706C6557
0A: 65624B69742F3533372E333620284B48
0B: 544D4C2C206C696B65204765636B6F29
0C: 204368726F6D652F33362E302E313938
0D: 352E313235205361666172692F353337
0E: 2E33360D0A0D0A00

Waiting response 
  Command Processing...
  Process Succeeded
HTTP/1.1 200 OK
Date: Tue, 21 Oct 2014 06:25:10 GMT
Server: Apache/2.2.15 (CentOS)
X-Powered-By: PHP/5.3.3
Set-Cookie: FASSID=c637h0hs62jvc9055f5krvpfc4; path=/
Cache-Control: max-age=0, no-cache, no-store, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Set-Cookie: FASSID=o4365cm2e7nqf4afflk727flr3; path=/
Set-Cookie: FASSID=u5h3v3tf0ik7kn2jv3os2aakc4; path=/
X-Mod-Pagespeed: 1.8.31.4-4056
Vary: Accept-Encoding,User-Agent
Content-Length: 25710
Connection: close
Content-Type: text/html; charset=UTF-8

<!DOCTYPE html>
<!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7" lang="en"> <![endif]-->
<!--[if IE 7]> <html class="no-js lt-ie9 lt-ie8" lang="en"> <![endif]-->
<!--[if IE 8]> <html class="no-js lt-ie9" lang="en"> <![endif]-->
<!--[if gt IE 8] -->
<html lang="en">
<!-- <![endif] -->


<head>

<meta charset="utf-8"/>
<!-- %meta{:content => "IE=edge,chrome=1", "http-equiv" => "X-UA-Compatible"} -->

<!--Google Apps verification-->

<title>FlashAir Developers - Home</title>
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>

<!--[if lt IE 9]>
    <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link href="/images/flashair_favicon.ico" rel="shortcut icon"/>
<link href="/images/apple-touch-icon-114x114-precomposed.png" rel="apple-touch-icon-precomposed" sizes="114x114"/>
<link href="/images/apple-touch-icon-72x72-precomposed.png" rel="apple-touch-icon-precomposed" sizes="72x72"/>
<link href="/images/apple-touch-icon-57x57-precomposed.png" rel="apple-touch-icon-precomposed"/>
<link href="/css/bootstrap.css" media="screen" rel="stylesheet" type="text/css"/>
<link href="/css/responsive.css" media="screen" rel="stylesheet" type="text/css"/>
<link href="/css/font-awesome.css" media="screen" rel="stylesheet" type="text/css"/>
<link href="/css/theme.css" media="screen" rel="stylesheet" type="text/css"/>
<link href="/css/fonts.css" media="screen" rel="stylesheet" type="text/css"/>
<link href="/css/prett
Success.
... (snip) ...

HTTP/1.1 200 OKと書かれた行から、 Success.の上の行までが、受信したデータです。 受信サイズ制限のため切れてしまっていますが、FlashAir Developersのページが受信できました。


サンプルコード

arduino_tutorial_06.zip (24KB)

本チュートリアルのサンプルコードはGPLv3および二条項BSDライセンスで提供されています。 詳細はダウンロードした各ファイルを参照してください。