ESP8266のSPIFFS+Reset/Restart


ESP8266ではSPIFFSと呼ばれるファイルシステムを使うことができます。
SPIFFSについてはこ ちらこ ちらで紹介されていますが、いずれもデータアップロードツールを使って
事前にファイルをアップロードし、アップロードしたファイルを読む内容です。

前回は単純にスケッチ内部でSPIFFS領域をフォーマットし、ファイルを読 み書きする方法を紹介しました。
そこで、Reset/RestartでSPIFFS領域が破棄されるのか、保持されるのか、以下のスケッチで確認してみました。
初回起動時かReset/Restartからの復帰かを判断するために、RTCユーザエリアを使っています。
/*
* ESP.reset()/ESP.resart()でSPIFFS領域がクリアされるかどうかのテスト
*
* SPIFFS doc see :https://github.com/esp8266/Arduino/blob/master/doc/filesystem.md
*/
#include "FS.h"

//RTC memory(512Byte)の定義
struct {
  uint32_t crc32; // CRC
  uint8_t data[508]; // User Data
} rtcData;

// Calculate CRC
uint32_t calculateCRC32(const uint8_t *data, size_t length) {
  uint32_t crc = 0xffffffff;
  while (length--) {
    uint8_t c = *data++;
    for (uint32_t i = 0x80; i > 0; i >>= 1) {
      bool bit = crc & 0x80000000;
      if (c & i) {
        bit = !bit;
      }
      crc <<= 1;
      if (bit) {
        crc ^= 0x04c11db7;
      }
    } // end for
  } // end while
  return crc;
}

 // Print RTC memory
void printMemory(int sz) {
  char buf[3];
 //  for (int i = 0; i < sizeof(rtcData); i++) {
  for (int i = 0; i < sz; i++) {
    sprintf(buf, "%02X", rtcData.data[i]);
    Serial.print(buf);
    if ((i + 1) % 32 == 0) {
      Serial.println();
    }
    else {
      Serial.print(" ");
    }
  } // end for
  Serial.println();
}

void listDir() {
  char cwdName[2];

  strcpy(cwdName,"/");
  Dir dir=SPIFFS.openDir(cwdName);
  while( dir.next()) {
    String fn, fs;
    fn = dir.fileName();
    fn.remove(0, 1);
    fs = String(dir.fileSize());
    Serial.println("<" + fn + "> size=" + fs);
  } // end while
}

void setup() {
  delay(500);
  Serial.begin(9600);
  Serial.println();


  //RTC memoryからデータを読み込む
  if (ESP.rtcUserMemoryRead(0, (uint32_t*) &rtcData, sizeof(rtcData))) {
    Serial.println("Read: ");
    printMemory(10);
    //読み込んだデータでCRC32を計算する
    uint32_t crcOfData = calculateCRC32(((uint8_t*) &rtcData) + 4, sizeof(rtcData) - 4);
    Serial.print("CRC32 of data: ");
    Serial.println(crcOfData, HEX);
    Serial.print("CRC32 read from RTC: ");
    Serial.println(rtcData.crc32, HEX);
    //CRC32が一致しないので初回起動時 RTC memoryをオール0で初期化
    if (crcOfData != rtcData.crc32) {
      Serial.println("CRC32 in RTC memory doesn't match CRC32 of data. Data is probably invalid!");
      for (int i = 0; i < sizeof(rtcData); i++) {
        rtcData.data[i] = 0;
      }
    }
    //CRC32が一致したのでReset/Restartからの復帰 RTC memoryの起動回数をインクリメント
    else {
      Serial.println("CRC32 check ok, data is probably valid.");
      rtcData.data[0]++;
    }
  }

  //CRC32を再計算
  rtcData.crc32 = calculateCRC32(((uint8_t*) &rtcData) + 4, sizeof(rtcData) - 4);
  //RTC memoryにデータを書き込む
  if (ESP.rtcUserMemoryWrite(0, (uint32_t*) &rtcData, sizeof(rtcData))) {
    Serial.println("Write: ");
    printMemory(10);
  }

  // 初回起動時
  if (rtcData.data[0] == 0) {
    SPIFFS.begin();
    // Next lines have to be done ONLY ONCE!!!!!When SPIFFS is formatted ONCE you can comment these lines out!!
    Serial.println("Please wait 30 secs for SPIFFS to be formatted");
    SPIFFS.format();
    Serial.println("Spiffs formatted");

    // open file for writing
    File f = SPIFFS.open("/f.txt", "w");
    if (!f) {
      Serial.println("file open failed");
    } else {
      Serial.println("====== Writing to SPIFFS file =========");
      // write 10 strings to file
      for (int i=1; i<=10; i++){
        f.print("Line : ");
        f.println(i);
      } // end for
      f.close();
    } // end if

    // list directory
    listDir();

    // open file for reading
    f = SPIFFS.open("/f.txt", "r");
    if (!f) {
      Serial.println("file open failed");
    } else {
      Serial.println("====== Reading from SPIFFS file =======");
      // write 10 strings to file
      for (int i=1; i<=10; i++){
        String s=f.readStringUntil('\n');
        Serial.print(i);
        Serial.print(":");
        Serial.println(s);
      } // end for
      f.close();
    } // end if

  // Reset/Restartからの復帰
  } else {
    Serial.println("SPIFFS Started");
    SPIFFS.begin();

    // list directory
    listDir();

    // open file for reading
    File f = SPIFFS.open("/f.txt", "r");
    if (!f) {
      Serial.println("file open failed");
    } else {
      Serial.println("====== Reading from SPIFFS file =======");
      // write 10 strings to file
      for (int i=1; i<=10; i++){
        String s=f.readStringUntil('\n');
        Serial.print(i);
        Serial.print(":");
        Serial.println(s);
      } // end for
      f.close();
    } // end if
  }

  for(int i=0;i<10;i++) delay(1000);
  Serial.print("rtcData.data[0]=");
  Serial.println(rtcData.data[0]);
  if ((rtcData.data[0] % 2) == 0) {
    Serial.println("Do ESP.reset");
    ESP.reset();
  } else {
    Serial.println("Do ESP.restart");
    ESP.restart();
  }


}

void loop() {
}

結果は以下の通りです。
Reset/Restartから復帰した時も、<f.txt>は読めることを確認しました。(下の赤字の部分)
Read:
81 F6 C1 FF 1C 2C 81 CF BE 73
CRC32 of data: 99AD5FF
CRC32 read from RTC: 964A405E
CRC32 in RTC memory doesn't match CRC32 of data. Data is probably invalid!
Write:
00 00 00 00 00 00 00 00 00 00
Please wait 30 secs for SPIFFS to be formatted
Spiffs formatted
====== Writing to SPIFFS file =========
<f.txt> size=101
====== Reading from SPIFFS file =======
1:Line : 1
2:Line : 2
3:Line : 3
4:Line : 4
5:Line : 5
6:Line : 6
7:Line : 7
8:Line : 8
9:Line : 9
10:Line : 10
rtcData.data[0]=0
Do ESP.reset・1ィホBV!リ貔
Read:
00 00 00 00 00 00 00 00 00 00
CRC32 of data: D549220F
CRC32 read from RTC: D549220F
CRC32 check ok, data is probably valid.
Write:
01 00 00 00 00 00 00 00 00 00
SPIFFS Started
<f.txt> size=101
====== Reading from SPIFFS file =======
1:Line : 1
2:Line : 2
3:Line : 3
4:Line : 4
5:Line : 5
6:Line : 6
7:Line : 7
8:Line : 8
9:Line : 9
10:Line : 10
rtcData.data[0]=1
Do ESP.restart
"?F1ェSホ・
Read:
01 00 00 00 00 00 00 00 00 00
CRC32 of data: 6CD8500C
CRC32 read from RTC: 6CD8500C
CRC32 check ok, data is probably valid.
Write:
02 00 00 00 00 00 00 00 00 00
SPIFFS Started
<f.txt> size=101
====== Reading from SPIFFS file =======
1:Line : 1
2:Line : 2
3:Line : 3
4:Line : 4
5:Line : 5
6:Line : 6
7:Line : 7
8:Line : 8
9:Line : 9
10:Line : 10
rtcData.data[0]=2

次回は、DeepSleepから復帰した時に、SPIFFS上に作られたファイルが保持されるのかどうか、確認してみます。

続く....