Go Down

Topic: Read filename from SD card, store to a string (Read 4417 times) previous topic - next topic

PaulS

Quote
Where is this from?

Left field. I thought you were trying to read the name FROM a file, not the name OF a file.

PeterH


Crap ok, found it.

I was using these:

//Add the SdFat Libraries
#include <SdFat.h>
#include <SdFatUtil.h>

not the base SD library.

I see available() now too.

Thanks


If you'd posted your actual code (in its entirety), we'd have known that.
I only provide help via the forum - please do not contact me for private consultancy.

WanaGo

#17
Nov 06, 2012, 11:24 pm Last Edit: Nov 06, 2012, 11:26 pm by WanaGo Reason: 1
I did say in post #1 I am using the SDFAT library, not the SD library. Also posted pieces of the SDFAT functions. I didnt even know there was a SD library 'wrapper' or whatever its called to be honest.

Tried implmenting the SD library instead, but its not compiling. Looks like the 2012 SDFAT library I am using is not quite the same as the 2009 SDFAT library which is part of the SD library included with Arduino 1.01

No luck so far, will keep trying.

PeterH

It's easy to find excuses not to, or reasons why we should have guessed or noticed some quirk of your solution, but there's simply no substitute for posting your actual code when you need help with a coding problem.
I only provide help via the forum - please do not contact me for private consultancy.

shanester

I'm a real noob, so don't jump on me as I haven't written any code.
I'm looking for a sample of code to do exactly what the OP was trying to do but I stumble into too many issues over creating a dynamic string array and reading each file name. There are too many libraries and I'm not a programmer. I'd appreciate some help.
I need a simple sketch that creates a character array, opens the root directory, reads the names and appends them to the array to allow it to be read and accessed later. This will be used to play .wav files from the card. I have code to read a named .wav file and play it from the SD card but this string manipulation part of the project eludes me.
I have looked at the CardInfo example but can't understand how to move the read list to a script. I've tried to modify the openNextFile example on the arduino reference site, but can't go from printing the file names to adding them to a script. I'm sure that this is simple but it's beyond me.
I know I'm asking for someone to post a short sketch for me, I do hope people don't find this offensive, but I am lost.

Thanks in advance

Shane

Paul Beaudet

#20
Jul 15, 2015, 11:31 pm Last Edit: Jul 15, 2015, 11:44 pm by Paul Beaudet
Probably should start another thread at this point, but this question is the same as the OP. Which I assume needs to be corrected to "read filename from SD card, initialize to a new array"

Here is some code demonstrating a async function (called every loop when active) in attempt to be created.
The challenge is accessing the returned (string/array?) as an array to deal with the letters of the filename independently. This way I can serve them to my haptic display to a user that types "ls" ala unix cli style.
Code: [Select]

void ls(boolean activate){  // list contents of working directory
  static boolean active = false;
  static File contents = workingDir.openNextFile();
  static byte index = 0;

  if(activate){ // given a 'true' is passed to ls it gets called every loop
    active = !active;
    if(!active){
      index = 0;
      contents.close();
      contents.rewindDirectory();
    }
  }

  if(active){ // when active 'ls' gets called every loop
    if(extHapticMessage(MONITOR_MODE)){  // returns true on complete letter
      if(contents){                      // given a file
        char name[15] = contents.name(); // <- problem: I dont know the size!
        if(name[index]){                 //
          extHapticMessage(name[index]); // vibrates an series of pagers
          keyOut(name[index]);           // prints letter w/ keyboard emulation
          index++;                       // iterate index for when pagers finish
        } else {                         // when filename is printed
          index = 0;                     // reset index
          if(contents.isDirectory()){keyOut('/');}  // trail a slash given dir
          contents.close();              // gracefully close the file
          keyOut(CARIAGE_RETURN);        // prepare to print next filename
          contents = workingDir.openNextFile();  // open next file
        }
      }
    }
  }
}

I apologize about my commenting style, I always make the assumption there is a syntax highlighter

This does not compile because the compiler wants to the the array (name[]) initialized to a brace-enclosed initializer. Which I can understand, it wants to know the size of what it is getting.

 Is there an better way to directly access what (file).name() returns? Maybe in a way I can pick off the individual letters at a time? (file).name() Seems to pass to Serial.println() a char array without much fuss. 

PaulS

Code: [Select]
        char name[15] = contents.name(); // <- problem: I dont know the size!

The value that the name() method returns is a pointer to a string. Is it the size of the pointer that you don't know (2 bytes) or the length of the string pointed to? If it's the latter, strlen() can help.

Or, strdup() will use malloc() to allocate space, and return a pointer to the duplicated string. You'll need to free() that memory when you are done with it.

Does the SD class support anything other than 8.3 format names? Don't you really already know the maximum length of the string?

Do you understand that that allocation and assignment will fail, since you can't assign a pointer to char array?

Paul Beaudet

#22
Jul 16, 2015, 04:03 pm Last Edit: Jul 16, 2015, 04:30 pm by Paul Beaudet
Is it the size of the pointer that you don't know (2 bytes) or the length of the string pointed to?
in reference to the comment-> // problem: I don't know the size
Scratch that. This was a comment out of ignorance, assuming the compiler needed to know the size of the a returned array that I now know isn't being returned.
An assumption rooted in seeing the function used like this -> Serial.println(myFile.name()) // no ref entry for .name()

Does the SD class support anything other than 8.3 format names? Don't you really already know the maximum length of the string?
Good point, so a max of 13 chars right? (8 for the name, one for the period, 3 for the extension, 1 for null)

Do you understand that that allocation and assignment will fail, since you can't assign a pointer to char array?
Thought it was returning the char array itself.

Guess bringing the string into another part of memory would be redundant if we have address to where it is already stored in memory. Please correct me if my understanding of pointers is wrong I haven't normally used them.

To exemplify my ignorance a little further I have to ask the question, does the name() returned pointer refer to an address on the SD card or one that has been loaded into ram already? (my assumption is ram because only 2 bytes are returned) In either case how would I go about addressing it in my function?

All I really need to is read each individual letter in the filename. Having the whole string at any given time is irrelevant to the function working so I don't really want to allocate memory for the whole string if I can avoid it. Every loop where a new letter is needed from the filename, myFile.name() will be called, at least in the way this function is used.
In that case can I just point to the next byte after the pointers address to get the second letter in the array?

Maybe I'm missing the concept completely or maybe seeing code examples would help would give me an ah ha moment.


Paul Beaudet

Ok, I think I came up with the solution
Code: [Select]

void ls(boolean activate){  // list contents of working directory
  static boolean active = false;
  static File contents = workingDir.openNextFile();
  static byte index = 0;

  if(activate){ // given a 'true' is passed to ls it gets called every loop
    active = !active;
    if(!active){
      index = 0;
      contents.close();
      contents.rewindDirectory();
    }
  }

  if(active){ // when active 'ls' gets called every loop
    if(extHapticMessage(MONITOR_MODE)){  // wait till letter is complete
      if(contents){                      // given a file
        char* name = contents.name();    // intilize pointer to array
        if(name[index]){                 // test for a char
          extHapticMessage(name[index]); // vibrates an series of pagers
          keyOut(name[index]);           // prints letter w/ keyboard emulation
          index++;                       // iterate index for when pagers finish
        } else {                         // when filename is printed
          index = 0;                     // reset index
          if(contents.isDirectory()){keyOut('/');}  // trail a slash given dir
          keyOut(CARIAGE_RETURN);        // prepare to print next filename
          contents.close();              // gracefully close the file
          contents = workingDir.openNextFile();  // open next file
        }
      }
    }
  }
}

tl;dr -> char* name = myFile.name()
Creates a pointer (physical address to the first byte of the array) that can be accessed like an array

Seems to work as expected, now to debug the more heuristic issues with my code. Thanks

PaulS

Quote
Guess bringing the string into another part of memory would be redundant if we have address to where it is already stored in memory.
That pointer will be overwritten when the next file is accessed. If you are creating a list, you need to copy the data.

Quote
To exemplify my ignorance a little further I have to ask the question, does the name() returned pointer refer to an address on the SD card or one that has been loaded into ram already?
SRAM.

Quote
In either case how would I go about addressing it in my function?
I see that you've figured that out.

Quote
In that case can I just point to the next byte after the pointers address to get the second letter in the array?
Yes. The index is an offset added to the address that the pointer points to to get to where the real data is.

Quote
Creates a pointer (physical address to the first byte of the array) that can be accessed like an array
Yes. Perhaps the above comment explains why that works. There is a very close association between arrays and pointers. Once you understand that, and that you must actually make a pointer to to somewhere, your there with understanding pointers.

Next step: Pointers to pointers and pointers to functions.

Paul Beaudet

That pointer will be overwritten when the next file is accessed. If you are creating a list, you need to copy the data.
SRAM.
Which is fine in this case. ls() just streams out the data. Maybe if I want to have a utility to select a file though, I can see where I may need to create a static array of pointers. Although that wont help if its just putting the filename in a buffer. Honestly its probably not that process intensive just to go back and read it every time needed instead of allocating some huge buffer that there is no room for.

With my application the user can only be shown so much information at a time anyhow.

I'm not sure about pointers to pointers right now, but pointers to functions may start to come in handy once I create mkdir(),cat(),rm(),cd(),cp(),mv() and so forth.

Go Up