本チュートリアルでは、iSDIOコマンドを使って、FlashAirの無線LANステータスを読み取ってみます。

ステータス読み取りの概要

下記の図は、簡易版仕様書から引用したiSDIOレジスタのメモリ配置です。

iSDIOレジスタのメモリ配置 (SD Specifications Part E7 iSDIO Simplifed Specification Version 1.10より抜粋)

Commands

iSDIOステータスは、アドレス0x400番地からはじまるページ(512バイト分の領域)を読み取ることで取得できます。

0x400~0x4FF番地はiSDIO共通ステータスです。 0x500~0x5FF番地はアプリケーションごとのステータスとなっており、 FlashAirの場合は、ここを読み取ることで無線LAN機能の各種情報が取得できます。

iSDIO共通ステータス (SD Specifications Part E7 iSDIO Simplifed Specification Version 1.10より抜粋)

Commands

iSDIO無線LAN機能ステータス (SD Specifications Part E7 iSDIO Simplifed Specification Version 1.10より抜粋)

Commands

ステータス読み取り関数の作成

0x400番地からの領域を読み取り、前述のステータスマップに従って、 読み取れた状態を表示する関数を作ります。

arduino_tutorial_03.ino (その1)

uint8_t buffer[512];

void printByte(uint8_t value) {
  Serial.print(value >> 4, HEX);
  Serial.print(value & 0xF, HEX);
}

void printBytes(uint8_t* p, uint32_t len) {
  for (int i = 0; i < len; ++i) {
    printByte(p[i]);
  }
}

void printIPAddress(uint8_t* p) {
  Serial.print(p[0], DEC);
  Serial.print('.');
  Serial.print(p[1], DEC);
  Serial.print('.');
  Serial.print(p[2], DEC);
  Serial.print('.');
  Serial.print(p[3], DEC);
}

boolean iSDIO_status() {
  Serial.print(F("\nRead iSDIO Status Register"));
  // Read iSDIO Status Register (E7 1.10 2.2.2.1)
  memset(buffer, 0, 0x200);
  if (!card.readExtMemory(1, 1, 0x400, 0x200, buffer)) {
    return false;
  }
  // Show values in the common status area.
  Serial.print(F("\n == iSDIO Status Registers == "));
  Serial.print(F("\n [0400h] Command Write Status: "));
  if (buffer[0x000] & 0x01) Serial.print(F("CWU "));
  if (buffer[0x000] & 0x02) Serial.print(F("CWA "));
  Serial.print(F("\n [0420h] iSDIO Status: "));
  if (buffer[0x020] & 0x01) Serial.print(F("CRU "));
  if (buffer[0x020] & 0x02) Serial.print(F("ESU "));
  if (buffer[0x020] & 0x04) Serial.print(F("MCU "));
  if (buffer[0x020] & 0x08) Serial.print(F("ASU "));
  Serial.print(F("\n [0422h] iSDIO Int Enable: "));
  if (buffer[0x022] & 0x01) Serial.print(F("CRU_ENA "));
  if (buffer[0x022] & 0x02) Serial.print(F("ESU_ENA "));
  if (buffer[0x022] & 0x04) Serial.print(F("MCU_ENA "));
  if (buffer[0x022] & 0x08) Serial.print(F("ASU_ENA "));
  Serial.print(F("\n [0424h] Error Status: "));
  if (buffer[0x024] & 0x01) Serial.print(F("CRE "));
  if (buffer[0x024] & 0x02) Serial.print(F("CWE "));
  if (buffer[0x024] & 0x04) Serial.print(F("RRE "));
  if (buffer[0x024] & 0x08) Serial.print(F("APE "));
  Serial.print(F("\n [0426h] Memory Status: "));
  if (buffer[0x026] & 0x01) Serial.print(F("MEX "));
  if (buffer[0x026] & 0x02) Serial.print(F("FAT "));
  for (int i = 0; i < 8; ++i) {
    uint8_t addr = 0x40 + i * 0x14;
    Serial.print(F("\n [04"));
    printByte(addr);
    Serial.print(F("h] Command Response Status #"));
    Serial.print(i + 1, DEC);
    Serial.print(F(": "));
    if (buffer[addr] & 0x01) {
      Serial.print(F("id = "));
      Serial.print(get_u16(buffer + addr + 2), DEC);
      Serial.print(F(", sequence id = "));
      Serial.print(get_u32(buffer + addr + 4), DEC);
      Serial.print(F(", status = "));
      switch (buffer[addr + 8]) {
        case 0x00: Serial.print(F("Initial")); break;
        case 0x01: Serial.print(F("Command Processing")); break;
        case 0x02: Serial.print(F("Command Rejected")); break;
        case 0x03: Serial.print(F("Process Succeeded")); break;
        case 0x04: Serial.print(F("Process Terminated")); break;
        default:   Serial.print(F("Process Failed ")); Serial.print(buffer[addr + 8], HEX); break;
      }
    } else {
      Serial.print(F("Not registered"));
    }
  }
  // Show values in the application status area.
  Serial.print(F("\n == Wireless LAN Status Registers =="));
  Serial.print(F("\n [0500h] DLNA Status: "));
  if (buffer[0x100] & 0x01) Serial.print(F("ULR "));
  if (buffer[0x100] & 0x02) Serial.print(F("DLU "));
  if (buffer[0x100] & 0x04) Serial.print(F("CBR "));
  if (buffer[0x100] & 0x08) Serial.print(F("CDR "));
  Serial.print(F("\n [0501h] P2P Status: "));
  if (buffer[0x101] & 0x01) Serial.print(F("ILU "));
  if (buffer[0x101] & 0x02) Serial.print(F("FLU "));
  Serial.print(F("\n [0502h] PTP Status: "));
  if (buffer[0x102] & 0x01) Serial.print(F("RPO "));
  if (buffer[0x102] & 0x02) Serial.print(F("RPD "));
  if (buffer[0x102] & 0x04) Serial.print(F("RPC "));
  if (buffer[0x102] & 0x08) Serial.print(F("CPI "));
  if (buffer[0x102] & 0x10) Serial.print(F("DPI "));
  if (buffer[0x102] & 0x20) Serial.print(F("CIL "));
  Serial.print(F("\n [0504h] Application: "));
  Serial.print(buffer[0x104]);
  Serial.print(F("\n [0506h] WLAN: "));
  if ((buffer[0x106] & 0x01) == 0x00) Serial.print(F("No Scan, "));
  if ((buffer[0x106] & 0x01) == 0x01) Serial.print(F("Scanning, "));
  if ((buffer[0x106] & 0x06) == 0x00) Serial.print(F("No WPS, "));
  if ((buffer[0x106] & 0x06) == 0x02) Serial.print(F("WPS with PIN, "));
  if ((buffer[0x106] & 0x06) == 0x04) Serial.print(F("WPS with PBC, "));
  if ((buffer[0x106] & 0x08) == 0x00) Serial.print(F("Group Client, "));
  if ((buffer[0x106] & 0x08) == 0x08) Serial.print(F("Group Owner "));
  if ((buffer[0x106] & 0x10) == 0x00) Serial.print(F("STA, "));
  if ((buffer[0x106] & 0x10) == 0x10) Serial.print(F("AP, "));
  if ((buffer[0x106] & 0x60) == 0x00) Serial.print(F("Initial, "));
  if ((buffer[0x106] & 0x60) == 0x20) Serial.print(F("Infrastructure, "));
  if ((buffer[0x106] & 0x60) == 0x40) Serial.print(F("Wi-Fi Direct, "));
  if ((buffer[0x106] & 0x80) == 0x00) Serial.print(F("No Connection, "));
  if ((buffer[0x106] & 0x80) == 0x80) Serial.print(F("Connected, "));
  Serial.print(F("\n [0508h] SSID: "));
  for (int i = 0; i < 32 && buffer[0x108 + i] != 0; ++i) { 
    Serial.print((char)buffer[0x108 + i]);
  }
  Serial.print(F("\n [0528h] Encryption Mode: "));
  switch (buffer[0x128]) {
    case 0 : Serial.print(F("Open System and no encryption")); break;
    case 1 : Serial.print(F("Open System and WEP")); break;
    case 2 : Serial.print(F("Shared Key and WEP")); break;
    case 3 : Serial.print(F("WPA-PSK and TKIP")); break;
    case 4 : Serial.print(F("WPA-PSK and AES")); break;
    case 5 : Serial.print(F("WPA2-PSK and TKIP")); break;
    case 6 : Serial.print(F("WPA2-PSK and AES")); break;
    default: Serial.print(F("Unknown"));
  }
  Serial.print(F("\n [0529h] Signal Strength: "));
  Serial.print(buffer[0x129], DEC);
  Serial.print(F("\n [052Ah] Channel: "));
  if (buffer[0x12A] == 0) Serial.print(F("No connection"));
  else Serial.print(buffer[0x12A], DEC);
  Serial.print(F("\n [0530h] MAC Address: "));
  printBytes(buffer + 0x130, 6);
  Serial.print(F("\n [0540h] ID: "));
  for (int i = 0; i < 16 && buffer[0x140 + i] != 0; ++i) { 
    Serial.print((char)buffer[0x140 + i]);
  }
  Serial.print(F("\n [0550h] IP Address: "));
  printIPAddress(buffer + 0x150);
  Serial.print(F("\n [0554h] Subnet Mask: "));
  printIPAddress(buffer + 0x154);
  Serial.print(F("\n [0558h] Default Gateway: "));
  printIPAddress(buffer + 0x158);
  Serial.print(F("\n [055Ch] Preferred DNS Server: "));
  printIPAddress(buffer + 0x15C);
  Serial.print(F("\n [0560h] Alternate DNS Server: "));
  printIPAddress(buffer + 0x160);
  Serial.print(F("\n [0564h] Proxy Server: "));
  if ((buffer[0x164] & 0x01) == 0x00) Serial.print(F("Disabled"));
  if ((buffer[0x164] & 0x01) == 0x01) Serial.print(F("Enabled"));
  Serial.print(F("\n [0570h] Date: "));
  Serial.print(buffer[0x171] + 1980, DEC); Serial.print('-');
  Serial.print(buffer[0x170] >> 4, DEC); Serial.print('-');
  Serial.print(buffer[0x170] & 0xF, DEC);
  Serial.print(F("\n [0572h] Time: "));
  Serial.print(buffer[0x173] >> 3, DEC); Serial.print(':');
  Serial.print(buffer[0x172] << 3 | buffer[0x170] >> 3, DEC); Serial.print(':');
  Serial.print((buffer[0x172] & 0x1F) * 2, DEC);
  Serial.print(F("\n [0574h] HTTP Status: "));
  Serial.print(buffer[0x174] & 0xEF, DEC);
  if ((buffer[0x174] & 0x80) == 0x00) Serial.print(F(" (No Processing)"));
  if ((buffer[0x174] & 0x80) == 0x80) Serial.print(F(" (Processing)"));
  Serial.print(F("\n [0575h] Power Save Management: "));
  if ((buffer[0x175] & 0x01) == 0x00) Serial.print(F("Power Save Mode Off"));
  if ((buffer[0x175] & 0x01) == 0x01) Serial.print(F("Power Save Mode On"));
  Serial.print(F("\n [0576h] File System Management: "));
  if ((buffer[0x176] & 0x01) == 0x00) Serial.print(F("FS Information may be modified"));
  if ((buffer[0x176] & 0x01) == 0x01) Serial.print(F("FS Information shall not be modified"));
  Serial.println();

  return true;
}

なお、Serial.print()Serial.println()は、「シリアルモニタ」に文字を出力するための関数ですが、 文字列引数をF()というマクロで囲っています。 通常文字列定数は、言語仕様上書き換え可能であるためRAM上に置かれてしまい、 たくさんの文字列表示をするとあっという間にメモリが不足してしまいます。 しかし、表示用の文字列は変更することがないため、RAMには置かずにメモリを節約したいところです。 そこで、F()マクロを使います。 囲まれた文字列はROM領域に置かれてRAMを消費しなくなります。

そして、setup()で呼び出します。

arduino_tutorial_03.ino (その2)

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();
  }

  if (iSDIO_status()) {
    Serial.print(F("\nOK"));
  } else {
    Serial.println(F("\nFailed to read status."));
  }
}

実行結果

これを実行するとたとえば下記のような出力が得られます。

実行結果例

Read iSDIO Status Register
 == iSDIO Status Registers == 
 [0400h] Command Write Status: 
 [0420h] iSDIO Status: CRU 
 [0422h] iSDIO Int Enable: 
 [0424h] Error Status: 
 [0426h] Memory Status: MEX 
 [0440] Command Response Status #1: id = 3, sequence id = 0, status = Process Succeeded
 [0454] Command Response Status #2: Not registered
 [0468] Command Response Status #3: Not registered
 [047C] Command Response Status #4: Not registered
 [0490] Command Response Status #5: Not registered
 [04A4] Command Response Status #6: Not registered
 [04B8] Command Response Status #7: Not registered
 [04CC] Command Response Status #8: Not registered
 == Wireless LAN Status Registers ==
 [0500h] DLNA Status: 
 [0501h] P2P Status: 
 [0502h] PTP Status: 
 [0504h] Application: 0
 [0506h] WLAN: No Scan, No WPS, Group Client, AP, Infrastructure, No Connection, 
 [0508h] SSID: flashair_sdio
 [0528h] Encryption Mode: WPA2-PSK and AES
 [0529h] Signal Strength: 0
 [052Ah] Channel: 11
 [0530h] MAC Address: B86B23733F4F
 [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
 [0564h] Proxy Server: Disabled
 [0570h] Date: 1980-0-0
 [0572h] Time: 0:0:0
 [0574h] HTTP Status: 0 (No Processing)
 [0575h] Power Save Management: Power Save Mode Off
 [0576h] File System Management: FS Information may be modified

OK

サンプルコード

arduino_tutorial_03.zip (23KB)

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