Jackson Lv
/
SD
SD
SD.cpp@0:405b46e831df, 2015-07-14 (annotated)
- Committer:
- Jackson_lv
- Date:
- Tue Jul 14 01:58:28 2015 +0000
- Revision:
- 0:405b46e831df
SD
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
Jackson_lv | 0:405b46e831df | 1 | /* |
Jackson_lv | 0:405b46e831df | 2 | |
Jackson_lv | 0:405b46e831df | 3 | SD - a slightly more friendly wrapper for sdfatlib |
Jackson_lv | 0:405b46e831df | 4 | |
Jackson_lv | 0:405b46e831df | 5 | This library aims to expose a subset of SD card functionality |
Jackson_lv | 0:405b46e831df | 6 | in the form of a higher level "wrapper" object. |
Jackson_lv | 0:405b46e831df | 7 | |
Jackson_lv | 0:405b46e831df | 8 | License: GNU General Public License V3 |
Jackson_lv | 0:405b46e831df | 9 | (Because sdfatlib is licensed with this.) |
Jackson_lv | 0:405b46e831df | 10 | |
Jackson_lv | 0:405b46e831df | 11 | (C) Copyright 2010 SparkFun Electronics |
Jackson_lv | 0:405b46e831df | 12 | |
Jackson_lv | 0:405b46e831df | 13 | |
Jackson_lv | 0:405b46e831df | 14 | This library provides four key benefits: |
Jackson_lv | 0:405b46e831df | 15 | |
Jackson_lv | 0:405b46e831df | 16 | * Including `SD.h` automatically creates a global |
Jackson_lv | 0:405b46e831df | 17 | `SD` object which can be interacted with in a similar |
Jackson_lv | 0:405b46e831df | 18 | manner to other standard global objects like `Serial` and `Ethernet`. |
Jackson_lv | 0:405b46e831df | 19 | |
Jackson_lv | 0:405b46e831df | 20 | * Boilerplate initialisation code is contained in one method named |
Jackson_lv | 0:405b46e831df | 21 | `begin` and no further objects need to be created in order to access |
Jackson_lv | 0:405b46e831df | 22 | the SD card. |
Jackson_lv | 0:405b46e831df | 23 | |
Jackson_lv | 0:405b46e831df | 24 | * Calls to `open` can supply a full path name including parent |
Jackson_lv | 0:405b46e831df | 25 | directories which simplifies interacting with files in subdirectories. |
Jackson_lv | 0:405b46e831df | 26 | |
Jackson_lv | 0:405b46e831df | 27 | * Utility methods are provided to determine whether a file exists |
Jackson_lv | 0:405b46e831df | 28 | and to create a directory heirarchy. |
Jackson_lv | 0:405b46e831df | 29 | |
Jackson_lv | 0:405b46e831df | 30 | |
Jackson_lv | 0:405b46e831df | 31 | Note however that not all functionality provided by the underlying |
Jackson_lv | 0:405b46e831df | 32 | sdfatlib library is exposed. |
Jackson_lv | 0:405b46e831df | 33 | |
Jackson_lv | 0:405b46e831df | 34 | */ |
Jackson_lv | 0:405b46e831df | 35 | |
Jackson_lv | 0:405b46e831df | 36 | /* |
Jackson_lv | 0:405b46e831df | 37 | |
Jackson_lv | 0:405b46e831df | 38 | Implementation Notes |
Jackson_lv | 0:405b46e831df | 39 | |
Jackson_lv | 0:405b46e831df | 40 | In order to handle multi-directory path traversal, functionality that |
Jackson_lv | 0:405b46e831df | 41 | requires this ability is implemented as callback functions. |
Jackson_lv | 0:405b46e831df | 42 | |
Jackson_lv | 0:405b46e831df | 43 | Individual methods call the `walkPath` function which performs the actual |
Jackson_lv | 0:405b46e831df | 44 | directory traversal (swapping between two different directory/file handles |
Jackson_lv | 0:405b46e831df | 45 | along the way) and at each level calls the supplied callback function. |
Jackson_lv | 0:405b46e831df | 46 | |
Jackson_lv | 0:405b46e831df | 47 | Some types of functionality will take an action at each level (e.g. exists |
Jackson_lv | 0:405b46e831df | 48 | or make directory) which others will only take an action at the bottom |
Jackson_lv | 0:405b46e831df | 49 | level (e.g. open). |
Jackson_lv | 0:405b46e831df | 50 | |
Jackson_lv | 0:405b46e831df | 51 | */ |
Jackson_lv | 0:405b46e831df | 52 | |
Jackson_lv | 0:405b46e831df | 53 | #include "SD.h" |
Jackson_lv | 0:405b46e831df | 54 | |
Jackson_lv | 0:405b46e831df | 55 | // Used by `getNextPathComponent` |
Jackson_lv | 0:405b46e831df | 56 | #define MAX_COMPONENT_LEN 12 // What is max length? |
Jackson_lv | 0:405b46e831df | 57 | #define PATH_COMPONENT_BUFFER_LEN MAX_COMPONENT_LEN+1 |
Jackson_lv | 0:405b46e831df | 58 | |
Jackson_lv | 0:405b46e831df | 59 | bool getNextPathComponent(char *path, unsigned int *p_offset, |
Jackson_lv | 0:405b46e831df | 60 | char *buffer) { |
Jackson_lv | 0:405b46e831df | 61 | /* |
Jackson_lv | 0:405b46e831df | 62 | |
Jackson_lv | 0:405b46e831df | 63 | Parse individual path components from a path. |
Jackson_lv | 0:405b46e831df | 64 | |
Jackson_lv | 0:405b46e831df | 65 | e.g. after repeated calls '/foo/bar/baz' will be split |
Jackson_lv | 0:405b46e831df | 66 | into 'foo', 'bar', 'baz'. |
Jackson_lv | 0:405b46e831df | 67 | |
Jackson_lv | 0:405b46e831df | 68 | This is similar to `strtok()` but copies the component into the |
Jackson_lv | 0:405b46e831df | 69 | supplied buffer rather than modifying the original string. |
Jackson_lv | 0:405b46e831df | 70 | |
Jackson_lv | 0:405b46e831df | 71 | |
Jackson_lv | 0:405b46e831df | 72 | `buffer` needs to be PATH_COMPONENT_BUFFER_LEN in size. |
Jackson_lv | 0:405b46e831df | 73 | |
Jackson_lv | 0:405b46e831df | 74 | `p_offset` needs to point to an integer of the offset at |
Jackson_lv | 0:405b46e831df | 75 | which the previous path component finished. |
Jackson_lv | 0:405b46e831df | 76 | |
Jackson_lv | 0:405b46e831df | 77 | Returns `true` if more components remain. |
Jackson_lv | 0:405b46e831df | 78 | |
Jackson_lv | 0:405b46e831df | 79 | Returns `false` if this is the last component. |
Jackson_lv | 0:405b46e831df | 80 | (This means path ended with 'foo' or 'foo/'.) |
Jackson_lv | 0:405b46e831df | 81 | |
Jackson_lv | 0:405b46e831df | 82 | */ |
Jackson_lv | 0:405b46e831df | 83 | |
Jackson_lv | 0:405b46e831df | 84 | // TODO: Have buffer local to this function, so we know it's the |
Jackson_lv | 0:405b46e831df | 85 | // correct length? |
Jackson_lv | 0:405b46e831df | 86 | |
Jackson_lv | 0:405b46e831df | 87 | int bufferOffset = 0; |
Jackson_lv | 0:405b46e831df | 88 | |
Jackson_lv | 0:405b46e831df | 89 | int offset = *p_offset; |
Jackson_lv | 0:405b46e831df | 90 | |
Jackson_lv | 0:405b46e831df | 91 | // Skip root or other separator |
Jackson_lv | 0:405b46e831df | 92 | if (path[offset] == '/') { |
Jackson_lv | 0:405b46e831df | 93 | offset++; |
Jackson_lv | 0:405b46e831df | 94 | } |
Jackson_lv | 0:405b46e831df | 95 | |
Jackson_lv | 0:405b46e831df | 96 | // Copy the next next path segment |
Jackson_lv | 0:405b46e831df | 97 | while (bufferOffset < MAX_COMPONENT_LEN |
Jackson_lv | 0:405b46e831df | 98 | && (path[offset] != '/') |
Jackson_lv | 0:405b46e831df | 99 | && (path[offset] != '\0')) { |
Jackson_lv | 0:405b46e831df | 100 | buffer[bufferOffset++] = path[offset++]; |
Jackson_lv | 0:405b46e831df | 101 | } |
Jackson_lv | 0:405b46e831df | 102 | |
Jackson_lv | 0:405b46e831df | 103 | buffer[bufferOffset] = '\0'; |
Jackson_lv | 0:405b46e831df | 104 | |
Jackson_lv | 0:405b46e831df | 105 | // Skip trailing separator so we can determine if this |
Jackson_lv | 0:405b46e831df | 106 | // is the last component in the path or not. |
Jackson_lv | 0:405b46e831df | 107 | if (path[offset] == '/') { |
Jackson_lv | 0:405b46e831df | 108 | offset++; |
Jackson_lv | 0:405b46e831df | 109 | } |
Jackson_lv | 0:405b46e831df | 110 | |
Jackson_lv | 0:405b46e831df | 111 | *p_offset = offset; |
Jackson_lv | 0:405b46e831df | 112 | |
Jackson_lv | 0:405b46e831df | 113 | return (path[offset] != '\0'); |
Jackson_lv | 0:405b46e831df | 114 | } |
Jackson_lv | 0:405b46e831df | 115 | |
Jackson_lv | 0:405b46e831df | 116 | |
Jackson_lv | 0:405b46e831df | 117 | |
Jackson_lv | 0:405b46e831df | 118 | boolean walkPath(char *filepath, SdFile& parentDir, |
Jackson_lv | 0:405b46e831df | 119 | boolean (*callback)(SdFile& parentDir, |
Jackson_lv | 0:405b46e831df | 120 | char *filePathComponent, |
Jackson_lv | 0:405b46e831df | 121 | boolean isLastComponent, |
Jackson_lv | 0:405b46e831df | 122 | void *object), |
Jackson_lv | 0:405b46e831df | 123 | void *object = NULL) { |
Jackson_lv | 0:405b46e831df | 124 | /* |
Jackson_lv | 0:405b46e831df | 125 | |
Jackson_lv | 0:405b46e831df | 126 | When given a file path (and parent directory--normally root), |
Jackson_lv | 0:405b46e831df | 127 | this function traverses the directories in the path and at each |
Jackson_lv | 0:405b46e831df | 128 | level calls the supplied callback function while also providing |
Jackson_lv | 0:405b46e831df | 129 | the supplied object for context if required. |
Jackson_lv | 0:405b46e831df | 130 | |
Jackson_lv | 0:405b46e831df | 131 | e.g. given the path '/foo/bar/baz' |
Jackson_lv | 0:405b46e831df | 132 | the callback would be called at the equivalent of |
Jackson_lv | 0:405b46e831df | 133 | '/foo', '/foo/bar' and '/foo/bar/baz'. |
Jackson_lv | 0:405b46e831df | 134 | |
Jackson_lv | 0:405b46e831df | 135 | The implementation swaps between two different directory/file |
Jackson_lv | 0:405b46e831df | 136 | handles as it traverses the directories and does not use recursion |
Jackson_lv | 0:405b46e831df | 137 | in an attempt to use memory efficiently. |
Jackson_lv | 0:405b46e831df | 138 | |
Jackson_lv | 0:405b46e831df | 139 | If a callback wishes to stop the directory traversal it should |
Jackson_lv | 0:405b46e831df | 140 | return false--in this case the function will stop the traversal, |
Jackson_lv | 0:405b46e831df | 141 | tidy up and return false. |
Jackson_lv | 0:405b46e831df | 142 | |
Jackson_lv | 0:405b46e831df | 143 | If a directory path doesn't exist at some point this function will |
Jackson_lv | 0:405b46e831df | 144 | also return false and not subsequently call the callback. |
Jackson_lv | 0:405b46e831df | 145 | |
Jackson_lv | 0:405b46e831df | 146 | If a directory path specified is complete, valid and the callback |
Jackson_lv | 0:405b46e831df | 147 | did not indicate the traversal should be interrupted then this |
Jackson_lv | 0:405b46e831df | 148 | function will return true. |
Jackson_lv | 0:405b46e831df | 149 | |
Jackson_lv | 0:405b46e831df | 150 | */ |
Jackson_lv | 0:405b46e831df | 151 | |
Jackson_lv | 0:405b46e831df | 152 | |
Jackson_lv | 0:405b46e831df | 153 | SdFile subfile1; |
Jackson_lv | 0:405b46e831df | 154 | SdFile subfile2; |
Jackson_lv | 0:405b46e831df | 155 | |
Jackson_lv | 0:405b46e831df | 156 | char buffer[PATH_COMPONENT_BUFFER_LEN]; |
Jackson_lv | 0:405b46e831df | 157 | |
Jackson_lv | 0:405b46e831df | 158 | unsigned int offset = 0; |
Jackson_lv | 0:405b46e831df | 159 | |
Jackson_lv | 0:405b46e831df | 160 | SdFile *p_parent; |
Jackson_lv | 0:405b46e831df | 161 | SdFile *p_child; |
Jackson_lv | 0:405b46e831df | 162 | |
Jackson_lv | 0:405b46e831df | 163 | SdFile *p_tmp_sdfile; |
Jackson_lv | 0:405b46e831df | 164 | |
Jackson_lv | 0:405b46e831df | 165 | p_child = &subfile1; |
Jackson_lv | 0:405b46e831df | 166 | |
Jackson_lv | 0:405b46e831df | 167 | p_parent = &parentDir; |
Jackson_lv | 0:405b46e831df | 168 | |
Jackson_lv | 0:405b46e831df | 169 | while (true) { |
Jackson_lv | 0:405b46e831df | 170 | |
Jackson_lv | 0:405b46e831df | 171 | boolean moreComponents = getNextPathComponent(filepath, &offset, buffer); |
Jackson_lv | 0:405b46e831df | 172 | |
Jackson_lv | 0:405b46e831df | 173 | boolean shouldContinue = callback((*p_parent), buffer, !moreComponents, object); |
Jackson_lv | 0:405b46e831df | 174 | |
Jackson_lv | 0:405b46e831df | 175 | if (!shouldContinue) { |
Jackson_lv | 0:405b46e831df | 176 | // TODO: Don't repeat this code? |
Jackson_lv | 0:405b46e831df | 177 | // If it's one we've created then we |
Jackson_lv | 0:405b46e831df | 178 | // don't need the parent handle anymore. |
Jackson_lv | 0:405b46e831df | 179 | if (p_parent != &parentDir) { |
Jackson_lv | 0:405b46e831df | 180 | (*p_parent).close(); |
Jackson_lv | 0:405b46e831df | 181 | } |
Jackson_lv | 0:405b46e831df | 182 | return false; |
Jackson_lv | 0:405b46e831df | 183 | } |
Jackson_lv | 0:405b46e831df | 184 | |
Jackson_lv | 0:405b46e831df | 185 | if (!moreComponents) { |
Jackson_lv | 0:405b46e831df | 186 | break; |
Jackson_lv | 0:405b46e831df | 187 | } |
Jackson_lv | 0:405b46e831df | 188 | |
Jackson_lv | 0:405b46e831df | 189 | boolean exists = (*p_child).open(*p_parent, buffer, O_RDONLY); |
Jackson_lv | 0:405b46e831df | 190 | |
Jackson_lv | 0:405b46e831df | 191 | // If it's one we've created then we |
Jackson_lv | 0:405b46e831df | 192 | // don't need the parent handle anymore. |
Jackson_lv | 0:405b46e831df | 193 | if (p_parent != &parentDir) { |
Jackson_lv | 0:405b46e831df | 194 | (*p_parent).close(); |
Jackson_lv | 0:405b46e831df | 195 | } |
Jackson_lv | 0:405b46e831df | 196 | |
Jackson_lv | 0:405b46e831df | 197 | // Handle case when it doesn't exist and we can't continue... |
Jackson_lv | 0:405b46e831df | 198 | if (exists) { |
Jackson_lv | 0:405b46e831df | 199 | // We alternate between two file handles as we go down |
Jackson_lv | 0:405b46e831df | 200 | // the path. |
Jackson_lv | 0:405b46e831df | 201 | if (p_parent == &parentDir) { |
Jackson_lv | 0:405b46e831df | 202 | p_parent = &subfile2; |
Jackson_lv | 0:405b46e831df | 203 | } |
Jackson_lv | 0:405b46e831df | 204 | |
Jackson_lv | 0:405b46e831df | 205 | p_tmp_sdfile = p_parent; |
Jackson_lv | 0:405b46e831df | 206 | p_parent = p_child; |
Jackson_lv | 0:405b46e831df | 207 | p_child = p_tmp_sdfile; |
Jackson_lv | 0:405b46e831df | 208 | } else { |
Jackson_lv | 0:405b46e831df | 209 | return false; |
Jackson_lv | 0:405b46e831df | 210 | } |
Jackson_lv | 0:405b46e831df | 211 | } |
Jackson_lv | 0:405b46e831df | 212 | |
Jackson_lv | 0:405b46e831df | 213 | if (p_parent != &parentDir) { |
Jackson_lv | 0:405b46e831df | 214 | (*p_parent).close(); // TODO: Return/ handle different? |
Jackson_lv | 0:405b46e831df | 215 | } |
Jackson_lv | 0:405b46e831df | 216 | |
Jackson_lv | 0:405b46e831df | 217 | return true; |
Jackson_lv | 0:405b46e831df | 218 | } |
Jackson_lv | 0:405b46e831df | 219 | |
Jackson_lv | 0:405b46e831df | 220 | |
Jackson_lv | 0:405b46e831df | 221 | |
Jackson_lv | 0:405b46e831df | 222 | /* |
Jackson_lv | 0:405b46e831df | 223 | |
Jackson_lv | 0:405b46e831df | 224 | The callbacks used to implement various functionality follow. |
Jackson_lv | 0:405b46e831df | 225 | |
Jackson_lv | 0:405b46e831df | 226 | Each callback is supplied with a parent directory handle, |
Jackson_lv | 0:405b46e831df | 227 | character string with the name of the current file path component, |
Jackson_lv | 0:405b46e831df | 228 | a flag indicating if this component is the last in the path and |
Jackson_lv | 0:405b46e831df | 229 | a pointer to an arbitrary object used for context. |
Jackson_lv | 0:405b46e831df | 230 | |
Jackson_lv | 0:405b46e831df | 231 | */ |
Jackson_lv | 0:405b46e831df | 232 | |
Jackson_lv | 0:405b46e831df | 233 | boolean callback_pathExists(SdFile& parentDir, char *filePathComponent, |
Jackson_lv | 0:405b46e831df | 234 | boolean isLastComponent, void *object) { |
Jackson_lv | 0:405b46e831df | 235 | /* |
Jackson_lv | 0:405b46e831df | 236 | |
Jackson_lv | 0:405b46e831df | 237 | Callback used to determine if a file/directory exists in parent |
Jackson_lv | 0:405b46e831df | 238 | directory. |
Jackson_lv | 0:405b46e831df | 239 | |
Jackson_lv | 0:405b46e831df | 240 | Returns true if file path exists. |
Jackson_lv | 0:405b46e831df | 241 | |
Jackson_lv | 0:405b46e831df | 242 | */ |
Jackson_lv | 0:405b46e831df | 243 | SdFile child; |
Jackson_lv | 0:405b46e831df | 244 | |
Jackson_lv | 0:405b46e831df | 245 | boolean exists = child.open(parentDir, filePathComponent, O_RDONLY); |
Jackson_lv | 0:405b46e831df | 246 | |
Jackson_lv | 0:405b46e831df | 247 | if (exists) { |
Jackson_lv | 0:405b46e831df | 248 | child.close(); |
Jackson_lv | 0:405b46e831df | 249 | } |
Jackson_lv | 0:405b46e831df | 250 | |
Jackson_lv | 0:405b46e831df | 251 | return exists; |
Jackson_lv | 0:405b46e831df | 252 | } |
Jackson_lv | 0:405b46e831df | 253 | |
Jackson_lv | 0:405b46e831df | 254 | |
Jackson_lv | 0:405b46e831df | 255 | |
Jackson_lv | 0:405b46e831df | 256 | boolean callback_makeDirPath(SdFile& parentDir, char *filePathComponent, |
Jackson_lv | 0:405b46e831df | 257 | boolean isLastComponent, void *object) { |
Jackson_lv | 0:405b46e831df | 258 | /* |
Jackson_lv | 0:405b46e831df | 259 | |
Jackson_lv | 0:405b46e831df | 260 | Callback used to create a directory in the parent directory if |
Jackson_lv | 0:405b46e831df | 261 | it does not already exist. |
Jackson_lv | 0:405b46e831df | 262 | |
Jackson_lv | 0:405b46e831df | 263 | Returns true if a directory was created or it already existed. |
Jackson_lv | 0:405b46e831df | 264 | |
Jackson_lv | 0:405b46e831df | 265 | */ |
Jackson_lv | 0:405b46e831df | 266 | boolean result = false; |
Jackson_lv | 0:405b46e831df | 267 | SdFile child; |
Jackson_lv | 0:405b46e831df | 268 | |
Jackson_lv | 0:405b46e831df | 269 | result = callback_pathExists(parentDir, filePathComponent, isLastComponent, object); |
Jackson_lv | 0:405b46e831df | 270 | if (!result) { |
Jackson_lv | 0:405b46e831df | 271 | result = child.makeDir(parentDir, filePathComponent); |
Jackson_lv | 0:405b46e831df | 272 | } |
Jackson_lv | 0:405b46e831df | 273 | |
Jackson_lv | 0:405b46e831df | 274 | return result; |
Jackson_lv | 0:405b46e831df | 275 | } |
Jackson_lv | 0:405b46e831df | 276 | |
Jackson_lv | 0:405b46e831df | 277 | |
Jackson_lv | 0:405b46e831df | 278 | /* |
Jackson_lv | 0:405b46e831df | 279 | |
Jackson_lv | 0:405b46e831df | 280 | boolean callback_openPath(SdFile& parentDir, char *filePathComponent, |
Jackson_lv | 0:405b46e831df | 281 | boolean isLastComponent, void *object) { |
Jackson_lv | 0:405b46e831df | 282 | |
Jackson_lv | 0:405b46e831df | 283 | Callback used to open a file specified by a filepath that may |
Jackson_lv | 0:405b46e831df | 284 | specify one or more directories above it. |
Jackson_lv | 0:405b46e831df | 285 | |
Jackson_lv | 0:405b46e831df | 286 | Expects the context object to be an instance of `SDClass` and |
Jackson_lv | 0:405b46e831df | 287 | will use the `file` property of the instance to open the requested |
Jackson_lv | 0:405b46e831df | 288 | file/directory with the associated file open mode property. |
Jackson_lv | 0:405b46e831df | 289 | |
Jackson_lv | 0:405b46e831df | 290 | Always returns true if the directory traversal hasn't reached the |
Jackson_lv | 0:405b46e831df | 291 | bottom of the directory heirarchy. |
Jackson_lv | 0:405b46e831df | 292 | |
Jackson_lv | 0:405b46e831df | 293 | Returns false once the file has been opened--to prevent the traversal |
Jackson_lv | 0:405b46e831df | 294 | from descending further. (This may be unnecessary.) |
Jackson_lv | 0:405b46e831df | 295 | |
Jackson_lv | 0:405b46e831df | 296 | if (isLastComponent) { |
Jackson_lv | 0:405b46e831df | 297 | SDClass *p_SD = static_cast<SDClass*>(object); |
Jackson_lv | 0:405b46e831df | 298 | p_SD->file.open(parentDir, filePathComponent, p_SD->fileOpenMode); |
Jackson_lv | 0:405b46e831df | 299 | if (p_SD->fileOpenMode == FILE_WRITE) { |
Jackson_lv | 0:405b46e831df | 300 | p_SD->file.seekSet(p_SD->file.fileSize()); |
Jackson_lv | 0:405b46e831df | 301 | } |
Jackson_lv | 0:405b46e831df | 302 | // TODO: Return file open result? |
Jackson_lv | 0:405b46e831df | 303 | return false; |
Jackson_lv | 0:405b46e831df | 304 | } |
Jackson_lv | 0:405b46e831df | 305 | return true; |
Jackson_lv | 0:405b46e831df | 306 | } |
Jackson_lv | 0:405b46e831df | 307 | */ |
Jackson_lv | 0:405b46e831df | 308 | |
Jackson_lv | 0:405b46e831df | 309 | |
Jackson_lv | 0:405b46e831df | 310 | |
Jackson_lv | 0:405b46e831df | 311 | boolean callback_remove(SdFile& parentDir, char *filePathComponent, |
Jackson_lv | 0:405b46e831df | 312 | boolean isLastComponent, void *object) { |
Jackson_lv | 0:405b46e831df | 313 | if (isLastComponent) { |
Jackson_lv | 0:405b46e831df | 314 | return SdFile::remove(parentDir, filePathComponent); |
Jackson_lv | 0:405b46e831df | 315 | } |
Jackson_lv | 0:405b46e831df | 316 | return true; |
Jackson_lv | 0:405b46e831df | 317 | } |
Jackson_lv | 0:405b46e831df | 318 | |
Jackson_lv | 0:405b46e831df | 319 | boolean callback_rmdir(SdFile& parentDir, char *filePathComponent, |
Jackson_lv | 0:405b46e831df | 320 | boolean isLastComponent, void *object) { |
Jackson_lv | 0:405b46e831df | 321 | if (isLastComponent) { |
Jackson_lv | 0:405b46e831df | 322 | SdFile f; |
Jackson_lv | 0:405b46e831df | 323 | if (!f.open(parentDir, filePathComponent, O_READ)) return false; |
Jackson_lv | 0:405b46e831df | 324 | return f.rmDir(); |
Jackson_lv | 0:405b46e831df | 325 | } |
Jackson_lv | 0:405b46e831df | 326 | return true; |
Jackson_lv | 0:405b46e831df | 327 | } |
Jackson_lv | 0:405b46e831df | 328 | |
Jackson_lv | 0:405b46e831df | 329 | |
Jackson_lv | 0:405b46e831df | 330 | |
Jackson_lv | 0:405b46e831df | 331 | /* Implementation of class used to create `SDCard` object. */ |
Jackson_lv | 0:405b46e831df | 332 | |
Jackson_lv | 0:405b46e831df | 333 | |
Jackson_lv | 0:405b46e831df | 334 | |
Jackson_lv | 0:405b46e831df | 335 | boolean SDClass::begin(uint8_t csPin) { |
Jackson_lv | 0:405b46e831df | 336 | /* |
Jackson_lv | 0:405b46e831df | 337 | |
Jackson_lv | 0:405b46e831df | 338 | Performs the initialisation required by the sdfatlib library. |
Jackson_lv | 0:405b46e831df | 339 | |
Jackson_lv | 0:405b46e831df | 340 | Return true if initialization succeeds, false otherwise. |
Jackson_lv | 0:405b46e831df | 341 | |
Jackson_lv | 0:405b46e831df | 342 | */ |
Jackson_lv | 0:405b46e831df | 343 | return card.init(SPI_HALF_SPEED, csPin) && |
Jackson_lv | 0:405b46e831df | 344 | volume.init(card) && |
Jackson_lv | 0:405b46e831df | 345 | root.openRoot(volume); |
Jackson_lv | 0:405b46e831df | 346 | } |
Jackson_lv | 0:405b46e831df | 347 | |
Jackson_lv | 0:405b46e831df | 348 | |
Jackson_lv | 0:405b46e831df | 349 | |
Jackson_lv | 0:405b46e831df | 350 | // this little helper is used to traverse paths |
Jackson_lv | 0:405b46e831df | 351 | SdFile SDClass::getParentDir(const char *filepath, int *index) { |
Jackson_lv | 0:405b46e831df | 352 | // get parent directory |
Jackson_lv | 0:405b46e831df | 353 | SdFile d1 = root; // start with the mostparent, root! |
Jackson_lv | 0:405b46e831df | 354 | SdFile d2; |
Jackson_lv | 0:405b46e831df | 355 | |
Jackson_lv | 0:405b46e831df | 356 | // we'll use the pointers to swap between the two objects |
Jackson_lv | 0:405b46e831df | 357 | SdFile *parent = &d1; |
Jackson_lv | 0:405b46e831df | 358 | SdFile *subdir = &d2; |
Jackson_lv | 0:405b46e831df | 359 | |
Jackson_lv | 0:405b46e831df | 360 | const char *origpath = filepath; |
Jackson_lv | 0:405b46e831df | 361 | |
Jackson_lv | 0:405b46e831df | 362 | while (strchr(filepath, '/')) { |
Jackson_lv | 0:405b46e831df | 363 | |
Jackson_lv | 0:405b46e831df | 364 | // get rid of leading /'s |
Jackson_lv | 0:405b46e831df | 365 | if (filepath[0] == '/') { |
Jackson_lv | 0:405b46e831df | 366 | filepath++; |
Jackson_lv | 0:405b46e831df | 367 | continue; |
Jackson_lv | 0:405b46e831df | 368 | } |
Jackson_lv | 0:405b46e831df | 369 | |
Jackson_lv | 0:405b46e831df | 370 | if (! strchr(filepath, '/')) { |
Jackson_lv | 0:405b46e831df | 371 | // it was in the root directory, so leave now |
Jackson_lv | 0:405b46e831df | 372 | break; |
Jackson_lv | 0:405b46e831df | 373 | } |
Jackson_lv | 0:405b46e831df | 374 | |
Jackson_lv | 0:405b46e831df | 375 | // extract just the name of the next subdirectory |
Jackson_lv | 0:405b46e831df | 376 | uint8_t idx = strchr(filepath, '/') - filepath; |
Jackson_lv | 0:405b46e831df | 377 | if (idx > 12) |
Jackson_lv | 0:405b46e831df | 378 | idx = 12; // dont let them specify long names |
Jackson_lv | 0:405b46e831df | 379 | char subdirname[13]; |
Jackson_lv | 0:405b46e831df | 380 | strncpy(subdirname, filepath, idx); |
Jackson_lv | 0:405b46e831df | 381 | subdirname[idx] = 0; |
Jackson_lv | 0:405b46e831df | 382 | |
Jackson_lv | 0:405b46e831df | 383 | // close the subdir (we reuse them) if open |
Jackson_lv | 0:405b46e831df | 384 | subdir->close(); |
Jackson_lv | 0:405b46e831df | 385 | if (! subdir->open(parent, subdirname, O_READ)) { |
Jackson_lv | 0:405b46e831df | 386 | // failed to open one of the subdirectories |
Jackson_lv | 0:405b46e831df | 387 | return SdFile(); |
Jackson_lv | 0:405b46e831df | 388 | } |
Jackson_lv | 0:405b46e831df | 389 | // move forward to the next subdirectory |
Jackson_lv | 0:405b46e831df | 390 | filepath += idx; |
Jackson_lv | 0:405b46e831df | 391 | |
Jackson_lv | 0:405b46e831df | 392 | // we reuse the objects, close it. |
Jackson_lv | 0:405b46e831df | 393 | parent->close(); |
Jackson_lv | 0:405b46e831df | 394 | |
Jackson_lv | 0:405b46e831df | 395 | // swap the pointers |
Jackson_lv | 0:405b46e831df | 396 | SdFile *t = parent; |
Jackson_lv | 0:405b46e831df | 397 | parent = subdir; |
Jackson_lv | 0:405b46e831df | 398 | subdir = t; |
Jackson_lv | 0:405b46e831df | 399 | } |
Jackson_lv | 0:405b46e831df | 400 | |
Jackson_lv | 0:405b46e831df | 401 | *index = (int)(filepath - origpath); |
Jackson_lv | 0:405b46e831df | 402 | // parent is now the parent diretory of the file! |
Jackson_lv | 0:405b46e831df | 403 | return *parent; |
Jackson_lv | 0:405b46e831df | 404 | } |
Jackson_lv | 0:405b46e831df | 405 | |
Jackson_lv | 0:405b46e831df | 406 | |
Jackson_lv | 0:405b46e831df | 407 | File SDClass::open(const char *filepath, uint8_t mode) { |
Jackson_lv | 0:405b46e831df | 408 | /* |
Jackson_lv | 0:405b46e831df | 409 | |
Jackson_lv | 0:405b46e831df | 410 | Open the supplied file path for reading or writing. |
Jackson_lv | 0:405b46e831df | 411 | |
Jackson_lv | 0:405b46e831df | 412 | The file content can be accessed via the `file` property of |
Jackson_lv | 0:405b46e831df | 413 | the `SDClass` object--this property is currently |
Jackson_lv | 0:405b46e831df | 414 | a standard `SdFile` object from `sdfatlib`. |
Jackson_lv | 0:405b46e831df | 415 | |
Jackson_lv | 0:405b46e831df | 416 | Defaults to read only. |
Jackson_lv | 0:405b46e831df | 417 | |
Jackson_lv | 0:405b46e831df | 418 | If `write` is true, default action (when `append` is true) is to |
Jackson_lv | 0:405b46e831df | 419 | append data to the end of the file. |
Jackson_lv | 0:405b46e831df | 420 | |
Jackson_lv | 0:405b46e831df | 421 | If `append` is false then the file will be truncated first. |
Jackson_lv | 0:405b46e831df | 422 | |
Jackson_lv | 0:405b46e831df | 423 | If the file does not exist and it is opened for writing the file |
Jackson_lv | 0:405b46e831df | 424 | will be created. |
Jackson_lv | 0:405b46e831df | 425 | |
Jackson_lv | 0:405b46e831df | 426 | An attempt to open a file for reading that does not exist is an |
Jackson_lv | 0:405b46e831df | 427 | error. |
Jackson_lv | 0:405b46e831df | 428 | |
Jackson_lv | 0:405b46e831df | 429 | */ |
Jackson_lv | 0:405b46e831df | 430 | |
Jackson_lv | 0:405b46e831df | 431 | int pathidx; |
Jackson_lv | 0:405b46e831df | 432 | |
Jackson_lv | 0:405b46e831df | 433 | // do the interative search |
Jackson_lv | 0:405b46e831df | 434 | SdFile parentdir = getParentDir(filepath, &pathidx); |
Jackson_lv | 0:405b46e831df | 435 | // no more subdirs! |
Jackson_lv | 0:405b46e831df | 436 | |
Jackson_lv | 0:405b46e831df | 437 | filepath += pathidx; |
Jackson_lv | 0:405b46e831df | 438 | |
Jackson_lv | 0:405b46e831df | 439 | if (! filepath[0]) { |
Jackson_lv | 0:405b46e831df | 440 | // it was the directory itself! |
Jackson_lv | 0:405b46e831df | 441 | return File(parentdir, "/"); |
Jackson_lv | 0:405b46e831df | 442 | } |
Jackson_lv | 0:405b46e831df | 443 | |
Jackson_lv | 0:405b46e831df | 444 | // Open the file itself |
Jackson_lv | 0:405b46e831df | 445 | SdFile file; |
Jackson_lv | 0:405b46e831df | 446 | |
Jackson_lv | 0:405b46e831df | 447 | // failed to open a subdir! |
Jackson_lv | 0:405b46e831df | 448 | if (!parentdir.isOpen()) |
Jackson_lv | 0:405b46e831df | 449 | return File(); |
Jackson_lv | 0:405b46e831df | 450 | |
Jackson_lv | 0:405b46e831df | 451 | // there is a special case for the Root directory since its a static dir |
Jackson_lv | 0:405b46e831df | 452 | if (parentdir.isRoot()) { |
Jackson_lv | 0:405b46e831df | 453 | if ( ! file.open(SD.root, filepath, mode)) { |
Jackson_lv | 0:405b46e831df | 454 | // failed to open the file :( |
Jackson_lv | 0:405b46e831df | 455 | return File(); |
Jackson_lv | 0:405b46e831df | 456 | } |
Jackson_lv | 0:405b46e831df | 457 | // dont close the root! |
Jackson_lv | 0:405b46e831df | 458 | } else { |
Jackson_lv | 0:405b46e831df | 459 | if ( ! file.open(parentdir, filepath, mode)) { |
Jackson_lv | 0:405b46e831df | 460 | return File(); |
Jackson_lv | 0:405b46e831df | 461 | } |
Jackson_lv | 0:405b46e831df | 462 | // close the parent |
Jackson_lv | 0:405b46e831df | 463 | parentdir.close(); |
Jackson_lv | 0:405b46e831df | 464 | } |
Jackson_lv | 0:405b46e831df | 465 | |
Jackson_lv | 0:405b46e831df | 466 | if (mode & (O_APPEND | O_WRITE)) |
Jackson_lv | 0:405b46e831df | 467 | file.seekSet(file.fileSize()); |
Jackson_lv | 0:405b46e831df | 468 | return File(file, filepath); |
Jackson_lv | 0:405b46e831df | 469 | } |
Jackson_lv | 0:405b46e831df | 470 | |
Jackson_lv | 0:405b46e831df | 471 | |
Jackson_lv | 0:405b46e831df | 472 | /* |
Jackson_lv | 0:405b46e831df | 473 | File SDClass::open(char *filepath, uint8_t mode) { |
Jackson_lv | 0:405b46e831df | 474 | // |
Jackson_lv | 0:405b46e831df | 475 | |
Jackson_lv | 0:405b46e831df | 476 | Open the supplied file path for reading or writing. |
Jackson_lv | 0:405b46e831df | 477 | |
Jackson_lv | 0:405b46e831df | 478 | The file content can be accessed via the `file` property of |
Jackson_lv | 0:405b46e831df | 479 | the `SDClass` object--this property is currently |
Jackson_lv | 0:405b46e831df | 480 | a standard `SdFile` object from `sdfatlib`. |
Jackson_lv | 0:405b46e831df | 481 | |
Jackson_lv | 0:405b46e831df | 482 | Defaults to read only. |
Jackson_lv | 0:405b46e831df | 483 | |
Jackson_lv | 0:405b46e831df | 484 | If `write` is true, default action (when `append` is true) is to |
Jackson_lv | 0:405b46e831df | 485 | append data to the end of the file. |
Jackson_lv | 0:405b46e831df | 486 | |
Jackson_lv | 0:405b46e831df | 487 | If `append` is false then the file will be truncated first. |
Jackson_lv | 0:405b46e831df | 488 | |
Jackson_lv | 0:405b46e831df | 489 | If the file does not exist and it is opened for writing the file |
Jackson_lv | 0:405b46e831df | 490 | will be created. |
Jackson_lv | 0:405b46e831df | 491 | |
Jackson_lv | 0:405b46e831df | 492 | An attempt to open a file for reading that does not exist is an |
Jackson_lv | 0:405b46e831df | 493 | error. |
Jackson_lv | 0:405b46e831df | 494 | |
Jackson_lv | 0:405b46e831df | 495 | // |
Jackson_lv | 0:405b46e831df | 496 | |
Jackson_lv | 0:405b46e831df | 497 | // TODO: Allow for read&write? (Possibly not, as it requires seek.) |
Jackson_lv | 0:405b46e831df | 498 | |
Jackson_lv | 0:405b46e831df | 499 | fileOpenMode = mode; |
Jackson_lv | 0:405b46e831df | 500 | walkPath(filepath, root, callback_openPath, this); |
Jackson_lv | 0:405b46e831df | 501 | |
Jackson_lv | 0:405b46e831df | 502 | return File(); |
Jackson_lv | 0:405b46e831df | 503 | |
Jackson_lv | 0:405b46e831df | 504 | } |
Jackson_lv | 0:405b46e831df | 505 | */ |
Jackson_lv | 0:405b46e831df | 506 | |
Jackson_lv | 0:405b46e831df | 507 | |
Jackson_lv | 0:405b46e831df | 508 | //boolean SDClass::close() { |
Jackson_lv | 0:405b46e831df | 509 | // /* |
Jackson_lv | 0:405b46e831df | 510 | // |
Jackson_lv | 0:405b46e831df | 511 | // Closes the file opened by the `open` method. |
Jackson_lv | 0:405b46e831df | 512 | // |
Jackson_lv | 0:405b46e831df | 513 | // */ |
Jackson_lv | 0:405b46e831df | 514 | // file.close(); |
Jackson_lv | 0:405b46e831df | 515 | //} |
Jackson_lv | 0:405b46e831df | 516 | |
Jackson_lv | 0:405b46e831df | 517 | |
Jackson_lv | 0:405b46e831df | 518 | boolean SDClass::exists(char *filepath) { |
Jackson_lv | 0:405b46e831df | 519 | /* |
Jackson_lv | 0:405b46e831df | 520 | |
Jackson_lv | 0:405b46e831df | 521 | Returns true if the supplied file path exists. |
Jackson_lv | 0:405b46e831df | 522 | |
Jackson_lv | 0:405b46e831df | 523 | */ |
Jackson_lv | 0:405b46e831df | 524 | return walkPath(filepath, root, callback_pathExists); |
Jackson_lv | 0:405b46e831df | 525 | } |
Jackson_lv | 0:405b46e831df | 526 | |
Jackson_lv | 0:405b46e831df | 527 | |
Jackson_lv | 0:405b46e831df | 528 | //boolean SDClass::exists(char *filepath, SdFile& parentDir) { |
Jackson_lv | 0:405b46e831df | 529 | // /* |
Jackson_lv | 0:405b46e831df | 530 | // |
Jackson_lv | 0:405b46e831df | 531 | // Returns true if the supplied file path rooted at `parentDir` |
Jackson_lv | 0:405b46e831df | 532 | // exists. |
Jackson_lv | 0:405b46e831df | 533 | // |
Jackson_lv | 0:405b46e831df | 534 | // */ |
Jackson_lv | 0:405b46e831df | 535 | // return walkPath(filepath, parentDir, callback_pathExists); |
Jackson_lv | 0:405b46e831df | 536 | //} |
Jackson_lv | 0:405b46e831df | 537 | |
Jackson_lv | 0:405b46e831df | 538 | |
Jackson_lv | 0:405b46e831df | 539 | boolean SDClass::mkdir(char *filepath) { |
Jackson_lv | 0:405b46e831df | 540 | /* |
Jackson_lv | 0:405b46e831df | 541 | |
Jackson_lv | 0:405b46e831df | 542 | Makes a single directory or a heirarchy of directories. |
Jackson_lv | 0:405b46e831df | 543 | |
Jackson_lv | 0:405b46e831df | 544 | A rough equivalent to `mkdir -p`. |
Jackson_lv | 0:405b46e831df | 545 | |
Jackson_lv | 0:405b46e831df | 546 | */ |
Jackson_lv | 0:405b46e831df | 547 | return walkPath(filepath, root, callback_makeDirPath); |
Jackson_lv | 0:405b46e831df | 548 | } |
Jackson_lv | 0:405b46e831df | 549 | |
Jackson_lv | 0:405b46e831df | 550 | boolean SDClass::rmdir(char *filepath) { |
Jackson_lv | 0:405b46e831df | 551 | /* |
Jackson_lv | 0:405b46e831df | 552 | |
Jackson_lv | 0:405b46e831df | 553 | Makes a single directory or a heirarchy of directories. |
Jackson_lv | 0:405b46e831df | 554 | |
Jackson_lv | 0:405b46e831df | 555 | A rough equivalent to `mkdir -p`. |
Jackson_lv | 0:405b46e831df | 556 | |
Jackson_lv | 0:405b46e831df | 557 | */ |
Jackson_lv | 0:405b46e831df | 558 | return walkPath(filepath, root, callback_rmdir); |
Jackson_lv | 0:405b46e831df | 559 | } |
Jackson_lv | 0:405b46e831df | 560 | |
Jackson_lv | 0:405b46e831df | 561 | boolean SDClass::remove(char *filepath) { |
Jackson_lv | 0:405b46e831df | 562 | return walkPath(filepath, root, callback_remove); |
Jackson_lv | 0:405b46e831df | 563 | } |
Jackson_lv | 0:405b46e831df | 564 | |
Jackson_lv | 0:405b46e831df | 565 | |
Jackson_lv | 0:405b46e831df | 566 | // allows you to recurse into a directory |
Jackson_lv | 0:405b46e831df | 567 | File File::openNextFile(uint8_t mode) { |
Jackson_lv | 0:405b46e831df | 568 | dir_t p; |
Jackson_lv | 0:405b46e831df | 569 | |
Jackson_lv | 0:405b46e831df | 570 | //Serial.print("\t\treading dir..."); |
Jackson_lv | 0:405b46e831df | 571 | while (_file->readDir(&p) > 0) { |
Jackson_lv | 0:405b46e831df | 572 | |
Jackson_lv | 0:405b46e831df | 573 | // done if past last used entry |
Jackson_lv | 0:405b46e831df | 574 | if (p.name[0] == DIR_NAME_FREE) { |
Jackson_lv | 0:405b46e831df | 575 | //Serial.println("end"); |
Jackson_lv | 0:405b46e831df | 576 | return File(); |
Jackson_lv | 0:405b46e831df | 577 | } |
Jackson_lv | 0:405b46e831df | 578 | |
Jackson_lv | 0:405b46e831df | 579 | // skip deleted entry and entries for . and .. |
Jackson_lv | 0:405b46e831df | 580 | if (p.name[0] == DIR_NAME_DELETED || p.name[0] == '.') { |
Jackson_lv | 0:405b46e831df | 581 | //Serial.println("dots"); |
Jackson_lv | 0:405b46e831df | 582 | continue; |
Jackson_lv | 0:405b46e831df | 583 | } |
Jackson_lv | 0:405b46e831df | 584 | |
Jackson_lv | 0:405b46e831df | 585 | // only list subdirectories and files |
Jackson_lv | 0:405b46e831df | 586 | if (!DIR_IS_FILE_OR_SUBDIR(&p)) { |
Jackson_lv | 0:405b46e831df | 587 | //Serial.println("notafile"); |
Jackson_lv | 0:405b46e831df | 588 | continue; |
Jackson_lv | 0:405b46e831df | 589 | } |
Jackson_lv | 0:405b46e831df | 590 | |
Jackson_lv | 0:405b46e831df | 591 | // print file name with possible blank fill |
Jackson_lv | 0:405b46e831df | 592 | SdFile f; |
Jackson_lv | 0:405b46e831df | 593 | char name[13]; |
Jackson_lv | 0:405b46e831df | 594 | _file->dirName(p, name); |
Jackson_lv | 0:405b46e831df | 595 | //Serial.print("try to open file "); |
Jackson_lv | 0:405b46e831df | 596 | //Serial.println(name); |
Jackson_lv | 0:405b46e831df | 597 | |
Jackson_lv | 0:405b46e831df | 598 | if (f.open(_file, name, mode)) { |
Jackson_lv | 0:405b46e831df | 599 | //Serial.println("OK!"); |
Jackson_lv | 0:405b46e831df | 600 | return File(f, name); |
Jackson_lv | 0:405b46e831df | 601 | } else { |
Jackson_lv | 0:405b46e831df | 602 | //Serial.println("ugh"); |
Jackson_lv | 0:405b46e831df | 603 | return File(); |
Jackson_lv | 0:405b46e831df | 604 | } |
Jackson_lv | 0:405b46e831df | 605 | } |
Jackson_lv | 0:405b46e831df | 606 | |
Jackson_lv | 0:405b46e831df | 607 | //Serial.println("nothing"); |
Jackson_lv | 0:405b46e831df | 608 | return File(); |
Jackson_lv | 0:405b46e831df | 609 | } |
Jackson_lv | 0:405b46e831df | 610 | |
Jackson_lv | 0:405b46e831df | 611 | void File::rewindDirectory(void) { |
Jackson_lv | 0:405b46e831df | 612 | if (isDirectory()) |
Jackson_lv | 0:405b46e831df | 613 | _file->rewind(); |
Jackson_lv | 0:405b46e831df | 614 | } |
Jackson_lv | 0:405b46e831df | 615 | |
Jackson_lv | 0:405b46e831df | 616 | SDClass SD; |