Skip to content
Browse files

Incorporating ladyada's SD changes (multifile & directories).

Grabbed a patch from this repository: https://github.com/adafruit/SD and updated it for Arduino 1.0 (using Arduino.h instead of WProgram.h).
  • Loading branch information...
1 parent 9f412a2 commit 059bc5f0224efc2b15489fae99a9f49dc15f1b53 @damellis damellis committed Apr 18, 2011
View
102 libraries/SD/File.cpp
@@ -14,52 +14,130 @@
#include <SD.h>
+/* for debugging file open/close leaks
+ uint8_t nfilecount=0;
+*/
+
+File::File(SdFile f, char *n) {
+ // oh man you are kidding me, new() doesnt exist? Ok we do it by hand!
+ _file = (SdFile *)malloc(sizeof(SdFile));
+ if (_file) {
+ memcpy(_file, &f, sizeof(SdFile));
+
+ strncpy(_name, n, 12);
+ _name[12] = 0;
+
+ /* for debugging file open/close leaks
+ nfilecount++;
+ Serial.print("Created \"");
+ Serial.print(n);
+ Serial.print("\": ");
+ Serial.println(nfilecount, DEC);
+ */
+ }
+}
+
+File::File(void) {
+ _file = 0;
+ _name[0] = 0;
+ //Serial.print("Created empty file object");
+}
+
+File::~File(void) {
+ // Serial.print("Deleted file object");
+}
+
+// returns a pointer to the file name
+char *File::name(void) {
+ return _name;
+}
+
+// a directory is a special type of file
+boolean File::isDirectory(void) {
+ return (_file && _file->isDir());
+}
+
+
void File::write(uint8_t val) {
- SD.file.write(val);
+ if (_file)
+ _file->write(val);
}
void File::write(const char *str) {
- SD.file.write(str);
+ if (_file)
+ _file->write(str);
}
void File::write(const uint8_t *buf, size_t size) {
- SD.file.write(buf, size);
+ if (_file)
+ _file->write(buf, size);
}
int File::peek() {
- char c = SD.file.read();
- if (c != -1) SD.file.seekCur(-1);
+ if (! _file)
+ return 0;
+
+ int c = _file->read();
+ if (c != -1) _file->seekCur(-1);
return c;
}
int File::read() {
- return SD.file.read();
+ if (_file)
+ return _file->read();
+ return -1;
+}
+
+// buffered read for more efficient, high speed reading
+int File::read(void *buf, uint16_t nbyte) {
+ if (_file)
+ return _file->read(buf, nbyte);
+ return 0;
}
int File::available() {
+ if (! _file) return 0;
return size() - position();
}
void File::flush() {
- SD.file.sync();
+ if (_file)
+ _file->sync();
}
boolean File::seek(uint32_t pos) {
- return SD.file.seekSet(pos);
+ if (! _file) return false;
+
+ return _file->seekSet(pos);
}
uint32_t File::position() {
- return SD.file.curPosition();
+ if (! _file) return -1;
+ return _file->curPosition();
}
uint32_t File::size() {
- return SD.file.fileSize();
+ if (! _file) return 0;
+ return _file->fileSize();
}
void File::close() {
- SD.file.close();
+ if (_file) {
+ _file->close();
+ free(_file);
+ _file = 0;
+
+ /* for debugging file open/close leaks
+ nfilecount--;
+ Serial.print("Deleted ");
+ Serial.println(nfilecount, DEC);
+ */
+ }
}
File::operator bool() {
- return SD.file.isOpen();
+ if (_file)
+ return _file->isOpen();
+ return false;
}
+
View
2 libraries/SD/README.txt
@@ -9,3 +9,5 @@ License: GNU General Public License V3
(C) Copyright 2010 SparkFun Electronics
+Now better than ever with optimization, multiple file support, directory handling, etc - ladyada!
+
View
183 libraries/SD/SD.cpp
@@ -275,10 +275,10 @@ boolean callback_makeDirPath(SdFile& parentDir, char *filePathComponent,
}
+ /*
boolean callback_openPath(SdFile& parentDir, char *filePathComponent,
boolean isLastComponent, void *object) {
- /*
Callback used to open a file specified by a filepath that may
specify one or more directories above it.
@@ -293,7 +293,6 @@ boolean callback_openPath(SdFile& parentDir, char *filePathComponent,
Returns false once the file has been opened--to prevent the traversal
from descending further. (This may be unnecessary.)
- */
if (isLastComponent) {
SDClass *p_SD = static_cast<SDClass*>(object);
p_SD->file.open(parentDir, filePathComponent, p_SD->fileOpenMode);
@@ -305,6 +304,8 @@ boolean callback_openPath(SdFile& parentDir, char *filePathComponent,
}
return true;
}
+ */
+
boolean callback_remove(SdFile& parentDir, char *filePathComponent,
@@ -345,6 +346,64 @@ boolean SDClass::begin(uint8_t csPin) {
}
+
+// this little helper is used to traverse paths
+SdFile SDClass::getParentDir(char *filepath, int *index) {
+ // get parent directory
+ SdFile d1 = root; // start with the mostparent, root!
+ SdFile d2;
+
+ // we'll use the pointers to swap between the two objects
+ SdFile *parent = &d1;
+ SdFile *subdir = &d2;
+
+ char *origpath = filepath;
+
+ while (strchr(filepath, '/')) {
+
+ // get rid of leading /'s
+ if (filepath[0] == '/') {
+ filepath++;
+ continue;
+ }
+
+ if (! strchr(filepath, '/')) {
+ // it was in the root directory, so leave now
+ break;
+ }
+
+ // extract just the name of the next subdirectory
+ uint8_t idx = strchr(filepath, '/') - filepath;
+ if (idx > 12)
+ idx = 12; // dont let them specify long names
+ char subdirname[13];
+ strncpy(subdirname, filepath, idx);
+ subdirname[idx] = 0;
+
+ // close the subdir (we reuse them) if open
+ subdir->close();
+ if (! subdir->open(parent, subdirname, O_READ)) {
+ // failed to open one of the subdirectories
+ return SdFile();
+ }
+ // move forward to the next subdirectory
+ filepath += idx;
+
+ // we reuse the objects, close it.
+ parent->close();
+
+ // swap the pointers
+ SdFile *t = parent;
+ parent = subdir;
+ subdir = t;
+ }
+
+ *index = (int)(filepath - origpath);
+ // parent is now the parent diretory of the file!
+ return *parent;
+}
+
+
File SDClass::open(char *filepath, uint8_t mode) {
/*
@@ -369,6 +428,72 @@ File SDClass::open(char *filepath, uint8_t mode) {
*/
+ int pathidx;
+
+ // do the interative search
+ SdFile parentdir = getParentDir(filepath, &pathidx);
+ // no more subdirs!
+
+ filepath += pathidx;
+
+ if (! filepath[0]) {
+ // it was the directory itself!
+ return File(parentdir, "/");
+ }
+
+ // Open the file itself
+ SdFile file;
+
+ // failed to open a subdir!
+ if (!parentdir.isOpen())
+ return File();
+
+ // there is a special case for the Root directory since its a static dir
+ if (parentdir.isRoot()) {
+ if ( ! file.open(SD.root, filepath, mode)) {
+ // failed to open the file :(
+ return File();
+ }
+ // dont close the root!
+ } else {
+ if ( ! file.open(parentdir, filepath, mode)) {
+ return File();
+ }
+ // close the parent
+ parentdir.close();
+ }
+
+ if (mode & (O_APPEND | O_WRITE))
+ file.seekSet(file.fileSize());
+ return File(file, filepath);
+}
+
+
+/*
+File SDClass::open(char *filepath, uint8_t mode) {
+ //
+
+ Open the supplied file path for reading or writing.
+
+ The file content can be accessed via the `file` property of
+ the `SDClass` object--this property is currently
+ a standard `SdFile` object from `sdfatlib`.
+
+ Defaults to read only.
+
+ If `write` is true, default action (when `append` is true) is to
+ append data to the end of the file.
+
+ If `append` is false then the file will be truncated first.
+
+ If the file does not exist and it is opened for writing the file
+ will be created.
+
+ An attempt to open a file for reading that does not exist is an
+ error.
+
+ //
+
// TODO: Allow for read&write? (Possibly not, as it requires seek.)
fileOpenMode = mode;
@@ -377,6 +502,7 @@ File SDClass::open(char *filepath, uint8_t mode) {
return File();
}
+*/
//boolean SDClass::close() {
@@ -436,4 +562,55 @@ boolean SDClass::remove(char *filepath) {
return walkPath(filepath, root, callback_remove);
}
-SDClass SD;
+
+// allows you to recurse into a directory
+File File::openNextFile(uint8_t mode) {
+ dir_t p;
+
+ //Serial.print("\t\treading dir...");
+ while (_file->readDir(&p) > 0) {
+
+ // done if past last used entry
+ if (p.name[0] == DIR_NAME_FREE) {
+ //Serial.println("end");
+ return File();
+ }
+
+ // skip deleted entry and entries for . and ..
+ if (p.name[0] == DIR_NAME_DELETED || p.name[0] == '.') {
+ //Serial.println("dots");
+ continue;
+ }
+
+ // only list subdirectories and files
+ if (!DIR_IS_FILE_OR_SUBDIR(&p)) {
+ //Serial.println("notafile");
+ continue;
+ }
+
+ // print file name with possible blank fill
+ SdFile f;
+ char name[13];
+ _file->dirName(p, name);
+ //Serial.print("try to open file ");
+ //Serial.println(name);
+
+ if (f.open(_file, name, mode)) {
+ //Serial.println("OK!");
+ return File(f, name);
+ } else {
+ //Serial.println("ugh");
+ return File();
+ }
+ }
+
+ //Serial.println("nothing");
+ return File();
+}
+
+void File::rewindDirectory(void) {
+ if (isDirectory())
+ _file->rewind();
+}
+
+SDClass SD;
View
16 libraries/SD/SD.h
@@ -24,19 +24,32 @@
#define FILE_WRITE (O_READ | O_WRITE | O_CREAT | O_SYNC)
class File : public Stream {
+ private:
+ char _name[13]; // our name
+ SdFile *_file; // underlying file pointer
+
public:
+ File(SdFile f, char *name); // wraps an underlying SdFile
+ File(void); // 'empty' constructor
+ ~File(void); // destructor
virtual void write(uint8_t);
virtual void write(const char *str);
virtual void write(const uint8_t *buf, size_t size);
virtual int read();
virtual int peek();
virtual int available();
virtual void flush();
+ int read(void *buf, uint16_t nbyte);
boolean seek(uint32_t pos);
uint32_t position();
uint32_t size();
void close();
operator bool();
+ char * name();
+
+ boolean isDirectory(void);
+ File openNextFile(uint8_t mode = O_RDONLY);
+ void rewindDirectory(void);
};
class SDClass {
@@ -47,6 +60,8 @@ class SDClass {
SdVolume volume;
SdFile root;
+ // my quick&dirty iterator, should be replaced
+ SdFile getParentDir(char *filepath, int *indx);
public:
// This needs to be called to set up the connection to the SD card
// before other methods are used.
@@ -70,7 +85,6 @@ class SDClass {
boolean rmdir(char *filepath);
private:
- SdFile file;
// This is used to determine the mode used to open a file
// it's here because it's the easiest place to pass the
View
108 libraries/SD/examples/CardInfo/CardInfo.pde
@@ -0,0 +1,108 @@
+/*
+ SD card test
+
+ This example shows how use the utility libraries on which the'
+ SD library is based in order to get info about your SD card.
+ Very useful for testing a card when you're not sure whether its working or not.
+
+ The circuit:
+ * SD card attached to SPI bus as follows:
+ ** MOSI - pin 11 on Arduino Uno/Duemilanove/Diecimila
+ ** MISO - pin 12 on Arduino Uno/Duemilanove/Diecimila
+ ** CLK - pin 13 on Arduino Uno/Duemilanove/Diecimila
+ ** CS - depends on your SD card shield or module
+
+
+ created 28 Mar 2011
+ by Limor Fried
+ */
+ // include the SD library:
+#include <SD.h>
+
+// set up variables using the SD utility library functions:
+Sd2Card card;
+SdVolume volume;
+SdFile root;
+
+// change this to match your SD shield or module;
+// Arduino Ethernet shield: pin 4
+// Adafruit SD shields and modules: pin 10
+// Sparkfun SD shield: pin 8
+const int chipSelect = 8;
+
+void setup()
+{
+ Serial.begin(9600);
+ Serial.print("\nInitializing SD card...");
+ // On the Ethernet Shield, CS is pin 4. It's set as an output by default.
+ // Note that even if it's not used as the CS pin, the hardware SS pin
+ // (10 on most Arduino boards, 53 on the Mega) must be left as an output
+ // or the SD library functions will not work.
+ pinMode(10, OUTPUT); // change this to 53 on a mega
+
+
+ // we'll use the initialization code from the utility libraries
+ // since we're just testing if the card is working!
+ if (!card.init(SPI_HALF_SPEED, chipSelect)) {
+ Serial.println("initialization failed. Things to check:");
+ Serial.println("* is a card is inserted?");
+ Serial.println("* Is your wiring correct?");
+ Serial.println("* did you change the chipSelect pin to match your shield or module?");
+ return;
+ } else {
+ Serial.println("Wiring is correct and a card is present.");
+ }
+
+ // print the type of card
+ Serial.print("\nCard type: ");
+ switch(card.type()) {
+ case SD_CARD_TYPE_SD1:
+ Serial.println("SD1");
+ break;
+ case SD_CARD_TYPE_SD2:
+ Serial.println("SD2");
+ break;
+ case SD_CARD_TYPE_SDHC:
+ Serial.println("SDHC");
+ break;
+ default:
+ Serial.println("Unknown");
+ }
+
+ // Now we will try to open the 'volume'/'partition' - it should be FAT16 or FAT32
+ if (!volume.init(card)) {
+ Serial.println("Could not find FAT16/FAT32 partition.\nMake sure you've formatted the card");
+ return;
+ }
+
+
+ // print the type and size of the first FAT-type volume
+ long volumesize;
+ Serial.print("\nVolume type is FAT");
+ Serial.println(volume.fatType(), DEC);
+ Serial.println();
+
+ volumesize = volume.blocksPerCluster(); // clusters are collections of blocks
+ volumesize *= volume.clusterCount(); // we'll have a lot of clusters
+ volumesize *= 512; // SD card blocks are always 512 bytes
+ Serial.print("Volume size (bytes): ");
+ Serial.println(volumesize);
+ Serial.print("Volume size (Kbytes): ");
+ volumesize /= 1024;
+ Serial.println(volumesize);
+ Serial.print("Volume size (Mbytes): ");
+ volumesize /= 1024;
+ Serial.println(volumesize);
+
+
+ Serial.println("\nFiles found on the card (name, date and size in bytes): ");
+ root.openRoot(volume);
+
+ // list all files in the card with date and size
+ root.ls(LS_R | LS_DATE | LS_SIZE);
+}
+
+
+void loop(void) {
+
+}
View
77 libraries/SD/examples/listfiles/listfiles.pde
@@ -0,0 +1,77 @@
+/*
+ SD card basic file example
+
+ This example shows how to create and destroy an SD card file
+ The circuit:
+ * SD card attached to SPI bus as follows:
+ ** MOSI - pin 11
+ ** MISO - pin 12
+ ** CLK - pin 13
+ ** CS - pin 4
+
+ created Nov 2010
+ by David A. Mellis
+ updated 2 Dec 2010
+ by Tom Igoe
+
+ This example code is in the public domain.
+
+ */
+#include <SD.h>
+
+File root;
+
+void setup()
+{
+ Serial.begin(9600);
+ Serial.print("Initializing SD card...");
+ // On the Ethernet Shield, CS is pin 4. It's set as an output by default.
+ // Note that even if it's not used as the CS pin, the hardware SS pin
+ // (10 on most Arduino boards, 53 on the Mega) must be left as an output
+ // or the SD library functions will not work.
+ pinMode(10, OUTPUT);
+
+ if (!SD.begin(10)) {
+ Serial.println("initialization failed!");
+ return;
+ }
+ Serial.println("initialization done.");
+
+ root = SD.open("/");
+
+ printDirectory(root, 0);
+
+ Serial.println("done!");
+}
+
+void loop()
+{
+ // nothing happens after setup finishes.
+}
+
+void printDirectory(File dir, int numTabs) {
+ while(true) {
+
+ File entry = dir.openNextFile();
+ if (! entry) {
+ // no more files
+ //Serial.println("**nomorefiles**");
+ break;
+ }
+ for (uint8_t i=0; i<numTabs; i++) {
+ Serial.print('\t');
+ }
+ Serial.print(entry.name());
+ if (entry.isDirectory()) {
+ Serial.println("/");
+ printDirectory(entry, numTabs+1);
+ } else {
+ // files have sizes, directories do not
+ Serial.print("\t\t");
+ Serial.println(entry.size(), DEC);
+ }
+ }
+}
+
+
+

0 comments on commit 059bc5f

Please sign in to comment.
Something went wrong with that request. Please try again.