APモードでの起動
本チュートリアルでは、iSDIOコマンドを使って、FlashAirの無線LANをAPモードで起動してみます。
概要
APモードの起動には、iSDIOで規定されているEstablishコマンドを使用します。
Establishコマンドの発行が完了した後、 FlashAirが実際に無線LAN APとして動作開始するまでには、 数秒~20秒程度の時間がかかります。 動作開始を確認するためには、ステータスレジスタを利用します。
チュートリアル3で ステータスレジスタの読み出し方を解説しましたが、 全部のステータスは必要ありませんので、 本チュートリアルでは、コマンド発行後の処理ステータスを確認する方法だけを切り出してみます。
また、Establishコマンドが正しく動作するためには、 FlashAirの無線LANが未接続状態になっていなければなりません。 そこで、このチュートリアルでは、無線LANを切断するためのDisconnectコマンドも実行してみましょう。
以下、 チュートリアル3のソースコードを元に追加・変更していきます。
シーケンスIDについて
前述のとおり、コマンドは発行してから処理が完了するまで時間がかかります。 最後に発行されたコマンドを識別するために、シーケンスIDという仕組みが取り入れられています。
iSDIOのシーケンスIDは、0以上の4バイトの符号なし数値です。 コマンドを新しく発行するたびに、シーケンスIDを新しい値(通常は以前の値に1加えたもの)に更新します。
FlashAirの起動時あるいはCGIでの指示により、FlashAir自身が無線LAN状態を変更した場合も、 iSDIOコマンドが発行されてシーケンスIDが変更される可能性があることに注意が必要です。
そのため、厳密にはコマンド発行の都度最新のシーケンスIDを取得して、 新しいシーケンスIDを作成するのが正しいでしょう。 ただし、本チュートリアルシリーズでは説明の簡略化のため、起動直後のシーケンスIDを読み取り、 それ以降は自分で管理したIDのみを使います。
自分が発行した最後のシーケンスIDを覚えておくため、変数を一つ用意します。
arduino_tutorial_04.ino (一部抜粋)
uint32_t nextSequenceId = 0;
Establishコマンドの発行
Establishは、無線LAN機能をAPモードで立ち上げるためのコマンドです。 同時に、HTTPサーバー機能とDHCPサーバー機能も立ち上がります。
詳細は、 SD Specifications Part E7 Wireless LAN Simplified Addendum Version 1.10 4.2.3 Estalibsh(ssid, networkKey, encMode) に規定されています。
コマンドデータを作るためには、下記の情報が必要です。
- コマンドID (
3
) - シーケンスID
- 引数個数 (
3
) - 引数
- SSID
- ネットワークキー (パスワード)
- セキュリティモード
arduino_tutorial_04.ino (一部抜粋)
boolean iSDIO_establish(uint32_t sequenceId) {
Serial.print(F("\nEstablish command: \n"));
memset(buffer, 0, 512);
uint8_t* p = buffer;
p = put_command_header(p, 1, 0);
p = put_command_info_header(p, 0x03, sequenceId, 3);
p = put_str_arg(p, "sdiotest");
p = put_str_arg(p, "12345678");
p = put_u8_arg(p, 0x06);
put_command_header(buffer, 1, (p - buffer));
printHex(buffer, (p - buffer));
return card.writeExtDataPort(1, 1, 0x000, buffer) ? true : false;
}
- 3行目~10行目
FlashAirに発行するコマンドのデータをArduinoのメモリ上に作っています。 - 5行目
ヘルパー関数を利用して、コマンドのヘッダを作っています。 最後の引数にはコマンドデータの長さ(バイト数)を入れますが、 可変長の引数があるため、引数を含んでいるため、後で計算します。 - 6行目
ヘルパー関数を利用して、コマンド情報のヘッダを作っています。 establishのコマンドID0x03
、シーケンスIDsequenceID
、引数の個数3
を指定しています。 - 7行目
1番目の引数SSIDを書き込んでいます。 文字列引数を書き込むヘルパー関数を利用しています。 - 8行目
同様に、2番目の引数ネットワークキーを書き込んでいます。 - 9行目
3番目の引数セキュリティモードを書き込んでいます。 ここでは、WPA2-PSK and AESを表す0x06
を指定しています。他の値については仕様書をご覧ください。 1バイトデータを書き込むヘルパー関数を利用しています。 - 10行目
全データが書き込まれ、バイト数が確定したので、コマンドヘッダを改めて書き込んでいます。 - 11行目
正しく作成されたかを確認する目的で、コマンドデータをダンプしています。printHex()
関数についてはサンプルコードを参照ください。 - 12行目
FlashAirに対してデータを書き込んでいます。
コマンド処理状況の確認
コマンド処理状況を確認するには、iSDIOのコマンドレスポンスステータスを読み取ります。
コマンドレスポンスステータス (SD Specifications Part E7 iSDIO Simplifed Specification Version 1.10より抜粋)
特に重要なのは、 _iSDIO command sequence id_と、 _Response Status_の2つです。 iSDIO command sequence idが、いま確認したいシーケンスIDと一致しているか確認します。 一致していることが確認できたら、Response Statusで処理状況を確認します。
なお、iSDIO規格では最大8つまでのコマンドを同時に発行できることになっており、 コマンドレスポンスステータスレジスタも8個ありますが、 FlashAirは1つまでの対応となっていますので、アドレス
0x440
のステータスを常に読み取ります。
以下に、指定したシーケンスIDのコマンドの終了を待機する関数を作成します。
arduino_tutorial_04.ino (一部抜粋)
boolean iSDIO_waitResponse(uint32_t sequenceId) {
Serial.print(F("\nWaiting response "));
uint8_t prev = 0xFF;
for (int i = 0; i < 20; ++i) {
memset(buffer, 0, 0x14);
// Read command response status.
if (!card.readExtMemory(1, 1, 0x440, 0x14, buffer)) {
return false;
}
uint8_t resp = get_u8(buffer + 8);
if (sequenceId == get_u32(buffer + 4)) {
if (prev != resp) {
switch (resp) {
case 0x00:
Serial.print(F("\n Initial"));
break;
case 0x01:
Serial.print(F("\n Command Processing"));
break;
case 0x02:
Serial.println(F("\n Command Rejected"));
return false;
case 0x03:
Serial.println(F("\n Process Succeeded"));
return true;
case 0x04:
Serial.println(F("\n Process Terminated"));
return false;
default:
Serial.print(F("\n Process Failed "));
Serial.println(resp, HEX);
return false;
}
prev = resp;
}
}
Serial.print(F("."));
delay(1000);
}
return false;
}
- 8行目
コマンドレスポンスステータスレジスタを読み取っています。 - 13行目
シーケンスIDが一致することを確認しています。 - 15行目~35行目
レスポンスステータスを確認してます。処理が完了すると、Process Succeededになります。 - 39行目
1秒ごとにこの確認を実行しています。
Disconnectコマンドの発行
Disconnectは、無線LANを切断するためのコマンドです。 同時に、HTTPサーバー機能とDHCPサーバー機能も停止します。
詳細は、 **SD Specifications Part E7 Wireless LAN Simplified Addendum Version 1.10 4.2.7 Disconnect(ssid, networkKey, encMode) ** に規定されています。
コマンドデータを作るためには、下記の情報が必要です。
- コマンドID (
7
) - シーケンスID
- 引数個数 (
0
) - 引数はありません。
arduino_tutorial_04.ino (一部抜粋)
boolean iSDIO_disconnect(uint32_t sequenceId) {
Serial.print(F("\nDisconnect command: \n"));
memset(buffer, 0, 512);
uint8_t* p = buffer;
p = put_command_header(p, 1, 0);
p = put_command_info_header(p, 0x07, sequenceId, 0);
put_command_header(buffer, 1, (p - buffer));
printHex(buffer, (p - buffer));
return card.writeExtDataPort(1, 1, 0x000, buffer) ? true : false;
}
メインプログラム
メインプログラムは、対話式のプログラムとしてみましょう。
Arduinoのシリアルターミナルで入力されたコマンド番号に従って、ステータス表示、Disconnect、Establish の各コマンドを実行します。
arduino_tutorial_04.ino (一部抜粋)
void loop() {
if (!iSDIO_status()) {
Serial.println(F("\nFailed to read status."));
}
Serial.print(F("\n0. Show status"));
Serial.print(F("\n1. Disconnect"));
Serial.print(F("\n2. Establish"));
Serial.print(F("\n\nCommand? (next sequence id = "));
Serial.print(nextSequenceId, DEC);
Serial.println(F(")"));
while (Serial.available() == 0);
char command = Serial.read();
switch (command - '0') {
case 0 :
break;
case 1 :
if (iSDIO_disconnect(nextSequenceId) &&
iSDIO_waitResponse(nextSequenceId)) {
Serial.println(F("\nSuccess."));
} else {
Serial.print(F("\nFailed or waiting. errorCode="));
Serial.println(card.errorCode(), HEX);
}
nextSequenceId++;
break;
case 2 :
if (iSDIO_establish(nextSequenceId) &&
iSDIO_waitResponse(nextSequenceId)) {
Serial.println(F("\nSuccess."));
} else {
Serial.print(F("\nFailed or waiting. errorCode="));
Serial.println(card.errorCode(), HEX);
}
nextSequenceId++;
break;
default :
Serial.println(F("\nUnknown command."));
break;
}
}
- 2行目
ステータス表示です。 - 6行目~11行目
実行できるコマンドおよび次のシーケンスIDを表示しています。 - 13行目~14行目
番号の入力を待っています。 - 16行目~42行目
入力された番号に従ってコマンドを実行します。
ステータス表示を
loop()
関数に含めましたので、
setup()
関数からは削除しましょう。
arduino_tutorial_04.ino (一部抜粋)
void setup() {
// Initialize UART for message print.
Serial.begin(9600);
while (!Serial) {
;
}
// Initialize SD card.
Serial.print(F("\nInitializing SD card..."));
if (card.init(SPI_HALF_SPEED, chipSelectPin)) {
Serial.print(F("OK"));
} else {
Serial.print(F("NG"));
abort();
}
// Read the previous sequence ID.
if (card.readExtMemory(1, 1, 0x420, 0x34, buffer)) {
if (buffer[0x20] == 0x01) {
nextSequenceId = get_u32(buffer + 0x24);
iSDIO_waitResponse(nextSequenceId);
nextSequenceId++;
} else {
nextSequenceId = 0;
}
} else {
Serial.println(F("\nFailed to read status."));
nextSequenceId = 0;
}
}
- 17行目~29行目
最後に使われたシーケンスIDを読み取っています。 さらに、直前のコマンドが実行中の場合は完了を待機しています。
実行結果
実行すると、例えば次のようになります。
Initializing SD card...OK
Wait for response
Process Succeeded
Read iSDIO Status Register
== iSDIO Status Registers ==
[0400h] Command Write Status:
... (snip) ...
[0440h] Command Response Status #1: id = 3, sequence id = 1, status = Process Succeeded
... (snip) ...
[0506h] WLAN: No Scan, No WPS, Group Client, AP, Infrastructure, No Connection,
... (snip) ...
[0550h] IP Address: 192.168.0.1
... (snip) ...
0. Show status
1. Disconnect
2. Establish
Command? (next sequence id = 2)
起動後の状態と、コマンドオプションを表示します。 この例では、起動時にFlashAirがAPモードで起動したことを表しています。
コマンドは、Arduino IDEのシリアルターミナル上部にあるボックスに入力します。
1
、Enterと入力してみましょう。
Disconnect command:
00: 01010000180000000000000000000700
01: 0700000000000000
Wait for response
Command Processing.
Process Succeeded
Success.
Read iSDIO Status Register
... (snip) ...
[0440h] Command Response Status #1: id = 7, sequence id = 2, status = Process Succeeded
... (snip) ...
[0506h] WLAN: No Scan, No WPS, Group Client, STA, Initial, No Connection,
... (snip) ...
[0550h] IP Address: 0.0.0.0
... (snip) ...
Command? (next sequence id = 3)
14行目が、DisconnectのコマンドID
7
、指定したシーケンスID、ステータス
Process Succeeded
になっていることから、 Disconnectコマンドが発行され、完了したことがわかります。 また、WLANステータスが
STA
でIP Addressの
0.0.0.0
であることから、無線LANが切断されていると判断できます。
3行目~4行目は、コマンドデータです。うまく動かないときは内容を確認してみてください。
引き続き、APモードの起動を行ってみましょう。
シリアルターミナルのボックスに、
2
、Enterと入力します。
Establish command:
00: 01010000380000000000000000000300
01: 0800000003000000080000007364696F
02: 74657374080000003132333435363738
03: 0100000006000000
Wait for response
Command Processing.....
Process Succeeded
Success.
Read iSDIO Status Register
... (snip) ...
[0440h] Command Response Status #1: id = 3, sequence id = 3, status = Process Succeeded
... (snip) ...
[0506h] WLAN: No Scan, No WPS, Group Client, AP, Infrastructure, No Connection,
[0508h] SSID: sdiotest
[0528h] Encryption Mode: WPA2-PSK and AES
[0529h] Signal Strength: 0
[052Ah] Channel: 11
[0530h] MAC Address: E8E0B758A7FB
[0540h] ID:
[0550h] IP Address: 192.168.0.1
[0554h] Subnet Mask: 255.255.255.0
[0558h] Default Gateway: 192.168.0.1
[055Ch] Preferred DNS Server: 192.168.0.1
[0560h] Alternate DNS Server: 0.0.0.0
... (snip) ...
EstablishのコマンドID
3
が実行されています。(16行目)
WLANステータスが
AP
およびIP Addressが
192.168.0.1
となっていることから、 FlashAirがAPモードで立ち上がっていることが確認できます。
サンプルコード
arduino_tutorial_04.zip (24KB)
本チュートリアルのサンプルコードはGPLv3および二条項BSDライセンスで提供されています。 詳細はダウンロードした各ファイルを参照してください。