Problem reading file from sd and store data into an array

Hi guys, I'm having issue reading some data stored into an sd and parse into an array of values.

The array are the following

ImpostazioneInt arraySDInt []
{
        { "timeoutTimerMax", timeoutTimerMax },
        { "timeoutDistance", timeoutDistance },
        { "GreenZoneCirc", GreenZoneCirc},
        { "exitTime_delay", exitTime_delay },
        { "TimeZone", TimeZone },
};

ImpostazioneBool arraySDBool []
{
        { "timeout", timeout },
        { "Daylight Savings Time", daylightSavingsTime }
};

I couldn't find a way to store both bools and long value so i created 2 struct:

struct ImpostazioneInt
{
  String NomeImpostazione;
  unsigned long Valore;
};

struct ImpostazioneBool
{
  String NomeImpostazione;
  bool Valore;
};

Now what i want from the following function is to scan tha settings file, store each row into a string, split it using strtok and parse it using as key value the first token (impostazione wich in italian means setting) scan trough the array, find the right setting and replace the second token which is the value (valore). As soon it find the right key it reads another row and so on.

This is the function:

void syncSDSettings()
{

  Serial.println("Starting settings sync.");
  File impostazioni = SD.open("/Impostazioni.txt", FILE_READ);

  String riga;
  size_t n;
  char buff[128];

  if(!impostazioni)                                                                    //se il file impostazioni viene letto procedi
  {
    Serial.println("ERROR, unable to read settings.txt");
  }
  else
  {
    while (impostazioni.available())                                                   //esegui il ciclo finche le righe del file non esauriscono
    {
      

      riga = impostazioni.readStringUntil('\n');                                      //legge da impostazioni una stringa fino al capo
      char* rigaChar;
      riga.toCharArray(rigaChar,128);


      Serial.println("Analyzing row: ");
      Serial.println(riga);
      Serial.println();
      Serial.println("Tokenizing");
      char *impostazione = strtok (rigaChar," = ");                //associa la prima parte della riga all'impostazione
      char *valore = strtok(NULL,";");                                       //associa la seconda parte al valore

      Serial.print("Value tokenized: ");
      Serial.print(impostazione);
      Serial.print(" : ");
      Serial.print(valore);
      Serial.println();


      if (valore=="TRUE" || valore =="FALSE")                                          //se il valore è un buleano associalo a ImpostazioneBool
      {
        Serial.println("Boolean value found");
        for (int i = 0; i < sizeof(arraySDBool)/sizeof(ImpostazioneBool); i++)                  //scansiona ogni settaggio di ImpostazioneBool
        {
          Serial.println("Checking occurance");
          if (strcmp(impostazione,  stringToChar128(arraySDInt[i].NomeImpostazione)))                                  //se l'etichetta corrisponde
          {
            Serial.println("Occurance found");
            if (strcmp(valore, "TRUE"))
            {
              arraySDBool[i].Valore = true;                                                       //associa a ImpostazioneBool il valore letto
            }
            else
            {
              arraySDBool[i].Valore = false; 
            }
            Serial.println("Value updated");
          }
        }
      }
      else                                                                            //avvia associazione di valori int
      {
        Serial.println("Int value found");
        for (int i = 0; i < sizeof(arraySDInt)/sizeof(ImpostazioneInt); i++)                  //scansiona ogni settaggio di ImpostazioneInt
        {
          Serial.println("Controllo corrispondenza etichetta");
          if (strcmp(impostazione,  stringToChar128(arraySDInt[i].NomeImpostazione)))                                  //se l'etichetta corrisponde
          {
            Serial.println("Corrispondenza trovata");
            arraySDInt[i].Valore = atoi(valore);
            Serial.println("Valore aggiornato");
          }
        }
      }
    }
    closeFile(impostazioni);
  }
}

This is what happens:

  • I have added some monitor outs to check if strtok is working but it's not, the values are both empty
  • the inner while works 1 time and then i have a runtime error

I know, i'm using String instead of c string, it seemed easier to me but it's still not working and i have tried tons of stuff to fix it but i could not make it work properly.

Do you have any idea?

P.S. I'm working with an esp32

I know, i'm using String instead of c string, it seemed easier to me but it's still not working and i have tried tons of stuff to fix it but i could not make it work properly.

Do you have any idea?

It is really not a very good idea to use 'String' within a struct. a String does not have a fixed size, and really is an object with a pointer to data. I am sure there is moments where it might work, but within a struct i think it is really not a very good plan.
Having said that, using strtok() on an esp may also get you into trouble (though it shouldn't, maybe they've finally fixed it) But you should switch to char-array but not like this

char* rigaChar;
      riga.toCharArray(rigaChar,128);

you've create a char * without declaring it's size.

Possibly.. You could store your results in c strings (Char arrays) but use one (1) global String to do your decoding and processing?

Just a thought.

-jim lee

Deva_Rishi:
It is really not a very good idea to use 'String' within a struct. a String does not have a fixed size, and really is an object with a pointer to data. I am sure there is moments where it might work, but within a struct i think it is really not a very good plan.
Having said that, using strtok() on an esp may also get you into trouble (though it shouldn't, maybe they've finally fixed it) But you should switch to char-array but not like this

char* rigaChar;

riga.toCharArray(rigaChar,128);



you've create a char * without declaring it's size.

Is there a bug with strtok on esp?
Is there any function for c string in order to split the row or i have to hard code it while I find the correct char? (like strtok but for c string)
I'm asking becouse I'll need to do a similar operation with different data.

jimLee:
Possibly.. You could store your results in c strings (Char arrays) but use one (1) global String to do your decoding and processing?

Ah ok, so you are saying to use c string instead of String inside the array and the struct and use only 1 String as a global temp variable to store rows, I think i tried that too but I had some issue comparing the results in order to parse the correct value into the correct slot of the array.

Is there a bug with strtok on esp?

Yes i there was (is) it manifests itself in causing the ESP to actually crash. Creating a function that splits c-string manually is not very hard to do though.

Ah ok, so you are saying to use c string instead of String inside the array and the struct and use only 1 String as a global temp variable to store rows, I think i tried that too but I had some issue comparing the results in order to parse the correct value into the correct slot of the array

This here is not working :

riga = impostazioni.readStringUntil('\n');                                      //legge da impostazioni una stringa fino al capo
      char* rigaChar;
      riga.toCharArray(rigaChar,128);

rigaChar is only the pointer, but points to an empty c-string, that you want to copy 128 characters to it doesn't really matter. How about using the 'String' class to do the parsing

riga = impostazioni.readStringUntil('=');                                      
      char rigaChar[riga.length() + 1];
      riga.toCharArray(rigaChar, riga.length() + 1);

that way you won't need strtok() Or probably even better, since the written data in the struct is anyway not going to change, create the struct like this

struct ImpostazioneInt
{
  const char NomeImpostazione[15];  // you can leave the size undefined  (as a const) and just use char * as  
                                                      // well, but i would fix the size. 
  unsigned long Valore;
};

and do the comparing of the tokens

String compareString = ??;
if (compareString == String (mpostazioneInt.NomeImpostazione)) etc...

but make sure that you take any white spaces in the file into account.