Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 13 of 13

Thread: SD.open(myString.c_str()) once worked but suddenly stopped working

  1. #1
    Senior Member
    Join Date
    Nov 2016
    Posts
    166

    SD.open(myString.c_str()) once worked but suddenly stopped working

    hi

    on my SDCard (T_3.6) I have the following structure:

    | - startCfg.txt
    | configs \ default.txt
    | configs \ myConf.txt
    | pattern \ default.txt
    | pattern \ myPattern.txt

    I read a main-configfile startCfg.txt to know which further config-files I need ro load.

    Everything worked well until I added the pattern-folder & files to the SD-Card .. oO .. I really did NO change to the code.. anyway, now the SD.open(fileToLoad.c_str()) does not work. When I write the path and file directly in SD.open() it works..

    Code:
    #include <SD.h>
    #include <SPI.h>
    
    #include <string.h>
    #include <ctype.h>
    #include <cfg.h>
    
    bool debug = true;
    
    /* #### READ SD #### */
    File root;
    File startCfg;
    File loadedCfg;
    File loadedPattern;
    const int chipSelect = BUILTIN_SDCARD;
    String cfgName;
    String cfgValue;
    String helpVarString;
    
    void setup() {
       // SERIAL PORT   
      Serial.begin(9600);
      while ( !Serial && (millis() < 4000) ) {
        // ..
      } 
      
      // INIT SD & LOAD CONFIG 
     Serial.println(".................. LOADING SD CONFIG  ");     
       
      if (!SD.begin(chipSelect)) {
        if(debug == true) {
          Serial.println("SD initialization failed!");
        }    
        return;
      }
    
    
      // READ INIT-CONFIG & LOAD INIT-MAPPING
      startCfg = SD.open("startCfg.txt");
      if (startCfg) { 
        Serial.println(".................. LOADING startCfg  "); 
        while (startCfg.available()) {
          helpVarString = startCfg.readStringUntil('\n');     
          cfgName = getValue(helpVarString, ':', 0);
          cfgValue = getValue(helpVarString, ':', 1); 
          
          if(cfgName == "MappingPreset") {
            // load cfg file
            loadCfgFile(cfgValue);
          } 
          
        }
        startCfg.close();
      } else {
        if(debug == true) {
          Serial.println("error opening startCfg.txt");
        }    
      }
    
    }
    
    void loop() {
      // put your main code here, to run repeatedly:
    
    }
    
    
    
    void loadCfgFile(String cfgFile) {  
      String fileToLoad = "/configs/" + cfgFile + ".txt";
      int trackCount = 0;
      
      loadedCfg = SD.open(fileToLoad.c_str());
      
      if (loadedCfg) {    
        while (loadedCfg.available()) {
          helpVarString = loadedCfg.readStringUntil('\n');      
          cfgName = getValue(helpVarString, ':', 0);
          cfgValue = getValue(helpVarString, ':', 1);
          
          if(cfgName == "END") {
            trackCount++;        
          }
            
          int b = atoi(cfgValue.c_str()); 
          //trackMidiMapping[trackCount].setTrackCtrl(cfgName, b, trackCount);
          Serial.println(cfgName);
        }
        loadedCfg.close();
      } else {
        Serial.print("error opening "); Serial.print(cfgFile); Serial.println(".txt");
      }  
    }
    
    
    String getValue(String data, char separator, int index) {
      int found = 0;
      int strIndex[] = { 0, -1 };
      int maxIndex = data.length() - 1;
    
      for (int i = 0; i <= maxIndex && found <= index; i++) {
        if (data.charAt(i) == separator || i == maxIndex) {
          found++;
          strIndex[0] = strIndex[1] + 1;
          strIndex[1] = (i == maxIndex) ? i + 1 : i;
        }
      }
      return found > index ? data.substring(strIndex[0], strIndex[1]) : "";
    }

  2. #2
    Senior Member+ manitou's Avatar
    Join Date
    Jan 2013
    Posts
    1,611
    One would need to know what's in startCfg.txt ...
    if cfgValue is not terminated with a ":", then the readStringUntil('\n') might be picking up a '\r'

  3. #3
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    3,672
    If it were me, probably the first thing I would do would be to print out what the myString.c_str()) actually produces...

    I would probably first try simply print it as a string. But if still not obvious would probably print out all of the bytes in HEX...

  4. #4
    Senior Member
    Join Date
    Nov 2016
    Posts
    166
    Quote Originally Posted by manitou View Post
    One would need to know what's in startCfg.txt ...
    if cfgValue is not terminated with a ":", then the readStringUntil('\n') might be picking up a '\r'
    hi
    so the content of startCfg.txt is:
    Code:
    MappingPreset:Default
    Pattern:Default

    Quote Originally Posted by KurtE View Post
    If it were me, probably the first thing I would do would be to print out what the myString.c_str()) actually produces...

    I would probably first try simply print it as a string. But if still not obvious would probably print out all of the bytes in HEX...
    the fileToLoad.c_str() prints me "Default.txt"

  5. #5
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    3,672
    Quote Originally Posted by AdmiralCrunch View Post
    the fileToLoad.c_str() prints me "Default.txt"
    Where did the "'s come from? Did that actually print out with the print, or just your typing it in? or...

    Again probably the same reason as manitou mentioned, the string might contain the \r character in it, which if you then simply did something like:
    Code:
    Serial.println(fileToLoad.c_str());
    Would simply also print out the CR without you really noticing the data...
    So if I were doing simple prints without printing complete string in HEX, I would maybe also do things like:
    Code:
    Serial.println(strlen(fileToLoad.c_str()));
    Or I might do something like:
    Code:
    Serial.printf("'%s'\n", fileToLoad.c_str());
    And of course that assumes that "Default.txt" is valid? What happend to the other part of the string?

  6. #6
    Senior Member
    Join Date
    Nov 2016
    Posts
    166
    Quote Originally Posted by KurtE View Post
    Where did the "'s come from? Did that actually print out with the print, or just your typing it in? or...
    oh I just typed it in here.., these are not there in the output.

    Quote Originally Posted by KurtE View Post
    Again probably the same reason as manitou mentioned, the string might contain the \r character in it, which if you then simply did something like:
    Code:
    Serial.println(fileToLoad.c_str());
    Would simply also print out the CR without you really noticing the data...
    So if I were doing simple prints without printing complete string in HEX, I would maybe also do things like:
    Code:
    Serial.println(strlen(fileToLoad.c_str()));
    Or I might do something like:
    Code:
    Serial.printf("'%s'\n", fileToLoad.c_str());
    I have deleted the file and written everything again from scratch, no whitespaces or nothing.. simply:
    Code:
    MappingPreset:Default
    Pattern:Default
    which tells me, that I need to load
    /configs/Default.txt


    but I will try strlen() out

    Quote Originally Posted by KurtE View Post
    And of course that assumes that "Default.txt" is valid?
    yes Default.txt is valid.. I can write the path in the function like SD.open("/configs/Default.txt"); and it works.

    Quote Originally Posted by KurtE View Post
    What happend to the other part of the string?
    what part do you mean?
    Code:
    helpVarString = startCfg.readStringUntil('\n');     
    cfgName = getValue(helpVarString, ':', 0); // gets me the string before ":"
    cfgValue = getValue(helpVarString, ':', 1); // gets me the string after ":"

  7. #7
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    3,672
    Quote Originally Posted by AdmiralCrunch View Post
    what part do you mean?
    Code:
    helpVarString = startCfg.readStringUntil('\n');     
    cfgName = getValue(helpVarString, ':', 0); // gets me the string before ":"
    cfgValue = getValue(helpVarString, ':', 1); // gets me the string after ":"
    You say that this works: SD.open("/configs/Default.txt");
    But that this: SD.open(fileToLoad.c_str());

    Does not work, and if you say Serial.println(fileToLoad.c_str())) prints only: Default.txt
    What happened to the /configs/ part of the string?

    I am assuming it is being generated by: String fileToLoad = "/configs/" + cfgFile + ".txt";

  8. #8
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    18,498
    Perhaps you're getting extra whitespace in the string, like a \r before the \n?

    Maybe try adding something like:

    Serial.println(strlen(fileToLoad.c_str()));

  9. #9
    Senior Member+ manitou's Avatar
    Join Date
    Jan 2013
    Posts
    1,611
    Quote Originally Posted by KurtE View Post
    you say Serial.println(fileToLoad.c_str())) prints only: Default.txt
    What happened to the /configs/ part of the string?
    That it only prints "Default.txt" probably confirms that '\r' is embedded in cfgFile string as suggested in post #2. the '\r' causes monitor to start the output at the left, wiping out /configs/

    as others have suggested, you could print out cfgValue in HEX to see "all" the characters in the string

    possible fix: change to readStringUntil('\r'), or add ":" to end of each line in startCfg.txt

    Windows editors terminate lines with CR LF, UNIX editors just LF (\n)

    EDIT: adding code to print cfgValue in HEX
    Code:
    ...
          cfgValue = getValue(helpVarString, ':', 1); 
          char str[32];
          for(int i=0;i<cfgValue.length();i++) {
            sprintf(str,"%02x ",cfgValue[i]);
            Serial.print(str);
          }
    ...
    
    and it prints 44 65 66 61 75 6c 74 0d
    notice the 0x0D at the end == '\r'
    Last edited by manitou; 08-15-2018 at 03:57 PM.

  10. #10
    Senior Member+ manitou's Avatar
    Join Date
    Jan 2013
    Posts
    1,611
    Interestingly you had the same bug in https://forum.pjrc.com/threads/52969...-sometimes-not

    Name:  bug.gif
Views: 112
Size:  8.2 KB
    asked and answered
    Last edited by manitou; 08-13-2018 at 10:54 PM.

  11. #11
    Senior Member
    Join Date
    Nov 2016
    Posts
    166
    Quote Originally Posted by PaulStoffregen View Post
    Perhaps you're getting extra whitespace in the string, like a \r before the \n?

    Maybe try adding something like:

    Serial.println(strlen(fileToLoad.c_str()));
    you are right ..oO .. there should be 20 chars in the string, but there are 21 ..

    is there a easy way to trim that in c++? .. I am searching my ass off but all I find seems way to complicated.

  12. #12
    Senior Member+ manitou's Avatar
    Join Date
    Jan 2013
    Posts
    1,611
    As noted in post #9, you could add ":" to the end of each line in startCfg.txt
    or
    cfgValue.trim(); removes trailing white space (including '\r') so that should do it.
    Last edited by manitou; 08-17-2018 at 05:32 PM.

  13. #13
    Senior Member
    Join Date
    Nov 2016
    Posts
    166
    Quote Originally Posted by manitou View Post
    As noted in post #9, you could add ":" to the end of each line in startCfg.txt
    or
    cfgValue.trim(); removes trailing white space (including '\r') so that should do it.
    thank you very much .. trim() works perfetly

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •