0

I intend to create a function to jsify sensors' content and save it on a SD-card or send through a http client. Except for the Serial.println's, the function is transcripted below.

String jsonificar(vector<vector<String>> sujeito){
  String json_txt = String(""), chave, valor;
  String chave_str, valor_str;

  json_txt+=String("{");
  for(unsigned int i = 0; i<sujeito.size(); i++){
    if(sujeito[i].size() != 2){
        Serial.println("Cada conteudo deve conter 2 textos!");
    }
    else{
        chave = sujeito[i][0];
        valor = sujeito[i][1];
        Serial.println(chave);
        Serial.println(valor);
        Serial.println(json_txt);
        json_txt += "\\\"";
        Serial.println(json_txt);
        json_txt += chave;
        Serial.println(json_txt);
        json_txt += "\\\"";
        Serial.println(json_txt);
        json_txt += ":";
        Serial.println(json_txt);
        json_txt += "\\\"";
        Serial.println(json_txt);
        json_txt += valor;
        Serial.println(json_txt);
        json_txt += "\\\"";
        Serial.println(json_txt);

        if(i != sujeito.size() - 1){
          json_txt += String(",");
        }
    }
  }

  json_txt+="}";
  Serial.println(json_txt);

  return json_txt;
}

The output on serial follows:

Output:

Chave1
Valor1
{
{\"
{\"Chave1
{\"Chave1\"
{\"Chave1\":
{\"Chave1\":\"
{\"Chave1\":\"Valor1
{\"Chave1\":\"Valor1\"
Chave2
Valor2
{\"Chave1\":\"Valor1\",
{\"Chave1\":\"Valor1\",\"
{\"Chave1\":\"Valor1\",\"    <===
{\"Chave1\":\"Valor1\",\"\"
{\"Chave1\":\"Valor1\",\"\": <===
{\"Chave1\":\"Valor1\",\"\": <===
{\"Chave1\":\"Valor1\",\"\": <===
{\"Chave1\":\"Valor1\",\"\": <===
{\"Chave1\":\"Valor1\",\"\":}

The arrows show the spots where the logs are different from expected: the keys and values provided are "Chave1", "Valor1", "Chave2", "Valor2". So, the key-value should be "Chave2":"Valor2". Would you have a grasp of this behaviour? I look forward for the answer!

  • How did you get std::vector into Arduino? It doesn't compile for me. – Maximilian Gerhardt Jun 15 '18 at 19:25
  • The same way one would use in default C++ appplication: using namespace std; You have answered your own question unpurposely ;P – Bruno Henrique Peixoto Jun 15 '18 at 19:29
  • 1
    The Arduino core implementation for AVR does not have these C++ STL types. Are you using an additional library like github.com/mike-matera/ArduinoSTL ? – Maximilian Gerhardt Jun 15 '18 at 19:31
  • Yes, I use ArduinoSTL. I also use PlatformIO as IDE and it says vector comes from namespace std. – Bruno Henrique Peixoto Jun 15 '18 at 19:34
  • You must be using this above library, no doubt. It does not work without it. I compiled this code and it ran without an error. Have a look at: pastebin.com/LPTYDje5 – Maximilian Gerhardt Jun 15 '18 at 19:35
3

Your "disappearing string" has the following cause: Out-of-Memory.

You are constructing lots of String objects in your code and are concatinating to one. That uses memory on the heap for each String (and realloc() when the String memory must be expanded).

Consider the following test sketch which includes your code but also adds a memory leak by 150 bytes in each iteration:

#include <Arduino.h>
#include <ArduinoSTL.h>
using namespace std;

extern unsigned int __heap_start;
extern void *__brkval;

/*
 * The free list structure as maintained by the
 * avr-libc memory allocation routines.
 */
struct __freelist {
    size_t sz;
    struct __freelist *nx;
};

/* The head of the free list structure */
extern struct __freelist *__flp;

/* Calculates the size of the free list */
int freeListSize() {
    struct __freelist* current;
    int total = 0;
    for (current = __flp; current; current = current->nx) {
        total += 2; /* Add two bytes for the memory block's header  */
        total += (int) current->sz;
    }
    return total;
}

int freeMemory() {
    int free_memory;
    if ((int) __brkval == 0) {
        free_memory = ((int) &free_memory) - ((int) &__heap_start);
    } else {
        free_memory = ((int) &free_memory) - ((int) __brkval);
        free_memory += freeListSize();
    }
    return free_memory;
}

String jsonificar(vector<vector<String>> sujeito) {
    String json_txt = String(""), chave, valor;
    String chave_str, valor_str;

    json_txt += String("{");
    for (unsigned int i = 0; i < sujeito.size(); i++) {
        if (sujeito[i].size() != 2) {
            Serial.println("Cada conteudo deve conter 2 textos!");
        } else {
            chave = sujeito[i][0];
            valor = sujeito[i][1];
            Serial.println(chave);
            Serial.println(valor);
            Serial.println(json_txt);
            json_txt += "\\\"";
            Serial.println(json_txt);
            json_txt += chave;
            Serial.println(json_txt);
            json_txt += "\\\"";
            Serial.println(json_txt);
            json_txt += ":";
            Serial.println(json_txt);
            json_txt += "\\\"";
            Serial.println(json_txt);
            json_txt += valor;
            Serial.println(json_txt);
            json_txt += "\\\"";
            Serial.println(json_txt);

            if (i != sujeito.size() - 1) {
                json_txt += String(",");
            }
        }
    }

    json_txt += "}";
    Serial.println(json_txt);

    return json_txt;
}

void setup(void) {
    Serial.begin(115200);
}

String myStr = "";

void loop(void) {

    Serial.print(F("Free Memory:"));
    Serial.println(freeMemory());

    //force a memory leak by allocating appending to a global String
    myStr +=
            "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
            "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";

    vector<vector<String>> v =
            { { "Chave1", "Valor1" }, { "Chave2", "Valor2" }, };

    jsonificar(v);
    delay(1000);
}

From the output we can see the exact point where we have enough memory and the result is correct, and where we don't have enough memory and the string just "disappears" because there was not enough memory to allocate it:

Free Memory:911
Chave1
Valor1
{
{\"
{\"Chave1
{\"Chave1\"
{\"Chave1\":
{\"Chave1\":\"
{\"Chave1\":\"Valor1
{\"Chave1\":\"Valor1\"
Chave2
Valor2
{\"Chave1\":\"Valor1\",
{\"Chave1\":\"Valor1\",\"
{\"Chave1\":\"Valor1\",\"Chave2
{\"Chave1\":\"Valor1\",\"Chave2\"
{\"Chave1\":\"Valor1\",\"Chave2\":
{\"Chave1\":\"Valor1\",\"Chave2\":\"
{\"Chave1\":\"Valor1\",\"Chave2\":\"Valor2
{\"Chave1\":\"Valor1\",\"Chave2\":\"Valor2\"
{\"Chave1\":\"Valor1\",\"Chave2\":\"Valor2\"}
Free Memory:761
Chave1
Valor1
{
{\"
{\"Chave1
{\"Chave1\"
{\"Chave1\":
{\"Chave1\":\"
{\"Chave1\":\"Valor1
{\"Chave1\":\"Valor1\"
Chave2
Valor2
{\"Chave1\":\"Valor1\",
{\"Chave1\":\"Valor1\",\"
{\"Chave1\":\"Valor1\",\"Chave2
{\"Chave1\":\"Valor1\",\"Chave2\"
{\"Chave1\":\"Valor1\",\"Chave2\":
{\"Chave1\":\"Valor1\",\"Chave2\":\"
{\"Chave1\":\"Valor1\",\"Chave2\":\"
{\"Chave1\":\"Valor1\",\"Chave2\":\"
{\"Chave1\":\"Valor1\",\"Chave2\":\"

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.