Skip to content

LittleFS upload "Success" but file read fails. #9126

@meakashrao

Description

@meakashrao

Board

ESP32-WROOM-32E-N4

Device Description

The hardware is custom, but I was able to update to and fro multiple Firmware Versions with the LITTLEFS Partitions.

Hardware Configuration

NA

Version

latest master (checkout manually)

IDE Name

Platform IO

Operating System

Windows 11

Flash frequency

40Mhz

PSRAM enabled

yes

Upload speed

460800

Description

  1. Platform IO Serial Update
    a) When I use Platform IO Core 6.1.13 and Home 3.4.4 with Espressif 32 v6.4.0, and upload firmware.bin file using the upload button and littlefs.bin using the upload FileSystem Image, my ESP is able to read the LITTLEFS file.
    b) When I upload using the OTA method by making the ESP go into Access Point Mode and use the files espota.py and esptool.py although both files are updated successfully my LittleFS read fails(mount doesn't but file read fails)
    I tried to format the LITTLEFS partion using the function "LittleFS.format()" and it returns successful and uploaded the LITTLEFS.bin again and it still resulted in File not present and File read failed.
    c) Then if I take the ESP, erase the flash contents, and repeat step 'a' things work again.

I am attaching a zip file with my files.
ESP_OTA_LITTLEFS_Details.zip

I have multiple sections where I send the Error Message using BLE a
The Error Messages are
a) it says "LITLFS-FileReadFail" in the function
void readFile(fs::FS &fs, const char * path), which basically just reads and serial prints contents of the 2 files in the data folder in Platform IO
b) Files not found
c) Reading fails again.

OTA upload Screenshots
Firmware File
image

SPIFFS Image:
image

Starting of the espota.py file
image

The whole espota.py and esptool.py are there in the zip

Sketch

I am attaching the LITTLEFS_Config.cpp here (it's included in the ZIP above as well)

#include "Arduino.h"
#include "main.h"
#include "LittleFS.h"  
#include "LITTLEFS_Config.h"
#include "Rotary_Encoder.h"
#include "Weight_Handler.h"
#include "FS.h"

// Function declarations
void checkLITTLEFSContent();              // Initializes LittleFS and reads the contents of the file
void readRGBPins(String line, String key);
void readHX711(String line, String key);
void readRGBArray(String line, String key);
void readQTempTrigger(String line, String key);
void parseIntArray(String valueStr, int* array, int arraySize);
void printArray(const int* array, int arraySize);
void listDir(fs::FS &fs, const char * dirname, uint8_t levels);
void readFile(fs::FS &fs, const char * path);
void readConfigFile(fs::FS &fs, const char * path);

void checkLITTLEFSContent()
{
    Serial.println("Mounting LittleFS...");
    if (!LittleFS.begin(true))
    {
        Serial.println("An Error has occurred while mounting LittleFS");
        //TODO: Error Handling
        errorType = 2;
        addErrorMessage("MountingLITLFSError");
        return;
    }

    listDir(LittleFS, "/", 0);

    String configFile = (machineVersion == "BB1") ? "/BB1_config.txt" : "/BB2_config.txt";

    readFile(LittleFS, configFile.c_str()); // Use c_str() to convert String to const char*
    readConfigFile(LittleFS, configFile.c_str());
}

void readFile(fs::FS &fs, const char * path)
{
  Serial.printf("Reading file: %s\r\n", path);

  File file = fs.open(path);
  if(!file || file.isDirectory())
  {
    Serial.println("- failed to open file for reading");
    addErrorMessage("LITLFS-FileReadFail");
    return;
  }

  Serial.println("File Content:");
  while(file.available())
  {
    Serial.write(file.read());
  }
  file.close();
}

// Function to list the contents of a directory
void listDir(fs::FS &fs, const char * dirname, uint8_t levels) 
{
    Serial.printf("Listing directory: %s\n", dirname);

    File root = fs.open(dirname);
    if (!root) 
    {
        Serial.println("- failed to open directory");
        //TODO: Error Handling
        errorType = 4;  
        addErrorMessage("Directory-openfaile");
        return;
    }
    if (!root.isDirectory()) 
    {
        Serial.println(" - not a directory");
        //TODO: Error Handling
        errorType = 5;  
        addErrorMessage("Not-a-directory----");
        return;
    }

    const char* fileNames[] = {"BB1_config.txt", "BB2_config.txt"};         // Define the file names to check in the directory
    bool foundFiles[] = {false, false};                                     // Corresponds to the files in fileNames
    int numberOfFiles = sizeof(fileNames) / sizeof(char*);

    File file = root.openNextFile();
    while (file) 
    {
        Serial.print(file.isDirectory() ? "  DIR : " : "  FILE: ");
        Serial.println(file.name());
        Serial.print(file.size());                              // Print the size of the file
        Serial.println(" bytes");

        for (int i = 0; i < numberOfFiles; i++) 
        {
            if (String(file.name()).endsWith(fileNames[i]))     // Check if the file name ends with the desired file name
            { 
                Serial.printf("Found: %s\n", file.name());
                foundFiles[i] = true; // Mark as found
            }
        }
        if (file.isDirectory() && levels) 
        {
            listDir(fs, file.name(), levels - 1);               // Recursively list subdirectories
        }
        file = root.openNextFile();
    }
    // Check which files were not found and print the messages after listing
    if (foundFiles[0] == false) 
    {
        Serial.printf("Not found: %s\n", fileNames[0]);
        //TODO: Error Handling
        errorType = 6;      
        addErrorMessage("BB1-config-notfound");                            
    }
    if (foundFiles[1] == false) 
    {
        Serial.printf("Not found: %s\n", fileNames[1]);
        //TODO: Error Handling
        errorType = 7;   
        addErrorMessage("BB2-config-notfound");                               
    }
}

void readRGBPins(String line, String key) 
{
    if (key.equalsIgnoreCase("RedLed") || key.equalsIgnoreCase("GreenLed")) {
        int pin = line.toInt();
        // Assign the pin to the respective LED
        if(key.equalsIgnoreCase("RedLed")) redPin = pin;
        if(key.equalsIgnoreCase("GreenLed")) greenPin = pin;
    }
}

void readHX711(String line, String key) 
{
    if (key.equalsIgnoreCase("HX711_DOUT")) 
	{
        actual_dout_pin = line.toInt(); 
    }
}

void readQTempTrigger(String line, String key) 
{
    if (key.equalsIgnoreCase("qTempTrigger")) 
	{
        qTempTrigger = line.toFloat();
    }
}

void readRGBArray(String line, String key) 
{
    if (key.equalsIgnoreCase("GreenRGB")) 
    {
        parseIntArray(line, greenRGB, 3);
    } 
    else if (key.equalsIgnoreCase("OrangeRGB")) 
    {
        parseIntArray(line, orangeRGB, 3);
    } 
    else if (key.equalsIgnoreCase("RedRGB")) 
    {
        parseIntArray(line, redRGB, 3);
    }
    else
    {

    }
}

void readConfigFile(fs::FS &fs, const char * path) 
{
    Serial.printf("Reading file: %s\n", path);

    File file = fs.open(path);
    if (!file || file.isDirectory()) 
    {
        Serial.println("- failed to open file for reading");
        //TODO: Error Handling
        errorType = 3;
        addErrorMessage("LITLFS2FileReadFail");
        return;
    }
    while (file.available()) 
    {
        String line = file.readStringUntil('\n');   // Read a line of text up to the newline character.
        line.trim();                                // Remove any leading or trailing whitespace from the line.
        int equalSignIndex = line.indexOf('=');     // Find the position of the equal sign, which separates the key from the value.
        if (equalSignIndex != -1)                   // If there is an equal sign, then it's a line with a setting to process.
        {                 
            String key = line.substring(0, equalSignIndex);     // Extract the key (the part of the line before the equal sign).
            key.trim();                                         // Remove any whitespace around the key.
            String valueStr = line.substring(equalSignIndex + 1);   // Extract the value (the part of the line after the equal sign).
            valueStr.trim();                                    // Remove any whitespace around the value.
            // Call the appropriate function to handle the setting based on the key.
            // These functions will parse the value string and set the corresponding configuration variables.
            readRGBPins(valueStr, key);
            readHX711(valueStr, key);
            //readQTempTrigger(valueStr, key);
            readRGBArray(valueStr, key);
        }
    }
    file.close();  // After reading all the settings, close the file.
}

/*
General function to parse a comma-separated list of "integers" from a String and store them into an array.
valueStr: The string containing the comma-separated values.
array: The integer array to store the parsed values.
arraySize: The size of the array to know how many elements to expect.

The current parseIntArray assumes that there are commas separating values. 
If there's any deviation in the file format (like spaces or other characters), it won't parse correctly.
*/
void parseIntArray(String valueStr, int* array, int arraySize) 
{
  int startIndex = 0;                    // Keeps track of the starting index of each number in the comma-separated list
  int commaIndex = 0;                    // Used to store the index of the found comma
  for (int i = 0; i < arraySize; i++)    // Loop through the expected number of elements in the array
  {
    commaIndex = valueStr.indexOf(',', startIndex);     // Find the next comma in the string starting from startIndex
    if (commaIndex == -1)                               // If no comma is found, this must be the last value, so set commaIndex to the end of the string
    {
      commaIndex = valueStr.length();
    }
    String numberStr = valueStr.substring(startIndex, commaIndex);      // Extract the substring representing the current number
    array[i] = numberStr.toInt();                                       // Convert the substring to an integer and store it in the array
    startIndex = commaIndex + 1;                                        // Set the starting index for the next number to be right after the current comma
  }
}

void printArray(const int* array, int arraySize) 
{
  Serial.print("[");
  for (int i = 0; i < arraySize; i++) 
  {
    Serial.print(array[i]);
    if (i < arraySize - 1) 
    {
      Serial.print(", ");
    }
  }
  Serial.println("]");
}

bool formatLittleFS()
{
    bool ret = LittleFS.format();
    return ret;
}

Debug Message

NA.

Other Steps to Reproduce

No response

I have checked existing issues, online documentation and the Troubleshooting Guide

  • I confirm I have checked existing issues, online documentation and Troubleshooting guide.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Status: SolvedThe issue has been resolved and requires no further action.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions