|
|
@@ -1,3 +1,13 @@ |
|
|
|
#include <Arduino.h> |
|
|
|
#include "SD.h" |
|
|
|
|
|
|
|
#include <utility/SdFat.h> |
|
|
|
#include <utility/SdFatUtil.h> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if 1 |
|
|
|
/* |
|
|
|
|
|
|
|
SD - a slightly more friendly wrapper for sdfatlib |
|
|
@@ -17,11 +27,11 @@ |
|
|
|
`SD` object which can be interacted with in a similar |
|
|
|
manner to other standard global objects like `Serial` and `Ethernet`. |
|
|
|
|
|
|
|
* Boilerplate initialisation code is contained in one method named |
|
|
|
* Boilerplate initialisation code is contained in one method named |
|
|
|
`begin` and no further objects need to be created in order to access |
|
|
|
the SD card. |
|
|
|
|
|
|
|
* Calls to `open` can supply a full path name including parent |
|
|
|
* Calls to `open` can supply a full path name including parent |
|
|
|
directories which simplifies interacting with files in subdirectories. |
|
|
|
|
|
|
|
* Utility methods are provided to determine whether a file exists |
|
|
@@ -37,7 +47,7 @@ |
|
|
|
|
|
|
|
Implementation Notes |
|
|
|
|
|
|
|
In order to handle multi-directory path traversal, functionality that |
|
|
|
In order to handle multi-directory path traversal, functionality that |
|
|
|
requires this ability is implemented as callback functions. |
|
|
|
|
|
|
|
Individual methods call the `walkPath` function which performs the actual |
|
|
@@ -93,7 +103,7 @@ bool getNextPathComponent(const char *path, unsigned int *p_offset, |
|
|
|
if (path[offset] == '/') { |
|
|
|
offset++; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Copy the next next path segment |
|
|
|
while (bufferOffset < MAX_COMPONENT_LEN |
|
|
|
&& (path[offset] != '/') |
|
|
@@ -116,14 +126,14 @@ bool getNextPathComponent(const char *path, unsigned int *p_offset, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
boolean walkPath(const char *filepath, SdFile& parentDir, |
|
|
|
boolean (*callback)(SdFile& parentDir, |
|
|
|
bool walkPath(const char *filepath, SdFile *parentDir, |
|
|
|
bool (*callback)(SdFile *parentDir, |
|
|
|
char *filePathComponent, |
|
|
|
boolean isLastComponent, |
|
|
|
bool isLastComponent, |
|
|
|
void *object), |
|
|
|
void *object = NULL) { |
|
|
|
/* |
|
|
|
|
|
|
|
|
|
|
|
When given a file path (and parent directory--normally root), |
|
|
|
this function traverses the directories in the path and at each |
|
|
|
level calls the supplied callback function while also providing |
|
|
@@ -154,52 +164,52 @@ boolean walkPath(const char *filepath, SdFile& parentDir, |
|
|
|
SdFile subfile1; |
|
|
|
SdFile subfile2; |
|
|
|
|
|
|
|
char buffer[PATH_COMPONENT_BUFFER_LEN]; |
|
|
|
char buffer[PATH_COMPONENT_BUFFER_LEN]; |
|
|
|
|
|
|
|
unsigned int offset = 0; |
|
|
|
|
|
|
|
SdFile *p_parent; |
|
|
|
SdFile *p_child; |
|
|
|
|
|
|
|
SdFile *p_tmp_sdfile; |
|
|
|
|
|
|
|
SdFile *p_tmp_sdfile; |
|
|
|
|
|
|
|
p_child = &subfile1; |
|
|
|
|
|
|
|
p_parent = &parentDir; |
|
|
|
|
|
|
|
p_parent = parentDir; |
|
|
|
|
|
|
|
while (true) { |
|
|
|
|
|
|
|
boolean moreComponents = getNextPathComponent(filepath, &offset, buffer); |
|
|
|
bool moreComponents = getNextPathComponent(filepath, &offset, buffer); |
|
|
|
|
|
|
|
boolean shouldContinue = callback((*p_parent), buffer, !moreComponents, object); |
|
|
|
bool shouldContinue = callback(p_parent, buffer, !moreComponents, object); |
|
|
|
|
|
|
|
if (!shouldContinue) { |
|
|
|
// TODO: Don't repeat this code? |
|
|
|
// If it's one we've created then we |
|
|
|
// don't need the parent handle anymore. |
|
|
|
if (p_parent != &parentDir) { |
|
|
|
if (p_parent != parentDir) { |
|
|
|
(*p_parent).close(); |
|
|
|
} |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (!moreComponents) { |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
boolean exists = (*p_child).open(*p_parent, buffer, O_RDONLY); |
|
|
|
|
|
|
|
bool exists = (*p_child).open(*p_parent, buffer, O_RDONLY); |
|
|
|
|
|
|
|
// If it's one we've created then we |
|
|
|
// don't need the parent handle anymore. |
|
|
|
if (p_parent != &parentDir) { |
|
|
|
if (p_parent != parentDir) { |
|
|
|
(*p_parent).close(); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Handle case when it doesn't exist and we can't continue... |
|
|
|
if (exists) { |
|
|
|
// We alternate between two file handles as we go down |
|
|
|
// the path. |
|
|
|
if (p_parent == &parentDir) { |
|
|
|
if (p_parent == parentDir) { |
|
|
|
p_parent = &subfile2; |
|
|
|
} |
|
|
|
|
|
|
@@ -210,8 +220,8 @@ boolean walkPath(const char *filepath, SdFile& parentDir, |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (p_parent != &parentDir) { |
|
|
|
|
|
|
|
if (p_parent != parentDir) { |
|
|
|
(*p_parent).close(); // TODO: Return/ handle different? |
|
|
|
} |
|
|
|
|
|
|
@@ -231,8 +241,8 @@ boolean walkPath(const char *filepath, SdFile& parentDir, |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
boolean callback_pathExists(SdFile& parentDir, char *filePathComponent, |
|
|
|
boolean isLastComponent, void *object) { |
|
|
|
bool callback_pathExists(SdFile *parentDir, char *filePathComponent, |
|
|
|
bool isLastComponent, void *object) { |
|
|
|
/* |
|
|
|
|
|
|
|
Callback used to determine if a file/directory exists in parent |
|
|
@@ -243,19 +253,19 @@ boolean callback_pathExists(SdFile& parentDir, char *filePathComponent, |
|
|
|
*/ |
|
|
|
SdFile child; |
|
|
|
|
|
|
|
boolean exists = child.open(parentDir, filePathComponent, O_RDONLY); |
|
|
|
|
|
|
|
bool exists = child.open(parentDir, filePathComponent, O_RDONLY); |
|
|
|
|
|
|
|
if (exists) { |
|
|
|
child.close(); |
|
|
|
child.close(); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return exists; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
boolean callback_makeDirPath(SdFile& parentDir, char *filePathComponent, |
|
|
|
boolean isLastComponent, void *object) { |
|
|
|
bool callback_makeDirPath(SdFile *parentDir, char *filePathComponent, |
|
|
|
bool isLastComponent, void *object) { |
|
|
|
/* |
|
|
|
|
|
|
|
Callback used to create a directory in the parent directory if |
|
|
@@ -264,22 +274,22 @@ boolean callback_makeDirPath(SdFile& parentDir, char *filePathComponent, |
|
|
|
Returns true if a directory was created or it already existed. |
|
|
|
|
|
|
|
*/ |
|
|
|
boolean result = false; |
|
|
|
bool result = false; |
|
|
|
SdFile child; |
|
|
|
|
|
|
|
|
|
|
|
result = callback_pathExists(parentDir, filePathComponent, isLastComponent, object); |
|
|
|
if (!result) { |
|
|
|
result = child.makeDir(parentDir, filePathComponent); |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return result; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* |
|
|
|
|
|
|
|
boolean callback_openPath(SdFile& parentDir, char *filePathComponent, |
|
|
|
boolean isLastComponent, void *object) { |
|
|
|
bool callback_openPath(SdFile *parentDir, char *filePathComponent, |
|
|
|
bool isLastComponent, void *object) { |
|
|
|
|
|
|
|
Callback used to open a file specified by a filepath that may |
|
|
|
specify one or more directories above it. |
|
|
@@ -309,16 +319,16 @@ boolean callback_openPath(SdFile& parentDir, char *filePathComponent, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
boolean callback_remove(SdFile& parentDir, char *filePathComponent, |
|
|
|
boolean isLastComponent, void *object) { |
|
|
|
bool callback_remove(SdFile *parentDir, char *filePathComponent, |
|
|
|
bool isLastComponent, void *object) { |
|
|
|
if (isLastComponent) { |
|
|
|
return SdFile::remove(parentDir, filePathComponent); |
|
|
|
} |
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
boolean callback_rmdir(SdFile& parentDir, char *filePathComponent, |
|
|
|
boolean isLastComponent, void *object) { |
|
|
|
bool callback_rmdir(SdFile *parentDir, char *filePathComponent, |
|
|
|
bool isLastComponent, void *object) { |
|
|
|
if (isLastComponent) { |
|
|
|
SdFile f; |
|
|
|
if (!f.open(parentDir, filePathComponent, O_READ)) return false; |
|
|
@@ -333,7 +343,7 @@ boolean callback_rmdir(SdFile& parentDir, char *filePathComponent, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
boolean SDClass::begin(uint8_t csPin) { |
|
|
|
bool SDClass::begin(uint8_t csPin) { |
|
|
|
/* |
|
|
|
|
|
|
|
Performs the initialisation required by the sdfatlib library. |
|
|
@@ -341,12 +351,16 @@ boolean SDClass::begin(uint8_t csPin) { |
|
|
|
Return true if initialization succeeds, false otherwise. |
|
|
|
|
|
|
|
*/ |
|
|
|
card = new Sd2Card(); |
|
|
|
volume = new SdVolume(); |
|
|
|
root = new SdFile(); |
|
|
|
|
|
|
|
|
|
|
|
if (root.isOpen()) root.close(); |
|
|
|
if (root->isOpen()) root->close(); |
|
|
|
|
|
|
|
return card.init(SPI_HALF_SPEED, csPin) && |
|
|
|
volume.init(card) && |
|
|
|
root.openRoot(volume); |
|
|
|
return card->init(SPI_HALF_SPEED, csPin) && |
|
|
|
volume->init(card) && |
|
|
|
root->openRoot(volume); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@@ -362,7 +376,7 @@ SdFile SDClass::getParentDir(const char *filepath, int *index) { |
|
|
|
// we'll use the pointers to swap between the two objects |
|
|
|
SdFile *parent = &d1; |
|
|
|
SdFile *subdir = &d2; |
|
|
|
|
|
|
|
|
|
|
|
const char *origpath = filepath; |
|
|
|
|
|
|
|
while (strchr(filepath, '/')) { |
|
|
@@ -372,7 +386,7 @@ SdFile SDClass::getParentDir(const char *filepath, int *index) { |
|
|
|
filepath++; |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (! strchr(filepath, '/')) { |
|
|
|
// it was in the root directory, so leave now |
|
|
|
break; |
|
|
@@ -443,26 +457,44 @@ File SDClass::open(const char *filepath, uint8_t mode) { |
|
|
|
filepath += pathidx; |
|
|
|
|
|
|
|
if (! filepath[0]) { |
|
|
|
// it was the directory itself! |
|
|
|
return File(parentdir, "/"); |
|
|
|
} |
|
|
|
// it was the directory itself! |
|
|
|
Serial.println("it was the directory itself"); |
|
|
|
|
|
|
|
// Open the file itself |
|
|
|
SdFile file; |
|
|
|
File ret = File(new SD_File(parentdir, "/")); |
|
|
|
ret.whoami(); |
|
|
|
return ret; |
|
|
|
} |
|
|
|
|
|
|
|
// failed to open a subdir! |
|
|
|
if (!parentdir.isOpen()) |
|
|
|
return File(); |
|
|
|
if (!parentdir.isOpen()) { |
|
|
|
return File(); |
|
|
|
} |
|
|
|
|
|
|
|
// convert mode to underlying SdFat |
|
|
|
if (mode == FILE_READ) { |
|
|
|
mode = O_READ; |
|
|
|
} else { // FILE_WRITE |
|
|
|
mode = O_READ | O_WRITE | O_CREAT; |
|
|
|
} |
|
|
|
|
|
|
|
// Open the file itself |
|
|
|
SdFile file; |
|
|
|
if ( ! file.open(parentdir, filepath, mode)) { |
|
|
|
return File(); |
|
|
|
return File(); |
|
|
|
} |
|
|
|
// close the parent |
|
|
|
parentdir.close(); |
|
|
|
|
|
|
|
if (mode & (O_APPEND | O_WRITE)) |
|
|
|
file.seekSet(file.fileSize()); |
|
|
|
return File(file, filepath); |
|
|
|
if (mode & (O_APPEND | O_WRITE)) { |
|
|
|
file.seekSet(file.fileSize()); |
|
|
|
} |
|
|
|
|
|
|
|
File ret = File(new SD_File(file, filepath)); |
|
|
|
|
|
|
|
Serial.println("open() return:"); |
|
|
|
ret.whoami(); |
|
|
|
return ret; |
|
|
|
//return SD_File(file, filepath); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@@ -502,7 +534,7 @@ File SDClass::open(char *filepath, uint8_t mode) { |
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
//boolean SDClass::close() { |
|
|
|
//bool SDClass::close() { |
|
|
|
// /* |
|
|
|
// |
|
|
|
// Closes the file opened by the `open` method. |
|
|
@@ -512,7 +544,7 @@ File SDClass::open(char *filepath, uint8_t mode) { |
|
|
|
//} |
|
|
|
|
|
|
|
|
|
|
|
boolean SDClass::exists(const char *filepath) { |
|
|
|
bool SDClass::exists(const char *filepath) { |
|
|
|
/* |
|
|
|
|
|
|
|
Returns true if the supplied file path exists. |
|
|
@@ -522,7 +554,7 @@ boolean SDClass::exists(const char *filepath) { |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//boolean SDClass::exists(char *filepath, SdFile& parentDir) { |
|
|
|
//bool SDClass::exists(char *filepath, SdFile& parentDir) { |
|
|
|
// /* |
|
|
|
// |
|
|
|
// Returns true if the supplied file path rooted at `parentDir` |
|
|
@@ -533,35 +565,36 @@ boolean SDClass::exists(const char *filepath) { |
|
|
|
//} |
|
|
|
|
|
|
|
|
|
|
|
boolean SDClass::mkdir(const char *filepath) { |
|
|
|
bool SDClass::mkdir(const char *filepath) { |
|
|
|
/* |
|
|
|
|
|
|
|
|
|
|
|
Makes a single directory or a heirarchy of directories. |
|
|
|
|
|
|
|
A rough equivalent to `mkdir -p`. |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
return walkPath(filepath, root, callback_makeDirPath); |
|
|
|
} |
|
|
|
|
|
|
|
boolean SDClass::rmdir(const char *filepath) { |
|
|
|
bool SDClass::rmdir(const char *filepath) { |
|
|
|
/* |
|
|
|
|
|
|
|
|
|
|
|
Makes a single directory or a heirarchy of directories. |
|
|
|
|
|
|
|
A rough equivalent to `mkdir -p`. |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
return walkPath(filepath, root, callback_rmdir); |
|
|
|
} |
|
|
|
|
|
|
|
boolean SDClass::remove(const char *filepath) { |
|
|
|
bool SDClass::remove(const char *filepath) { |
|
|
|
return walkPath(filepath, root, callback_remove); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// allows you to recurse into a directory |
|
|
|
File File::openNextFile(uint8_t mode) { |
|
|
|
File SD_File::openNextFile(uint8_t mode) |
|
|
|
{ |
|
|
|
dir_t p; |
|
|
|
|
|
|
|
//Serial.print("\t\treading dir..."); |
|
|
@@ -594,7 +627,7 @@ File File::openNextFile(uint8_t mode) { |
|
|
|
|
|
|
|
if (f.open(_file, name, mode)) { |
|
|
|
//Serial.println("OK!"); |
|
|
|
return File(f, name); |
|
|
|
return File(new SD_File(f, name)); |
|
|
|
} else { |
|
|
|
//Serial.println("ugh"); |
|
|
|
return File(); |
|
|
@@ -605,10 +638,11 @@ File File::openNextFile(uint8_t mode) { |
|
|
|
return File(); |
|
|
|
} |
|
|
|
|
|
|
|
void File::rewindDirectory(void) { |
|
|
|
void SD_File::rewindDirectory(void) { |
|
|
|
if (isDirectory()) |
|
|
|
_file->rewind(); |
|
|
|
} |
|
|
|
|
|
|
|
SDClass SD; |
|
|
|
#endif |
|
|
|
#endif |