Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

some of keys and values would be changed after opening a file #1643

Closed
YvanLin opened this issue Aug 29, 2021 · 3 comments
Closed

some of keys and values would be changed after opening a file #1643

YvanLin opened this issue Aug 29, 2021 · 3 comments
Labels
question v6 ArduinoJson 6

Comments

@YvanLin
Copy link

YvanLin commented Aug 29, 2021

This is my code. It's an operation that I read a configuration file then rewrite it with a new config.

#include <ArduinoJson.h>
#include <LittleFS.h>

bool loadConfig(StaticJsonDocument<200> &doc)
{
  File configFile = LittleFS.open("/config.json", "r");
  if (!configFile)
  {
    Serial.println("Failed to open config file");
    clearFile(configFile);
    return false;
  }

  size_t size = configFile.size();
  if (size > 1024)
  {
    Serial.println("Config file size is too large");
    clearFile(configFile);
    return false;
  }
  std::unique_ptr<char[]> buf(new char[size]);
  configFile.readBytes(buf.get(), size);

  auto error = deserializeJson(doc, buf.get());
  if (error)
  {
    Serial.println("Failed to parse config file");
    clearFile(configFile);
    return false;
  }
  clearFile(configFile);
  return true;
}

bool saveConfig(bool load)
{
  StaticJsonDocument<200> doc;
  if(load){
    loadConfig(doc);
  }
  Serial.println("after load config");
  serializeJson(doc, Serial);
  Serial.println();


  File configFile = LittleFS.open("/config.json", "w");
  
  Serial.println("after load file");
  serializeJson(doc, Serial);
  Serial.println();
  doc["serverName"] = "api.example.com";
  doc["accessToken"] = "something";
  
  Serial.println("after change config");
  serializeJson(doc, Serial);
  Serial.println();
  
  if (!configFile)
  {
    Serial.println("Failed to open config file for writing");
    clearFile(configFile);
    return false;
  }
  serializeJson(doc, configFile);
  clearFile(configFile);
  Serial.println();

  return true;
}

void clearFile(File &file){
  file.close();
}


void setup()
{
  Serial.begin(115200);
  Serial.println("");
  delay(1000);
  Serial.println("Mounting FS...");

  if (!LittleFS.begin())
  {
    Serial.println("Failed to mount file system");
    return;
  }
  saveConfig(false);
}

void loop()
{
  saveConfig(true);
  delay(5000);
}

And this is a part of output from serial

after load config
null
after load file
null
after change config
{"serverName":"api.example.com","accessToken":"something"}

after load config
{"serverName":"api.example.com","accessToken":"something"}
after load file
{"":"api.example.com","accessToken":"something"}
after change config
{"":"api.example.com","accessToken":"something","serverName":"api.example.com"}

after load config
{"":"api.example.com","accessToken":"something","serverName":"api.example.com"}
after load file
{"":"","accessToken":"something","serverName":"api.example.com"}
after change config
{"":"","accessToken":"something","serverName":"api.example.com"}

Form the output informations, we can see that the value from the json document was changed without reason. I was wondering if I am wrong and how I can fix the problem. Thanks~❤

@bblanchon
Copy link
Owner

Hi @YvanLin,

Because you pass a char* to deserializeJson(), you use the "zero-copy" mode. Instead of copying the strings into the JsonDocument, ArduinoJson stores pointers. This saves a lot of space in the JsonDocument but requires that the input buffer remains in memory, which is not the case here.

The simple solution is to remove the buf variable entirely and pass file to deserializeJson().
You can see an example with all the best practices in JsonConfigFile.ino (it uses SD, but the principles apply to LittleFS as well).

BTW, why did you decided to go with std::unique_ptr<char[]>, did you see that in a tutorial or something?

Best regards,
Benoit

@YvanLin
Copy link
Author

YvanLin commented Aug 30, 2021

Hi @YvanLin,

Because you pass a char* to deserializeJson(), you use the "zero-copy" mode. Instead of copying the strings into the JsonDocument, ArduinoJson stores pointers. This saves a lot of space in the JsonDocument but requires that the input buffer remains in memory, which is not the case here.

The simple solution is to remove the buf variable entirely and pass file to deserializeJson().
You can see an example with all the best practices in JsonConfigFile.ino (it uses SD, but the principles apply to LittleFS as well).

BTW, why did you decided to go with std::unique_ptr<char[]>, did you see that in a tutorial or something?

Best regards,
Benoit

@bblanchon Thanks a lot. The problem is solved.

I used code from esp8266 examples.

@bblanchon
Copy link
Owner

Thank you for the information.
I just opened a pull request to remove std::unique_ptr<char[]> from the example.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Oct 4, 2021
@bblanchon bblanchon added the v6 ArduinoJson 6 label Feb 6, 2024
# for free to subscribe to this conversation on GitHub. Already have an account? #.
Labels
question v6 ArduinoJson 6
Projects
None yet
Development

No branches or pull requests

2 participants