arduino-libraries / Arduino_UnifiedStorage

Read and write files to flash, USB mass storage and SD cards in a unified way.
GNU Lesser General Public License v2.1
12 stars 3 forks source link

Document LittleFS path length limitation #42

Open aliphys opened 7 months ago

aliphys commented 7 months ago

Following testing with both Renesas configurations (Portenta C33 with Vision Shield & Breakout) as well as mbed (Portenta H7 + Vision Shield), it is observed that the maximum path length is 255 characters. This limitation is present for LittleFS partitions on internal storage, SD and USB.

This limitation, if part of design, should be documented.

This is demonstrated through the test sketches below which creates a 255/256 character file (including the extension) and then reads it. As a representative example, the following two sketches are provided for the Portenta H7 with the Vision Shield and internal storage. Similar observations are made for the Portenta C33 as well as USB and SD storage.

255 Character Filename - PASS

Sketch ``` #include "Arduino_UnifiedStorage.h" #include "CRC.h" // https://github.com/RobTillaart/CRC InternalStorage storage; CRC8 crc; const char testCaseID[] = "AUS_SPIS_FNBLFS_009"; void setup() { Serial.begin(115200); while (!Serial); Serial.println("---"); Serial.print("Test Case ID: "); Serial.println(testCaseID); Serial.println("---"); Arduino_UnifiedStorage::debuggingModeEnabled = false; if (Arduino_UnifiedStorage::debuggingModeEnabled) { Serial.println("Arduino_UnifiedStorage debug messages ON."); } storage = InternalStorage(); storage.format(FS_LITTLEFS); if(!storage.begin()){ Serial.println("Error mounting storage device."); } // specify Test strings & CRC const char testContent[] = "Hello World!"; for (int i = 0; i < strlen(testContent); i++) { crc.add(testContent[i]); } uint8_t testContentCRC8 = crc.calc(); crc.reset(); Serial.println("testContent value:" + String(testContent) + ". With CRC value:" + String(testContentCRC8)); const char testFilename[] = "255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255.txt"; for (int i = 0; i < strlen(testFilename); i++) { crc.add(testFilename[i]); } uint8_t testFilenameCRC8 = crc.calc(); crc.reset(); Serial.println("testFilename value:" + String(testFilename) + ". With CRC value:" + String(testFilenameCRC8)); // Create empty file and set to WRITE mode Folder root = storage.getRootFolder(); UFile file1 = root.createFile(testFilename, FileMode::WRITE); file1.write(testContent); file1.changeMode(FileMode::READ); file1.seek(0); String dataRead = ""; while (file1.available()) { char data = file1.read(); crc.add(data); dataRead += data; } Serial.println(); uint8_t dataReadCRC = crc.calc(); Serial.println("Files found:"); std::vector files = root.getFiles(); // Print files for (UFile file : files) { Serial.print("[F] "); Serial.println(file.getPath()); } Serial.println("Data read was " + dataRead + " with CRC value " + String(dataReadCRC)); } void loop() { } ```
Serial Monitor ``` --- Test Case ID: AUS_SPIS_FNBLFS_009 --- testContent value:Hello World!. With CRC value:28 testFilename value:255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255.txt. With CRC value:127 Files found: [F] /internal/255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255chars255.txt Data read was Hello World! with CRC value 28 ```

256 Character Filename - FAIL

Sketch ``` #include "Arduino_UnifiedStorage.h" #include "CRC.h" // https://github.com/RobTillaart/CRC InternalStorage storage; CRC8 crc; const char testCaseID[] = "AUS_SPIS_FNBLFS_010"; void setup() { Serial.begin(115200); while (!Serial); Serial.println("---"); Serial.print("Test Case ID: "); Serial.println(testCaseID); Serial.println("---"); Arduino_UnifiedStorage::debuggingModeEnabled = false; if (Arduino_UnifiedStorage::debuggingModeEnabled) { Serial.println("Arduino_UnifiedStorage debug messages ON."); } storage = InternalStorage(); storage.format(FS_LITTLEFS); if(!storage.begin()){ Serial.println("Error mounting storage device."); } // specify Test strings & CRC const char testContent[] = "Hello World!"; for (int i = 0; i < strlen(testContent); i++) { crc.add(testContent[i]); } uint8_t testContentCRC8 = crc.calc(); crc.reset(); Serial.println("testContent value:" + String(testContent) + ". With CRC value:" + String(testContentCRC8)); const char testFilename[] = "256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256c.txt"; for (int i = 0; i < strlen(testFilename); i++) { crc.add(testFilename[i]); } uint8_t testFilenameCRC8 = crc.calc(); crc.reset(); Serial.println("testFilename value:" + String(testFilename) + ". With CRC value:" + String(testFilenameCRC8)); // Create empty file and set to WRITE mode Folder root = storage.getRootFolder(); UFile file1 = root.createFile(testFilename, FileMode::WRITE); file1.write(testContent); file1.changeMode(FileMode::READ); file1.seek(0); String dataRead = ""; while (file1.available()) { char data = file1.read(); crc.add(data); dataRead += data; } Serial.println(); uint8_t dataReadCRC = crc.calc(); Serial.println("Files found:"); std::vector files = root.getFiles(); // Print files for (UFile file : files) { Serial.print("[F] "); Serial.println(file.getPath()); } Serial.println("Data read was " + dataRead + " with CRC value " + String(dataReadCRC)); } void loop() { } ```
Serial Monitor ``` --- Test Case ID: AUS_SPIS_FNBLFS_010 --- testContent value:Hello World!. With CRC value:28 testFilename value:256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256chars256c.txt. With CRC value:182 Files found: [F] /internal/ Data read was with CRC value 0 ```

Additional information

On the Renasas core (Portenta C33), the LittleFS driver sets the maximum character length to 255 characters via LFS_NAME_MAX.

// Maximum name size in bytes, may be redefined to reduce the size of the
// info struct. Limited to <= 1022. Stored in superblock and must be
// respected by other littlefs drivers.
#ifndef LFS_NAME_MAX
#define LFS_NAME_MAX 255
#endif

On the mbed core (Portenta H7), the LittleFS driver also sets the maximum character length to 255 characters via LFS_NAME_MAX.


// Max name size in bytes
#ifndef LFS_NAME_MAX
#define LFS_NAME_MAX 255
#endif

In both cases for both the mbed and Renasas core, a lfs_info structure adds an addtion byte LFS_NAME_MAX+1 to account for a null terminated string that corresponds to the test outcome.

aliphys commented 7 months ago

LFS_NAME_MAX in Arduino implementations of LittleFS

Repo LFS_NAME_MAX value Location
arduino/mbed-os 255 storage/filesystem/littlefs/littlefs/lfs.h
arduino/ArduinoCore-renesas 255 extras/Filesystems/littlefs/lfs.h
arduino/ArduinoCore-mbed 255 cores/arduino/mbed/storage/filesystem/littlefs/littlefs/lfs.h

LFS_NAME_MAX in selected third party implementations of LittleFS

Repo LFS_NAME_MAX value Location
esp8266/Arduino 32 libraries/LittleFS/src/lfs.c
littlefs-project/littlefs 255 lfs.h
alibaba/AliOS-Things 255 components/littlefs/src/littlefs-v220/include/lfs.h
adafruit/Adafruit_nRF52_Arduino 255 libraries/Adafruit_LittleFS/src/littlefs/lfs.h
RAKWireless/RAK-nRF52-Arduino 255 libraries/Adafruit_LittleFS/src/littlefs/lfs.h

Additional context:

Szybet commented 6 months ago

I did in fact spend 8 hours pin pointing that mklittlefs was the issue. My god...

Anyway, thanks for the notes here!