Skip to content
GitLab
Projects Groups Snippets
  • /
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
    • Contribute to GitLab
  • Sign in / Register
  • A ArduinoJson
  • Project information
    • Project information
    • Activity
    • Labels
    • Members
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
  • Issues 24
    • Issues 24
    • List
    • Boards
    • Service Desk
    • Milestones
  • Merge requests 0
    • Merge requests 0
  • CI/CD
    • CI/CD
    • Pipelines
    • Jobs
    • Schedules
  • Deployments
    • Deployments
    • Environments
    • Releases
  • Packages and registries
    • Packages and registries
    • Package Registry
    • Infrastructure Registry
  • Monitor
    • Monitor
    • Incidents
  • Analytics
    • Analytics
    • Value stream
    • CI/CD
    • Repository
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar
  • Benoît Blanchon
  • ArduinoJson
  • Issues
  • #1210
Closed
Open
Issue created Mar 10, 2020 by Administrator@rootContributor

PlatformIO + ESP8266 + Debug mode = Stack overflow

Created by: lbussy

I am using the code right out of your book examples. Whenever I run it a second time (when it should have already created the /config.json) it tells me it "Failed to deserialize configuration." When the JSON prints it looks fine, and I have run it through a JSON Validator and it returns ok.

The only changes I've made are as follows:

  • Renamed SpiffsConfig.ino to main.cpp as I am using PlatformIO
  • Added prototypes for the functions at the top of the main.cpp

I'm not going to include that code - because I got it from you. :)

So - problem statement: I am unable to use the example provided.

It never seems to be able to deserialize the file. The file prints out fine when writing, but when the ESP restarts the file is unable to deserialize again. The file exists.

Here's some demo code I made trying to make sense of it (using the same Config.h and Config.cpp):

#include <FS.h>
#include "Config.h"

const char *filename = "/config.json";
Config config;

bool loadConfig(const char *filename, Config &config);
bool saveConfig(const char *filename, const Config &config);
void setDefaultConfig();
bool printFile(const char *filename);
bool listFiles();
bool listFileSystemInfo();
void printConfig();
void setup();
void loop();

bool loadConfig(const char *filename, Config &config) {
    // Loads the configuration from a file on SPIFFS
    bool retVal;
    // Mount SPIFFS
    if (SPIFFS.begin()) {
        // Open file for reading
        File file = SPIFFS.open(filename, "r");
        // This may fail if the file is missing
        if (!file) {
            Serial.println(F("Failed to open config file."));
            retVal = false;
        } else {
            // Parse the JSON object in the file
            // This may fail if the JSON is invalid
            if (!deserializeConfig(file, config)) {
                Serial.println(F("Failed to deserialize configuration, here's the file we attempted:"));
                printFile(filename);
                SPIFFS.remove(filename);
                Serial.println(F("Deleted corrupt file."));
                retVal = false;
            } else {
                retVal = true;
            }
            file.close();
        }
        SPIFFS.end();
    } else {
        Serial.println(F("Unable to start SPIFFS in loadConfig()."));
        retVal = false;
    }
    return retVal;
}

bool saveConfig(const char *filename, const Config &config) {
    bool retVal;
    // Open file for writing
    if (SPIFFS.begin()) {
        File file = SPIFFS.open(filename, "w");
        if (!file) {
            Serial.println(F("Failed to create config file."));
            retVal = false;
        } else {
            // Serialize JSON to file
            bool success = serializeConfig(config, file);
            if (!success) {
                Serial.println(F("Failed to serialize configuration."));
                retVal = false;
            } else {
                retVal = true;
            }
            file.close();
        }
        SPIFFS.end();
    } else {
        Serial.println(F("Unable to start SPIFFS in saveConfig()."));
        retVal = false;
    }
    return retVal;
}

void setDefaultConfig() {
    // Initialize configuration with defaults
    Serial.println(F("Setting default config."));
    strcpy(config.server.host, "example.com");
    strcpy(config.server.path, "/resource");
    strcpy(config.server.username, "admin");
    strcpy(config.server.password, "s3cr3t");
    strcpy(config.accessPoint[0].ssid, "SSID 1");
    strcpy(config.accessPoint[0].passphrase, "Passphrase 1");
    strcpy(config.accessPoint[1].ssid, "SSID 2");
    strcpy(config.accessPoint[1].passphrase, "Passphrase 2");
    config.accessPoints = 2;
}

bool printFile(const char *filename) {
    // Prints the content of a file to the Serial
    bool retVal;
    // Open file for reading
    if (SPIFFS.begin()) {
        File file = SPIFFS.open(filename, "r");
        if (!file) {
            Serial.println(F("Failed to open file for printing."));
            retVal = false;
        } else {
            // Extract each by one by one
            while (file.available()) {
                Serial.print((char)file.read());
            }
            Serial.println();
            file.close();
            retVal = true;
        }
        SPIFFS.end();
    } else {
        Serial.println(F("Unable to start SPIFFS in printFile()."));
        retVal = false;
    }
    return retVal;
}

bool listFileSystemInfo() {
    bool retVal;
    if (SPIFFS.begin()) {
        retVal = true;
        // List filesystem information
        FSInfo fs_info;
        SPIFFS.info(fs_info);
        Serial.println(F("-------------------"));
        Serial.print(F("Total Bytes: "));
        Serial.println(fs_info.totalBytes);
        Serial.print(F("Used Bytes: "));
        Serial.println(fs_info.usedBytes);
        Serial.print(F("Block Size: "));
        Serial.println(fs_info.blockSize);
        Serial.print(F("Page Size: "));
        Serial.println(fs_info.pageSize);
        Serial.print(F("Max Open Files: "));
        Serial.println(fs_info.maxOpenFiles);
        Serial.print(F("Max Path Length: "));
        Serial.println(fs_info.maxPathLength);
        Serial.println(F("-------------------"));
        SPIFFS.end();
        return true;
    } else {
        Serial.println(F("Unable to start SPIFFS in listFileSystemInfo()."));
        retVal = false;
    }
    return retVal;
}

bool listFiles() {
    bool retVal;
    if (SPIFFS.begin()) {
        Dir dir = SPIFFS.openDir("");
        int files = 0;
        while (dir.next()) {
            if (files == 0)
                Serial.println(F("-------------------"));

            Serial.print(dir.fileName());
            Serial.print(F(" - "));
            Serial.print(dir.fileSize());
            Serial.println(F("B"));
            files++;
        }
        if (files > 0)
            Serial.println(F("-------------------"));
        SPIFFS.end();
        retVal = true;
    } else {
        Serial.println(F("Unable to start SPIFFS in listFiles()."));
        retVal = false;
    }
    return retVal;
}

void printConfig() {
    // TODO:  Iterate through stuff
}

void setup() {
    delay(1000);
    Serial.begin(BAUD);

    if (!listFileSystemInfo()) {
        Serial.println(F("Error: Unable to list file system info."));
    } else {
        if (!listFiles()) {
            Serial.println(F("Error: Unable to list files."));
        } else {
            // Load configuration
            if (!loadConfig(filename, config)) {
                Serial.println(F("Error: Unable to load configuration."));
                // Set default configuration
                setDefaultConfig();
                // Save configuration
                if (!saveConfig(filename, config)) {
                    Serial.println(F("Error: Unable to save configuration."));
                } else {
                    // Dump config file
                    if (!printFile(filename)) {
                        Serial.println(F("Error: Unable to print configuration file."));
                    }
                }
            } else {
                Serial.println(F("Everything seems ok."));
            }
        }
    }
}

void loop() {}

Currently, it all works as expected the first time. Subsequently, when it should be loading the configuration it fails:

-------------------
Total Bytes: 957314
Used Bytes: 753
Block Size: 8192
Page Size: 256
Max Open Files: 5
Max Path Length: 32
-------------------
-------------------
/config.json - 309B
-------------------
Failed to deserialize configuration, here's the file we attempted:
{
  "server": {
    "username": "admin",
    "password": "s3cr3t",
    "host": "example.com",
    "path": "/resource"
  },
  "access_points": [
    {
      "ssid": "SSID 1",
      "passphrase": "Passphrase 1"
    },
    {
      "ssid": "SSID 2",
      "passphrase": "Passphrase 2"
    }
  ]
}
Deleted corrupt file.
Error: Unable to load configuration.
Setting default config.
{
  "server": {
    "username": "admin",
    "password": "s3cr3t",
    "host": "example.com",
    "path": "/resource"
  },
  "access_points": [
    {
      "ssid": "SSID 1",
      "passphrase": "Passphrase 1"
    },
    {
      "ssid": "SSID 2",
      "passphrase": "Passphrase 2"
    }
  ]
}

So you can see that the file looks right, it is 309 bytes in length (which is correct) yet still does not deserialize.

ETA: A debug line in deserializeConfig() tells me that it fails because of IncompleteInput.

Assignee
Assign to
Time tracking