#include "storage.h" #ifdef HAS_SDCARD #include "FS.h" #include "SD.h" #include "SPI.h" #endif #include "LittleFS.h" DynStorage::DynStorage() : isInited(0) {} static void initLittleFS() { LittleFS.begin(); contentFS = &LittleFS; } #ifdef HAS_SDCARD static SPIClass* spi; static void initSDCard() { uint8_t spi_bus = VSPI; // SD.begin and spi.begin are allocating memory so we dont want to do that if(!spi) { spi = new SPIClass(spi_bus); spi->begin(SD_CARD_CLK, SD_CARD_MISO, SD_CARD_MOSI, SD_CARD_SS); bool res = SD.begin(SD_CARD_SS, *spi, 40000000); if (!res) { Serial.println("Card Mount Failed"); return; } } uint8_t cardType = SD.cardType(); if (cardType == CARD_NONE) { Serial.println("No SD card attached"); return; } contentFS = &SD; } #endif size_t DynStorage::freeSpace(){ this->begin(); #ifdef HAS_SDCARD return SD.totalBytes() - SD.usedBytes(); #endif return LittleFS.totalBytes() - LittleFS.usedBytes(); } void copyFile(File in, File out) { Serial.print("Copying "); Serial.print(in.path()); Serial.print(" to "); Serial.println(out.path()); size_t n; uint8_t buf[64]; while ((n = in.read(buf, sizeof(buf))) > 0) { out.write(buf, n); } } #ifdef HAS_SDCARD void copyBetweenFS(FS& sourceFS, const char* source_path, FS& targetFS) { File root = sourceFS.open(source_path); char next_path[128]; if (root.isDirectory()) { if (!contentFS->exists(root.path())) { if (!contentFS->mkdir(root.path())) { Serial.print("Failed to create directory "); Serial.println(root.path()); return; } } File file = root.openNextFile(); while (file) { if (file.isDirectory()) { sprintf(next_path, "%s/%s\0", root.path(), file.path()); copyBetweenFS(sourceFS, file.path(), targetFS); } else { File target = contentFS->open(file.path(), "w"); if (target) { copyFile(file, target); target.close(); file.close(); } else { Serial.print("Couldn't create high target file"); Serial.println(file.path()); return; } } file = root.openNextFile(); } } else { File target = contentFS->open(root.path(), "w"); if (target) { copyFile(root, target); } else { Serial.print("Couldn't create target file "); Serial.println(root.path()); return; } } } void copyIfNeeded(const char* path) { if (!contentFS->exists(path) && LittleFS.exists(path)) { Serial.printf("SDCard does not contain %s, littleFS does, copying\n", path); copyBetweenFS(LittleFS, path, *contentFS); } } #endif void DynStorage::begin() { initLittleFS(); #ifdef HAS_SDCARD initSDCard(); copyIfNeeded("/index.html"); copyIfNeeded("/fonts"); copyIfNeeded("/www"); copyIfNeeded("/tagtypes"); copyIfNeeded("/AP_FW_Pack.bin"); copyIfNeeded("/tag_md5_db.json"); copyIfNeeded("/update_actions.json"); copyIfNeeded("/content_template.json"); #endif if (!contentFS->exists("/current")) { contentFS->mkdir("/current"); } if (!contentFS->exists("/temp")) { contentFS->mkdir("/temp"); } } void DynStorage::end() { #ifdef HAS_SDCARD initLittleFS(); if (SD_CARD_CLK == FLASHER_AP_CLK || SD_CARD_MISO == FLASHER_AP_MISO || SD_CARD_MOSI == FLASHER_AP_MOSI) { Serial.println("Tearing down SD card connection"); copyBetweenFS(*contentFS, "/tag_md5_db.json", LittleFS); copyBetweenFS(*contentFS, "/AP_FW_Pack.bin", LittleFS); if (contentFS->exists("/AP_force_flash.bin")) { copyBetweenFS(*contentFS, "/AP_force_flash.bin", LittleFS); contentFS->remove("/AP_force_flash.bin"); } Serial.println("Swapping to LittleFS"); contentFS = &LittleFS; } #endif } void listDir(fs::FS& fs, const char* dirname, uint8_t levels) { Storage.begin(); Serial.printf(" \n "); Serial.printf("Listing directory: %s\n", dirname); File root = fs.open(dirname); if (!root) { Serial.println("Failed to open directory"); return; } if (!root.isDirectory()) { Serial.println("Not a directory"); return; } File file = root.openNextFile(); while (file) { if (!strcmp("System Volume Information", file.name())) { file = root.openNextFile(); continue; } if (file.isDirectory()) { Serial.print(" DIR : "); Serial.println(file.name()); if (levels) { listDir(fs, file.path(), levels - 1); } Serial.println(); } else { Serial.print(" FILE: "); Serial.print(file.name()); Serial.print(" SIZE: "); Serial.println(file.size()); } file = root.openNextFile(); } } void DynStorage::listFiles() { listDir(LittleFS, "/", 1); #ifdef HAS_SDCARD listDir(*contentFS, "/", 1); #endif } fs::FS* contentFS; DynStorage Storage;