/ ESP32S2_TFT_AdBlocker / filesystem.cpp
filesystem.cpp
  1  // SPDX-FileCopyrightText: 2022 ladyada
  2  // SPDX-License-Identifier: GPL-3.0-or-later
  3  
  4  #include "config.h"
  5  #include "SdFat.h"
  6  #include "Adafruit_SPIFlash.h"
  7  #include "Adafruit_TinyUSB.h"
  8  #include <ArduinoJson.h>
  9  
 10  
 11  #if defined(EXPOSE_FS_ON_MSD)
 12  // USB Mass Storage object
 13  Adafruit_USBD_MSC usb_msc;
 14  #endif
 15  
 16  
 17  volatile bool fs_changed = false;
 18  extern Adafruit_FlashTransport_ESP32 flashTransport;  // internal SPI flash access
 19  extern Adafruit_SPIFlash flash; 
 20  extern FatFileSystem fatfs;  // file system object from SdFat
 21  
 22  
 23  const char *secrets_filename = "secrets.json";
 24  StaticJsonDocument<512> doc;
 25  extern char ssid[80];
 26  extern char password[80];
 27  extern char hostname[80];
 28  extern char hostfile[255];
 29  
 30  int32_t msc_read_cb (uint32_t lba, void* buffer, uint32_t bufsize);
 31  int32_t msc_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize);
 32  void msc_flush_cb (void);
 33  
 34  bool init_filesystem(void) {
 35    #if defined(EXPOSE_FS_ON_MSD)
 36    // Set disk vendor id, product id and revision with string up to 8, 16, 4 characters respectively
 37    usb_msc.setID("Adafruit", "External Flash", "1.0");
 38  
 39    // Set callback
 40    usb_msc.setReadWriteCallback(msc_read_cb, msc_write_cb, msc_flush_cb);
 41  
 42    // Set disk size, block size should be 512 regardless of spi flash page size
 43    usb_msc.setCapacity(flash.size()/512, 512);
 44  
 45    // MSC is ready for read/write
 46    usb_msc.setUnitReady(true);
 47    
 48    usb_msc.begin();
 49  #endif
 50  
 51    // Init file system on the flash
 52    if (! fatfs.begin(&flash)) {
 53      return false;
 54    }
 55  
 56    DBG_OUTPUT_PORT.begin(115200);
 57    DBG_OUTPUT_PORT.setDebugOutput(true);
 58    DBG_OUTPUT_PORT.println("Adafruit TinyUSB Mass Storage External Flash example");
 59    DBG_OUTPUT_PORT.print("JEDEC ID: 0x"); 
 60    DBG_OUTPUT_PORT.println(flash.getJEDECID(), HEX);
 61    DBG_OUTPUT_PORT.print("Flash size: "); 
 62    DBG_OUTPUT_PORT.print(flash.size() / 1024); 
 63    DBG_OUTPUT_PORT.println(" KB");
 64    DBG_OUTPUT_PORT.print("\n");
 65  
 66    File root = fatfs.open("/");
 67    File file;
 68    if (! root)  {
 69      DBG_OUTPUT_PORT.println("Couldn't open filesystem?");
 70      return false;
 71    }
 72    DBG_OUTPUT_PORT.println("Flash contents:");
 73  
 74    // Open next file in root.
 75    // Warning, openNext starts at the current directory position
 76    // so a rewind of the directory may be required.
 77    while ( file.openNext(&root, O_RDONLY) )
 78    {
 79      file.printFileSize(&DBG_OUTPUT_PORT);
 80      DBG_OUTPUT_PORT.write(' ');
 81      file.printName(&DBG_OUTPUT_PORT);
 82      if ( file.isDir() )
 83      {
 84        // Indicate a directory.
 85        DBG_OUTPUT_PORT.write('/');
 86      }
 87      DBG_OUTPUT_PORT.println();
 88      file.close();
 89    }
 90    root.close();
 91    DBG_OUTPUT_PORT.println();
 92  
 93    Serial.printf("Free space: %d bytes\n", flashFreeSpace());
 94    
 95    return true;
 96  }
 97  
 98  
 99  size_t flashFreeSpace(void) {
100     size_t freeclust = fatfs.vol()->freeClusterCount();
101     return freeclust*512; 
102  }
103  
104  bool parseSecrets() {
105    // open file for parsing
106    File secretsFile = fatfs.open(secrets_filename);
107    if (!secretsFile) {
108      DBG_OUTPUT_PORT.println("ERROR: Could not open secrets.json file for reading!");
109      return false;
110    }
111  
112    // check if we can deserialize the secrets.json file
113    DeserializationError err = deserializeJson(doc, secretsFile);
114    if (err) {
115      DBG_OUTPUT_PORT.println("ERROR: deserializeJson() failed with code ");
116      DBG_OUTPUT_PORT.println(err.c_str());
117  
118      return false;
119    }
120  
121    // next, we detect the network interface from the `secrets.json`
122    DBG_OUTPUT_PORT.println("Attempting to find network interface...");
123    strlcpy(ssid, doc["ssid"] | DEFAULT_SSID, sizeof(ssid));
124    strlcpy(password, doc["password"] | DEFAULT_PASSWORD, sizeof(password));
125    strlcpy(hostname, doc["hostname"] | DEFAULT_HOSTNAME, sizeof(hostname));
126    strlcpy(hostfile, doc["hostfile"] | DEFAULT_HOSTFILE, sizeof(hostfile));
127         
128    // close the tempFile
129    secretsFile.close();
130    return true;
131  }
132  
133  
134  
135  // Callback invoked when received READ10 command.
136  // Copy disk's data to buffer (up to bufsize) and 
137  // return number of copied bytes (must be multiple of block size) 
138  int32_t msc_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
139  {
140    // Note: SPIFLash Block API: readBlocks/writeBlocks/syncBlocks
141    // already include 4K sector caching internally. We don't need to cache it, yahhhh!!
142    return flash.readBlocks(lba, (uint8_t*) buffer, bufsize/512) ? bufsize : -1;
143  }
144  
145  // Callback invoked when received WRITE10 command.
146  // Process data in buffer to disk's storage and 
147  // return number of written bytes (must be multiple of block size)
148  int32_t msc_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
149  {
150    digitalWrite(LED_BUILTIN, HIGH);
151  
152    // Note: SPIFLash Block API: readBlocks/writeBlocks/syncBlocks
153    // already include 4K sector caching internally. We don't need to cache it, yahhhh!!
154    return flash.writeBlocks(lba, buffer, bufsize/512) ? bufsize : -1;
155  }
156  
157  // Callback invoked when WRITE10 command is completed (status received and accepted by host).
158  // used to flush any pending cache.
159  void msc_flush_cb (void)
160  {
161    // sync with flash
162    flash.syncBlocks();
163  
164    // clear file system's cache to force refresh
165    fatfs.cacheClear();
166  
167    fs_changed = true;
168  
169    digitalWrite(LED_BUILTIN, LOW);
170  }