/ 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 }