├── File.cpp ├── README.md ├── examples ├── nanosdcard │ └── nanosdcard.ino │ │ └── nanosdcard.ino.ino ├── nanosdcard1 │ └── nanosdcard1.ino └── nanosdcard2 │ └── nanosdcard2.ino ├── keywords.txt ├── mySD.cpp ├── mySD.h └── utility ├── FatStructs.h ├── Sd2Card.cpp ├── Sd2Card.h ├── Sd2PinMap.h ├── SdFat.h ├── SdFatUtil.h ├── SdFatmainpage.h ├── SdFile.cpp ├── SdInfo.h └── SdVolume.cpp /File.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | SD - a slightly more friendly wrapper for sdfatlib 4 | 5 | This library aims to expose a subset of SD card functionality 6 | in the form of a higher level "wrapper" object. 7 | 8 | License: GNU General Public License V3 9 | (Because sdfatlib is licensed with this.) 10 | 11 | (C) Copyright 2010 SparkFun Electronics 12 | 13 | */ 14 | 15 | #include 16 | 17 | /* for debugging file open/close leaks 18 | uint8_t nfilecount=0; 19 | */ 20 | 21 | namespace ext{ 22 | File::File(SdFile f, const char *n) { 23 | // oh man you are kidding me, new() doesnt exist? Ok we do it by hand! 24 | _file = (SdFile *)malloc(sizeof(SdFile)); 25 | if (_file) { 26 | memcpy(_file, &f, sizeof(SdFile)); 27 | 28 | strncpy(_name, n, 12); 29 | _name[12] = 0; 30 | 31 | /* for debugging file open/close leaks 32 | nfilecount++; 33 | Serial.print("Created \""); 34 | Serial.print(n); 35 | Serial.print("\": "); 36 | Serial.println(nfilecount, DEC); 37 | */ 38 | } 39 | } 40 | 41 | File::File(void) { 42 | _file = 0; 43 | _name[0] = 0; 44 | //Serial.print("Created empty file object"); 45 | } 46 | 47 | File::~File(void) { 48 | // Serial.print("Deleted file object"); 49 | } 50 | 51 | // returns a pointer to the file name 52 | char *File::name(void) { 53 | return _name; 54 | } 55 | 56 | // a directory is a special type of file 57 | boolean File::isDirectory(void) { 58 | return (_file && _file->isDir()); 59 | } 60 | 61 | 62 | size_t File::write(uint8_t val) { 63 | return write(&val, 1); 64 | } 65 | 66 | size_t File::write(const uint8_t *buf, size_t size) { 67 | size_t t; 68 | if (!_file) { 69 | setWriteError(); 70 | return 0; 71 | } 72 | _file->clearWriteError(); 73 | t = _file->write(buf, size); 74 | if (_file->getWriteError()) { 75 | setWriteError(); 76 | return 0; 77 | } 78 | return t; 79 | } 80 | 81 | int File::peek() { 82 | if (! _file) 83 | return 0; 84 | 85 | int c = _file->read(); 86 | if (c != -1) _file->seekCur(-1); 87 | return c; 88 | } 89 | 90 | int File::read() { 91 | if (_file) 92 | return _file->read(); 93 | return -1; 94 | } 95 | 96 | // buffered read for more efficient, high speed reading 97 | int File::read(void *buf, uint16_t nbyte) { 98 | if (_file) 99 | return _file->read(buf, nbyte); 100 | return 0; 101 | } 102 | 103 | int File::available() { 104 | if (! _file) return 0; 105 | 106 | uint32_t n = size() - position(); 107 | 108 | return n > 0X7FFF ? 0X7FFF : n; 109 | } 110 | 111 | void File::flush() { 112 | if (_file) 113 | _file->sync(); 114 | } 115 | 116 | boolean File::seek(uint32_t pos) { 117 | if (! _file) return false; 118 | 119 | return _file->seekSet(pos); 120 | } 121 | 122 | uint32_t File::position() { 123 | if (! _file) return -1; 124 | return _file->curPosition(); 125 | } 126 | 127 | uint32_t File::size() { 128 | if (! _file) return 0; 129 | return _file->fileSize(); 130 | } 131 | 132 | void File::close() { 133 | if (_file) { 134 | _file->close(); 135 | free(_file); 136 | _file = 0; 137 | 138 | /* for debugging file open/close leaks 139 | nfilecount--; 140 | Serial.print("Deleted "); 141 | Serial.println(nfilecount, DEC); 142 | */ 143 | } 144 | } 145 | 146 | File::operator bool() { 147 | if (_file) 148 | return _file->isOpen(); 149 | return false; 150 | } 151 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | visit IOTSHARING.COM for more 2 | # esp32_nanosdcard 3 | this library is for Arduino, I modified it to adapt with ESP32 4 | 5 | use ext::File instead of using File 6 | 7 | Demo 7: How to use Arduino ESP32 to store data to sdcard 8 | http://www.iotsharing.com/2017/05/how-to-use-arduino-esp32-to-store-data-to-sdcard.html 9 | -------------------------------------------------------------------------------- /examples/nanosdcard/nanosdcard.ino/nanosdcard.ino.ino: -------------------------------------------------------------------------------- 1 | /* 2 | SD card test 3 | 4 | This example shows how use the utility libraries on which the' 5 | SD library is based in order to get info about your SD card. 6 | Very useful for testing a card when you're not sure whether its working or not. 7 | 8 | The circuit: 9 | * SD card attached to SPI bus as follows: 10 | ** UNO: MOSI - pin 11, MISO - pin 12, CLK - pin 13, CS - pin 4 (CS pin can be changed) 11 | and pin #10 (SS) must be an output 12 | ** Mega: MOSI - pin 51, MISO - pin 50, CLK - pin 52, CS - pin 4 (CS pin can be changed) 13 | and pin #52 (SS) must be an output 14 | ** Leonardo: Connect to hardware SPI via the ICSP header 15 | Pin 4 used here for consistency with other Arduino examples 16 | 17 | 18 | created 28 Mar 2011 by Limor Fried 19 | modified 9 Apr 2012 by Tom Igoe 20 | */ 21 | // include the SD library: 22 | #include 23 | #include 24 | 25 | // set up variables using the SD utility library functions: 26 | Sd2Card card; 27 | SdVolume volume; 28 | SdFile root; 29 | 30 | // change this to match your SD shield or module; 31 | // Arduino Ethernet shield: pin 4 32 | // Adafruit SD shields and modules: pin 10 33 | // Sparkfun SD shield: pin 8 34 | const int chipSelect = 17; 35 | 36 | void setup() 37 | { 38 | // Open serial communications and wait for port to open: 39 | Serial.begin(115200); 40 | while (!Serial) { 41 | ; // wait for serial port to connect. Needed for Leonardo only 42 | } 43 | 44 | 45 | Serial.print("\nInitializing SD card..."); 46 | // On the Ethernet Shield, CS is pin 4. It's set as an output by default. 47 | // Note that even if it's not used as the CS pin, the hardware SS pin 48 | // (10 on most Arduino boards, 53 on the Mega) must be left as an output 49 | // or the SD library functions will not work. 50 | pinMode(SS, OUTPUT); 51 | 52 | 53 | // we'll use the initialization code from the utility libraries 54 | // since we're just testing if the card is working! 55 | while (!card.init(SPI_HALF_SPEED, 17, 14, 12, 15)) { 56 | Serial.println("initialization failed. Things to check:"); 57 | Serial.println("* is a card is inserted?"); 58 | Serial.println("* Is your wiring correct?"); 59 | Serial.println("* did you change the chipSelect pin to match your shield or module?"); 60 | } 61 | 62 | // print the type of card 63 | Serial.print("\nCard type: "); 64 | switch(card.type()) { 65 | case SD_CARD_TYPE_SD1: 66 | Serial.println("SD1"); 67 | break; 68 | case SD_CARD_TYPE_SD2: 69 | Serial.println("SD2"); 70 | break; 71 | case SD_CARD_TYPE_SDHC: 72 | Serial.println("SDHC"); 73 | break; 74 | default: 75 | Serial.println("Unknown"); 76 | } 77 | 78 | // Now we will try to open the 'volume'/'partition' - it should be FAT16 or FAT32 79 | if (!volume.init(card)) { 80 | Serial.println("Could not find FAT16/FAT32 partition.\nMake sure you've formatted the card"); 81 | return; 82 | } 83 | 84 | 85 | // print the type and size of the first FAT-type volume 86 | uint32_t volumesize; 87 | Serial.print("\nVolume type is FAT"); 88 | Serial.println(volume.fatType(), DEC); 89 | Serial.println(); 90 | 91 | volumesize = volume.blocksPerCluster(); // clusters are collections of blocks 92 | volumesize *= volume.clusterCount(); // we'll have a lot of clusters 93 | volumesize *= 512; // SD card blocks are always 512 bytes 94 | Serial.print("Volume size (bytes): "); 95 | Serial.println(volumesize); 96 | Serial.print("Volume size (Kbytes): "); 97 | volumesize /= 1024; 98 | Serial.println(volumesize); 99 | Serial.print("Volume size (Mbytes): "); 100 | volumesize /= 1024; 101 | Serial.println(volumesize); 102 | 103 | 104 | Serial.println("\nFiles found on the card (name, date and size in bytes): "); 105 | root.openRoot(volume); 106 | 107 | // list all files in the card with date and size 108 | root.ls(LS_R | LS_DATE | LS_SIZE); 109 | } 110 | 111 | 112 | void loop(void) { 113 | 114 | } 115 | -------------------------------------------------------------------------------- /examples/nanosdcard1/nanosdcard1.ino: -------------------------------------------------------------------------------- 1 | /* 2 | SD card basic file example 3 | 4 | This example shows how to create and destroy an SD card file 5 | The circuit: 6 | * SD card attached to SPI bus as follows: 7 | ** UNO: MOSI - pin 11, MISO - pin 12, CLK - pin 13, CS - pin 4 (CS pin can be changed) 8 | and pin #10 (SS) must be an output 9 | ** Mega: MOSI - pin 51, MISO - pin 50, CLK - pin 52, CS - pin 4 (CS pin can be changed) 10 | and pin #52 (SS) must be an output 11 | ** Leonardo: Connect to hardware SPI via the ICSP header 12 | 13 | created Nov 2010 by David A. Mellis 14 | modified 9 Apr 2012 by Tom Igoe 15 | modified 13 June 2012 by Limor Fried 16 | 17 | This example code is in the public domain. 18 | 19 | */ 20 | #include 21 | #include 22 | 23 | ext::File root; 24 | 25 | // change this to match your SD shield or module; 26 | // Arduino Ethernet shield: pin 4 27 | // Adafruit SD shields and modules: pin 10 28 | // Sparkfun SD shield: pin 8 29 | const int chipSelect = 4; 30 | 31 | void setup() 32 | { 33 | // Open serial communications and wait for port to open: 34 | Serial.begin(115200); 35 | while (!Serial) { 36 | ; // wait for serial port to connect. Needed for Leonardo only 37 | } 38 | 39 | 40 | Serial.print("Initializing SD card..."); 41 | // On the Ethernet Shield, CS is pin 4. It's set as an output by default. 42 | // Note that even if it's not used as the CS pin, the hardware SS pin 43 | // (10 on Arduino Uno boards, 53 on the Mega) must be left as an output 44 | // or the SD library functions will not work. 45 | pinMode(SS, OUTPUT); 46 | 47 | if (!SD.begin(17, 14, 12, 15)) { 48 | Serial.println("initialization failed!"); 49 | return; 50 | } 51 | Serial.println("initialization done."); 52 | 53 | root = SD.open("/"); 54 | 55 | printDirectory(root, 0); 56 | 57 | Serial.println("done!"); 58 | } 59 | 60 | void loop() 61 | { 62 | // nothing happens after setup finishes. 63 | } 64 | 65 | void printDirectory(ext::File dir, int numTabs) { 66 | // Begin at the start of the directory 67 | dir.rewindDirectory(); 68 | 69 | while(true) { 70 | ext::File entry = dir.openNextFile(); 71 | if (! entry) { 72 | // no more files 73 | //Serial.println("**nomorefiles**"); 74 | break; 75 | } 76 | for (uint8_t i=0; i 22 | #include 23 | 24 | ext::File myFile; 25 | 26 | // change this to match your SD shield or module; 27 | // Arduino Ethernet shield: pin 4 28 | // Adafruit SD shields and modules: pin 10 29 | // Sparkfun SD shield: pin 8 30 | const int chipSelect = 4; 31 | 32 | void setup() 33 | { 34 | // Open serial communications and wait for port to open: 35 | Serial.begin(115200); 36 | while (!Serial) { 37 | ; // wait for serial port to connect. Needed for Leonardo only 38 | } 39 | 40 | 41 | Serial.print("Initializing SD card..."); 42 | // On the Ethernet Shield, CS is pin 4. It's set as an output by default. 43 | // Note that even if it's not used as the CS pin, the hardware SS pin 44 | // (10 on most Arduino boards, 53 on the Mega) must be left as an output 45 | // or the SD library functions will not work. 46 | pinMode(SS, OUTPUT); 47 | 48 | if (!SD.begin(17, 14, 12, 15)) { 49 | Serial.println("initialization failed!"); 50 | return; 51 | } 52 | Serial.println("initialization done."); 53 | 54 | // open the file. note that only one file can be open at a time, 55 | // so you have to close this one before opening another. 56 | myFile = SD.open("test.txt", FILE_WRITE); 57 | 58 | // if the file opened okay, write to it: 59 | if (myFile) { 60 | Serial.print("Writing to test.txt..."); 61 | myFile.println("testing 1, 2, 3."); 62 | // close the file: 63 | myFile.close(); 64 | Serial.println("done."); 65 | } else { 66 | // if the file didn't open, print an error: 67 | Serial.println("error opening test.txt"); 68 | } 69 | 70 | // re-open the file for reading: 71 | myFile = SD.open("test.txt"); 72 | if (myFile) { 73 | Serial.println("test.txt:"); 74 | 75 | // read from the file until there's nothing else in it: 76 | while (myFile.available()) { 77 | Serial.write(myFile.read()); 78 | } 79 | // close the file: 80 | myFile.close(); 81 | } else { 82 | // if the file didn't open, print an error: 83 | Serial.println("error opening test.txt"); 84 | } 85 | } 86 | 87 | void loop() 88 | { 89 | // nothing happens after setup 90 | } 91 | 92 | 93 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map SD 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | 9 | mySD KEYWORD1 10 | File KEYWORD1 11 | 12 | ####################################### 13 | # Methods and Functions (KEYWORD2) 14 | ####################################### 15 | begin KEYWORD2 16 | exists KEYWORD2 17 | mkdir KEYWORD2 18 | remove KEYWORD2 19 | rmdir KEYWORD2 20 | open KEYWORD2 21 | close KEYWORD2 22 | seek KEYWORD2 23 | position KEYWORD2 24 | size KEYWORD2 25 | 26 | ####################################### 27 | # Constants (LITERAL1) 28 | ####################################### 29 | FILE_READ LITERAL1 30 | FILE_WRITE LITERAL1 31 | -------------------------------------------------------------------------------- /mySD.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | SD - a slightly more friendly wrapper for sdfatlib 4 | 5 | This library aims to expose a subset of SD card functionality 6 | in the form of a higher level "wrapper" object. 7 | 8 | License: GNU General Public License V3 9 | (Because sdfatlib is licensed with this.) 10 | 11 | (C) Copyright 2010 SparkFun Electronics 12 | 13 | 14 | This library provides four key benefits: 15 | 16 | * Including `SD.h` automatically creates a global 17 | `SD` object which can be interacted with in a similar 18 | manner to other standard global objects like `Serial` and `Ethernet`. 19 | 20 | * Boilerplate initialisation code is contained in one method named 21 | `begin` and no further objects need to be created in order to access 22 | the SD card. 23 | 24 | * Calls to `open` can supply a full path name including parent 25 | directories which simplifies interacting with files in subdirectories. 26 | 27 | * Utility methods are provided to determine whether a file exists 28 | and to create a directory heirarchy. 29 | 30 | 31 | Note however that not all functionality provided by the underlying 32 | sdfatlib library is exposed. 33 | 34 | */ 35 | 36 | /* 37 | 38 | Implementation Notes 39 | 40 | In order to handle multi-directory path traversal, functionality that 41 | requires this ability is implemented as callback functions. 42 | 43 | Individual methods call the `walkPath` function which performs the actual 44 | directory traversal (swapping between two different directory/file handles 45 | along the way) and at each level calls the supplied callback function. 46 | 47 | Some types of functionality will take an action at each level (e.g. exists 48 | or make directory) which others will only take an action at the bottom 49 | level (e.g. open). 50 | 51 | */ 52 | 53 | #include "mySD.h" 54 | 55 | // Used by `getNextPathComponent` 56 | #define MAX_COMPONENT_LEN 12 // What is max length? 57 | #define PATH_COMPONENT_BUFFER_LEN MAX_COMPONENT_LEN+1 58 | 59 | bool getNextPathComponent(char *path, unsigned int *p_offset, 60 | char *buffer) { 61 | /* 62 | 63 | Parse individual path components from a path. 64 | 65 | e.g. after repeated calls '/foo/bar/baz' will be split 66 | into 'foo', 'bar', 'baz'. 67 | 68 | This is similar to `strtok()` but copies the component into the 69 | supplied buffer rather than modifying the original string. 70 | 71 | 72 | `buffer` needs to be PATH_COMPONENT_BUFFER_LEN in size. 73 | 74 | `p_offset` needs to point to an integer of the offset at 75 | which the previous path component finished. 76 | 77 | Returns `true` if more components remain. 78 | 79 | Returns `false` if this is the last component. 80 | (This means path ended with 'foo' or 'foo/'.) 81 | 82 | */ 83 | 84 | // TODO: Have buffer local to this function, so we know it's the 85 | // correct length? 86 | 87 | int bufferOffset = 0; 88 | 89 | int offset = *p_offset; 90 | 91 | // Skip root or other separator 92 | if (path[offset] == '/') { 93 | offset++; 94 | } 95 | 96 | // Copy the next next path segment 97 | while (bufferOffset < MAX_COMPONENT_LEN 98 | && (path[offset] != '/') 99 | && (path[offset] != '\0')) { 100 | buffer[bufferOffset++] = path[offset++]; 101 | } 102 | 103 | buffer[bufferOffset] = '\0'; 104 | 105 | // Skip trailing separator so we can determine if this 106 | // is the last component in the path or not. 107 | if (path[offset] == '/') { 108 | offset++; 109 | } 110 | 111 | *p_offset = offset; 112 | 113 | return (path[offset] != '\0'); 114 | } 115 | 116 | 117 | 118 | boolean walkPath(char *filepath, SdFile& parentDir, 119 | boolean (*callback)(SdFile& parentDir, 120 | char *filePathComponent, 121 | boolean isLastComponent, 122 | void *object), 123 | void *object = NULL) { 124 | /* 125 | 126 | When given a file path (and parent directory--normally root), 127 | this function traverses the directories in the path and at each 128 | level calls the supplied callback function while also providing 129 | the supplied object for context if required. 130 | 131 | e.g. given the path '/foo/bar/baz' 132 | the callback would be called at the equivalent of 133 | '/foo', '/foo/bar' and '/foo/bar/baz'. 134 | 135 | The implementation swaps between two different directory/file 136 | handles as it traverses the directories and does not use recursion 137 | in an attempt to use memory efficiently. 138 | 139 | If a callback wishes to stop the directory traversal it should 140 | return false--in this case the function will stop the traversal, 141 | tidy up and return false. 142 | 143 | If a directory path doesn't exist at some point this function will 144 | also return false and not subsequently call the callback. 145 | 146 | If a directory path specified is complete, valid and the callback 147 | did not indicate the traversal should be interrupted then this 148 | function will return true. 149 | 150 | */ 151 | 152 | 153 | SdFile subfile1; 154 | SdFile subfile2; 155 | 156 | char buffer[PATH_COMPONENT_BUFFER_LEN]; 157 | 158 | unsigned int offset = 0; 159 | 160 | SdFile *p_parent; 161 | SdFile *p_child; 162 | 163 | SdFile *p_tmp_sdfile; 164 | 165 | p_child = &subfile1; 166 | 167 | p_parent = &parentDir; 168 | 169 | while (true) { 170 | 171 | boolean moreComponents = getNextPathComponent(filepath, &offset, buffer); 172 | 173 | boolean shouldContinue = callback((*p_parent), buffer, !moreComponents, object); 174 | 175 | if (!shouldContinue) { 176 | // TODO: Don't repeat this code? 177 | // If it's one we've created then we 178 | // don't need the parent handle anymore. 179 | if (p_parent != &parentDir) { 180 | (*p_parent).close(); 181 | } 182 | return false; 183 | } 184 | 185 | if (!moreComponents) { 186 | break; 187 | } 188 | 189 | boolean exists = (*p_child).open(*p_parent, buffer, F_RDONLY); 190 | 191 | // If it's one we've created then we 192 | // don't need the parent handle anymore. 193 | if (p_parent != &parentDir) { 194 | (*p_parent).close(); 195 | } 196 | 197 | // Handle case when it doesn't exist and we can't continue... 198 | if (exists) { 199 | // We alternate between two file handles as we go down 200 | // the path. 201 | if (p_parent == &parentDir) { 202 | p_parent = &subfile2; 203 | } 204 | 205 | p_tmp_sdfile = p_parent; 206 | p_parent = p_child; 207 | p_child = p_tmp_sdfile; 208 | } else { 209 | return false; 210 | } 211 | } 212 | 213 | if (p_parent != &parentDir) { 214 | (*p_parent).close(); // TODO: Return/ handle different? 215 | } 216 | 217 | return true; 218 | } 219 | 220 | 221 | 222 | /* 223 | 224 | The callbacks used to implement various functionality follow. 225 | 226 | Each callback is supplied with a parent directory handle, 227 | character string with the name of the current file path component, 228 | a flag indicating if this component is the last in the path and 229 | a pointer to an arbitrary object used for context. 230 | 231 | */ 232 | 233 | boolean callback_pathExists(SdFile& parentDir, char *filePathComponent, 234 | boolean isLastComponent, void *object) { 235 | /* 236 | 237 | Callback used to determine if a file/directory exists in parent 238 | directory. 239 | 240 | Returns true if file path exists. 241 | 242 | */ 243 | SdFile child; 244 | 245 | boolean exists = child.open(parentDir, filePathComponent, F_RDONLY); 246 | 247 | if (exists) { 248 | child.close(); 249 | } 250 | 251 | return exists; 252 | } 253 | 254 | 255 | 256 | boolean callback_makeDirPath(SdFile& parentDir, char *filePathComponent, 257 | boolean isLastComponent, void *object) { 258 | /* 259 | 260 | Callback used to create a directory in the parent directory if 261 | it does not already exist. 262 | 263 | Returns true if a directory was created or it already existed. 264 | 265 | */ 266 | boolean result = false; 267 | SdFile child; 268 | 269 | result = callback_pathExists(parentDir, filePathComponent, isLastComponent, object); 270 | if (!result) { 271 | result = child.makeDir(parentDir, filePathComponent); 272 | } 273 | 274 | return result; 275 | } 276 | 277 | 278 | /* 279 | 280 | boolean callback_openPath(SdFile& parentDir, char *filePathComponent, 281 | boolean isLastComponent, void *object) { 282 | 283 | Callback used to open a file specified by a filepath that may 284 | specify one or more directories above it. 285 | 286 | Expects the context object to be an instance of `SDClass` and 287 | will use the `file` property of the instance to open the requested 288 | file/directory with the associated file open mode property. 289 | 290 | Always returns true if the directory traversal hasn't reached the 291 | bottom of the directory heirarchy. 292 | 293 | Returns false once the file has been opened--to prevent the traversal 294 | from descending further. (This may be unnecessary.) 295 | 296 | if (isLastComponent) { 297 | SDClass *p_SD = static_cast(object); 298 | p_SD->file.open(parentDir, filePathComponent, p_SD->fileOpenMode); 299 | if (p_SD->fileOpenMode == FILE_WRITE) { 300 | p_SD->file.seekSet(p_SD->file.fileSize()); 301 | } 302 | // TODO: Return file open result? 303 | return false; 304 | } 305 | return true; 306 | } 307 | */ 308 | 309 | 310 | 311 | boolean callback_remove(SdFile& parentDir, char *filePathComponent, 312 | boolean isLastComponent, void *object) { 313 | if (isLastComponent) { 314 | return SdFile::remove(parentDir, filePathComponent); 315 | } 316 | return true; 317 | } 318 | 319 | boolean callback_rmdir(SdFile& parentDir, char *filePathComponent, 320 | boolean isLastComponent, void *object) { 321 | if (isLastComponent) { 322 | SdFile f; 323 | if (!f.open(parentDir, filePathComponent, F_READ)) return false; 324 | return f.rmDir(); 325 | } 326 | return true; 327 | } 328 | 329 | 330 | 331 | /* Implementation of class used to create `SDCard` object. */ 332 | 333 | 334 | 335 | boolean SDClass::begin(uint8_t csPin, int8_t mosi, int8_t miso, int8_t sck) { 336 | /* 337 | 338 | Performs the initialisation required by the sdfatlib library. 339 | 340 | Return true if initialization succeeds, false otherwise. 341 | 342 | */ 343 | return card.init(SPI_HALF_SPEED, csPin, mosi, miso, sck) && 344 | volume.init(card) && 345 | root.openRoot(volume); 346 | } 347 | 348 | //call this when a card is removed. It will allow you to inster and initialise a new card. 349 | void SDClass::end() 350 | { 351 | root.close(); 352 | } 353 | 354 | 355 | // this little helper is used to traverse paths 356 | SdFile SDClass::getParentDir(const char *filepath, int *index) { 357 | // get parent directory 358 | SdFile d1 = root; // start with the mostparent, root! 359 | SdFile d2; 360 | 361 | // we'll use the pointers to swap between the two objects 362 | SdFile *parent = &d1; 363 | SdFile *subdir = &d2; 364 | 365 | const char *origpath = filepath; 366 | 367 | while (strchr(filepath, '/')) { 368 | 369 | // get rid of leading /'s 370 | if (filepath[0] == '/') { 371 | filepath++; 372 | continue; 373 | } 374 | 375 | if (! strchr(filepath, '/')) { 376 | // it was in the root directory, so leave now 377 | break; 378 | } 379 | 380 | // extract just the name of the next subdirectory 381 | uint8_t idx = strchr(filepath, '/') - filepath; 382 | if (idx > 12) 383 | idx = 12; // dont let them specify long names 384 | char subdirname[13]; 385 | strncpy(subdirname, filepath, idx); 386 | subdirname[idx] = 0; 387 | 388 | // close the subdir (we reuse them) if open 389 | subdir->close(); 390 | if (! subdir->open(parent, subdirname, F_READ)) { 391 | // failed to open one of the subdirectories 392 | return SdFile(); 393 | } 394 | // move forward to the next subdirectory 395 | filepath += idx; 396 | 397 | // we reuse the objects, close it. 398 | parent->close(); 399 | 400 | // swap the pointers 401 | SdFile *t = parent; 402 | parent = subdir; 403 | subdir = t; 404 | } 405 | 406 | *index = (int)(filepath - origpath); 407 | // parent is now the parent diretory of the file! 408 | return *parent; 409 | } 410 | 411 | 412 | ext::File SDClass::open(const char *filepath, uint8_t mode) { 413 | /* 414 | 415 | Open the supplied file path for reading or writing. 416 | 417 | The file content can be accessed via the `file` property of 418 | the `SDClass` object--this property is currently 419 | a standard `SdFile` object from `sdfatlib`. 420 | 421 | Defaults to read only. 422 | 423 | If `write` is true, default action (when `append` is true) is to 424 | append data to the end of the file. 425 | 426 | If `append` is false then the file will be truncated first. 427 | 428 | If the file does not exist and it is opened for writing the file 429 | will be created. 430 | 431 | An attempt to open a file for reading that does not exist is an 432 | error. 433 | 434 | */ 435 | 436 | int pathidx; 437 | 438 | // do the interative search 439 | SdFile parentdir = getParentDir(filepath, &pathidx); 440 | // no more subdirs! 441 | 442 | filepath += pathidx; 443 | 444 | if (! filepath[0]) { 445 | // it was the directory itself! 446 | return ext::File(parentdir, "/"); 447 | } 448 | 449 | // Open the file itself 450 | SdFile file; 451 | 452 | // failed to open a subdir! 453 | if (!parentdir.isOpen()) 454 | return ext::File(); 455 | 456 | // there is a special case for the Root directory since its a static dir 457 | if (parentdir.isRoot()) { 458 | if ( ! file.open(root, filepath, mode)) { 459 | // failed to open the file :( 460 | return ext::File(); 461 | } 462 | // dont close the root! 463 | } else { 464 | if ( ! file.open(parentdir, filepath, mode)) { 465 | return ext::File(); 466 | } 467 | // close the parent 468 | parentdir.close(); 469 | } 470 | 471 | if (mode & (F_APPEND | F_WRITE)) 472 | file.seekSet(file.fileSize()); 473 | return ext::File(file, filepath); 474 | } 475 | 476 | 477 | /* 478 | File SDClass::open(char *filepath, uint8_t mode) { 479 | // 480 | 481 | Open the supplied file path for reading or writing. 482 | 483 | The file content can be accessed via the `file` property of 484 | the `SDClass` object--this property is currently 485 | a standard `SdFile` object from `sdfatlib`. 486 | 487 | Defaults to read only. 488 | 489 | If `write` is true, default action (when `append` is true) is to 490 | append data to the end of the file. 491 | 492 | If `append` is false then the file will be truncated first. 493 | 494 | If the file does not exist and it is opened for writing the file 495 | will be created. 496 | 497 | An attempt to open a file for reading that does not exist is an 498 | error. 499 | 500 | // 501 | 502 | // TODO: Allow for read&write? (Possibly not, as it requires seek.) 503 | 504 | fileOpenMode = mode; 505 | walkPath(filepath, root, callback_openPath, this); 506 | 507 | return ext::File(); 508 | 509 | } 510 | */ 511 | 512 | 513 | //boolean SDClass::close() { 514 | // /* 515 | // 516 | // Closes the file opened by the `open` method. 517 | // 518 | // */ 519 | // file.close(); 520 | //} 521 | 522 | 523 | boolean SDClass::exists(char *filepath) { 524 | /* 525 | 526 | Returns true if the supplied file path exists. 527 | 528 | */ 529 | return walkPath(filepath, root, callback_pathExists); 530 | } 531 | 532 | 533 | //boolean SDClass::exists(char *filepath, SdFile& parentDir) { 534 | // /* 535 | // 536 | // Returns true if the supplied file path rooted at `parentDir` 537 | // exists. 538 | // 539 | // */ 540 | // return walkPath(filepath, parentDir, callback_pathExists); 541 | //} 542 | 543 | 544 | boolean SDClass::mkdir(char *filepath) { 545 | /* 546 | 547 | Makes a single directory or a heirarchy of directories. 548 | 549 | A rough equivalent to `mkdir -p`. 550 | 551 | */ 552 | return walkPath(filepath, root, callback_makeDirPath); 553 | } 554 | 555 | boolean SDClass::rmdir(char *filepath) { 556 | /* 557 | 558 | Makes a single directory or a heirarchy of directories. 559 | 560 | A rough equivalent to `mkdir -p`. 561 | 562 | */ 563 | return walkPath(filepath, root, callback_rmdir); 564 | } 565 | 566 | boolean SDClass::remove(char *filepath) { 567 | return walkPath(filepath, root, callback_remove); 568 | } 569 | 570 | void SDClass::enableCRC(boolean mode) { 571 | card.enableCRC(mode); 572 | } 573 | 574 | 575 | // allows you to recurse into a directory 576 | ext::File ext::File::openNextFile(uint8_t mode) { 577 | dir_t p; 578 | 579 | //Serial.print("\t\treading dir..."); 580 | while (_file->readDir(&p) > 0) { 581 | 582 | // done if past last used entry 583 | if (p.name[0] == DIR_NAME_FREE) { 584 | //Serial.println("end"); 585 | return ext::File(); 586 | } 587 | 588 | // skip deleted entry and entries for . and .. 589 | if (p.name[0] == DIR_NAME_DELETED || p.name[0] == '.') { 590 | //Serial.println("dots"); 591 | continue; 592 | } 593 | 594 | // only list subdirectories and files 595 | if (!DIR_IS_FILE_OR_SUBDIR(&p)) { 596 | //Serial.println("notafile"); 597 | continue; 598 | } 599 | 600 | // print file name with possible blank fill 601 | SdFile f; 602 | char name[13]; 603 | _file->dirName(p, name); 604 | //Serial.print("try to open file "); 605 | //Serial.println(name); 606 | 607 | if (f.open(_file, name, mode)) { 608 | //Serial.println("OK!"); 609 | return ext::File(f, name); 610 | } else { 611 | //Serial.println("ugh"); 612 | return ext::File(); 613 | } 614 | } 615 | 616 | //Serial.println("nothing"); 617 | return ext::File(); 618 | } 619 | 620 | void ext::File::rewindDirectory(void) { 621 | if (isDirectory()) 622 | _file->rewind(); 623 | } 624 | 625 | SDClass SD; 626 | -------------------------------------------------------------------------------- /mySD.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | SD - a slightly more friendly wrapper for sdfatlib 4 | 5 | This library aims to expose a subset of SD card functionality 6 | in the form of a higher level "wrapper" object. 7 | 8 | License: GNU General Public License V3 9 | (Because sdfatlib is licensed with this.) 10 | 11 | (C) Copyright 2010 SparkFun Electronics 12 | 13 | */ 14 | 15 | #ifndef __SD_H__ 16 | #define __SD_H__ 17 | 18 | #if ARDUINO >= 100 19 | #include "Arduino.h" 20 | #else 21 | #include "WProgram.h" 22 | #endif 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #define FILE_READ F_READ 30 | #define FILE_WRITE (F_READ | F_WRITE | F_CREAT) 31 | 32 | namespace ext{ 33 | class File : public Stream { 34 | private: 35 | char _name[13]; // our name 36 | SdFile *_file; // underlying file pointer 37 | 38 | public: 39 | File(SdFile f, const char *name); // wraps an underlying SdFile 40 | File(void); // 'empty' constructor 41 | ~File(void); // destructor 42 | #if ARDUINO >= 100 43 | virtual size_t write(uint8_t); 44 | virtual size_t write(const uint8_t *buf, size_t size); 45 | #else 46 | virtual void write(uint8_t); 47 | virtual void write(const uint8_t *buf, size_t size); 48 | #endif 49 | virtual int read(); 50 | virtual int peek(); 51 | virtual int available(); 52 | virtual void flush(); 53 | int read(void *buf, uint16_t nbyte); 54 | boolean seek(uint32_t pos); 55 | uint32_t position(); 56 | uint32_t size(); 57 | void close(); 58 | operator bool(); 59 | char * name(); 60 | 61 | boolean isDirectory(void); 62 | File openNextFile(uint8_t mode = F_RDONLY); 63 | void rewindDirectory(void); 64 | 65 | using Print::write; 66 | }; 67 | } 68 | 69 | class SDClass { 70 | 71 | private: 72 | // These are required for initialisation and use of sdfatlib 73 | Sd2Card card; 74 | SdVolume volume; 75 | SdFile root; 76 | 77 | // my quick&dirty iterator, should be replaced 78 | SdFile getParentDir(const char *filepath, int *indx); 79 | public: 80 | // This needs to be called to set up the connection to the SD card 81 | // before other methods are used. 82 | boolean begin(uint8_t csPin = SD_CHIP_SELECT_PIN, int8_t mosi = -1, int8_t miso = -1, int8_t sck = -1); 83 | 84 | //call this when a card is removed. It will allow you to inster and initialise a new card. 85 | void end(); 86 | 87 | // Open the specified file/directory with the supplied mode (e.g. read or 88 | // write, etc). Returns a File object for interacting with the file. 89 | // Note that currently only one file can be open at a time. 90 | ext::File open(const char *filename, uint8_t mode = FILE_READ); 91 | 92 | // Methods to determine if the requested file path exists. 93 | boolean exists(char *filepath); 94 | 95 | // Create the requested directory heirarchy--if intermediate directories 96 | // do not exist they will be created. 97 | boolean mkdir(char *filepath); 98 | 99 | // Delete the file. 100 | boolean remove(char *filepath); 101 | 102 | boolean rmdir(char *filepath); 103 | 104 | void enableCRC(boolean mode); 105 | 106 | private: 107 | 108 | // This is used to determine the mode used to open a file 109 | // it's here because it's the easiest place to pass the 110 | // information through the directory walking function. But 111 | // it's probably not the best place for it. 112 | // It shouldn't be set directly--it is set via the parameters to `open`. 113 | int fileOpenMode; 114 | 115 | friend class File; 116 | friend boolean callback_openPath(SdFile&, char *, boolean, void *); 117 | }; 118 | 119 | extern SDClass SD; 120 | 121 | #endif 122 | -------------------------------------------------------------------------------- /utility/FatStructs.h: -------------------------------------------------------------------------------- 1 | /* Arduino SdFat Library 2 | * Copyright (C) 2009 by William Greiman 3 | * 4 | * This file is part of the Arduino SdFat Library 5 | * 6 | * This Library is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This Library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with the Arduino SdFat Library. If not, see 18 | * . 19 | */ 20 | #ifndef FatStructs_h 21 | #define FatStructs_h 22 | /** 23 | * \file 24 | * FAT file structures 25 | */ 26 | /* 27 | * mostly from Microsoft document fatgen103.doc 28 | * http://www.microsoft.com/whdc/system/platform/firmware/fatgen.mspx 29 | */ 30 | //------------------------------------------------------------------------------ 31 | /** Value for byte 510 of boot block or MBR */ 32 | uint8_t const BOOTSIG0 = 0X55; 33 | /** Value for byte 511 of boot block or MBR */ 34 | uint8_t const BOOTSIG1 = 0XAA; 35 | //------------------------------------------------------------------------------ 36 | /** 37 | * \struct partitionTable 38 | * \brief MBR partition table entry 39 | * 40 | * A partition table entry for a MBR formatted storage device. 41 | * The MBR partition table has four entries. 42 | */ 43 | struct partitionTable { 44 | /** 45 | * Boot Indicator . Indicates whether the volume is the active 46 | * partition. Legal values include: 0X00. Do not use for booting. 47 | * 0X80 Active partition. 48 | */ 49 | uint8_t boot; 50 | /** 51 | * Head part of Cylinder-head-sector address of the first block in 52 | * the partition. Legal values are 0-255. Only used in old PC BIOS. 53 | */ 54 | uint8_t beginHead; 55 | /** 56 | * Sector part of Cylinder-head-sector address of the first block in 57 | * the partition. Legal values are 1-63. Only used in old PC BIOS. 58 | */ 59 | unsigned beginSector : 6; 60 | /** High bits cylinder for first block in partition. */ 61 | unsigned beginCylinderHigh : 2; 62 | /** 63 | * Combine beginCylinderLow with beginCylinderHigh. Legal values 64 | * are 0-1023. Only used in old PC BIOS. 65 | */ 66 | uint8_t beginCylinderLow; 67 | /** 68 | * Partition type. See defines that begin with PART_TYPE_ for 69 | * some Microsoft partition types. 70 | */ 71 | uint8_t type; 72 | /** 73 | * head part of cylinder-head-sector address of the last sector in the 74 | * partition. Legal values are 0-255. Only used in old PC BIOS. 75 | */ 76 | uint8_t endHead; 77 | /** 78 | * Sector part of cylinder-head-sector address of the last sector in 79 | * the partition. Legal values are 1-63. Only used in old PC BIOS. 80 | */ 81 | unsigned endSector : 6; 82 | /** High bits of end cylinder */ 83 | unsigned endCylinderHigh : 2; 84 | /** 85 | * Combine endCylinderLow with endCylinderHigh. Legal values 86 | * are 0-1023. Only used in old PC BIOS. 87 | */ 88 | uint8_t endCylinderLow; 89 | /** Logical block address of the first block in the partition. */ 90 | uint32_t firstSector; 91 | /** Length of the partition, in blocks. */ 92 | uint32_t totalSectors; 93 | } __attribute__((packed)); 94 | /** Type name for partitionTable */ 95 | typedef struct partitionTable part_t; 96 | //------------------------------------------------------------------------------ 97 | /** 98 | * \struct masterBootRecord 99 | * 100 | * \brief Master Boot Record 101 | * 102 | * The first block of a storage device that is formatted with a MBR. 103 | */ 104 | struct masterBootRecord { 105 | /** Code Area for master boot program. */ 106 | uint8_t codeArea[440]; 107 | /** Optional WindowsNT disk signature. May contain more boot code. */ 108 | uint32_t diskSignature; 109 | /** Usually zero but may be more boot code. */ 110 | uint16_t usuallyZero; 111 | /** Partition tables. */ 112 | part_t part[4]; 113 | /** First MBR signature byte. Must be 0X55 */ 114 | uint8_t mbrSig0; 115 | /** Second MBR signature byte. Must be 0XAA */ 116 | uint8_t mbrSig1; 117 | } __attribute__((packed)); 118 | /** Type name for masterBootRecord */ 119 | typedef struct masterBootRecord mbr_t; 120 | //------------------------------------------------------------------------------ 121 | /** 122 | * \struct biosParmBlock 123 | * 124 | * \brief BIOS parameter block 125 | * 126 | * The BIOS parameter block describes the physical layout of a FAT volume. 127 | */ 128 | struct biosParmBlock { 129 | /** 130 | * Count of bytes per sector. This value may take on only the 131 | * following values: 512, 1024, 2048 or 4096 132 | */ 133 | uint16_t bytesPerSector; 134 | /** 135 | * Number of sectors per allocation unit. This value must be a 136 | * power of 2 that is greater than 0. The legal values are 137 | * 1, 2, 4, 8, 16, 32, 64, and 128. 138 | */ 139 | uint8_t sectorsPerCluster; 140 | /** 141 | * Number of sectors before the first FAT. 142 | * This value must not be zero. 143 | */ 144 | uint16_t reservedSectorCount; 145 | /** The count of FAT data structures on the volume. This field should 146 | * always contain the value 2 for any FAT volume of any type. 147 | */ 148 | uint8_t fatCount; 149 | /** 150 | * For FAT12 and FAT16 volumes, this field contains the count of 151 | * 32-byte directory entries in the root directory. For FAT32 volumes, 152 | * this field must be set to 0. For FAT12 and FAT16 volumes, this 153 | * value should always specify a count that when multiplied by 32 154 | * results in a multiple of bytesPerSector. FAT16 volumes should 155 | * use the value 512. 156 | */ 157 | uint16_t rootDirEntryCount; 158 | /** 159 | * This field is the old 16-bit total count of sectors on the volume. 160 | * This count includes the count of all sectors in all four regions 161 | * of the volume. This field can be 0; if it is 0, then totalSectors32 162 | * must be non-zero. For FAT32 volumes, this field must be 0. For 163 | * FAT12 and FAT16 volumes, this field contains the sector count, and 164 | * totalSectors32 is 0 if the total sector count fits 165 | * (is less than 0x10000). 166 | */ 167 | uint16_t totalSectors16; 168 | /** 169 | * This dates back to the old MS-DOS 1.x media determination and is 170 | * no longer usually used for anything. 0xF8 is the standard value 171 | * for fixed (non-removable) media. For removable media, 0xF0 is 172 | * frequently used. Legal values are 0xF0 or 0xF8-0xFF. 173 | */ 174 | uint8_t mediaType; 175 | /** 176 | * Count of sectors occupied by one FAT on FAT12/FAT16 volumes. 177 | * On FAT32 volumes this field must be 0, and sectorsPerFat32 178 | * contains the FAT size count. 179 | */ 180 | uint16_t sectorsPerFat16; 181 | /** Sectors per track for interrupt 0x13. Not used otherwise. */ 182 | uint16_t sectorsPerTrtack; 183 | /** Number of heads for interrupt 0x13. Not used otherwise. */ 184 | uint16_t headCount; 185 | /** 186 | * Count of hidden sectors preceding the partition that contains this 187 | * FAT volume. This field is generally only relevant for media 188 | * visible on interrupt 0x13. 189 | */ 190 | uint32_t hidddenSectors; 191 | /** 192 | * This field is the new 32-bit total count of sectors on the volume. 193 | * This count includes the count of all sectors in all four regions 194 | * of the volume. This field can be 0; if it is 0, then 195 | * totalSectors16 must be non-zero. 196 | */ 197 | uint32_t totalSectors32; 198 | /** 199 | * Count of sectors occupied by one FAT on FAT32 volumes. 200 | */ 201 | uint32_t sectorsPerFat32; 202 | /** 203 | * This field is only defined for FAT32 media and does not exist on 204 | * FAT12 and FAT16 media. 205 | * Bits 0-3 -- Zero-based number of active FAT. 206 | * Only valid if mirroring is disabled. 207 | * Bits 4-6 -- Reserved. 208 | * Bit 7 -- 0 means the FAT is mirrored at runtime into all FATs. 209 | * -- 1 means only one FAT is active; it is the one referenced in bits 0-3. 210 | * Bits 8-15 -- Reserved. 211 | */ 212 | uint16_t fat32Flags; 213 | /** 214 | * FAT32 version. High byte is major revision number. 215 | * Low byte is minor revision number. Only 0.0 define. 216 | */ 217 | uint16_t fat32Version; 218 | /** 219 | * Cluster number of the first cluster of the root directory for FAT32. 220 | * This usually 2 but not required to be 2. 221 | */ 222 | uint32_t fat32RootCluster; 223 | /** 224 | * Sector number of FSINFO structure in the reserved area of the 225 | * FAT32 volume. Usually 1. 226 | */ 227 | uint16_t fat32FSInfo; 228 | /** 229 | * If non-zero, indicates the sector number in the reserved area 230 | * of the volume of a copy of the boot record. Usually 6. 231 | * No value other than 6 is recommended. 232 | */ 233 | uint16_t fat32BackBootBlock; 234 | /** 235 | * Reserved for future expansion. Code that formats FAT32 volumes 236 | * should always set all of the bytes of this field to 0. 237 | */ 238 | uint8_t fat32Reserved[12]; 239 | } __attribute__((packed)); 240 | /** Type name for biosParmBlock */ 241 | typedef struct biosParmBlock bpb_t; 242 | //------------------------------------------------------------------------------ 243 | /** 244 | * \struct fat32BootSector 245 | * 246 | * \brief Boot sector for a FAT16 or FAT32 volume. 247 | * 248 | */ 249 | struct fat32BootSector { 250 | /** X86 jmp to boot program */ 251 | uint8_t jmpToBootCode[3]; 252 | /** informational only - don't depend on it */ 253 | char oemName[8]; 254 | /** BIOS Parameter Block */ 255 | bpb_t bpb; 256 | /** for int0x13 use value 0X80 for hard drive */ 257 | uint8_t driveNumber; 258 | /** used by Windows NT - should be zero for FAT */ 259 | uint8_t reserved1; 260 | /** 0X29 if next three fields are valid */ 261 | uint8_t bootSignature; 262 | /** usually generated by combining date and time */ 263 | uint32_t volumeSerialNumber; 264 | /** should match volume label in root dir */ 265 | char volumeLabel[11]; 266 | /** informational only - don't depend on it */ 267 | char fileSystemType[8]; 268 | /** X86 boot code */ 269 | uint8_t bootCode[420]; 270 | /** must be 0X55 */ 271 | uint8_t bootSectorSig0; 272 | /** must be 0XAA */ 273 | uint8_t bootSectorSig1; 274 | } __attribute__((packed)); 275 | //------------------------------------------------------------------------------ 276 | // End Of Chain values for FAT entries 277 | /** FAT16 end of chain value used by Microsoft. */ 278 | uint16_t const FAT16EOC = 0XFFFF; 279 | /** Minimum value for FAT16 EOC. Use to test for EOC. */ 280 | uint16_t const FAT16EOC_MIN = 0XFFF8; 281 | /** FAT32 end of chain value used by Microsoft. */ 282 | uint32_t const FAT32EOC = 0X0FFFFFFF; 283 | /** Minimum value for FAT32 EOC. Use to test for EOC. */ 284 | uint32_t const FAT32EOC_MIN = 0X0FFFFFF8; 285 | /** Mask a for FAT32 entry. Entries are 28 bits. */ 286 | uint32_t const FAT32MASK = 0X0FFFFFFF; 287 | 288 | /** Type name for fat32BootSector */ 289 | typedef struct fat32BootSector fbs_t; 290 | //------------------------------------------------------------------------------ 291 | /** 292 | * \struct directoryEntry 293 | * \brief FAT short directory entry 294 | * 295 | * Short means short 8.3 name, not the entry size. 296 | * 297 | * Date Format. A FAT directory entry date stamp is a 16-bit field that is 298 | * basically a date relative to the MS-DOS epoch of 01/01/1980. Here is the 299 | * format (bit 0 is the LSB of the 16-bit word, bit 15 is the MSB of the 300 | * 16-bit word): 301 | * 302 | * Bits 9-15: Count of years from 1980, valid value range 0-127 303 | * inclusive (1980-2107). 304 | * 305 | * Bits 5-8: Month of year, 1 = January, valid value range 1-12 inclusive. 306 | * 307 | * Bits 0-4: Day of month, valid value range 1-31 inclusive. 308 | * 309 | * Time Format. A FAT directory entry time stamp is a 16-bit field that has 310 | * a granularity of 2 seconds. Here is the format (bit 0 is the LSB of the 311 | * 16-bit word, bit 15 is the MSB of the 16-bit word). 312 | * 313 | * Bits 11-15: Hours, valid value range 0-23 inclusive. 314 | * 315 | * Bits 5-10: Minutes, valid value range 0-59 inclusive. 316 | * 317 | * Bits 0-4: 2-second count, valid value range 0-29 inclusive (0 - 58 seconds). 318 | * 319 | * The valid time range is from Midnight 00:00:00 to 23:59:58. 320 | */ 321 | struct directoryEntry { 322 | /** 323 | * Short 8.3 name. 324 | * The first eight bytes contain the file name with blank fill. 325 | * The last three bytes contain the file extension with blank fill. 326 | */ 327 | uint8_t name[11]; 328 | /** Entry attributes. 329 | * 330 | * The upper two bits of the attribute byte are reserved and should 331 | * always be set to 0 when a file is created and never modified or 332 | * looked at after that. See defines that begin with DIR_ATT_. 333 | */ 334 | uint8_t attributes; 335 | /** 336 | * Reserved for use by Windows NT. Set value to 0 when a file is 337 | * created and never modify or look at it after that. 338 | */ 339 | uint8_t reservedNT; 340 | /** 341 | * The granularity of the seconds part of creationTime is 2 seconds 342 | * so this field is a count of tenths of a second and its valid 343 | * value range is 0-199 inclusive. (WHG note - seems to be hundredths) 344 | */ 345 | uint8_t creationTimeTenths; 346 | /** Time file was created. */ 347 | uint16_t creationTime; 348 | /** Date file was created. */ 349 | uint16_t creationDate; 350 | /** 351 | * Last access date. Note that there is no last access time, only 352 | * a date. This is the date of last read or write. In the case of 353 | * a write, this should be set to the same date as lastWriteDate. 354 | */ 355 | uint16_t lastAccessDate; 356 | /** 357 | * High word of this entry's first cluster number (always 0 for a 358 | * FAT12 or FAT16 volume). 359 | */ 360 | uint16_t firstClusterHigh; 361 | /** Time of last write. File creation is considered a write. */ 362 | uint16_t lastWriteTime; 363 | /** Date of last write. File creation is considered a write. */ 364 | uint16_t lastWriteDate; 365 | /** Low word of this entry's first cluster number. */ 366 | uint16_t firstClusterLow; 367 | /** 32-bit unsigned holding this file's size in bytes. */ 368 | uint32_t fileSize; 369 | } __attribute__((packed)); 370 | //------------------------------------------------------------------------------ 371 | // Definitions for directory entries 372 | // 373 | /** Type name for directoryEntry */ 374 | typedef struct directoryEntry dir_t; 375 | /** escape for name[0] = 0XE5 */ 376 | uint8_t const DIR_NAME_0XE5 = 0X05; 377 | /** name[0] value for entry that is free after being "deleted" */ 378 | uint8_t const DIR_NAME_DELETED = 0XE5; 379 | /** name[0] value for entry that is free and no allocated entries follow */ 380 | uint8_t const DIR_NAME_FREE = 0X00; 381 | /** file is read-only */ 382 | uint8_t const DIR_ATT_READ_ONLY = 0X01; 383 | /** File should hidden in directory listings */ 384 | uint8_t const DIR_ATT_HIDDEN = 0X02; 385 | /** Entry is for a system file */ 386 | uint8_t const DIR_ATT_SYSTEM = 0X04; 387 | /** Directory entry contains the volume label */ 388 | uint8_t const DIR_ATT_VOLUME_ID = 0X08; 389 | /** Entry is for a directory */ 390 | uint8_t const DIR_ATT_DIRECTORY = 0X10; 391 | /** Old DOS archive bit for backup support */ 392 | uint8_t const DIR_ATT_ARCHIVE = 0X20; 393 | /** Test value for long name entry. Test is 394 | (d->attributes & DIR_ATT_LONG_NAME_MASK) == DIR_ATT_LONG_NAME. */ 395 | uint8_t const DIR_ATT_LONG_NAME = 0X0F; 396 | /** Test mask for long name entry */ 397 | uint8_t const DIR_ATT_LONG_NAME_MASK = 0X3F; 398 | /** defined attribute bits */ 399 | uint8_t const DIR_ATT_DEFINED_BITS = 0X3F; 400 | /** Directory entry is part of a long name */ 401 | static inline uint8_t DIR_IS_LONG_NAME(const dir_t* dir) { 402 | return (dir->attributes & DIR_ATT_LONG_NAME_MASK) == DIR_ATT_LONG_NAME; 403 | } 404 | /** Mask for file/subdirectory tests */ 405 | uint8_t const DIR_ATT_FILE_TYPE_MASK = (DIR_ATT_VOLUME_ID | DIR_ATT_DIRECTORY); 406 | /** Directory entry is for a file */ 407 | static inline uint8_t DIR_IS_FILE(const dir_t* dir) { 408 | return (dir->attributes & DIR_ATT_FILE_TYPE_MASK) == 0; 409 | } 410 | /** Directory entry is for a subdirectory */ 411 | static inline uint8_t DIR_IS_SUBDIR(const dir_t* dir) { 412 | return (dir->attributes & DIR_ATT_FILE_TYPE_MASK) == DIR_ATT_DIRECTORY; 413 | } 414 | /** Directory entry is for a file or subdirectory */ 415 | static inline uint8_t DIR_IS_FILE_OR_SUBDIR(const dir_t* dir) { 416 | return (dir->attributes & DIR_ATT_VOLUME_ID) == 0; 417 | } 418 | #endif // FatStructs_h 419 | -------------------------------------------------------------------------------- /utility/Sd2Card.cpp: -------------------------------------------------------------------------------- 1 | /* Arduino Sd2Card Library 2 | * Copyright (C) 2009 by William Greiman 3 | * 4 | * This file is part of the Arduino Sd2Card Library 5 | * 6 | * This Library is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This Library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with the Arduino Sd2Card Library. If not, see 18 | * . 19 | */ 20 | #define USE_SPI_LIB 21 | #if ARDUINO >= 100 22 | #include "Arduino.h" 23 | #else 24 | #include "WProgram.h" 25 | #endif 26 | #include "Sd2Card.h" 27 | //------------------------------------------------------------------------------ 28 | #ifdef __arm__ 29 | static int8_t mosiPin_, misoPin_, clockPin_; 30 | static volatile RwReg *mosiport, *clkport, *misoport; 31 | static uint32_t mosipinmask, clkpinmask, misopinmask; 32 | #else 33 | static int8_t mosiPin_, misoPin_, clockPin_; 34 | static volatile uint32_t *mosiport, *clkport, *misoport; 35 | static uint32_t mosipinmask, clkpinmask, misopinmask; 36 | #endif 37 | 38 | //------------------------------------------------------------------------------ 39 | /** nop to tune soft SPI timing */ 40 | #define nop asm volatile ("nop\n\t") 41 | 42 | #ifndef SOFTWARE_SPI 43 | #ifdef USE_SPI_LIB 44 | #include 45 | #endif 46 | // functions for hardware SPI 47 | /** Send a byte to the card */ 48 | static void spiSend(uint8_t b) { 49 | if (clockPin_ == -1) { 50 | #ifndef USE_SPI_LIB 51 | SPDR = b; 52 | while (!(SPSR & (1 << SPIF))); 53 | #else 54 | SPI.transfer(b); 55 | #endif 56 | } else { 57 | noInterrupts(); 58 | // Fast SPI bitbang swiped from LPD8806 library 59 | for (uint8_t i = 0; i < 8; i++) { 60 | *clkport &= ~clkpinmask; 61 | if (b & 0x80) 62 | *mosiport |= mosipinmask; 63 | else 64 | *mosiport &= ~mosipinmask; 65 | *clkport |= clkpinmask; 66 | b <<= 1; 67 | } 68 | nop;nop;nop;nop; 69 | *clkport &= ~clkpinmask; 70 | 71 | interrupts(); 72 | } 73 | } 74 | /** Receive a byte from the card */ 75 | static uint8_t spiRec(void) { 76 | if (clockPin_ == -1) { 77 | #ifndef USE_SPI_LIB 78 | spiSend(0XFF); 79 | return SPDR; 80 | #else 81 | return SPI.transfer(0xFF); 82 | #endif 83 | } else { 84 | uint8_t data = 0; 85 | // no interrupts during byte receive - about 8 us 86 | noInterrupts(); 87 | // output pin high - like sending 0XFF 88 | *mosiport |= mosipinmask; 89 | 90 | for (uint8_t i = 0; i < 8; i++) { 91 | *clkport |= clkpinmask; 92 | data <<= 1; 93 | 94 | //if (fastDigitalRead(SPI_MISO_PIN)) data |= 1; 95 | if ((*misoport) & misopinmask) data |= 1; 96 | 97 | *clkport &= ~clkpinmask; 98 | 99 | // adjust so SCK is nice 100 | nop; 101 | nop; 102 | } 103 | // enable interrupts 104 | interrupts(); 105 | return data; 106 | } 107 | } 108 | #else // SOFTWARE_SPI 109 | //------------------------------------------------------------------------------ 110 | /** Soft SPI receive */ 111 | uint8_t spiRec(void) { 112 | uint8_t data = 0; 113 | // no interrupts during byte receive - about 8 us 114 | cli(); 115 | // output pin high - like sending 0XFF 116 | fastDigitalWrite(SPI_MOSI_PIN, HIGH); 117 | 118 | for (uint8_t i = 0; i < 8; i++) { 119 | fastDigitalWrite(SPI_SCK_PIN, HIGH); 120 | 121 | // adjust so SCK is nice 122 | nop; 123 | nop; 124 | 125 | data <<= 1; 126 | 127 | if (fastDigitalRead(SPI_MISO_PIN)) data |= 1; 128 | 129 | fastDigitalWrite(SPI_SCK_PIN, LOW); 130 | } 131 | // enable interrupts 132 | sei(); 133 | return data; 134 | } 135 | //------------------------------------------------------------------------------ 136 | /** Soft SPI send */ 137 | void spiSend(uint8_t data) { 138 | // no interrupts during byte send - about 8 us 139 | cli(); 140 | for (uint8_t i = 0; i < 8; i++) { 141 | fastDigitalWrite(SPI_SCK_PIN, LOW); 142 | 143 | fastDigitalWrite(SPI_MOSI_PIN, data & 0X80); 144 | 145 | data <<= 1; 146 | 147 | fastDigitalWrite(SPI_SCK_PIN, HIGH); 148 | } 149 | // hold SCK high for a few ns 150 | nop; 151 | nop; 152 | nop; 153 | nop; 154 | 155 | fastDigitalWrite(SPI_SCK_PIN, LOW); 156 | // enable interrupts 157 | sei(); 158 | } 159 | #endif // SOFTWARE_SPI 160 | //------------------------------------------------------------------------------ 161 | // send command and return error code. Return zero for OK 162 | uint8_t Sd2Card::cardCommand(uint8_t cmd, uint32_t arg) { 163 | // end read if in partialBlockRead mode 164 | readEnd(); 165 | 166 | // select card 167 | chipSelectLow(); 168 | 169 | // wait up to 300 ms if busy 170 | waitNotBusy(300); 171 | 172 | // send command 173 | spiSend(cmd | 0x40); 174 | 175 | // send argument 176 | for (int8_t s = 24; s >= 0; s -= 8) spiSend(arg >> s); 177 | 178 | // send CRC 179 | uint8_t crc = 0XFF; 180 | if (cmd == CMD0) crc = 0X95; // correct crc for CMD0 with arg 0 181 | if (cmd == CMD8) crc = 0X87; // correct crc for CMD8 with arg 0X1AA 182 | spiSend(crc); 183 | 184 | // wait for response 185 | for (uint8_t i = 0; ((status_ = spiRec()) & 0X80) && i != 0XFF; i++); 186 | return status_; 187 | } 188 | //------------------------------------------------------------------------------ 189 | /** 190 | * Determine the size of an SD flash memory card. 191 | * 192 | * \return The number of 512 byte data blocks in the card 193 | * or zero if an error occurs. 194 | */ 195 | uint32_t Sd2Card::cardSize(void) { 196 | csd_t csd; 197 | if (!readCSD(&csd)) return 0; 198 | if (csd.v1.csd_ver == 0) { 199 | uint8_t read_bl_len = csd.v1.read_bl_len; 200 | uint16_t c_size = (csd.v1.c_size_high << 10) 201 | | (csd.v1.c_size_mid << 2) | csd.v1.c_size_low; 202 | uint8_t c_size_mult = (csd.v1.c_size_mult_high << 1) 203 | | csd.v1.c_size_mult_low; 204 | return (uint32_t)(c_size + 1) << (c_size_mult + read_bl_len - 7); 205 | } else if (csd.v2.csd_ver == 1) { 206 | uint32_t c_size = ((uint32_t)csd.v2.c_size_high << 16) 207 | | (csd.v2.c_size_mid << 8) | csd.v2.c_size_low; 208 | return (c_size + 1) << 10; 209 | } else { 210 | error(SD_CARD_ERROR_BAD_CSD); 211 | return 0; 212 | } 213 | } 214 | //------------------------------------------------------------------------------ 215 | void Sd2Card::chipSelectHigh(void) { 216 | digitalWrite(chipSelectPin_, HIGH); 217 | } 218 | //------------------------------------------------------------------------------ 219 | void Sd2Card::chipSelectLow(void) { 220 | digitalWrite(chipSelectPin_, LOW); 221 | } 222 | //------------------------------------------------------------------------------ 223 | /** Erase a range of blocks. 224 | * 225 | * \param[in] firstBlock The address of the first block in the range. 226 | * \param[in] lastBlock The address of the last block in the range. 227 | * 228 | * \note This function requests the SD card to do a flash erase for a 229 | * range of blocks. The data on the card after an erase operation is 230 | * either 0 or 1, depends on the card vendor. The card must support 231 | * single block erase. 232 | * 233 | * \return The value one, true, is returned for success and 234 | * the value zero, false, is returned for failure. 235 | */ 236 | uint8_t Sd2Card::erase(uint32_t firstBlock, uint32_t lastBlock) { 237 | if (!eraseSingleBlockEnable()) { 238 | error(SD_CARD_ERROR_ERASE_SINGLE_BLOCK); 239 | goto fail; 240 | } 241 | if (type_ != SD_CARD_TYPE_SDHC) { 242 | firstBlock <<= 9; 243 | lastBlock <<= 9; 244 | } 245 | if (cardCommand(CMD32, firstBlock) 246 | || cardCommand(CMD33, lastBlock) 247 | || cardCommand(CMD38, 0)) { 248 | error(SD_CARD_ERROR_ERASE); 249 | goto fail; 250 | } 251 | if (!waitNotBusy(SD_ERASE_TIMEOUT)) { 252 | error(SD_CARD_ERROR_ERASE_TIMEOUT); 253 | goto fail; 254 | } 255 | chipSelectHigh(); 256 | return true; 257 | 258 | fail: 259 | chipSelectHigh(); 260 | return false; 261 | } 262 | //------------------------------------------------------------------------------ 263 | /** Determine if card supports single block erase. 264 | * 265 | * \return The value one, true, is returned if single block erase is supported. 266 | * The value zero, false, is returned if single block erase is not supported. 267 | */ 268 | uint8_t Sd2Card::eraseSingleBlockEnable(void) { 269 | csd_t csd; 270 | return readCSD(&csd) ? csd.v1.erase_blk_en : 0; 271 | } 272 | //------------------------------------------------------------------------------ 273 | /** 274 | * Initialize an SD flash memory card. 275 | * 276 | * \param[in] sckRateID SPI clock rate selector. See setSckRate(). 277 | * \param[in] chipSelectPin SD chip select pin number. 278 | * 279 | * \return The value one, true, is returned for success and 280 | * the value zero, false, is returned for failure. The reason for failure 281 | * can be determined by calling errorCode() and errorData(). 282 | */ 283 | uint8_t Sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin, int8_t mosiPin, int8_t misoPin, int8_t clockPin) { 284 | writeCRC_ = errorCode_ = inBlock_ = partialBlockRead_ = type_ = 0; 285 | chipSelectPin_ = chipSelectPin; 286 | mosiPin_ = mosiPin; 287 | misoPin_ = misoPin; 288 | clockPin_ = clockPin; 289 | // 16-bit init start time allows over a minute 290 | uint16_t t0 = (uint16_t)millis(); 291 | uint32_t arg; 292 | 293 | // set pin modes 294 | pinMode(chipSelectPin_, OUTPUT); 295 | chipSelectHigh(); 296 | 297 | if (clockPin != -1) { 298 | // use slow bitbang mode 299 | pinMode(misoPin_, INPUT); 300 | pinMode(mosiPin_, OUTPUT); 301 | pinMode(clockPin_, OUTPUT); 302 | clkport = portOutputRegister(digitalPinToPort(clockPin_)); 303 | clkpinmask = digitalPinToBitMask(clockPin_); 304 | mosiport = portOutputRegister(digitalPinToPort(mosiPin_)); 305 | mosipinmask = digitalPinToBitMask(mosiPin_); 306 | misoport = portInputRegister(digitalPinToPort(misoPin_)); 307 | misopinmask = digitalPinToBitMask(misoPin_); 308 | } else { 309 | 310 | #ifndef USE_SPI_LIB 311 | pinMode(SPI_MISO_PIN, INPUT); 312 | pinMode(SPI_MOSI_PIN, OUTPUT); 313 | pinMode(SPI_SCK_PIN, OUTPUT); 314 | #endif 315 | 316 | #ifndef SOFTWARE_SPI 317 | #ifndef USE_SPI_LIB 318 | // SS must be in output mode even it is not chip select 319 | pinMode(SS_PIN, OUTPUT); 320 | digitalWrite(SS_PIN, HIGH); // disable any SPI device using hardware SS pin 321 | // Enable SPI, Master, clock rate f_osc/128 322 | SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0); 323 | // clear double speed 324 | SPSR &= ~(1 << SPI2X); 325 | #else // USE_SPI_LIB 326 | SPI.begin(); 327 | #ifdef SPI_CLOCK_DIV128 328 | SPI.setClockDivider(SPI_CLOCK_DIV128); 329 | #else 330 | SPI.setClockDivider(255); 331 | #endif 332 | #endif // USE_SPI_LIB 333 | #endif // SOFTWARE_SPI 334 | } 335 | // must supply min of 74 clock cycles with CS high. 336 | for (uint8_t i = 0; i < 10; i++) spiSend(0XFF); 337 | 338 | chipSelectLow(); 339 | 340 | // command to go idle in SPI mode 341 | while ((status_ = cardCommand(CMD0, 0)) != R1_IDLE_STATE) { 342 | if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) { 343 | error(SD_CARD_ERROR_CMD0); 344 | goto fail; 345 | } 346 | } 347 | // check SD version 348 | if ((cardCommand(CMD8, 0x1AA) & R1_ILLEGAL_COMMAND)) { 349 | type(SD_CARD_TYPE_SD1); 350 | } else { 351 | // only need last byte of r7 response 352 | for (uint8_t i = 0; i < 4; i++) status_ = spiRec(); 353 | if (status_ != 0XAA) { 354 | error(SD_CARD_ERROR_CMD8); 355 | goto fail; 356 | } 357 | type(SD_CARD_TYPE_SD2); 358 | } 359 | // initialize card and send host supports SDHC if SD2 360 | arg = type() == SD_CARD_TYPE_SD2 ? 0X40000000 : 0; 361 | 362 | while ((status_ = cardAcmd(ACMD41, arg)) != R1_READY_STATE) { 363 | // check for timeout 364 | if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) { 365 | error(SD_CARD_ERROR_ACMD41); 366 | goto fail; 367 | } 368 | } 369 | // if SD2 read OCR register to check for SDHC card 370 | if (type() == SD_CARD_TYPE_SD2) { 371 | if (cardCommand(CMD58, 0)) { 372 | error(SD_CARD_ERROR_CMD58); 373 | goto fail; 374 | } 375 | if ((spiRec() & 0XC0) == 0XC0) type(SD_CARD_TYPE_SDHC); 376 | // discard rest of ocr - contains allowed voltage range 377 | for (uint8_t i = 0; i < 3; i++) spiRec(); 378 | } 379 | chipSelectHigh(); 380 | 381 | #ifndef SOFTWARE_SPI 382 | if (clockPin_ == -1) 383 | return setSckRate(sckRateID); 384 | else 385 | return true; 386 | #else // SOFTWARE_SPI 387 | return true; 388 | #endif // SOFTWARE_SPI 389 | 390 | fail: 391 | chipSelectHigh(); 392 | return false; 393 | } 394 | //------------------------------------------------------------------------------ 395 | /** 396 | * Enable or disable partial block reads. 397 | * 398 | * Enabling partial block reads improves performance by allowing a block 399 | * to be read over the SPI bus as several sub-blocks. Errors may occur 400 | * if the time between reads is too long since the SD card may timeout. 401 | * The SPI SS line will be held low until the entire block is read or 402 | * readEnd() is called. 403 | * 404 | * Use this for applications like the Adafruit Wave Shield. 405 | * 406 | * \param[in] value The value TRUE (non-zero) or FALSE (zero).) 407 | */ 408 | void Sd2Card::partialBlockRead(uint8_t value) { 409 | readEnd(); 410 | partialBlockRead_ = value; 411 | } 412 | //------------------------------------------------------------------------------ 413 | /** 414 | * Read a 512 byte block from an SD card device. 415 | * 416 | * \param[in] block Logical block to be read. 417 | * \param[out] dst Pointer to the location that will receive the data. 418 | 419 | * \return The value one, true, is returned for success and 420 | * the value zero, false, is returned for failure. 421 | */ 422 | uint8_t Sd2Card::readBlock(uint32_t block, uint8_t* dst) { 423 | return readData(block, 0, 512, dst); 424 | } 425 | //------------------------------------------------------------------------------ 426 | /** 427 | * Read part of a 512 byte block from an SD card. 428 | * 429 | * \param[in] block Logical block to be read. 430 | * \param[in] offset Number of bytes to skip at start of block 431 | * \param[out] dst Pointer to the location that will receive the data. 432 | * \param[in] count Number of bytes to read 433 | * \return The value one, true, is returned for success and 434 | * the value zero, false, is returned for failure. 435 | */ 436 | uint8_t Sd2Card::readData(uint32_t block, 437 | uint16_t offset, uint16_t count, uint8_t* dst) { 438 | uint16_t n; 439 | if (count == 0) return true; 440 | if ((count + offset) > 512) { 441 | goto fail; 442 | } 443 | if (!inBlock_ || block != block_ || offset < offset_) { 444 | block_ = block; 445 | // use address if not SDHC card 446 | if (type()!= SD_CARD_TYPE_SDHC) block <<= 9; 447 | if (cardCommand(CMD17, block)) { 448 | error(SD_CARD_ERROR_CMD17); 449 | goto fail; 450 | } 451 | if (!waitStartBlock()) { 452 | goto fail; 453 | } 454 | offset_ = 0; 455 | inBlock_ = 1; 456 | } 457 | 458 | #ifdef OPTIMIZE_HARDWARE_SPI 459 | // start first spi transfer 460 | SPDR = 0XFF; 461 | 462 | // skip data before offset 463 | for (;offset_ < offset; offset_++) { 464 | while (!(SPSR & (1 << SPIF))); 465 | SPDR = 0XFF; 466 | } 467 | // transfer data 468 | n = count - 1; 469 | for (uint16_t i = 0; i < n; i++) { 470 | while (!(SPSR & (1 << SPIF))); 471 | dst[i] = SPDR; 472 | SPDR = 0XFF; 473 | } 474 | // wait for last byte 475 | while (!(SPSR & (1 << SPIF))); 476 | dst[n] = SPDR; 477 | 478 | #else // OPTIMIZE_HARDWARE_SPI 479 | 480 | // skip data before offset 481 | for (;offset_ < offset; offset_++) { 482 | spiRec(); 483 | } 484 | // transfer data 485 | for (uint16_t i = 0; i < count; i++) { 486 | dst[i] = spiRec(); 487 | } 488 | #endif // OPTIMIZE_HARDWARE_SPI 489 | 490 | offset_ += count; 491 | if (!partialBlockRead_ || offset_ >= 512) { 492 | // read rest of data, checksum and set chip select high 493 | readEnd(); 494 | } 495 | return true; 496 | 497 | fail: 498 | chipSelectHigh(); 499 | return false; 500 | } 501 | //------------------------------------------------------------------------------ 502 | /** Skip remaining data in a block when in partial block read mode. */ 503 | void Sd2Card::readEnd(void) { 504 | if (inBlock_) { 505 | // skip data and crc 506 | #ifdef OPTIMIZE_HARDWARE_SPI 507 | // optimize skip for hardware 508 | SPDR = 0XFF; 509 | while (offset_++ < 513) { 510 | while (!(SPSR & (1 << SPIF))); 511 | SPDR = 0XFF; 512 | } 513 | // wait for last crc byte 514 | while (!(SPSR & (1 << SPIF))); 515 | #else // OPTIMIZE_HARDWARE_SPI 516 | while (offset_++ < 514) spiRec(); 517 | #endif // OPTIMIZE_HARDWARE_SPI 518 | chipSelectHigh(); 519 | inBlock_ = 0; 520 | } 521 | } 522 | //------------------------------------------------------------------------------ 523 | /** read CID or CSR register */ 524 | uint8_t Sd2Card::readRegister(uint8_t cmd, void* buf) { 525 | uint8_t* dst = reinterpret_cast(buf); 526 | if (cardCommand(cmd, 0)) { 527 | error(SD_CARD_ERROR_READ_REG); 528 | goto fail; 529 | } 530 | if (!waitStartBlock()) goto fail; 531 | // transfer data 532 | for (uint16_t i = 0; i < 16; i++) dst[i] = spiRec(); 533 | spiRec(); // get first crc byte 534 | spiRec(); // get second crc byte 535 | chipSelectHigh(); 536 | return true; 537 | 538 | fail: 539 | chipSelectHigh(); 540 | return false; 541 | } 542 | //------------------------------------------------------------------------------ 543 | /** 544 | * Set the SPI clock rate. 545 | * 546 | * \param[in] sckRateID A value in the range [0, 6]. 547 | * 548 | * The SPI clock will be set to F_CPU/pow(2, 1 + sckRateID). The maximum 549 | * SPI rate is F_CPU/2 for \a sckRateID = 0 and the minimum rate is F_CPU/128 550 | * for \a scsRateID = 6. 551 | * 552 | * \return The value one, true, is returned for success and the value zero, 553 | * false, is returned for an invalid value of \a sckRateID. 554 | */ 555 | uint8_t Sd2Card::setSckRate(uint8_t sckRateID) { 556 | if (sckRateID > 6) { 557 | error(SD_CARD_ERROR_SCK_RATE); 558 | return false; 559 | } 560 | #ifndef USE_SPI_LIB 561 | // see avr processor datasheet for SPI register bit definitions 562 | if ((sckRateID & 1) || sckRateID == 6) { 563 | SPSR &= ~(1 << SPI2X); 564 | } else { 565 | SPSR |= (1 << SPI2X); 566 | } 567 | SPCR &= ~((1 < SD_READ_TIMEOUT) { 605 | error(SD_CARD_ERROR_READ_TIMEOUT); 606 | goto fail; 607 | } 608 | } 609 | if (status_ != DATA_START_BLOCK) { 610 | error(SD_CARD_ERROR_READ); 611 | goto fail; 612 | } 613 | return true; 614 | 615 | fail: 616 | chipSelectHigh(); 617 | return false; 618 | } 619 | //------------------------------------------------------------------------------ 620 | /** 621 | * Writes a 512 byte block to an SD card. 622 | * 623 | * \param[in] blockNumber Logical block to be written. 624 | * \param[in] src Pointer to the location of the data to be written. 625 | * \return The value one, true, is returned for success and 626 | * the value zero, false, is returned for failure. 627 | */ 628 | uint8_t Sd2Card::writeBlock(uint32_t blockNumber, const uint8_t* src) { 629 | #if SD_PROTECT_BLOCK_ZERO 630 | // don't allow write to first block 631 | if (blockNumber == 0) { 632 | error(SD_CARD_ERROR_WRITE_BLOCK_ZERO); 633 | goto fail; 634 | } 635 | #endif // SD_PROTECT_BLOCK_ZERO 636 | 637 | // use address if not SDHC card 638 | if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9; 639 | if (cardCommand(CMD24, blockNumber)) { 640 | error(SD_CARD_ERROR_CMD24); 641 | goto fail; 642 | } 643 | if (!writeData(DATA_START_BLOCK, src)) goto fail; 644 | 645 | // wait for flash programming to complete 646 | if (!waitNotBusy(SD_WRITE_TIMEOUT)) { 647 | error(SD_CARD_ERROR_WRITE_TIMEOUT); 648 | goto fail; 649 | } 650 | // response is r2 so get and check two bytes for nonzero 651 | if (cardCommand(CMD13, 0) || spiRec()) { 652 | error(SD_CARD_ERROR_WRITE_PROGRAMMING); 653 | goto fail; 654 | } 655 | chipSelectHigh(); 656 | return true; 657 | 658 | fail: 659 | chipSelectHigh(); 660 | return false; 661 | } 662 | //------------------------------------------------------------------------------ 663 | /** Write one data block in a multiple block write sequence */ 664 | uint8_t Sd2Card::writeData(const uint8_t* src) { 665 | // wait for previous write to finish 666 | if (!waitNotBusy(SD_WRITE_TIMEOUT)) { 667 | error(SD_CARD_ERROR_WRITE_MULTIPLE); 668 | chipSelectHigh(); 669 | return false; 670 | } 671 | return writeData(WRITE_MULTIPLE_TOKEN, src); 672 | } 673 | //------------------------------------------------------------------------------ 674 | // send one block of data for write block or write multiple blocks 675 | uint8_t Sd2Card::writeData(uint8_t token, const uint8_t* src) { 676 | 677 | // CRC16 checksum is supposed to be ignored in SPI mode (unless 678 | // explicitly enabled) and a dummy value is normally written. 679 | // A few funny cards (e.g. Eye-Fi X2) expect a valid CRC anyway. 680 | // Call setCRC(true) to enable CRC16 checksum on block writes. 681 | // This has a noticeable impact on write speed. :( 682 | int16_t crc; 683 | if(writeCRC_) { 684 | int16_t i, x; 685 | // CRC16 code via Scott Dattalo www.dattalo.com 686 | for(crc=i=0; i<512; i++) { 687 | x = ((crc >> 8) ^ src[i]) & 0xff; 688 | x ^= x >> 4; 689 | crc = (crc << 8) ^ (x << 12) ^ (x << 5) ^ x; 690 | } 691 | } else { 692 | crc = 0xffff; // Dummy CRC value 693 | } 694 | 695 | #ifdef OPTIMIZE_HARDWARE_SPI 696 | 697 | // send data - optimized loop 698 | SPDR = token; 699 | 700 | // send two byte per iteration 701 | for (uint16_t i = 0; i < 512; i += 2) { 702 | while (!(SPSR & (1 << SPIF))); 703 | SPDR = src[i]; 704 | while (!(SPSR & (1 << SPIF))); 705 | SPDR = src[i+1]; 706 | } 707 | 708 | // wait for last data byte 709 | while (!(SPSR & (1 << SPIF))); 710 | 711 | #else // OPTIMIZE_HARDWARE_SPI 712 | spiSend(token); 713 | for (uint16_t i = 0; i < 512; i++) { 714 | spiSend(src[i]); 715 | } 716 | #endif // OPTIMIZE_HARDWARE_SPI 717 | 718 | spiSend(crc >> 8); // Might be dummy value, that's OK 719 | spiSend(crc); 720 | 721 | status_ = spiRec(); 722 | if ((status_ & DATA_RES_MASK) != DATA_RES_ACCEPTED) { 723 | error(SD_CARD_ERROR_WRITE); 724 | chipSelectHigh(); 725 | return false; 726 | } 727 | return true; 728 | } 729 | //------------------------------------------------------------------------------ 730 | /** Start a write multiple blocks sequence. 731 | * 732 | * \param[in] blockNumber Address of first block in sequence. 733 | * \param[in] eraseCount The number of blocks to be pre-erased. 734 | * 735 | * \note This function is used with writeData() and writeStop() 736 | * for optimized multiple block writes. 737 | * 738 | * \return The value one, true, is returned for success and 739 | * the value zero, false, is returned for failure. 740 | */ 741 | uint8_t Sd2Card::writeStart(uint32_t blockNumber, uint32_t eraseCount) { 742 | #if SD_PROTECT_BLOCK_ZERO 743 | // don't allow write to first block 744 | if (blockNumber == 0) { 745 | error(SD_CARD_ERROR_WRITE_BLOCK_ZERO); 746 | goto fail; 747 | } 748 | #endif // SD_PROTECT_BLOCK_ZERO 749 | // send pre-erase count 750 | if (cardAcmd(ACMD23, eraseCount)) { 751 | error(SD_CARD_ERROR_ACMD23); 752 | goto fail; 753 | } 754 | // use address if not SDHC card 755 | if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9; 756 | if (cardCommand(CMD25, blockNumber)) { 757 | error(SD_CARD_ERROR_CMD25); 758 | goto fail; 759 | } 760 | return true; 761 | 762 | fail: 763 | chipSelectHigh(); 764 | return false; 765 | } 766 | //------------------------------------------------------------------------------ 767 | /** End a write multiple blocks sequence. 768 | * 769 | * \return The value one, true, is returned for success and 770 | * the value zero, false, is returned for failure. 771 | */ 772 | uint8_t Sd2Card::writeStop(void) { 773 | if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto fail; 774 | spiSend(STOP_TRAN_TOKEN); 775 | if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto fail; 776 | chipSelectHigh(); 777 | return true; 778 | 779 | fail: 780 | error(SD_CARD_ERROR_STOP_TRAN); 781 | chipSelectHigh(); 782 | return false; 783 | } 784 | 785 | void Sd2Card::enableCRC(uint8_t mode) { 786 | writeCRC_ = mode; 787 | } 788 | 789 | -------------------------------------------------------------------------------- /utility/Sd2Card.h: -------------------------------------------------------------------------------- 1 | /* Arduino Sd2Card Library 2 | * Copyright (C) 2009 by William Greiman 3 | * 4 | * This file is part of the Arduino Sd2Card Library 5 | * 6 | * This Library is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This Library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with the Arduino Sd2Card Library. If not, see 18 | * . 19 | */ 20 | #ifndef Sd2Card_h 21 | #define Sd2Card_h 22 | /** 23 | * \file 24 | * Sd2Card class 25 | */ 26 | #include "Sd2PinMap.h" 27 | #include "SdInfo.h" 28 | /** Set SCK to max rate of F_CPU/2. See Sd2Card::setSckRate(). */ 29 | uint8_t const SPI_FULL_SPEED = 0; 30 | /** Set SCK rate to F_CPU/4. See Sd2Card::setSckRate(). */ 31 | uint8_t const SPI_HALF_SPEED = 1; 32 | /** Set SCK rate to F_CPU/8. Sd2Card::setSckRate(). */ 33 | uint8_t const SPI_QUARTER_SPEED = 2; 34 | /** 35 | * USE_SPI_LIB: if set, use the SPI library bundled with Arduino IDE, otherwise 36 | * run with a standalone driver for AVR. 37 | */ 38 | #define USE_SPI_LIB 39 | /** 40 | * Define MEGA_SOFT_SPI non-zero to use software SPI on Mega Arduinos. 41 | * Pins used are SS 10, MOSI 11, MISO 12, and SCK 13. 42 | * 43 | * MEGA_SOFT_SPI allows an unmodified Adafruit GPS Shield to be used 44 | * on Mega Arduinos. Software SPI works well with GPS Shield V1.1 45 | * but many SD cards will fail with GPS Shield V1.0. 46 | */ 47 | #define MEGA_SOFT_SPI 0 48 | //------------------------------------------------------------------------------ 49 | #if MEGA_SOFT_SPI && (defined(__AVR_ATmega1280__)||defined(__AVR_ATmega2560__)) 50 | #define SOFTWARE_SPI 51 | #endif // MEGA_SOFT_SPI 52 | //------------------------------------------------------------------------------ 53 | // SPI pin definitions 54 | // 55 | #ifndef SOFTWARE_SPI 56 | // hardware pin defs 57 | /** 58 | * SD Chip Select pin 59 | * 60 | * Warning if this pin is redefined the hardware SS will pin will be enabled 61 | * as an output by init(). An avr processor will not function as an SPI 62 | * master unless SS is set to output mode. 63 | */ 64 | /** The default chip select pin for the SD card is SS. */ 65 | uint8_t const SD_CHIP_SELECT_PIN = SS_PIN; 66 | // The following three pins must not be redefined for hardware SPI. 67 | /** SPI Master Out Slave In pin */ 68 | uint8_t const SPI_MOSI_PIN = MOSI_PIN; 69 | /** SPI Master In Slave Out pin */ 70 | uint8_t const SPI_MISO_PIN = MISO_PIN; 71 | /** SPI Clock pin */ 72 | uint8_t const SPI_SCK_PIN = SCK_PIN; 73 | /** optimize loops for hardware SPI */ 74 | #ifndef USE_SPI_LIB 75 | #define OPTIMIZE_HARDWARE_SPI 76 | #endif 77 | 78 | #else // SOFTWARE_SPI 79 | // define software SPI pins so Mega can use unmodified GPS Shield 80 | /** SPI chip select pin */ 81 | uint8_t const SD_CHIP_SELECT_PIN = 10; 82 | /** SPI Master Out Slave In pin */ 83 | uint8_t const SPI_MOSI_PIN = 11; 84 | /** SPI Master In Slave Out pin */ 85 | uint8_t const SPI_MISO_PIN = 12; 86 | /** SPI Clock pin */ 87 | uint8_t const SPI_SCK_PIN = 13; 88 | #endif // SOFTWARE_SPI 89 | //------------------------------------------------------------------------------ 90 | /** Protect block zero from write if nonzero */ 91 | #define SD_PROTECT_BLOCK_ZERO 1 92 | /** init timeout ms */ 93 | uint16_t const SD_INIT_TIMEOUT = 2000; 94 | /** erase timeout ms */ 95 | uint16_t const SD_ERASE_TIMEOUT = 10000; 96 | /** read timeout ms */ 97 | uint16_t const SD_READ_TIMEOUT = 300; 98 | /** write time out ms */ 99 | uint16_t const SD_WRITE_TIMEOUT = 600; 100 | //------------------------------------------------------------------------------ 101 | // SD card errors 102 | /** timeout error for command CMD0 */ 103 | uint8_t const SD_CARD_ERROR_CMD0 = 0X1; 104 | /** CMD8 was not accepted - not a valid SD card*/ 105 | uint8_t const SD_CARD_ERROR_CMD8 = 0X2; 106 | /** card returned an error response for CMD17 (read block) */ 107 | uint8_t const SD_CARD_ERROR_CMD17 = 0X3; 108 | /** card returned an error response for CMD24 (write block) */ 109 | uint8_t const SD_CARD_ERROR_CMD24 = 0X4; 110 | /** WRITE_MULTIPLE_BLOCKS command failed */ 111 | uint8_t const SD_CARD_ERROR_CMD25 = 0X05; 112 | /** card returned an error response for CMD58 (read OCR) */ 113 | uint8_t const SD_CARD_ERROR_CMD58 = 0X06; 114 | /** SET_WR_BLK_ERASE_COUNT failed */ 115 | uint8_t const SD_CARD_ERROR_ACMD23 = 0X07; 116 | /** card's ACMD41 initialization process timeout */ 117 | uint8_t const SD_CARD_ERROR_ACMD41 = 0X08; 118 | /** card returned a bad CSR version field */ 119 | uint8_t const SD_CARD_ERROR_BAD_CSD = 0X09; 120 | /** erase block group command failed */ 121 | uint8_t const SD_CARD_ERROR_ERASE = 0X0A; 122 | /** card not capable of single block erase */ 123 | uint8_t const SD_CARD_ERROR_ERASE_SINGLE_BLOCK = 0X0B; 124 | /** Erase sequence timed out */ 125 | uint8_t const SD_CARD_ERROR_ERASE_TIMEOUT = 0X0C; 126 | /** card returned an error token instead of read data */ 127 | uint8_t const SD_CARD_ERROR_READ = 0X0D; 128 | /** read CID or CSD failed */ 129 | uint8_t const SD_CARD_ERROR_READ_REG = 0X0E; 130 | /** timeout while waiting for start of read data */ 131 | uint8_t const SD_CARD_ERROR_READ_TIMEOUT = 0X0F; 132 | /** card did not accept STOP_TRAN_TOKEN */ 133 | uint8_t const SD_CARD_ERROR_STOP_TRAN = 0X10; 134 | /** card returned an error token as a response to a write operation */ 135 | uint8_t const SD_CARD_ERROR_WRITE = 0X11; 136 | /** attempt to write protected block zero */ 137 | uint8_t const SD_CARD_ERROR_WRITE_BLOCK_ZERO = 0X12; 138 | /** card did not go ready for a multiple block write */ 139 | uint8_t const SD_CARD_ERROR_WRITE_MULTIPLE = 0X13; 140 | /** card returned an error to a CMD13 status check after a write */ 141 | uint8_t const SD_CARD_ERROR_WRITE_PROGRAMMING = 0X14; 142 | /** timeout occurred during write programming */ 143 | uint8_t const SD_CARD_ERROR_WRITE_TIMEOUT = 0X15; 144 | /** incorrect rate selected */ 145 | uint8_t const SD_CARD_ERROR_SCK_RATE = 0X16; 146 | //------------------------------------------------------------------------------ 147 | // card types 148 | /** Standard capacity V1 SD card */ 149 | uint8_t const SD_CARD_TYPE_SD1 = 1; 150 | /** Standard capacity V2 SD card */ 151 | uint8_t const SD_CARD_TYPE_SD2 = 2; 152 | /** High Capacity SD card */ 153 | uint8_t const SD_CARD_TYPE_SDHC = 3; 154 | //------------------------------------------------------------------------------ 155 | /** 156 | * \class Sd2Card 157 | * \brief Raw access to SD and SDHC flash memory cards. 158 | */ 159 | class Sd2Card { 160 | public: 161 | /** Construct an instance of Sd2Card. */ 162 | Sd2Card(void) : errorCode_(0), inBlock_(0), partialBlockRead_(0), type_(0) {} 163 | uint32_t cardSize(void); 164 | uint8_t erase(uint32_t firstBlock, uint32_t lastBlock); 165 | uint8_t eraseSingleBlockEnable(void); 166 | /** 167 | * \return error code for last error. See Sd2Card.h for a list of error codes. 168 | */ 169 | uint8_t errorCode(void) const {return errorCode_;} 170 | /** \return error data for last error. */ 171 | uint8_t errorData(void) const {return status_;} 172 | /** 173 | * Initialize an SD flash memory card with default clock rate and chip 174 | * select pin. See sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin). 175 | */ 176 | uint8_t init(void) { 177 | return init(SPI_FULL_SPEED, SD_CHIP_SELECT_PIN); 178 | } 179 | /** 180 | * Initialize an SD flash memory card with the selected SPI clock rate 181 | * and the default SD chip select pin. 182 | * See sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin). 183 | */ 184 | uint8_t init(uint8_t sckRateID) { 185 | return init(sckRateID, SD_CHIP_SELECT_PIN); 186 | } 187 | uint8_t init(uint8_t sckRateID, uint8_t chipSelectPin, int8_t mosiPin = -1, int8_t misoPin = -1, int8_t clockPin = -1); 188 | void partialBlockRead(uint8_t value); 189 | /** Returns the current value, true or false, for partial block read. */ 190 | uint8_t partialBlockRead(void) const {return partialBlockRead_;} 191 | uint8_t readBlock(uint32_t block, uint8_t* dst); 192 | uint8_t readData(uint32_t block, 193 | uint16_t offset, uint16_t count, uint8_t* dst); 194 | /** 195 | * Read a cards CID register. The CID contains card identification 196 | * information such as Manufacturer ID, Product name, Product serial 197 | * number and Manufacturing date. */ 198 | uint8_t readCID(cid_t* cid) { 199 | return readRegister(CMD10, cid); 200 | } 201 | /** 202 | * Read a cards CSD register. The CSD contains Card-Specific Data that 203 | * provides information regarding access to the card's contents. */ 204 | uint8_t readCSD(csd_t* csd) { 205 | return readRegister(CMD9, csd); 206 | } 207 | void readEnd(void); 208 | uint8_t setSckRate(uint8_t sckRateID); 209 | /** Return the card type: SD V1, SD V2 or SDHC */ 210 | uint8_t type(void) const {return type_;} 211 | uint8_t writeBlock(uint32_t blockNumber, const uint8_t* src); 212 | uint8_t writeData(const uint8_t* src); 213 | uint8_t writeStart(uint32_t blockNumber, uint32_t eraseCount); 214 | uint8_t writeStop(void); 215 | void enableCRC(uint8_t mode); 216 | 217 | private: 218 | uint32_t block_; 219 | uint8_t chipSelectPin_; 220 | uint8_t errorCode_; 221 | uint8_t inBlock_; 222 | uint16_t offset_; 223 | uint8_t partialBlockRead_; 224 | uint8_t status_; 225 | uint8_t type_; 226 | uint8_t writeCRC_; 227 | 228 | 229 | // private functions 230 | uint8_t cardAcmd(uint8_t cmd, uint32_t arg) { 231 | cardCommand(CMD55, 0); 232 | return cardCommand(cmd, arg); 233 | } 234 | uint8_t cardCommand(uint8_t cmd, uint32_t arg); 235 | void error(uint8_t code) {errorCode_ = code;} 236 | uint8_t readRegister(uint8_t cmd, void* buf); 237 | uint8_t sendWriteCommand(uint32_t blockNumber, uint32_t eraseCount); 238 | void chipSelectHigh(void); 239 | void chipSelectLow(void); 240 | void type(uint8_t value) {type_ = value;} 241 | uint8_t waitNotBusy(uint16_t timeoutMillis); 242 | uint8_t writeData(uint8_t token, const uint8_t* src); 243 | uint8_t waitStartBlock(void); 244 | }; 245 | #endif // Sd2Card_h 246 | -------------------------------------------------------------------------------- /utility/Sd2PinMap.h: -------------------------------------------------------------------------------- 1 | /* Arduino SdFat Library 2 | * Copyright (C) 2010 by William Greiman 3 | * 4 | * This file is part of the Arduino SdFat Library 5 | * 6 | * This Library is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This Library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with the Arduino SdFat Library. If not, see 18 | * . 19 | */ 20 | #ifndef Sd2PinMap_h 21 | #define Sd2PinMap_h 22 | 23 | #include 24 | 25 | uint8_t const SS_PIN = SS; 26 | uint8_t const MOSI_PIN = MOSI; 27 | uint8_t const MISO_PIN = MISO; 28 | uint8_t const SCK_PIN = SCK; 29 | 30 | #endif // Sd2PinMap_h 31 | /* Arduino SdFat Library 32 | * Copyright (C) 2010 by William Greiman 33 | * 34 | * This file is part of the Arduino SdFat Library 35 | * 36 | * This Library is free software: you can redistribute it and/or modify 37 | * it under the terms of the GNU General Public License as published by 38 | * the Free Software Foundation, either version 3 of the License, or 39 | * (at your option) any later version. 40 | * 41 | * This Library is distributed in the hope that it will be useful, 42 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 43 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 44 | * GNU General Public License for more details. 45 | * 46 | * You should have received a copy of the GNU General Public License 47 | * along with the Arduino SdFat Library. If not, see 48 | * . 49 | */ 50 | #ifndef ESP32 51 | #if defined(__arm__) // Arduino Due Board follows 52 | 53 | #ifndef Sd2PinMap_h 54 | #define Sd2PinMap_h 55 | 56 | #include 57 | 58 | uint8_t const SS_PIN = SS; 59 | uint8_t const MOSI_PIN = MOSI; 60 | uint8_t const MISO_PIN = MISO; 61 | uint8_t const SCK_PIN = SCK; 62 | 63 | #endif // Sd2PinMap_h 64 | 65 | #elif defined(__AVR__) // Other AVR based Boards follows 66 | 67 | // Warning this file was generated by a program. 68 | #ifndef Sd2PinMap_h 69 | #define Sd2PinMap_h 70 | #include 71 | 72 | //------------------------------------------------------------------------------ 73 | /** struct for mapping digital pins */ 74 | struct pin_map_t { 75 | volatile uint8_t* ddr; 76 | volatile uint8_t* pin; 77 | volatile uint8_t* port; 78 | uint8_t bit; 79 | }; 80 | //------------------------------------------------------------------------------ 81 | #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) 82 | // Mega 83 | 84 | // Two Wire (aka I2C) ports 85 | uint8_t const SDA_PIN = 20; 86 | uint8_t const SCL_PIN = 21; 87 | 88 | // SPI port 89 | uint8_t const SS_PIN = 53; 90 | uint8_t const MOSI_PIN = 51; 91 | uint8_t const MISO_PIN = 50; 92 | uint8_t const SCK_PIN = 52; 93 | 94 | static const pin_map_t digitalPinMap[] = { 95 | {&DDRE, &PINE, &PORTE, 0}, // E0 0 96 | {&DDRE, &PINE, &PORTE, 1}, // E1 1 97 | {&DDRE, &PINE, &PORTE, 4}, // E4 2 98 | {&DDRE, &PINE, &PORTE, 5}, // E5 3 99 | {&DDRG, &PING, &PORTG, 5}, // G5 4 100 | {&DDRE, &PINE, &PORTE, 3}, // E3 5 101 | {&DDRH, &PINH, &PORTH, 3}, // H3 6 102 | {&DDRH, &PINH, &PORTH, 4}, // H4 7 103 | {&DDRH, &PINH, &PORTH, 5}, // H5 8 104 | {&DDRH, &PINH, &PORTH, 6}, // H6 9 105 | {&DDRB, &PINB, &PORTB, 4}, // B4 10 106 | {&DDRB, &PINB, &PORTB, 5}, // B5 11 107 | {&DDRB, &PINB, &PORTB, 6}, // B6 12 108 | {&DDRB, &PINB, &PORTB, 7}, // B7 13 109 | {&DDRJ, &PINJ, &PORTJ, 1}, // J1 14 110 | {&DDRJ, &PINJ, &PORTJ, 0}, // J0 15 111 | {&DDRH, &PINH, &PORTH, 1}, // H1 16 112 | {&DDRH, &PINH, &PORTH, 0}, // H0 17 113 | {&DDRD, &PIND, &PORTD, 3}, // D3 18 114 | {&DDRD, &PIND, &PORTD, 2}, // D2 19 115 | {&DDRD, &PIND, &PORTD, 1}, // D1 20 116 | {&DDRD, &PIND, &PORTD, 0}, // D0 21 117 | {&DDRA, &PINA, &PORTA, 0}, // A0 22 118 | {&DDRA, &PINA, &PORTA, 1}, // A1 23 119 | {&DDRA, &PINA, &PORTA, 2}, // A2 24 120 | {&DDRA, &PINA, &PORTA, 3}, // A3 25 121 | {&DDRA, &PINA, &PORTA, 4}, // A4 26 122 | {&DDRA, &PINA, &PORTA, 5}, // A5 27 123 | {&DDRA, &PINA, &PORTA, 6}, // A6 28 124 | {&DDRA, &PINA, &PORTA, 7}, // A7 29 125 | {&DDRC, &PINC, &PORTC, 7}, // C7 30 126 | {&DDRC, &PINC, &PORTC, 6}, // C6 31 127 | {&DDRC, &PINC, &PORTC, 5}, // C5 32 128 | {&DDRC, &PINC, &PORTC, 4}, // C4 33 129 | {&DDRC, &PINC, &PORTC, 3}, // C3 34 130 | {&DDRC, &PINC, &PORTC, 2}, // C2 35 131 | {&DDRC, &PINC, &PORTC, 1}, // C1 36 132 | {&DDRC, &PINC, &PORTC, 0}, // C0 37 133 | {&DDRD, &PIND, &PORTD, 7}, // D7 38 134 | {&DDRG, &PING, &PORTG, 2}, // G2 39 135 | {&DDRG, &PING, &PORTG, 1}, // G1 40 136 | {&DDRG, &PING, &PORTG, 0}, // G0 41 137 | {&DDRL, &PINL, &PORTL, 7}, // L7 42 138 | {&DDRL, &PINL, &PORTL, 6}, // L6 43 139 | {&DDRL, &PINL, &PORTL, 5}, // L5 44 140 | {&DDRL, &PINL, &PORTL, 4}, // L4 45 141 | {&DDRL, &PINL, &PORTL, 3}, // L3 46 142 | {&DDRL, &PINL, &PORTL, 2}, // L2 47 143 | {&DDRL, &PINL, &PORTL, 1}, // L1 48 144 | {&DDRL, &PINL, &PORTL, 0}, // L0 49 145 | {&DDRB, &PINB, &PORTB, 3}, // B3 50 146 | {&DDRB, &PINB, &PORTB, 2}, // B2 51 147 | {&DDRB, &PINB, &PORTB, 1}, // B1 52 148 | {&DDRB, &PINB, &PORTB, 0}, // B0 53 149 | {&DDRF, &PINF, &PORTF, 0}, // F0 54 150 | {&DDRF, &PINF, &PORTF, 1}, // F1 55 151 | {&DDRF, &PINF, &PORTF, 2}, // F2 56 152 | {&DDRF, &PINF, &PORTF, 3}, // F3 57 153 | {&DDRF, &PINF, &PORTF, 4}, // F4 58 154 | {&DDRF, &PINF, &PORTF, 5}, // F5 59 155 | {&DDRF, &PINF, &PORTF, 6}, // F6 60 156 | {&DDRF, &PINF, &PORTF, 7}, // F7 61 157 | {&DDRK, &PINK, &PORTK, 0}, // K0 62 158 | {&DDRK, &PINK, &PORTK, 1}, // K1 63 159 | {&DDRK, &PINK, &PORTK, 2}, // K2 64 160 | {&DDRK, &PINK, &PORTK, 3}, // K3 65 161 | {&DDRK, &PINK, &PORTK, 4}, // K4 66 162 | {&DDRK, &PINK, &PORTK, 5}, // K5 67 163 | {&DDRK, &PINK, &PORTK, 6}, // K6 68 164 | {&DDRK, &PINK, &PORTK, 7} // K7 69 165 | }; 166 | //------------------------------------------------------------------------------ 167 | #elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__) 168 | // Sanguino 169 | 170 | // Two Wire (aka I2C) ports 171 | uint8_t const SDA_PIN = 17; 172 | uint8_t const SCL_PIN = 18; 173 | 174 | // SPI port 175 | uint8_t const SS_PIN = 4; 176 | uint8_t const MOSI_PIN = 5; 177 | uint8_t const MISO_PIN = 6; 178 | uint8_t const SCK_PIN = 7; 179 | 180 | static const pin_map_t digitalPinMap[] = { 181 | {&DDRB, &PINB, &PORTB, 0}, // B0 0 182 | {&DDRB, &PINB, &PORTB, 1}, // B1 1 183 | {&DDRB, &PINB, &PORTB, 2}, // B2 2 184 | {&DDRB, &PINB, &PORTB, 3}, // B3 3 185 | {&DDRB, &PINB, &PORTB, 4}, // B4 4 186 | {&DDRB, &PINB, &PORTB, 5}, // B5 5 187 | {&DDRB, &PINB, &PORTB, 6}, // B6 6 188 | {&DDRB, &PINB, &PORTB, 7}, // B7 7 189 | {&DDRD, &PIND, &PORTD, 0}, // D0 8 190 | {&DDRD, &PIND, &PORTD, 1}, // D1 9 191 | {&DDRD, &PIND, &PORTD, 2}, // D2 10 192 | {&DDRD, &PIND, &PORTD, 3}, // D3 11 193 | {&DDRD, &PIND, &PORTD, 4}, // D4 12 194 | {&DDRD, &PIND, &PORTD, 5}, // D5 13 195 | {&DDRD, &PIND, &PORTD, 6}, // D6 14 196 | {&DDRD, &PIND, &PORTD, 7}, // D7 15 197 | {&DDRC, &PINC, &PORTC, 0}, // C0 16 198 | {&DDRC, &PINC, &PORTC, 1}, // C1 17 199 | {&DDRC, &PINC, &PORTC, 2}, // C2 18 200 | {&DDRC, &PINC, &PORTC, 3}, // C3 19 201 | {&DDRC, &PINC, &PORTC, 4}, // C4 20 202 | {&DDRC, &PINC, &PORTC, 5}, // C5 21 203 | {&DDRC, &PINC, &PORTC, 6}, // C6 22 204 | {&DDRC, &PINC, &PORTC, 7}, // C7 23 205 | {&DDRA, &PINA, &PORTA, 7}, // A7 24 206 | {&DDRA, &PINA, &PORTA, 6}, // A6 25 207 | {&DDRA, &PINA, &PORTA, 5}, // A5 26 208 | {&DDRA, &PINA, &PORTA, 4}, // A4 27 209 | {&DDRA, &PINA, &PORTA, 3}, // A3 28 210 | {&DDRA, &PINA, &PORTA, 2}, // A2 29 211 | {&DDRA, &PINA, &PORTA, 1}, // A1 30 212 | {&DDRA, &PINA, &PORTA, 0} // A0 31 213 | }; 214 | //------------------------------------------------------------------------------ 215 | #elif defined(__AVR_ATmega32U4__) 216 | // Leonardo 217 | 218 | // Two Wire (aka I2C) ports 219 | uint8_t const SDA_PIN = 2; 220 | uint8_t const SCL_PIN = 3; 221 | 222 | // SPI port 223 | uint8_t const SS_PIN = 17; 224 | uint8_t const MOSI_PIN = 16; 225 | uint8_t const MISO_PIN = 14; 226 | uint8_t const SCK_PIN = 15; 227 | 228 | static const pin_map_t digitalPinMap[] = { 229 | {&DDRD, &PIND, &PORTD, 2}, // D2 0 230 | {&DDRD, &PIND, &PORTD, 3}, // D3 1 231 | {&DDRD, &PIND, &PORTD, 1}, // D1 2 232 | {&DDRD, &PIND, &PORTD, 0}, // D0 3 233 | {&DDRD, &PIND, &PORTD, 4}, // D4 4 234 | {&DDRC, &PINC, &PORTC, 6}, // C6 5 235 | {&DDRD, &PIND, &PORTD, 7}, // D7 6 236 | {&DDRE, &PINE, &PORTE, 6}, // E6 7 237 | {&DDRB, &PINB, &PORTB, 4}, // B4 8 238 | {&DDRB, &PINB, &PORTB, 5}, // B5 9 239 | {&DDRB, &PINB, &PORTB, 6}, // B6 10 240 | {&DDRB, &PINB, &PORTB, 7}, // B7 11 241 | {&DDRD, &PIND, &PORTD, 6}, // D6 12 242 | {&DDRC, &PINC, &PORTC, 7}, // C7 13 243 | {&DDRB, &PINB, &PORTB, 3}, // B3 14 244 | {&DDRB, &PINB, &PORTB, 1}, // B1 15 245 | {&DDRB, &PINB, &PORTB, 2}, // B2 16 246 | {&DDRB, &PINB, &PORTB, 0}, // B0 17 247 | {&DDRF, &PINF, &PORTF, 7}, // F7 18 248 | {&DDRF, &PINF, &PORTF, 6}, // F6 19 249 | {&DDRF, &PINF, &PORTF, 5}, // F5 20 250 | {&DDRF, &PINF, &PORTF, 4}, // F4 21 251 | {&DDRF, &PINF, &PORTF, 1}, // F1 22 252 | {&DDRF, &PINF, &PORTF, 0}, // F0 23 253 | }; 254 | //------------------------------------------------------------------------------ 255 | #elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__) 256 | // Teensy++ 1.0 & 2.0 257 | 258 | // Two Wire (aka I2C) ports 259 | uint8_t const SDA_PIN = 1; 260 | uint8_t const SCL_PIN = 0; 261 | 262 | // SPI port 263 | uint8_t const SS_PIN = 20; 264 | uint8_t const MOSI_PIN = 22; 265 | uint8_t const MISO_PIN = 23; 266 | uint8_t const SCK_PIN = 21; 267 | 268 | static const pin_map_t digitalPinMap[] = { 269 | {&DDRD, &PIND, &PORTD, 0}, // D0 0 270 | {&DDRD, &PIND, &PORTD, 1}, // D1 1 271 | {&DDRD, &PIND, &PORTD, 2}, // D2 2 272 | {&DDRD, &PIND, &PORTD, 3}, // D3 3 273 | {&DDRD, &PIND, &PORTD, 4}, // D4 4 274 | {&DDRD, &PIND, &PORTD, 5}, // D5 5 275 | {&DDRD, &PIND, &PORTD, 6}, // D6 6 276 | {&DDRD, &PIND, &PORTD, 7}, // D7 7 277 | {&DDRE, &PINE, &PORTE, 0}, // E0 8 278 | {&DDRE, &PINE, &PORTE, 1}, // E1 9 279 | {&DDRC, &PINC, &PORTC, 0}, // C0 10 280 | {&DDRC, &PINC, &PORTC, 1}, // C1 11 281 | {&DDRC, &PINC, &PORTC, 2}, // C2 12 282 | {&DDRC, &PINC, &PORTC, 3}, // C3 13 283 | {&DDRC, &PINC, &PORTC, 4}, // C4 14 284 | {&DDRC, &PINC, &PORTC, 5}, // C5 15 285 | {&DDRC, &PINC, &PORTC, 6}, // C6 16 286 | {&DDRC, &PINC, &PORTC, 7}, // C7 17 287 | {&DDRE, &PINE, &PORTE, 6}, // E6 18 288 | {&DDRE, &PINE, &PORTE, 7}, // E7 19 289 | {&DDRB, &PINB, &PORTB, 0}, // B0 20 290 | {&DDRB, &PINB, &PORTB, 1}, // B1 21 291 | {&DDRB, &PINB, &PORTB, 2}, // B2 22 292 | {&DDRB, &PINB, &PORTB, 3}, // B3 23 293 | {&DDRB, &PINB, &PORTB, 4}, // B4 24 294 | {&DDRB, &PINB, &PORTB, 5}, // B5 25 295 | {&DDRB, &PINB, &PORTB, 6}, // B6 26 296 | {&DDRB, &PINB, &PORTB, 7}, // B7 27 297 | {&DDRA, &PINA, &PORTA, 0}, // A0 28 298 | {&DDRA, &PINA, &PORTA, 1}, // A1 29 299 | {&DDRA, &PINA, &PORTA, 2}, // A2 30 300 | {&DDRA, &PINA, &PORTA, 3}, // A3 31 301 | {&DDRA, &PINA, &PORTA, 4}, // A4 32 302 | {&DDRA, &PINA, &PORTA, 5}, // A5 33 303 | {&DDRA, &PINA, &PORTA, 6}, // A6 34 304 | {&DDRA, &PINA, &PORTA, 7}, // A7 35 305 | {&DDRE, &PINE, &PORTE, 4}, // E4 36 306 | {&DDRE, &PINE, &PORTE, 5}, // E5 37 307 | {&DDRF, &PINF, &PORTF, 0}, // F0 38 308 | {&DDRF, &PINF, &PORTF, 1}, // F1 39 309 | {&DDRF, &PINF, &PORTF, 2}, // F2 40 310 | {&DDRF, &PINF, &PORTF, 3}, // F3 41 311 | {&DDRF, &PINF, &PORTF, 4}, // F4 42 312 | {&DDRF, &PINF, &PORTF, 5}, // F5 43 313 | {&DDRF, &PINF, &PORTF, 6}, // F6 44 314 | {&DDRF, &PINF, &PORTF, 7} // F7 45 315 | }; 316 | //------------------------------------------------------------------------------ 317 | #else // defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) 318 | // 168 and 328 Arduinos 319 | 320 | // Two Wire (aka I2C) ports 321 | uint8_t const SDA_PIN = 18; 322 | uint8_t const SCL_PIN = 19; 323 | 324 | // SPI port 325 | uint8_t const SS_PIN = 10; 326 | uint8_t const MOSI_PIN = 11; 327 | uint8_t const MISO_PIN = 12; 328 | uint8_t const SCK_PIN = 13; 329 | 330 | static const pin_map_t digitalPinMap[] = { 331 | {&DDRD, &PIND, &PORTD, 0}, // D0 0 332 | {&DDRD, &PIND, &PORTD, 1}, // D1 1 333 | {&DDRD, &PIND, &PORTD, 2}, // D2 2 334 | {&DDRD, &PIND, &PORTD, 3}, // D3 3 335 | {&DDRD, &PIND, &PORTD, 4}, // D4 4 336 | {&DDRD, &PIND, &PORTD, 5}, // D5 5 337 | {&DDRD, &PIND, &PORTD, 6}, // D6 6 338 | {&DDRD, &PIND, &PORTD, 7}, // D7 7 339 | {&DDRB, &PINB, &PORTB, 0}, // B0 8 340 | {&DDRB, &PINB, &PORTB, 1}, // B1 9 341 | {&DDRB, &PINB, &PORTB, 2}, // B2 10 342 | {&DDRB, &PINB, &PORTB, 3}, // B3 11 343 | {&DDRB, &PINB, &PORTB, 4}, // B4 12 344 | {&DDRB, &PINB, &PORTB, 5}, // B5 13 345 | {&DDRC, &PINC, &PORTC, 0}, // C0 14 346 | {&DDRC, &PINC, &PORTC, 1}, // C1 15 347 | {&DDRC, &PINC, &PORTC, 2}, // C2 16 348 | {&DDRC, &PINC, &PORTC, 3}, // C3 17 349 | {&DDRC, &PINC, &PORTC, 4}, // C4 18 350 | {&DDRC, &PINC, &PORTC, 5} // C5 19 351 | }; 352 | #endif // defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) 353 | //------------------------------------------------------------------------------ 354 | static const uint8_t digitalPinCount = sizeof(digitalPinMap)/sizeof(pin_map_t); 355 | 356 | uint8_t badPinNumber(void) 357 | __attribute__((error("Pin number is too large or not a constant"))); 358 | 359 | static inline __attribute__((always_inline)) 360 | uint8_t getPinMode(uint8_t pin) { 361 | if (__builtin_constant_p(pin) && pin < digitalPinCount) { 362 | return (*digitalPinMap[pin].ddr >> digitalPinMap[pin].bit) & 1; 363 | } else { 364 | return badPinNumber(); 365 | } 366 | } 367 | static inline __attribute__((always_inline)) 368 | void setPinMode(uint8_t pin, uint8_t mode) { 369 | if (__builtin_constant_p(pin) && pin < digitalPinCount) { 370 | if (mode) { 371 | *digitalPinMap[pin].ddr |= 1 << digitalPinMap[pin].bit; 372 | } else { 373 | *digitalPinMap[pin].ddr &= ~(1 << digitalPinMap[pin].bit); 374 | } 375 | } else { 376 | badPinNumber(); 377 | } 378 | } 379 | static inline __attribute__((always_inline)) 380 | uint8_t fastDigitalRead(uint8_t pin) { 381 | if (__builtin_constant_p(pin) && pin < digitalPinCount) { 382 | return (*digitalPinMap[pin].pin >> digitalPinMap[pin].bit) & 1; 383 | } else { 384 | return badPinNumber(); 385 | } 386 | } 387 | static inline __attribute__((always_inline)) 388 | void fastDigitalWrite(uint8_t pin, uint8_t value) { 389 | if (__builtin_constant_p(pin) && pin < digitalPinCount) { 390 | if (value) { 391 | *digitalPinMap[pin].port |= 1 << digitalPinMap[pin].bit; 392 | } else { 393 | *digitalPinMap[pin].port &= ~(1 << digitalPinMap[pin].bit); 394 | } 395 | } else { 396 | badPinNumber(); 397 | } 398 | } 399 | #endif // Sd2PinMap_h 400 | 401 | #else 402 | #error Architecture or board not supported. 403 | #endif 404 | #else 405 | #ifndef Sd2PinMap_h 406 | #define Sd2PinMap_h 407 | 408 | #include 409 | 410 | uint8_t const SS_PIN = SS; 411 | uint8_t const MOSI_PIN = MOSI; 412 | uint8_t const MISO_PIN = MISO; 413 | uint8_t const SCK_PIN = SCK; 414 | 415 | #endif // Sd2PinMap_h 416 | #endif 417 | -------------------------------------------------------------------------------- /utility/SdFat.h: -------------------------------------------------------------------------------- 1 | /* Arduino SdFat Library 2 | * Copyright (C) 2009 by William Greiman 3 | * 4 | * This file is part of the Arduino SdFat Library 5 | * 6 | * This Library is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This Library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with the Arduino SdFat Library. If not, see 18 | * . 19 | */ 20 | #ifndef SdFat_h 21 | #define SdFat_h 22 | /** 23 | * \file 24 | * SdFile and SdVolume classes 25 | */ 26 | #ifdef __AVR__ 27 | #include 28 | #endif 29 | #include "Sd2Card.h" 30 | #include "FatStructs.h" 31 | #include "Print.h" 32 | //------------------------------------------------------------------------------ 33 | /** 34 | * Allow use of deprecated functions if non-zero 35 | */ 36 | #define ALLOW_DEPRECATED_FUNCTIONS 1 37 | //------------------------------------------------------------------------------ 38 | // forward declaration since SdVolume is used in SdFile 39 | class SdVolume; 40 | //============================================================================== 41 | // SdFile class 42 | 43 | // flags for ls() 44 | /** ls() flag to print modify date */ 45 | #define LS_DATE 1 46 | /** ls() flag to print file size */ 47 | #define LS_SIZE 2 48 | /** ls() flag for recursive list of subdirectories */ 49 | #define LS_R 4 50 | 51 | // use the gnu style oflag in open() 52 | /** open() oflag for reading */ 53 | #define F_READ 0X01 54 | /** open() oflag - same as F_READ */ 55 | #define F_RDONLY F_READ 56 | /** open() oflag for write */ 57 | #define F_WRITE 0X02 58 | /** open() oflag - same as F_WRITE */ 59 | #define F_WRONLY F_WRITE 60 | /** open() oflag for reading and writing */ 61 | #define F_RDWR (F_READ | F_WRITE) 62 | /** open() oflag mask for access modes */ 63 | #define F_ACCMODE (F_READ | F_WRITE) 64 | /** The file offset shall be set to the end of the file prior to each write. */ 65 | #define F_APPEND 0X04 66 | /** synchronous writes - call sync() after each write */ 67 | #define F_SYNC 0X08 68 | /** create the file if nonexistent */ 69 | #define F_CREAT 0X10 70 | /** If F_CREAT and F_EXCL are set, open() shall fail if the file exists */ 71 | #define F_EXCL 0X20 72 | /** truncate the file to zero length */ 73 | #define F_TRUNC 0X40 74 | 75 | // flags for timestamp 76 | /** set the file's last access date */ 77 | #define T_ACCESS 1 78 | /** set the file's creation date and time */ 79 | #define T_CREATE 2 80 | /** Set the file's write date and time */ 81 | #define T_WRITE 4 82 | // values for type_ 83 | /** This SdFile has not been opened. */ 84 | #define FAT_FILE_TYPE_CLOSED 0 85 | /** SdFile for a file */ 86 | #define FAT_FILE_TYPE_NORMAL 1 87 | /** SdFile for a FAT16 root directory */ 88 | #define FAT_FILE_TYPE_ROOT16 2 89 | /** SdFile for a FAT32 root directory */ 90 | #define FAT_FILE_TYPE_ROOT32 3 91 | /** SdFile for a subdirectory */ 92 | #define FAT_FILE_TYPE_SUBDIR 4 93 | /** Test value for directory type */ 94 | #define FAT_FILE_TYPE_MIN_DIR FAT_FILE_TYPE_ROOT16 95 | 96 | /** date field for FAT directory entry */ 97 | static inline uint16_t FAT_DATE(uint16_t year, uint8_t month, uint8_t day) { 98 | return (year - 1980) << 9 | month << 5 | day; 99 | } 100 | /** year part of FAT directory date field */ 101 | static inline uint16_t FAT_YEAR(uint16_t fatDate) { 102 | return 1980 + (fatDate >> 9); 103 | } 104 | /** month part of FAT directory date field */ 105 | static inline uint8_t FAT_MONTH(uint16_t fatDate) { 106 | return (fatDate >> 5) & 0XF; 107 | } 108 | /** day part of FAT directory date field */ 109 | static inline uint8_t FAT_DAY(uint16_t fatDate) { 110 | return fatDate & 0X1F; 111 | } 112 | /** time field for FAT directory entry */ 113 | static inline uint16_t FAT_TIME(uint8_t hour, uint8_t minute, uint8_t second) { 114 | return hour << 11 | minute << 5 | second >> 1; 115 | } 116 | /** hour part of FAT directory time field */ 117 | static inline uint8_t FAT_HOUR(uint16_t fatTime) { 118 | return fatTime >> 11; 119 | } 120 | /** minute part of FAT directory time field */ 121 | static inline uint8_t FAT_MINUTE(uint16_t fatTime) { 122 | return(fatTime >> 5) & 0X3F; 123 | } 124 | /** second part of FAT directory time field */ 125 | static inline uint8_t FAT_SECOND(uint16_t fatTime) { 126 | return 2*(fatTime & 0X1F); 127 | } 128 | /** Default date for file timestamps is 1 Jan 2000 */ 129 | uint16_t const FAT_DEFAULT_DATE = ((2000 - 1980) << 9) | (1 << 5) | 1; 130 | /** Default time for file timestamp is 1 am */ 131 | uint16_t const FAT_DEFAULT_TIME = (1 << 11); 132 | //------------------------------------------------------------------------------ 133 | /** 134 | * \class SdFile 135 | * \brief Access FAT16 and FAT32 files on SD and SDHC cards. 136 | */ 137 | class SdFile : public Print { 138 | public: 139 | /** Create an instance of SdFile. */ 140 | SdFile(void) : type_(FAT_FILE_TYPE_CLOSED) {} 141 | /** 142 | * writeError is set to true if an error occurs during a write(). 143 | * Set writeError to false before calling print() and/or write() and check 144 | * for true after calls to print() and/or write(). 145 | */ 146 | //bool writeError; 147 | /** 148 | * Cancel unbuffered reads for this file. 149 | * See setUnbufferedRead() 150 | */ 151 | void clearUnbufferedRead(void) { 152 | flags_ &= ~F_FILE_UNBUFFERED_READ; 153 | } 154 | uint8_t close(void); 155 | uint8_t contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock); 156 | uint8_t createContiguous(SdFile* dirFile, 157 | const char* fileName, uint32_t size); 158 | /** \return The current cluster number for a file or directory. */ 159 | uint32_t curCluster(void) const {return curCluster_;} 160 | /** \return The current position for a file or directory. */ 161 | uint32_t curPosition(void) const {return curPosition_;} 162 | /** 163 | * Set the date/time callback function 164 | * 165 | * \param[in] dateTime The user's call back function. The callback 166 | * function is of the form: 167 | * 168 | * \code 169 | * void dateTime(uint16_t* date, uint16_t* time) { 170 | * uint16_t year; 171 | * uint8_t month, day, hour, minute, second; 172 | * 173 | * // User gets date and time from GPS or real-time clock here 174 | * 175 | * // return date using FAT_DATE macro to format fields 176 | * *date = FAT_DATE(year, month, day); 177 | * 178 | * // return time using FAT_TIME macro to format fields 179 | * *time = FAT_TIME(hour, minute, second); 180 | * } 181 | * \endcode 182 | * 183 | * Sets the function that is called when a file is created or when 184 | * a file's directory entry is modified by sync(). All timestamps, 185 | * access, creation, and modify, are set when a file is created. 186 | * sync() maintains the last access date and last modify date/time. 187 | * 188 | * See the timestamp() function. 189 | */ 190 | static void dateTimeCallback( 191 | void (*dateTime)(uint16_t* date, uint16_t* time)) { 192 | dateTime_ = dateTime; 193 | } 194 | /** 195 | * Cancel the date/time callback function. 196 | */ 197 | static void dateTimeCallbackCancel(void) { 198 | // use explicit zero since NULL is not defined for Sanguino 199 | dateTime_ = 0; 200 | } 201 | /** \return Address of the block that contains this file's directory. */ 202 | uint32_t dirBlock(void) const {return dirBlock_;} 203 | uint8_t dirEntry(dir_t* dir); 204 | /** \return Index of this file's directory in the block dirBlock. */ 205 | uint8_t dirIndex(void) const {return dirIndex_;} 206 | static void dirName(const dir_t& dir, char* name); 207 | /** \return The total number of bytes in a file or directory. */ 208 | uint32_t fileSize(void) const {return fileSize_;} 209 | /** \return The first cluster number for a file or directory. */ 210 | uint32_t firstCluster(void) const {return firstCluster_;} 211 | /** \return True if this is a SdFile for a directory else false. */ 212 | uint8_t isDir(void) const {return type_ >= FAT_FILE_TYPE_MIN_DIR;} 213 | /** \return True if this is a SdFile for a file else false. */ 214 | uint8_t isFile(void) const {return type_ == FAT_FILE_TYPE_NORMAL;} 215 | /** \return True if this is a SdFile for an open file/directory else false. */ 216 | uint8_t isOpen(void) const {return type_ != FAT_FILE_TYPE_CLOSED;} 217 | /** \return True if this is a SdFile for a subdirectory else false. */ 218 | uint8_t isSubDir(void) const {return type_ == FAT_FILE_TYPE_SUBDIR;} 219 | /** \return True if this is a SdFile for the root directory. */ 220 | uint8_t isRoot(void) const { 221 | return type_ == FAT_FILE_TYPE_ROOT16 || type_ == FAT_FILE_TYPE_ROOT32; 222 | } 223 | void ls(uint8_t flags = 0, uint8_t indent = 0); 224 | uint8_t makeDir(SdFile* dir, const char* dirName); 225 | uint8_t open(SdFile* dirFile, uint16_t index, uint8_t oflag); 226 | uint8_t open(SdFile* dirFile, const char* fileName, uint8_t oflag); 227 | 228 | uint8_t openRoot(SdVolume* vol); 229 | static void printDirName(const dir_t& dir, uint8_t width); 230 | static void printFatDate(uint16_t fatDate); 231 | static void printFatTime(uint16_t fatTime); 232 | static void printTwoDigits(uint8_t v); 233 | /** 234 | * Read the next byte from a file. 235 | * 236 | * \return For success read returns the next byte in the file as an int. 237 | * If an error occurs or end of file is reached -1 is returned. 238 | */ 239 | int16_t read(void) { 240 | uint8_t b; 241 | return read(&b, 1) == 1 ? b : -1; 242 | } 243 | int16_t read(void* buf, uint16_t nbyte); 244 | int8_t readDir(dir_t* dir); 245 | static uint8_t remove(SdFile* dirFile, const char* fileName); 246 | uint8_t remove(void); 247 | /** Set the file's current position to zero. */ 248 | void rewind(void) { 249 | curPosition_ = curCluster_ = 0; 250 | } 251 | uint8_t rmDir(void); 252 | uint8_t rmRfStar(void); 253 | /** Set the files position to current position + \a pos. See seekSet(). */ 254 | uint8_t seekCur(uint32_t pos) { 255 | return seekSet(curPosition_ + pos); 256 | } 257 | /** 258 | * Set the files current position to end of file. Useful to position 259 | * a file for append. See seekSet(). 260 | */ 261 | uint8_t seekEnd(void) {return seekSet(fileSize_);} 262 | uint8_t seekSet(uint32_t pos); 263 | /** 264 | * Use unbuffered reads to access this file. Used with Wave 265 | * Shield ISR. Used with Sd2Card::partialBlockRead() in WaveRP. 266 | * 267 | * Not recommended for normal applications. 268 | */ 269 | void setUnbufferedRead(void) { 270 | if (isFile()) flags_ |= F_FILE_UNBUFFERED_READ; 271 | } 272 | uint8_t timestamp(uint8_t flag, uint16_t year, uint8_t month, uint8_t day, 273 | uint8_t hour, uint8_t minute, uint8_t second); 274 | uint8_t sync(void); 275 | /** Type of this SdFile. You should use isFile() or isDir() instead of type() 276 | * if possible. 277 | * 278 | * \return The file or directory type. 279 | */ 280 | uint8_t type(void) const {return type_;} 281 | uint8_t truncate(uint32_t size); 282 | /** \return Unbuffered read flag. */ 283 | uint8_t unbufferedRead(void) const { 284 | return flags_ & F_FILE_UNBUFFERED_READ; 285 | } 286 | /** \return SdVolume that contains this file. */ 287 | SdVolume* volume(void) const {return vol_;} 288 | size_t write(uint8_t b); 289 | size_t write(const void* buf, uint16_t nbyte); 290 | size_t write(const char* str); 291 | #ifdef __AVR__ 292 | void write_P(PGM_P str); 293 | void writeln_P(PGM_P str); 294 | #endif 295 | //------------------------------------------------------------------------------ 296 | #if ALLOW_DEPRECATED_FUNCTIONS 297 | // Deprecated functions - suppress cpplint warnings with NOLINT comment 298 | /** \deprecated Use: 299 | * uint8_t SdFile::contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock); 300 | */ 301 | uint8_t contiguousRange(uint32_t& bgnBlock, uint32_t& endBlock) { // NOLINT 302 | return contiguousRange(&bgnBlock, &endBlock); 303 | } 304 | /** \deprecated Use: 305 | * uint8_t SdFile::createContiguous(SdFile* dirFile, 306 | * const char* fileName, uint32_t size) 307 | */ 308 | uint8_t createContiguous(SdFile& dirFile, // NOLINT 309 | const char* fileName, uint32_t size) { 310 | return createContiguous(&dirFile, fileName, size); 311 | } 312 | 313 | /** 314 | * \deprecated Use: 315 | * static void SdFile::dateTimeCallback( 316 | * void (*dateTime)(uint16_t* date, uint16_t* time)); 317 | */ 318 | static void dateTimeCallback( 319 | void (*dateTime)(uint16_t& date, uint16_t& time)) { // NOLINT 320 | oldDateTime_ = dateTime; 321 | dateTime_ = dateTime ? oldToNew : 0; 322 | } 323 | /** \deprecated Use: uint8_t SdFile::dirEntry(dir_t* dir); */ 324 | uint8_t dirEntry(dir_t& dir) {return dirEntry(&dir);} // NOLINT 325 | /** \deprecated Use: 326 | * uint8_t SdFile::makeDir(SdFile* dir, const char* dirName); 327 | */ 328 | uint8_t makeDir(SdFile& dir, const char* dirName) { // NOLINT 329 | return makeDir(&dir, dirName); 330 | } 331 | /** \deprecated Use: 332 | * uint8_t SdFile::open(SdFile* dirFile, const char* fileName, uint8_t oflag); 333 | */ 334 | uint8_t open(SdFile& dirFile, // NOLINT 335 | const char* fileName, uint8_t oflag) { 336 | return open(&dirFile, fileName, oflag); 337 | } 338 | /** \deprecated Do not use in new apps */ 339 | uint8_t open(SdFile& dirFile, const char* fileName) { // NOLINT 340 | return open(dirFile, fileName, F_RDWR); 341 | } 342 | /** \deprecated Use: 343 | * uint8_t SdFile::open(SdFile* dirFile, uint16_t index, uint8_t oflag); 344 | */ 345 | uint8_t open(SdFile& dirFile, uint16_t index, uint8_t oflag) { // NOLINT 346 | return open(&dirFile, index, oflag); 347 | } 348 | /** \deprecated Use: uint8_t SdFile::openRoot(SdVolume* vol); */ 349 | uint8_t openRoot(SdVolume& vol) {return openRoot(&vol);} // NOLINT 350 | 351 | /** \deprecated Use: int8_t SdFile::readDir(dir_t* dir); */ 352 | int8_t readDir(dir_t& dir) {return readDir(&dir);} // NOLINT 353 | /** \deprecated Use: 354 | * static uint8_t SdFile::remove(SdFile* dirFile, const char* fileName); 355 | */ 356 | static uint8_t remove(SdFile& dirFile, const char* fileName) { // NOLINT 357 | return remove(&dirFile, fileName); 358 | } 359 | //------------------------------------------------------------------------------ 360 | // rest are private 361 | private: 362 | static void (*oldDateTime_)(uint16_t& date, uint16_t& time); // NOLINT 363 | static void oldToNew(uint16_t* date, uint16_t* time) { 364 | uint16_t d; 365 | uint16_t t; 366 | oldDateTime_(d, t); 367 | *date = d; 368 | *time = t; 369 | } 370 | #endif // ALLOW_DEPRECATED_FUNCTIONS 371 | private: 372 | // bits defined in flags_ 373 | // should be 0XF 374 | static uint8_t const F_OFLAG = (F_ACCMODE | F_APPEND | F_SYNC); 375 | // available bits 376 | static uint8_t const F_UNUSED = 0X30; 377 | // use unbuffered SD read 378 | static uint8_t const F_FILE_UNBUFFERED_READ = 0X40; 379 | // sync of directory entry required 380 | static uint8_t const F_FILE_DIR_DIRTY = 0X80; 381 | 382 | // make sure F_OFLAG is ok 383 | #if ((F_UNUSED | F_FILE_UNBUFFERED_READ | F_FILE_DIR_DIRTY) & F_OFLAG) 384 | #error flags_ bits conflict 385 | #endif // flags_ bits 386 | 387 | // private data 388 | uint8_t flags_; // See above for definition of flags_ bits 389 | uint8_t type_; // type of file see above for values 390 | uint32_t curCluster_; // cluster for current file position 391 | uint32_t curPosition_; // current file position in bytes from beginning 392 | uint32_t dirBlock_; // SD block that contains directory entry for file 393 | uint8_t dirIndex_; // index of entry in dirBlock 0 <= dirIndex_ <= 0XF 394 | uint32_t fileSize_; // file size in bytes 395 | uint32_t firstCluster_; // first cluster of file 396 | SdVolume* vol_; // volume where file is located 397 | 398 | // private functions 399 | uint8_t addCluster(void); 400 | uint8_t addDirCluster(void); 401 | dir_t* cacheDirEntry(uint8_t action); 402 | static void (*dateTime_)(uint16_t* date, uint16_t* time); 403 | static uint8_t make83Name(const char* str, uint8_t* name); 404 | uint8_t openCachedEntry(uint8_t cacheIndex, uint8_t oflags); 405 | dir_t* readDirCache(void); 406 | }; 407 | //============================================================================== 408 | // SdVolume class 409 | /** 410 | * \brief Cache for an SD data block 411 | */ 412 | union cache_t { 413 | /** Used to access cached file data blocks. */ 414 | uint8_t data[512]; 415 | /** Used to access cached FAT16 entries. */ 416 | uint16_t fat16[256]; 417 | /** Used to access cached FAT32 entries. */ 418 | uint32_t fat32[128]; 419 | /** Used to access cached directory entries. */ 420 | dir_t dir[16]; 421 | /** Used to access a cached MasterBoot Record. */ 422 | mbr_t mbr; 423 | /** Used to access to a cached FAT boot sector. */ 424 | fbs_t fbs; 425 | }; 426 | //------------------------------------------------------------------------------ 427 | /** 428 | * \class SdVolume 429 | * \brief Access FAT16 and FAT32 volumes on SD and SDHC cards. 430 | */ 431 | class SdVolume { 432 | public: 433 | /** Create an instance of SdVolume */ 434 | SdVolume(void) :allocSearchStart_(2), fatType_(0) {} 435 | /** Clear the cache and returns a pointer to the cache. Used by the WaveRP 436 | * recorder to do raw write to the SD card. Not for normal apps. 437 | */ 438 | static uint8_t* cacheClear(void) { 439 | cacheFlush(); 440 | cacheBlockNumber_ = 0XFFFFFFFF; 441 | return cacheBuffer_.data; 442 | } 443 | /** 444 | * Initialize a FAT volume. Try partition one first then try super 445 | * floppy format. 446 | * 447 | * \param[in] dev The Sd2Card where the volume is located. 448 | * 449 | * \return The value one, true, is returned for success and 450 | * the value zero, false, is returned for failure. Reasons for 451 | * failure include not finding a valid partition, not finding a valid 452 | * FAT file system or an I/O error. 453 | */ 454 | uint8_t init(Sd2Card* dev) { return init(dev, 1) ? true : init(dev, 0);} 455 | uint8_t init(Sd2Card* dev, uint8_t part); 456 | 457 | // inline functions that return volume info 458 | /** \return The volume's cluster size in blocks. */ 459 | uint8_t blocksPerCluster(void) const {return blocksPerCluster_;} 460 | /** \return The number of blocks in one FAT. */ 461 | uint32_t blocksPerFat(void) const {return blocksPerFat_;} 462 | /** \return The total number of clusters in the volume. */ 463 | uint32_t clusterCount(void) const {return clusterCount_;} 464 | /** \return The shift count required to multiply by blocksPerCluster. */ 465 | uint8_t clusterSizeShift(void) const {return clusterSizeShift_;} 466 | /** \return The logical block number for the start of file data. */ 467 | uint32_t dataStartBlock(void) const {return dataStartBlock_;} 468 | /** \return The number of FAT structures on the volume. */ 469 | uint8_t fatCount(void) const {return fatCount_;} 470 | /** \return The logical block number for the start of the first FAT. */ 471 | uint32_t fatStartBlock(void) const {return fatStartBlock_;} 472 | /** \return The FAT type of the volume. Values are 12, 16 or 32. */ 473 | uint8_t fatType(void) const {return fatType_;} 474 | /** \return The number of entries in the root directory for FAT16 volumes. */ 475 | uint32_t rootDirEntryCount(void) const {return rootDirEntryCount_;} 476 | /** \return The logical block number for the start of the root directory 477 | on FAT16 volumes or the first cluster number on FAT32 volumes. */ 478 | uint32_t rootDirStart(void) const {return rootDirStart_;} 479 | /** return a pointer to the Sd2Card object for this volume */ 480 | static Sd2Card* sdCard(void) {return sdCard_;} 481 | //------------------------------------------------------------------------------ 482 | #if ALLOW_DEPRECATED_FUNCTIONS 483 | // Deprecated functions - suppress cpplint warnings with NOLINT comment 484 | /** \deprecated Use: uint8_t SdVolume::init(Sd2Card* dev); */ 485 | uint8_t init(Sd2Card& dev) {return init(&dev);} // NOLINT 486 | 487 | /** \deprecated Use: uint8_t SdVolume::init(Sd2Card* dev, uint8_t vol); */ 488 | uint8_t init(Sd2Card& dev, uint8_t part) { // NOLINT 489 | return init(&dev, part); 490 | } 491 | #endif // ALLOW_DEPRECATED_FUNCTIONS 492 | //------------------------------------------------------------------------------ 493 | private: 494 | // Allow SdFile access to SdVolume private data. 495 | friend class SdFile; 496 | 497 | // value for action argument in cacheRawBlock to indicate read from cache 498 | static uint8_t const CACHE_FOR_READ = 0; 499 | // value for action argument in cacheRawBlock to indicate cache dirty 500 | static uint8_t const CACHE_FOR_WRITE = 1; 501 | 502 | static cache_t cacheBuffer_; // 512 byte cache for device blocks 503 | static uint32_t cacheBlockNumber_; // Logical number of block in the cache 504 | static Sd2Card* sdCard_; // Sd2Card object for cache 505 | static uint8_t cacheDirty_; // cacheFlush() will write block if true 506 | static uint32_t cacheMirrorBlock_; // block number for mirror FAT 507 | // 508 | uint32_t allocSearchStart_; // start cluster for alloc search 509 | uint8_t blocksPerCluster_; // cluster size in blocks 510 | uint32_t blocksPerFat_; // FAT size in blocks 511 | uint32_t clusterCount_; // clusters in one FAT 512 | uint8_t clusterSizeShift_; // shift to convert cluster count to block count 513 | uint32_t dataStartBlock_; // first data block number 514 | uint8_t fatCount_; // number of FATs on volume 515 | uint32_t fatStartBlock_; // start block for first FAT 516 | uint8_t fatType_; // volume type (12, 16, OR 32) 517 | uint16_t rootDirEntryCount_; // number of entries in FAT16 root dir 518 | uint32_t rootDirStart_; // root start block for FAT16, cluster for FAT32 519 | //---------------------------------------------------------------------------- 520 | uint8_t allocContiguous(uint32_t count, uint32_t* curCluster); 521 | uint8_t blockOfCluster(uint32_t position) const { 522 | return (position >> 9) & (blocksPerCluster_ - 1);} 523 | uint32_t clusterStartBlock(uint32_t cluster) const { 524 | return dataStartBlock_ + ((cluster - 2) << clusterSizeShift_);} 525 | uint32_t blockNumber(uint32_t cluster, uint32_t position) const { 526 | return clusterStartBlock(cluster) + blockOfCluster(position);} 527 | static uint8_t cacheFlush(void); 528 | static uint8_t cacheRawBlock(uint32_t blockNumber, uint8_t action); 529 | static void cacheSetDirty(void) {cacheDirty_ |= CACHE_FOR_WRITE;} 530 | static uint8_t cacheZeroBlock(uint32_t blockNumber); 531 | uint8_t chainSize(uint32_t beginCluster, uint32_t* size) const; 532 | uint8_t fatGet(uint32_t cluster, uint32_t* value) const; 533 | uint8_t fatPut(uint32_t cluster, uint32_t value); 534 | uint8_t fatPutEOC(uint32_t cluster) { 535 | return fatPut(cluster, 0x0FFFFFFF); 536 | } 537 | uint8_t freeChain(uint32_t cluster); 538 | uint8_t isEOC(uint32_t cluster) const { 539 | return cluster >= (fatType_ == 16 ? FAT16EOC_MIN : FAT32EOC_MIN); 540 | } 541 | uint8_t readBlock(uint32_t block, uint8_t* dst) { 542 | return sdCard_->readBlock(block, dst);} 543 | uint8_t readData(uint32_t block, uint16_t offset, 544 | uint16_t count, uint8_t* dst) { 545 | return sdCard_->readData(block, offset, count, dst); 546 | } 547 | uint8_t writeBlock(uint32_t block, const uint8_t* dst) { 548 | return sdCard_->writeBlock(block, dst); 549 | } 550 | }; 551 | #endif // SdFat_h 552 | -------------------------------------------------------------------------------- /utility/SdFatUtil.h: -------------------------------------------------------------------------------- 1 | /* Arduino SdFat Library 2 | * Copyright (C) 2008 by William Greiman 3 | * 4 | * This file is part of the Arduino SdFat Library 5 | * 6 | * This Library is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This Library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | 16 | * You should have received a copy of the GNU General Public License 17 | * along with the Arduino SdFat Library. If not, see 18 | * . 19 | */ 20 | #ifndef SdFatUtil_h 21 | #define SdFatUtil_h 22 | /** 23 | * \file 24 | * Useful utility functions. 25 | */ 26 | #include 27 | #ifdef __AVR__ 28 | #include 29 | /** Store and print a string in flash memory.*/ 30 | #define PgmPrint(x) SerialPrint_P(PSTR(x)) 31 | /** Store and print a string in flash memory followed by a CR/LF.*/ 32 | #define PgmPrintln(x) SerialPrintln_P(PSTR(x)) 33 | /** Defined so doxygen works for function definitions. */ 34 | #endif 35 | #define NOINLINE __attribute__((noinline,unused)) 36 | #define UNUSEDOK __attribute__((unused)) 37 | //------------------------------------------------------------------------------ 38 | /** Return the number of bytes currently free in RAM. */ 39 | static UNUSEDOK int FreeRam(void) { 40 | extern int __bss_end; 41 | extern int* __brkval; 42 | int free_memory; 43 | if (reinterpret_cast(__brkval) == 0) { 44 | // if no heap use from end of bss section 45 | free_memory = reinterpret_cast(&free_memory) 46 | - reinterpret_cast(&__bss_end); 47 | } else { 48 | // use from top of stack to heap 49 | free_memory = reinterpret_cast(&free_memory) 50 | - reinterpret_cast(__brkval); 51 | } 52 | return free_memory; 53 | } 54 | #ifdef __AVR__ 55 | //------------------------------------------------------------------------------ 56 | /** 57 | * %Print a string in flash memory to the serial port. 58 | * 59 | * \param[in] str Pointer to string stored in flash memory. 60 | */ 61 | static NOINLINE void SerialPrint_P(PGM_P str) { 62 | for (uint8_t c; (c = pgm_read_byte(str)); str++) Serial.write(c); 63 | } 64 | //------------------------------------------------------------------------------ 65 | /** 66 | * %Print a string in flash memory followed by a CR/LF. 67 | * 68 | * \param[in] str Pointer to string stored in flash memory. 69 | */ 70 | static NOINLINE void SerialPrintln_P(PGM_P str) { 71 | SerialPrint_P(str); 72 | Serial.println(); 73 | } 74 | #endif // __AVR__ 75 | #endif // #define SdFatUtil_h 76 | -------------------------------------------------------------------------------- /utility/SdFatmainpage.h: -------------------------------------------------------------------------------- 1 | /* Arduino SdFat Library 2 | * Copyright (C) 2009 by William Greiman 3 | * 4 | * This file is part of the Arduino SdFat Library 5 | * 6 | * This Library is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This Library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with the Arduino SdFat Library. If not, see 18 | * . 19 | */ 20 | 21 | /** 22 | \mainpage Arduino SdFat Library 23 |
Copyright © 2009 by William Greiman 24 |
25 | 26 | \section Intro Introduction 27 | The Arduino SdFat Library is a minimal implementation of FAT16 and FAT32 28 | file systems on SD flash memory cards. Standard SD and high capacity 29 | SDHC cards are supported. 30 | 31 | The SdFat only supports short 8.3 names. 32 | 33 | The main classes in SdFat are Sd2Card, SdVolume, and SdFile. 34 | 35 | The Sd2Card class supports access to standard SD cards and SDHC cards. Most 36 | applications will only need to call the Sd2Card::init() member function. 37 | 38 | The SdVolume class supports FAT16 and FAT32 partitions. Most applications 39 | will only need to call the SdVolume::init() member function. 40 | 41 | The SdFile class provides file access functions such as open(), read(), 42 | remove(), write(), close() and sync(). This class supports access to the root 43 | directory and subdirectories. 44 | 45 | A number of example are provided in the SdFat/examples folder. These were 46 | developed to test SdFat and illustrate its use. 47 | 48 | SdFat was developed for high speed data recording. SdFat was used to implement 49 | an audio record/play class, WaveRP, for the Adafruit Wave Shield. This 50 | application uses special Sd2Card calls to write to contiguous files in raw mode. 51 | These functions reduce write latency so that audio can be recorded with the 52 | small amount of RAM in the Arduino. 53 | 54 | \section SDcard SD\SDHC Cards 55 | 56 | Arduinos access SD cards using the cards SPI protocol. PCs, Macs, and 57 | most consumer devices use the 4-bit parallel SD protocol. A card that 58 | functions well on A PC or Mac may not work well on the Arduino. 59 | 60 | Most cards have good SPI read performance but cards vary widely in SPI 61 | write performance. Write performance is limited by how efficiently the 62 | card manages internal erase/remapping operations. The Arduino cannot 63 | optimize writes to reduce erase operations because of its limit RAM. 64 | 65 | SanDisk cards generally have good write performance. They seem to have 66 | more internal RAM buffering than other cards and therefore can limit 67 | the number of flash erase operations that the Arduino forces due to its 68 | limited RAM. 69 | 70 | \section Hardware Hardware Configuration 71 | 72 | SdFat was developed using an 73 | Adafruit Industries 74 | Wave Shield. 75 | 76 | The hardware interface to the SD card should not use a resistor based level 77 | shifter. SdFat sets the SPI bus frequency to 8 MHz which results in signal 78 | rise times that are too slow for the edge detectors in many newer SD card 79 | controllers when resistor voltage dividers are used. 80 | 81 | The 5 to 3.3 V level shifter for 5 V Arduinos should be IC based like the 82 | 74HC4050N based circuit shown in the file SdLevel.png. The Adafruit Wave Shield 83 | uses a 74AHC125N. Gravitech sells SD and MicroSD Card Adapters based on the 84 | 74LCX245. 85 | 86 | If you are using a resistor based level shifter and are having problems try 87 | setting the SPI bus frequency to 4 MHz. This can be done by using 88 | card.init(SPI_HALF_SPEED) to initialize the SD card. 89 | 90 | \section comment Bugs and Comments 91 | 92 | If you wish to report bugs or have comments, send email to fat16lib@sbcglobal.net. 93 | 94 | \section SdFatClass SdFat Usage 95 | 96 | SdFat uses a slightly restricted form of short names. 97 | Only printable ASCII characters are supported. No characters with code point 98 | values greater than 127 are allowed. Space is not allowed even though space 99 | was allowed in the API of early versions of DOS. 100 | 101 | Short names are limited to 8 characters followed by an optional period (.) 102 | and extension of up to 3 characters. The characters may be any combination 103 | of letters and digits. The following special characters are also allowed: 104 | 105 | $ % ' - _ @ ~ ` ! ( ) { } ^ # & 106 | 107 | Short names are always converted to upper case and their original case 108 | value is lost. 109 | 110 | \note 111 | The Arduino Print class uses character 112 | at a time writes so it was necessary to use a \link SdFile::sync() sync() \endlink 113 | function to control when data is written to the SD card. 114 | 115 | \par 116 | An application which writes to a file using \link Print::print() print()\endlink, 117 | \link Print::println() println() \endlink 118 | or \link SdFile::write write() \endlink must call \link SdFile::sync() sync() \endlink 119 | at the appropriate time to force data and directory information to be written 120 | to the SD Card. Data and directory information are also written to the SD card 121 | when \link SdFile::close() close() \endlink is called. 122 | 123 | \par 124 | Applications must use care calling \link SdFile::sync() sync() \endlink 125 | since 2048 bytes of I/O is required to update file and 126 | directory information. This includes writing the current data block, reading 127 | the block that contains the directory entry for update, writing the directory 128 | block back and reading back the current data block. 129 | 130 | It is possible to open a file with two or more instances of SdFile. A file may 131 | be corrupted if data is written to the file by more than one instance of SdFile. 132 | 133 | \section HowTo How to format SD Cards as FAT Volumes 134 | 135 | You should use a freshly formatted SD card for best performance. FAT 136 | file systems become slower if many files have been created and deleted. 137 | This is because the directory entry for a deleted file is marked as deleted, 138 | but is not deleted. When a new file is created, these entries must be scanned 139 | before creating the file, a flaw in the FAT design. Also files can become 140 | fragmented which causes reads and writes to be slower. 141 | 142 | Microsoft operating systems support removable media formatted with a 143 | Master Boot Record, MBR, or formatted as a super floppy with a FAT Boot Sector 144 | in block zero. 145 | 146 | Microsoft operating systems expect MBR formatted removable media 147 | to have only one partition. The first partition should be used. 148 | 149 | Microsoft operating systems do not support partitioning SD flash cards. 150 | If you erase an SD card with a program like KillDisk, Most versions of 151 | Windows will format the card as a super floppy. 152 | 153 | The best way to restore an SD card's format is to use SDFormatter 154 | which can be downloaded from: 155 | 156 | http://www.sdcard.org/consumers/formatter/ 157 | 158 | SDFormatter aligns flash erase boundaries with file 159 | system structures which reduces write latency and file system overhead. 160 | 161 | SDFormatter does not have an option for FAT type so it may format 162 | small cards as FAT12. 163 | 164 | After the MBR is restored by SDFormatter you may need to reformat small 165 | cards that have been formatted FAT12 to force the volume type to be FAT16. 166 | 167 | If you reformat the SD card with an OS utility, choose a cluster size that 168 | will result in: 169 | 170 | 4084 < CountOfClusters && CountOfClusters < 65525 171 | 172 | The volume will then be FAT16. 173 | 174 | If you are formatting an SD card on OS X or Linux, be sure to use the first 175 | partition. Format this partition with a cluster count in above range. 176 | 177 | \section References References 178 | 179 | Adafruit Industries: 180 | 181 | http://www.adafruit.com/ 182 | 183 | http://www.ladyada.net/make/waveshield/ 184 | 185 | The Arduino site: 186 | 187 | http://www.arduino.cc/ 188 | 189 | For more information about FAT file systems see: 190 | 191 | http://www.microsoft.com/whdc/system/platform/firmware/fatgen.mspx 192 | 193 | For information about using SD cards as SPI devices see: 194 | 195 | http://www.sdcard.org/developers/tech/sdcard/pls/Simplified_Physical_Layer_Spec.pdf 196 | 197 | The ATmega328 datasheet: 198 | 199 | http://www.atmel.com/dyn/resources/prod_documents/doc8161.pdf 200 | 201 | 202 | */ 203 | -------------------------------------------------------------------------------- /utility/SdFile.cpp: -------------------------------------------------------------------------------- 1 | /* Arduino SdFat Library 2 | * Copyright (C) 2009 by William Greiman 3 | * 4 | * This file is part of the Arduino SdFat Library 5 | * 6 | * This Library is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This Library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with the Arduino SdFat Library. If not, see 18 | * . 19 | */ 20 | #include "SdFat.h" 21 | #ifdef __AVR__ 22 | #include 23 | #endif 24 | #include 25 | //------------------------------------------------------------------------------ 26 | // callback function for date/time 27 | void (*SdFile::dateTime_)(uint16_t* date, uint16_t* time) = NULL; 28 | 29 | #if ALLOW_DEPRECATED_FUNCTIONS 30 | // suppress cpplint warnings with NOLINT comment 31 | void (*SdFile::oldDateTime_)(uint16_t& date, uint16_t& time) = NULL; // NOLINT 32 | #endif // ALLOW_DEPRECATED_FUNCTIONS 33 | //------------------------------------------------------------------------------ 34 | // add a cluster to a file 35 | uint8_t SdFile::addCluster() { 36 | if (!vol_->allocContiguous(1, &curCluster_)) return false; 37 | 38 | // if first cluster of file link to directory entry 39 | if (firstCluster_ == 0) { 40 | firstCluster_ = curCluster_; 41 | flags_ |= F_FILE_DIR_DIRTY; 42 | } 43 | return true; 44 | } 45 | //------------------------------------------------------------------------------ 46 | // Add a cluster to a directory file and zero the cluster. 47 | // return with first block of cluster in the cache 48 | uint8_t SdFile::addDirCluster(void) { 49 | if (!addCluster()) return false; 50 | 51 | // zero data in cluster insure first cluster is in cache 52 | uint32_t block = vol_->clusterStartBlock(curCluster_); 53 | for (uint8_t i = vol_->blocksPerCluster_; i != 0; i--) { 54 | if (!SdVolume::cacheZeroBlock(block + i - 1)) return false; 55 | } 56 | // Increase directory file size by cluster size 57 | fileSize_ += 512UL << vol_->clusterSizeShift_; 58 | return true; 59 | } 60 | //------------------------------------------------------------------------------ 61 | // cache a file's directory entry 62 | // return pointer to cached entry or null for failure 63 | dir_t* SdFile::cacheDirEntry(uint8_t action) { 64 | if (!SdVolume::cacheRawBlock(dirBlock_, action)) return NULL; 65 | return SdVolume::cacheBuffer_.dir + dirIndex_; 66 | } 67 | //------------------------------------------------------------------------------ 68 | /** 69 | * Close a file and force cached data and directory information 70 | * to be written to the storage device. 71 | * 72 | * \return The value one, true, is returned for success and 73 | * the value zero, false, is returned for failure. 74 | * Reasons for failure include no file is open or an I/O error. 75 | */ 76 | uint8_t SdFile::close(void) { 77 | if (!sync())return false; 78 | type_ = FAT_FILE_TYPE_CLOSED; 79 | return true; 80 | } 81 | //------------------------------------------------------------------------------ 82 | /** 83 | * Check for contiguous file and return its raw block range. 84 | * 85 | * \param[out] bgnBlock the first block address for the file. 86 | * \param[out] endBlock the last block address for the file. 87 | * 88 | * \return The value one, true, is returned for success and 89 | * the value zero, false, is returned for failure. 90 | * Reasons for failure include file is not contiguous, file has zero length 91 | * or an I/O error occurred. 92 | */ 93 | uint8_t SdFile::contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock) { 94 | // error if no blocks 95 | if (firstCluster_ == 0) return false; 96 | 97 | for (uint32_t c = firstCluster_; ; c++) { 98 | uint32_t next; 99 | if (!vol_->fatGet(c, &next)) return false; 100 | 101 | // check for contiguous 102 | if (next != (c + 1)) { 103 | // error if not end of chain 104 | if (!vol_->isEOC(next)) return false; 105 | *bgnBlock = vol_->clusterStartBlock(firstCluster_); 106 | *endBlock = vol_->clusterStartBlock(c) 107 | + vol_->blocksPerCluster_ - 1; 108 | return true; 109 | } 110 | } 111 | } 112 | //------------------------------------------------------------------------------ 113 | /** 114 | * Create and open a new contiguous file of a specified size. 115 | * 116 | * \note This function only supports short DOS 8.3 names. 117 | * See open() for more information. 118 | * 119 | * \param[in] dirFile The directory where the file will be created. 120 | * \param[in] fileName A valid DOS 8.3 file name. 121 | * \param[in] size The desired file size. 122 | * 123 | * \return The value one, true, is returned for success and 124 | * the value zero, false, is returned for failure. 125 | * Reasons for failure include \a fileName contains 126 | * an invalid DOS 8.3 file name, the FAT volume has not been initialized, 127 | * a file is already open, the file already exists, the root 128 | * directory is full or an I/O error. 129 | * 130 | */ 131 | uint8_t SdFile::createContiguous(SdFile* dirFile, 132 | const char* fileName, uint32_t size) { 133 | // don't allow zero length file 134 | if (size == 0) return false; 135 | if (!open(dirFile, fileName, F_CREAT | F_EXCL | F_RDWR)) return false; 136 | 137 | // calculate number of clusters needed 138 | uint32_t count = ((size - 1) >> (vol_->clusterSizeShift_ + 9)) + 1; 139 | 140 | // allocate clusters 141 | if (!vol_->allocContiguous(count, &firstCluster_)) { 142 | remove(); 143 | return false; 144 | } 145 | fileSize_ = size; 146 | 147 | // insure sync() will update dir entry 148 | flags_ |= F_FILE_DIR_DIRTY; 149 | return sync(); 150 | } 151 | //------------------------------------------------------------------------------ 152 | /** 153 | * Return a files directory entry 154 | * 155 | * \param[out] dir Location for return of the files directory entry. 156 | * 157 | * \return The value one, true, is returned for success and 158 | * the value zero, false, is returned for failure. 159 | */ 160 | uint8_t SdFile::dirEntry(dir_t* dir) { 161 | // make sure fields on SD are correct 162 | if (!sync()) return false; 163 | 164 | // read entry 165 | dir_t* p = cacheDirEntry(SdVolume::CACHE_FOR_READ); 166 | if (!p) return false; 167 | 168 | // copy to caller's struct 169 | memcpy(dir, p, sizeof(dir_t)); 170 | return true; 171 | } 172 | //------------------------------------------------------------------------------ 173 | /** 174 | * Format the name field of \a dir into the 13 byte array 175 | * \a name in standard 8.3 short name format. 176 | * 177 | * \param[in] dir The directory structure containing the name. 178 | * \param[out] name A 13 byte char array for the formatted name. 179 | */ 180 | void SdFile::dirName(const dir_t& dir, char* name) { 181 | uint8_t j = 0; 182 | for (uint8_t i = 0; i < 11; i++) { 183 | if (dir.name[i] == ' ')continue; 184 | if (i == 8) name[j++] = '.'; 185 | name[j++] = dir.name[i]; 186 | } 187 | name[j] = 0; 188 | } 189 | //------------------------------------------------------------------------------ 190 | /** List directory contents to Serial. 191 | * 192 | * \param[in] flags The inclusive OR of 193 | * 194 | * LS_DATE - %Print file modification date 195 | * 196 | * LS_SIZE - %Print file size. 197 | * 198 | * LS_R - Recursive list of subdirectories. 199 | * 200 | * \param[in] indent Amount of space before file name. Used for recursive 201 | * list to indicate subdirectory level. 202 | */ 203 | void SdFile::ls(uint8_t flags, uint8_t indent) { 204 | dir_t* p; 205 | 206 | rewind(); 207 | while ((p = readDirCache())) { 208 | // done if past last used entry 209 | if (p->name[0] == DIR_NAME_FREE) break; 210 | 211 | // skip deleted entry and entries for . and .. 212 | if (p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') continue; 213 | 214 | // only list subdirectories and files 215 | if (!DIR_IS_FILE_OR_SUBDIR(p)) continue; 216 | 217 | // print any indent spaces 218 | for (int8_t i = 0; i < indent; i++) Serial.print(' '); 219 | 220 | // print file name with possible blank fill 221 | printDirName(*p, flags & (LS_DATE | LS_SIZE) ? 14 : 0); 222 | 223 | // print modify date/time if requested 224 | if (flags & LS_DATE) { 225 | printFatDate(p->lastWriteDate); 226 | Serial.print(' '); 227 | printFatTime(p->lastWriteTime); 228 | } 229 | // print size if requested 230 | if (!DIR_IS_SUBDIR(p) && (flags & LS_SIZE)) { 231 | Serial.print(' '); 232 | Serial.print(p->fileSize); 233 | } 234 | Serial.println(); 235 | 236 | // list subdirectory content if requested 237 | if ((flags & LS_R) && DIR_IS_SUBDIR(p)) { 238 | uint16_t index = curPosition()/32 - 1; 239 | SdFile s; 240 | if (s.open(this, index, F_READ)) s.ls(flags, indent + 2); 241 | seekSet(32 * (index + 1)); 242 | } 243 | } 244 | } 245 | //------------------------------------------------------------------------------ 246 | // format directory name field from a 8.3 name string 247 | uint8_t SdFile::make83Name(const char* str, uint8_t* name) { 248 | uint8_t c; 249 | uint8_t n = 7; // max index for part before dot 250 | uint8_t i = 0; 251 | // blank fill name and extension 252 | while (i < 11) name[i++] = ' '; 253 | i = 0; 254 | while ((c = *str++) != '\0') { 255 | if (c == '.') { 256 | if (n == 10) return false; // only one dot allowed 257 | n = 10; // max index for full 8.3 name 258 | i = 8; // place for extension 259 | } else { 260 | // illegal FAT characters 261 | uint8_t b; 262 | #if defined(__AVR__) 263 | PGM_P p = PSTR("|<>^+=?/[];,*\"\\"); 264 | while ((b = pgm_read_byte(p++))) if (b == c) return false; 265 | #elif defined(__arm__) 266 | const uint8_t valid[] = "|<>^+=?/[];,*\"\\"; 267 | const uint8_t *p = valid; 268 | while ((b = *p++)) if (b == c) return false; 269 | #endif 270 | // check size and only allow ASCII printable characters 271 | if (i > n || c < 0X21 || c > 0X7E)return false; 272 | // only upper case allowed in 8.3 names - convert lower to upper 273 | name[i++] = c < 'a' || c > 'z' ? c : c + ('A' - 'a'); 274 | } 275 | } 276 | // must have a file name, extension is optional 277 | return name[0] != ' '; 278 | } 279 | //------------------------------------------------------------------------------ 280 | /** Make a new directory. 281 | * 282 | * \param[in] dir An open SdFat instance for the directory that will containing 283 | * the new directory. 284 | * 285 | * \param[in] dirName A valid 8.3 DOS name for the new directory. 286 | * 287 | * \return The value one, true, is returned for success and 288 | * the value zero, false, is returned for failure. 289 | * Reasons for failure include this SdFile is already open, \a dir is not a 290 | * directory, \a dirName is invalid or already exists in \a dir. 291 | */ 292 | uint8_t SdFile::makeDir(SdFile* dir, const char* dirName) { 293 | dir_t d; 294 | 295 | // create a normal file 296 | if (!open(dir, dirName, F_CREAT | F_EXCL | F_RDWR)) return false; 297 | 298 | // convert SdFile to directory 299 | flags_ = F_READ; 300 | type_ = FAT_FILE_TYPE_SUBDIR; 301 | 302 | // allocate and zero first cluster 303 | if (!addDirCluster())return false; 304 | 305 | // force entry to SD 306 | if (!sync()) return false; 307 | 308 | // cache entry - should already be in cache due to sync() call 309 | dir_t* p = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); 310 | if (!p) return false; 311 | 312 | // change directory entry attribute 313 | p->attributes = DIR_ATT_DIRECTORY; 314 | 315 | // make entry for '.' 316 | memcpy(&d, p, sizeof(d)); 317 | for (uint8_t i = 1; i < 11; i++) d.name[i] = ' '; 318 | d.name[0] = '.'; 319 | 320 | // cache block for '.' and '..' 321 | uint32_t block = vol_->clusterStartBlock(firstCluster_); 322 | if (!SdVolume::cacheRawBlock(block, SdVolume::CACHE_FOR_WRITE)) return false; 323 | 324 | // copy '.' to block 325 | memcpy(&SdVolume::cacheBuffer_.dir[0], &d, sizeof(d)); 326 | 327 | // make entry for '..' 328 | d.name[1] = '.'; 329 | if (dir->isRoot()) { 330 | d.firstClusterLow = 0; 331 | d.firstClusterHigh = 0; 332 | } else { 333 | d.firstClusterLow = dir->firstCluster_ & 0XFFFF; 334 | d.firstClusterHigh = dir->firstCluster_ >> 16; 335 | } 336 | // copy '..' to block 337 | memcpy(&SdVolume::cacheBuffer_.dir[1], &d, sizeof(d)); 338 | 339 | // set position after '..' 340 | curPosition_ = 2 * sizeof(d); 341 | 342 | // write first block 343 | return SdVolume::cacheFlush(); 344 | } 345 | //------------------------------------------------------------------------------ 346 | /** 347 | * Open a file or directory by name. 348 | * 349 | * \param[in] dirFile An open SdFat instance for the directory containing the 350 | * file to be opened. 351 | * 352 | * \param[in] fileName A valid 8.3 DOS name for a file to be opened. 353 | * 354 | * \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive 355 | * OR of flags from the following list 356 | * 357 | * F_READ - Open for reading. 358 | * 359 | * F_RDONLY - Same as F_READ. 360 | * 361 | * F_WRITE - Open for writing. 362 | * 363 | * F_WRONLY - Same as F_WRITE. 364 | * 365 | * F_RDWR - Open for reading and writing. 366 | * 367 | * F_APPEND - If set, the file offset shall be set to the end of the 368 | * file prior to each write. 369 | * 370 | * F_CREAT - If the file exists, this flag has no effect except as noted 371 | * under F_EXCL below. Otherwise, the file shall be created 372 | * 373 | * F_EXCL - If F_CREAT and F_EXCL are set, open() shall fail if the file exists. 374 | * 375 | * F_SYNC - Call sync() after each write. This flag should not be used with 376 | * write(uint8_t), write_P(PGM_P), writeln_P(PGM_P), or the Arduino Print class. 377 | * These functions do character at a time writes so sync() will be called 378 | * after each byte. 379 | * 380 | * F_TRUNC - If the file exists and is a regular file, and the file is 381 | * successfully opened and is not read only, its length shall be truncated to 0. 382 | * 383 | * \note Directory files must be opened read only. Write and truncation is 384 | * not allowed for directory files. 385 | * 386 | * \return The value one, true, is returned for success and 387 | * the value zero, false, is returned for failure. 388 | * Reasons for failure include this SdFile is already open, \a difFile is not 389 | * a directory, \a fileName is invalid, the file does not exist 390 | * or can't be opened in the access mode specified by oflag. 391 | */ 392 | uint8_t SdFile::open(SdFile* dirFile, const char* fileName, uint8_t oflag) { 393 | uint8_t dname[11]; 394 | dir_t* p; 395 | 396 | // error if already open 397 | if (isOpen())return false; 398 | 399 | if (!make83Name(fileName, dname)) return false; 400 | vol_ = dirFile->vol_; 401 | dirFile->rewind(); 402 | 403 | // bool for empty entry found 404 | uint8_t emptyFound = false; 405 | 406 | // search for file 407 | while (dirFile->curPosition_ < dirFile->fileSize_) { 408 | uint8_t index = 0XF & (dirFile->curPosition_ >> 5); 409 | p = dirFile->readDirCache(); 410 | if (p == NULL) return false; 411 | 412 | if (p->name[0] == DIR_NAME_FREE || p->name[0] == DIR_NAME_DELETED) { 413 | // remember first empty slot 414 | if (!emptyFound) { 415 | emptyFound = true; 416 | dirIndex_ = index; 417 | dirBlock_ = SdVolume::cacheBlockNumber_; 418 | } 419 | // done if no entries follow 420 | if (p->name[0] == DIR_NAME_FREE) break; 421 | } else if (!memcmp(dname, p->name, 11)) { 422 | // don't open existing file if F_CREAT and F_EXCL 423 | if ((oflag & (F_CREAT | F_EXCL)) == (F_CREAT | F_EXCL)) return false; 424 | 425 | // open found file 426 | return openCachedEntry(0XF & index, oflag); 427 | } 428 | } 429 | // only create file if F_CREAT and F_WRITE 430 | if ((oflag & (F_CREAT | F_WRITE)) != (F_CREAT | F_WRITE)) return false; 431 | 432 | // cache found slot or add cluster if end of file 433 | if (emptyFound) { 434 | p = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); 435 | if (!p) return false; 436 | } else { 437 | if (dirFile->type_ == FAT_FILE_TYPE_ROOT16) return false; 438 | 439 | // add and zero cluster for dirFile - first cluster is in cache for write 440 | if (!dirFile->addDirCluster()) return false; 441 | 442 | // use first entry in cluster 443 | dirIndex_ = 0; 444 | p = SdVolume::cacheBuffer_.dir; 445 | } 446 | // initialize as empty file 447 | memset(p, 0, sizeof(dir_t)); 448 | memcpy(p->name, dname, 11); 449 | 450 | // set timestamps 451 | if (dateTime_) { 452 | // call user function 453 | dateTime_(&p->creationDate, &p->creationTime); 454 | } else { 455 | // use default date/time 456 | p->creationDate = FAT_DEFAULT_DATE; 457 | p->creationTime = FAT_DEFAULT_TIME; 458 | } 459 | p->lastAccessDate = p->creationDate; 460 | p->lastWriteDate = p->creationDate; 461 | p->lastWriteTime = p->creationTime; 462 | 463 | // force write of entry to SD 464 | if (!SdVolume::cacheFlush()) return false; 465 | 466 | // open entry in cache 467 | return openCachedEntry(dirIndex_, oflag); 468 | } 469 | //------------------------------------------------------------------------------ 470 | /** 471 | * Open a file by index. 472 | * 473 | * \param[in] dirFile An open SdFat instance for the directory. 474 | * 475 | * \param[in] index The \a index of the directory entry for the file to be 476 | * opened. The value for \a index is (directory file position)/32. 477 | * 478 | * \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive 479 | * OR of flags F_READ, F_WRITE, F_TRUNC, and F_SYNC. 480 | * 481 | * See open() by fileName for definition of flags and return values. 482 | * 483 | */ 484 | uint8_t SdFile::open(SdFile* dirFile, uint16_t index, uint8_t oflag) { 485 | // error if already open 486 | if (isOpen())return false; 487 | 488 | // don't open existing file if F_CREAT and F_EXCL - user call error 489 | if ((oflag & (F_CREAT | F_EXCL)) == (F_CREAT | F_EXCL)) return false; 490 | 491 | vol_ = dirFile->vol_; 492 | 493 | // seek to location of entry 494 | if (!dirFile->seekSet(32 * index)) return false; 495 | 496 | // read entry into cache 497 | dir_t* p = dirFile->readDirCache(); 498 | if (p == NULL) return false; 499 | 500 | // error if empty slot or '.' or '..' 501 | if (p->name[0] == DIR_NAME_FREE || 502 | p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') { 503 | return false; 504 | } 505 | // open cached entry 506 | return openCachedEntry(index & 0XF, oflag); 507 | } 508 | //------------------------------------------------------------------------------ 509 | // open a cached directory entry. Assumes vol_ is initializes 510 | uint8_t SdFile::openCachedEntry(uint8_t dirIndex, uint8_t oflag) { 511 | // location of entry in cache 512 | dir_t* p = SdVolume::cacheBuffer_.dir + dirIndex; 513 | 514 | // write or truncate is an error for a directory or read-only file 515 | if (p->attributes & (DIR_ATT_READ_ONLY | DIR_ATT_DIRECTORY)) { 516 | if (oflag & (F_WRITE | F_TRUNC)) return false; 517 | } 518 | // remember location of directory entry on SD 519 | dirIndex_ = dirIndex; 520 | dirBlock_ = SdVolume::cacheBlockNumber_; 521 | 522 | // copy first cluster number for directory fields 523 | firstCluster_ = (uint32_t)p->firstClusterHigh << 16; 524 | firstCluster_ |= p->firstClusterLow; 525 | 526 | // make sure it is a normal file or subdirectory 527 | if (DIR_IS_FILE(p)) { 528 | fileSize_ = p->fileSize; 529 | type_ = FAT_FILE_TYPE_NORMAL; 530 | } else if (DIR_IS_SUBDIR(p)) { 531 | if (!vol_->chainSize(firstCluster_, &fileSize_)) return false; 532 | type_ = FAT_FILE_TYPE_SUBDIR; 533 | } else { 534 | return false; 535 | } 536 | // save open flags for read/write 537 | flags_ = oflag & (F_ACCMODE | F_SYNC | F_APPEND); 538 | 539 | // set to start of file 540 | curCluster_ = 0; 541 | curPosition_ = 0; 542 | 543 | // truncate file to zero length if requested 544 | if (oflag & F_TRUNC) return truncate(0); 545 | return true; 546 | } 547 | //------------------------------------------------------------------------------ 548 | /** 549 | * Open a volume's root directory. 550 | * 551 | * \param[in] vol The FAT volume containing the root directory to be opened. 552 | * 553 | * \return The value one, true, is returned for success and 554 | * the value zero, false, is returned for failure. 555 | * Reasons for failure include the FAT volume has not been initialized 556 | * or it a FAT12 volume. 557 | */ 558 | uint8_t SdFile::openRoot(SdVolume* vol) { 559 | // error if file is already open 560 | if (isOpen()) return false; 561 | 562 | if (vol->fatType() == 16) { 563 | type_ = FAT_FILE_TYPE_ROOT16; 564 | firstCluster_ = 0; 565 | fileSize_ = 32 * vol->rootDirEntryCount(); 566 | } else if (vol->fatType() == 32) { 567 | type_ = FAT_FILE_TYPE_ROOT32; 568 | firstCluster_ = vol->rootDirStart(); 569 | if (!vol->chainSize(firstCluster_, &fileSize_)) return false; 570 | } else { 571 | // volume is not initialized or FAT12 572 | return false; 573 | } 574 | vol_ = vol; 575 | // read only 576 | flags_ = F_READ; 577 | 578 | // set to start of file 579 | curCluster_ = 0; 580 | curPosition_ = 0; 581 | 582 | // root has no directory entry 583 | dirBlock_ = 0; 584 | dirIndex_ = 0; 585 | return true; 586 | } 587 | //------------------------------------------------------------------------------ 588 | /** %Print the name field of a directory entry in 8.3 format to Serial. 589 | * 590 | * \param[in] dir The directory structure containing the name. 591 | * \param[in] width Blank fill name if length is less than \a width. 592 | */ 593 | void SdFile::printDirName(const dir_t& dir, uint8_t width) { 594 | uint8_t w = 0; 595 | for (uint8_t i = 0; i < 11; i++) { 596 | if (dir.name[i] == ' ')continue; 597 | if (i == 8) { 598 | Serial.print('.'); 599 | w++; 600 | } 601 | Serial.write(dir.name[i]); 602 | w++; 603 | } 604 | if (DIR_IS_SUBDIR(&dir)) { 605 | Serial.print('/'); 606 | w++; 607 | } 608 | while (w < width) { 609 | Serial.print(' '); 610 | w++; 611 | } 612 | } 613 | //------------------------------------------------------------------------------ 614 | /** %Print a directory date field to Serial. 615 | * 616 | * Format is yyyy-mm-dd. 617 | * 618 | * \param[in] fatDate The date field from a directory entry. 619 | */ 620 | void SdFile::printFatDate(uint16_t fatDate) { 621 | Serial.print(FAT_YEAR(fatDate)); 622 | Serial.print('-'); 623 | printTwoDigits(FAT_MONTH(fatDate)); 624 | Serial.print('-'); 625 | printTwoDigits(FAT_DAY(fatDate)); 626 | } 627 | //------------------------------------------------------------------------------ 628 | /** %Print a directory time field to Serial. 629 | * 630 | * Format is hh:mm:ss. 631 | * 632 | * \param[in] fatTime The time field from a directory entry. 633 | */ 634 | void SdFile::printFatTime(uint16_t fatTime) { 635 | printTwoDigits(FAT_HOUR(fatTime)); 636 | Serial.print(':'); 637 | printTwoDigits(FAT_MINUTE(fatTime)); 638 | Serial.print(':'); 639 | printTwoDigits(FAT_SECOND(fatTime)); 640 | } 641 | //------------------------------------------------------------------------------ 642 | /** %Print a value as two digits to Serial. 643 | * 644 | * \param[in] v Value to be printed, 0 <= \a v <= 99 645 | */ 646 | void SdFile::printTwoDigits(uint8_t v) { 647 | char str[3]; 648 | str[0] = '0' + v/10; 649 | str[1] = '0' + v % 10; 650 | str[2] = 0; 651 | Serial.print(str); 652 | } 653 | //------------------------------------------------------------------------------ 654 | /** 655 | * Read data from a file starting at the current position. 656 | * 657 | * \param[out] buf Pointer to the location that will receive the data. 658 | * 659 | * \param[in] nbyte Maximum number of bytes to read. 660 | * 661 | * \return For success read() returns the number of bytes read. 662 | * A value less than \a nbyte, including zero, will be returned 663 | * if end of file is reached. 664 | * If an error occurs, read() returns -1. Possible errors include 665 | * read() called before a file has been opened, corrupt file system 666 | * or an I/O error occurred. 667 | */ 668 | int16_t SdFile::read(void* buf, uint16_t nbyte) { 669 | uint8_t* dst = reinterpret_cast(buf); 670 | 671 | // error if not open or write only 672 | if (!isOpen() || !(flags_ & F_READ)) return -1; 673 | 674 | // max bytes left in file 675 | if (nbyte > (fileSize_ - curPosition_)) nbyte = fileSize_ - curPosition_; 676 | 677 | // amount left to read 678 | uint16_t toRead = nbyte; 679 | while (toRead > 0) { 680 | uint32_t block; // raw device block number 681 | uint16_t offset = curPosition_ & 0X1FF; // offset in block 682 | if (type_ == FAT_FILE_TYPE_ROOT16) { 683 | block = vol_->rootDirStart() + (curPosition_ >> 9); 684 | } else { 685 | uint8_t blockOfCluster = vol_->blockOfCluster(curPosition_); 686 | if (offset == 0 && blockOfCluster == 0) { 687 | // start of new cluster 688 | if (curPosition_ == 0) { 689 | // use first cluster in file 690 | curCluster_ = firstCluster_; 691 | } else { 692 | // get next cluster from FAT 693 | if (!vol_->fatGet(curCluster_, &curCluster_)) return -1; 694 | } 695 | } 696 | block = vol_->clusterStartBlock(curCluster_) + blockOfCluster; 697 | } 698 | uint16_t n = toRead; 699 | 700 | // amount to be read from current block 701 | if (n > (512 - offset)) n = 512 - offset; 702 | 703 | // no buffering needed if n == 512 or user requests no buffering 704 | if ((unbufferedRead() || n == 512) && 705 | block != SdVolume::cacheBlockNumber_) { 706 | if (!vol_->readData(block, offset, n, dst)) return -1; 707 | dst += n; 708 | } else { 709 | // read block to cache and copy data to caller 710 | if (!SdVolume::cacheRawBlock(block, SdVolume::CACHE_FOR_READ)) return -1; 711 | uint8_t* src = SdVolume::cacheBuffer_.data + offset; 712 | uint8_t* end = src + n; 713 | while (src != end) *dst++ = *src++; 714 | } 715 | curPosition_ += n; 716 | toRead -= n; 717 | } 718 | return nbyte; 719 | } 720 | //------------------------------------------------------------------------------ 721 | /** 722 | * Read the next directory entry from a directory file. 723 | * 724 | * \param[out] dir The dir_t struct that will receive the data. 725 | * 726 | * \return For success readDir() returns the number of bytes read. 727 | * A value of zero will be returned if end of file is reached. 728 | * If an error occurs, readDir() returns -1. Possible errors include 729 | * readDir() called before a directory has been opened, this is not 730 | * a directory file or an I/O error occurred. 731 | */ 732 | int8_t SdFile::readDir(dir_t* dir) { 733 | int8_t n; 734 | // if not a directory file or miss-positioned return an error 735 | if (!isDir() || (0X1F & curPosition_)) return -1; 736 | 737 | while ((n = read(dir, sizeof(dir_t))) == sizeof(dir_t)) { 738 | // last entry if DIR_NAME_FREE 739 | if (dir->name[0] == DIR_NAME_FREE) break; 740 | // skip empty entries and entry for . and .. 741 | if (dir->name[0] == DIR_NAME_DELETED || dir->name[0] == '.') continue; 742 | // return if normal file or subdirectory 743 | if (DIR_IS_FILE_OR_SUBDIR(dir)) return n; 744 | } 745 | // error, end of file, or past last entry 746 | return n < 0 ? -1 : 0; 747 | } 748 | //------------------------------------------------------------------------------ 749 | // Read next directory entry into the cache 750 | // Assumes file is correctly positioned 751 | dir_t* SdFile::readDirCache(void) { 752 | // error if not directory 753 | if (!isDir()) return NULL; 754 | 755 | // index of entry in cache 756 | uint8_t i = (curPosition_ >> 5) & 0XF; 757 | 758 | // use read to locate and cache block 759 | if (read() < 0) return NULL; 760 | 761 | // advance to next entry 762 | curPosition_ += 31; 763 | 764 | // return pointer to entry 765 | return (SdVolume::cacheBuffer_.dir + i); 766 | } 767 | //------------------------------------------------------------------------------ 768 | /** 769 | * Remove a file. 770 | * 771 | * The directory entry and all data for the file are deleted. 772 | * 773 | * \note This function should not be used to delete the 8.3 version of a 774 | * file that has a long name. For example if a file has the long name 775 | * "New Text Document.txt" you should not delete the 8.3 name "NEWTEX~1.TXT". 776 | * 777 | * \return The value one, true, is returned for success and 778 | * the value zero, false, is returned for failure. 779 | * Reasons for failure include the file read-only, is a directory, 780 | * or an I/O error occurred. 781 | */ 782 | uint8_t SdFile::remove(void) { 783 | // free any clusters - will fail if read-only or directory 784 | if (!truncate(0)) return false; 785 | 786 | // cache directory entry 787 | dir_t* d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); 788 | if (!d) return false; 789 | 790 | // mark entry deleted 791 | d->name[0] = DIR_NAME_DELETED; 792 | 793 | // set this SdFile closed 794 | type_ = FAT_FILE_TYPE_CLOSED; 795 | 796 | // write entry to SD 797 | return SdVolume::cacheFlush(); 798 | } 799 | //------------------------------------------------------------------------------ 800 | /** 801 | * Remove a file. 802 | * 803 | * The directory entry and all data for the file are deleted. 804 | * 805 | * \param[in] dirFile The directory that contains the file. 806 | * \param[in] fileName The name of the file to be removed. 807 | * 808 | * \note This function should not be used to delete the 8.3 version of a 809 | * file that has a long name. For example if a file has the long name 810 | * "New Text Document.txt" you should not delete the 8.3 name "NEWTEX~1.TXT". 811 | * 812 | * \return The value one, true, is returned for success and 813 | * the value zero, false, is returned for failure. 814 | * Reasons for failure include the file is a directory, is read only, 815 | * \a dirFile is not a directory, \a fileName is not found 816 | * or an I/O error occurred. 817 | */ 818 | uint8_t SdFile::remove(SdFile* dirFile, const char* fileName) { 819 | SdFile file; 820 | if (!file.open(dirFile, fileName, F_WRITE)) return false; 821 | return file.remove(); 822 | } 823 | //------------------------------------------------------------------------------ 824 | /** Remove a directory file. 825 | * 826 | * The directory file will be removed only if it is empty and is not the 827 | * root directory. rmDir() follows DOS and Windows and ignores the 828 | * read-only attribute for the directory. 829 | * 830 | * \note This function should not be used to delete the 8.3 version of a 831 | * directory that has a long name. For example if a directory has the 832 | * long name "New folder" you should not delete the 8.3 name "NEWFOL~1". 833 | * 834 | * \return The value one, true, is returned for success and 835 | * the value zero, false, is returned for failure. 836 | * Reasons for failure include the file is not a directory, is the root 837 | * directory, is not empty, or an I/O error occurred. 838 | */ 839 | uint8_t SdFile::rmDir(void) { 840 | // must be open subdirectory 841 | if (!isSubDir()) return false; 842 | 843 | rewind(); 844 | 845 | // make sure directory is empty 846 | while (curPosition_ < fileSize_) { 847 | dir_t* p = readDirCache(); 848 | if (p == NULL) return false; 849 | // done if past last used entry 850 | if (p->name[0] == DIR_NAME_FREE) break; 851 | // skip empty slot or '.' or '..' 852 | if (p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') continue; 853 | // error not empty 854 | if (DIR_IS_FILE_OR_SUBDIR(p)) return false; 855 | } 856 | // convert empty directory to normal file for remove 857 | type_ = FAT_FILE_TYPE_NORMAL; 858 | flags_ |= F_WRITE; 859 | return remove(); 860 | } 861 | //------------------------------------------------------------------------------ 862 | /** Recursively delete a directory and all contained files. 863 | * 864 | * This is like the Unix/Linux 'rm -rf *' if called with the root directory 865 | * hence the name. 866 | * 867 | * Warning - This will remove all contents of the directory including 868 | * subdirectories. The directory will then be removed if it is not root. 869 | * The read-only attribute for files will be ignored. 870 | * 871 | * \note This function should not be used to delete the 8.3 version of 872 | * a directory that has a long name. See remove() and rmDir(). 873 | * 874 | * \return The value one, true, is returned for success and 875 | * the value zero, false, is returned for failure. 876 | */ 877 | uint8_t SdFile::rmRfStar(void) { 878 | rewind(); 879 | while (curPosition_ < fileSize_) { 880 | SdFile f; 881 | 882 | // remember position 883 | uint16_t index = curPosition_/32; 884 | 885 | dir_t* p = readDirCache(); 886 | if (!p) return false; 887 | 888 | // done if past last entry 889 | if (p->name[0] == DIR_NAME_FREE) break; 890 | 891 | // skip empty slot or '.' or '..' 892 | if (p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') continue; 893 | 894 | // skip if part of long file name or volume label in root 895 | if (!DIR_IS_FILE_OR_SUBDIR(p)) continue; 896 | 897 | if (!f.open(this, index, F_READ)) return false; 898 | if (f.isSubDir()) { 899 | // recursively delete 900 | if (!f.rmRfStar()) return false; 901 | } else { 902 | // ignore read-only 903 | f.flags_ |= F_WRITE; 904 | if (!f.remove()) return false; 905 | } 906 | // position to next entry if required 907 | if (curPosition_ != (32*(index + 1))) { 908 | if (!seekSet(32*(index + 1))) return false; 909 | } 910 | } 911 | // don't try to delete root 912 | if (isRoot()) return true; 913 | return rmDir(); 914 | } 915 | //------------------------------------------------------------------------------ 916 | /** 917 | * Sets a file's position. 918 | * 919 | * \param[in] pos The new position in bytes from the beginning of the file. 920 | * 921 | * \return The value one, true, is returned for success and 922 | * the value zero, false, is returned for failure. 923 | */ 924 | uint8_t SdFile::seekSet(uint32_t pos) { 925 | // error if file not open or seek past end of file 926 | if (!isOpen() || pos > fileSize_) return false; 927 | 928 | if (type_ == FAT_FILE_TYPE_ROOT16) { 929 | curPosition_ = pos; 930 | return true; 931 | } 932 | if (pos == 0) { 933 | // set position to start of file 934 | curCluster_ = 0; 935 | curPosition_ = 0; 936 | return true; 937 | } 938 | // calculate cluster index for cur and new position 939 | uint32_t nCur = (curPosition_ - 1) >> (vol_->clusterSizeShift_ + 9); 940 | uint32_t nNew = (pos - 1) >> (vol_->clusterSizeShift_ + 9); 941 | 942 | if (nNew < nCur || curPosition_ == 0) { 943 | // must follow chain from first cluster 944 | curCluster_ = firstCluster_; 945 | } else { 946 | // advance from curPosition 947 | nNew -= nCur; 948 | } 949 | while (nNew--) { 950 | if (!vol_->fatGet(curCluster_, &curCluster_)) return false; 951 | } 952 | curPosition_ = pos; 953 | return true; 954 | } 955 | //------------------------------------------------------------------------------ 956 | /** 957 | * The sync() call causes all modified data and directory fields 958 | * to be written to the storage device. 959 | * 960 | * \return The value one, true, is returned for success and 961 | * the value zero, false, is returned for failure. 962 | * Reasons for failure include a call to sync() before a file has been 963 | * opened or an I/O error. 964 | */ 965 | uint8_t SdFile::sync(void) { 966 | // only allow open files and directories 967 | if (!isOpen()) return false; 968 | 969 | if (flags_ & F_FILE_DIR_DIRTY) { 970 | dir_t* d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); 971 | if (!d) return false; 972 | 973 | // do not set filesize for dir files 974 | if (!isDir()) d->fileSize = fileSize_; 975 | 976 | // update first cluster fields 977 | d->firstClusterLow = firstCluster_ & 0XFFFF; 978 | d->firstClusterHigh = firstCluster_ >> 16; 979 | 980 | // set modify time if user supplied a callback date/time function 981 | if (dateTime_) { 982 | dateTime_(&d->lastWriteDate, &d->lastWriteTime); 983 | d->lastAccessDate = d->lastWriteDate; 984 | } 985 | // clear directory dirty 986 | flags_ &= ~F_FILE_DIR_DIRTY; 987 | } 988 | return SdVolume::cacheFlush(); 989 | } 990 | //------------------------------------------------------------------------------ 991 | /** 992 | * Set a file's timestamps in its directory entry. 993 | * 994 | * \param[in] flags Values for \a flags are constructed by a bitwise-inclusive 995 | * OR of flags from the following list 996 | * 997 | * T_ACCESS - Set the file's last access date. 998 | * 999 | * T_CREATE - Set the file's creation date and time. 1000 | * 1001 | * T_WRITE - Set the file's last write/modification date and time. 1002 | * 1003 | * \param[in] year Valid range 1980 - 2107 inclusive. 1004 | * 1005 | * \param[in] month Valid range 1 - 12 inclusive. 1006 | * 1007 | * \param[in] day Valid range 1 - 31 inclusive. 1008 | * 1009 | * \param[in] hour Valid range 0 - 23 inclusive. 1010 | * 1011 | * \param[in] minute Valid range 0 - 59 inclusive. 1012 | * 1013 | * \param[in] second Valid range 0 - 59 inclusive 1014 | * 1015 | * \note It is possible to set an invalid date since there is no check for 1016 | * the number of days in a month. 1017 | * 1018 | * \note 1019 | * Modify and access timestamps may be overwritten if a date time callback 1020 | * function has been set by dateTimeCallback(). 1021 | * 1022 | * \return The value one, true, is returned for success and 1023 | * the value zero, false, is returned for failure. 1024 | */ 1025 | uint8_t SdFile::timestamp(uint8_t flags, uint16_t year, uint8_t month, 1026 | uint8_t day, uint8_t hour, uint8_t minute, uint8_t second) { 1027 | if (!isOpen() 1028 | || year < 1980 1029 | || year > 2107 1030 | || month < 1 1031 | || month > 12 1032 | || day < 1 1033 | || day > 31 1034 | || hour > 23 1035 | || minute > 59 1036 | || second > 59) { 1037 | return false; 1038 | } 1039 | dir_t* d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); 1040 | if (!d) return false; 1041 | 1042 | uint16_t dirDate = FAT_DATE(year, month, day); 1043 | uint16_t dirTime = FAT_TIME(hour, minute, second); 1044 | if (flags & T_ACCESS) { 1045 | d->lastAccessDate = dirDate; 1046 | } 1047 | if (flags & T_CREATE) { 1048 | d->creationDate = dirDate; 1049 | d->creationTime = dirTime; 1050 | // seems to be units of 1/100 second not 1/10 as Microsoft states 1051 | d->creationTimeTenths = second & 1 ? 100 : 0; 1052 | } 1053 | if (flags & T_WRITE) { 1054 | d->lastWriteDate = dirDate; 1055 | d->lastWriteTime = dirTime; 1056 | } 1057 | SdVolume::cacheSetDirty(); 1058 | return sync(); 1059 | } 1060 | //------------------------------------------------------------------------------ 1061 | /** 1062 | * Truncate a file to a specified length. The current file position 1063 | * will be maintained if it is less than or equal to \a length otherwise 1064 | * it will be set to end of file. 1065 | * 1066 | * \param[in] length The desired length for the file. 1067 | * 1068 | * \return The value one, true, is returned for success and 1069 | * the value zero, false, is returned for failure. 1070 | * Reasons for failure include file is read only, file is a directory, 1071 | * \a length is greater than the current file size or an I/O error occurs. 1072 | */ 1073 | uint8_t SdFile::truncate(uint32_t length) { 1074 | // error if not a normal file or read-only 1075 | if (!isFile() || !(flags_ & F_WRITE)) return false; 1076 | 1077 | // error if length is greater than current size 1078 | if (length > fileSize_) return false; 1079 | 1080 | // fileSize and length are zero - nothing to do 1081 | if (fileSize_ == 0) return true; 1082 | 1083 | // remember position for seek after truncation 1084 | uint32_t newPos = curPosition_ > length ? length : curPosition_; 1085 | 1086 | // position to last cluster in truncated file 1087 | if (!seekSet(length)) return false; 1088 | 1089 | if (length == 0) { 1090 | // free all clusters 1091 | if (!vol_->freeChain(firstCluster_)) return false; 1092 | firstCluster_ = 0; 1093 | } else { 1094 | uint32_t toFree; 1095 | if (!vol_->fatGet(curCluster_, &toFree)) return false; 1096 | 1097 | if (!vol_->isEOC(toFree)) { 1098 | // free extra clusters 1099 | if (!vol_->freeChain(toFree)) return false; 1100 | 1101 | // current cluster is end of chain 1102 | if (!vol_->fatPutEOC(curCluster_)) return false; 1103 | } 1104 | } 1105 | fileSize_ = length; 1106 | 1107 | // need to update directory entry 1108 | flags_ |= F_FILE_DIR_DIRTY; 1109 | 1110 | if (!sync()) return false; 1111 | 1112 | // set file to correct position 1113 | return seekSet(newPos); 1114 | } 1115 | //------------------------------------------------------------------------------ 1116 | /** 1117 | * Write data to an open file. 1118 | * 1119 | * \note Data is moved to the cache but may not be written to the 1120 | * storage device until sync() is called. 1121 | * 1122 | * \param[in] buf Pointer to the location of the data to be written. 1123 | * 1124 | * \param[in] nbyte Number of bytes to write. 1125 | * 1126 | * \return For success write() returns the number of bytes written, always 1127 | * \a nbyte. If an error occurs, write() returns -1. Possible errors 1128 | * include write() is called before a file has been opened, write is called 1129 | * for a read-only file, device is full, a corrupt file system or an I/O error. 1130 | * 1131 | */ 1132 | size_t SdFile::write(const void* buf, uint16_t nbyte) { 1133 | // convert void* to uint8_t* - must be before goto statements 1134 | const uint8_t* src = reinterpret_cast(buf); 1135 | 1136 | // number of bytes left to write - must be before goto statements 1137 | uint16_t nToWrite = nbyte; 1138 | 1139 | // error if not a normal file or is read-only 1140 | if (!isFile() || !(flags_ & F_WRITE)) goto writeErrorReturn; 1141 | 1142 | // seek to end of file if append flag 1143 | if ((flags_ & F_APPEND) && curPosition_ != fileSize_) { 1144 | if (!seekEnd()) goto writeErrorReturn; 1145 | } 1146 | 1147 | while (nToWrite > 0) { 1148 | uint8_t blockOfCluster = vol_->blockOfCluster(curPosition_); 1149 | uint16_t blockOffset = curPosition_ & 0X1FF; 1150 | if (blockOfCluster == 0 && blockOffset == 0) { 1151 | // start of new cluster 1152 | if (curCluster_ == 0) { 1153 | if (firstCluster_ == 0) { 1154 | // allocate first cluster of file 1155 | if (!addCluster()) goto writeErrorReturn; 1156 | } else { 1157 | curCluster_ = firstCluster_; 1158 | } 1159 | } else { 1160 | uint32_t next; 1161 | if (!vol_->fatGet(curCluster_, &next)) return false; 1162 | if (vol_->isEOC(next)) { 1163 | // add cluster if at end of chain 1164 | if (!addCluster()) goto writeErrorReturn; 1165 | } else { 1166 | curCluster_ = next; 1167 | } 1168 | } 1169 | } 1170 | // max space in block 1171 | uint16_t n = 512 - blockOffset; 1172 | 1173 | // lesser of space and amount to write 1174 | if (n > nToWrite) n = nToWrite; 1175 | 1176 | // block for data write 1177 | uint32_t block = vol_->clusterStartBlock(curCluster_) + blockOfCluster; 1178 | if (n == 512) { 1179 | // full block - don't need to use cache 1180 | // invalidate cache if block is in cache 1181 | if (SdVolume::cacheBlockNumber_ == block) { 1182 | SdVolume::cacheBlockNumber_ = 0XFFFFFFFF; 1183 | } 1184 | if (!vol_->writeBlock(block, src)) goto writeErrorReturn; 1185 | src += 512; 1186 | } else { 1187 | if (blockOffset == 0 && curPosition_ >= fileSize_) { 1188 | // start of new block don't need to read into cache 1189 | if (!SdVolume::cacheFlush()) goto writeErrorReturn; 1190 | SdVolume::cacheBlockNumber_ = block; 1191 | SdVolume::cacheSetDirty(); 1192 | } else { 1193 | // rewrite part of block 1194 | if (!SdVolume::cacheRawBlock(block, SdVolume::CACHE_FOR_WRITE)) { 1195 | goto writeErrorReturn; 1196 | } 1197 | } 1198 | uint8_t* dst = SdVolume::cacheBuffer_.data + blockOffset; 1199 | uint8_t* end = dst + n; 1200 | while (dst != end) *dst++ = *src++; 1201 | } 1202 | nToWrite -= n; 1203 | curPosition_ += n; 1204 | } 1205 | if (curPosition_ > fileSize_) { 1206 | // update fileSize and insure sync will update dir entry 1207 | fileSize_ = curPosition_; 1208 | flags_ |= F_FILE_DIR_DIRTY; 1209 | } else if (dateTime_ && nbyte) { 1210 | // insure sync will update modified date and time 1211 | flags_ |= F_FILE_DIR_DIRTY; 1212 | } 1213 | 1214 | if (flags_ & F_SYNC) { 1215 | if (!sync()) goto writeErrorReturn; 1216 | } 1217 | return nbyte; 1218 | 1219 | writeErrorReturn: 1220 | // return for write error 1221 | //writeError = true; 1222 | setWriteError(); 1223 | return 0; 1224 | } 1225 | //------------------------------------------------------------------------------ 1226 | /** 1227 | * Write a byte to a file. Required by the Arduino Print class. 1228 | * 1229 | * Use SdFile::writeError to check for errors. 1230 | */ 1231 | size_t SdFile::write(uint8_t b) { 1232 | return write(&b, 1); 1233 | } 1234 | //------------------------------------------------------------------------------ 1235 | /** 1236 | * Write a string to a file. Used by the Arduino Print class. 1237 | * 1238 | * Use SdFile::writeError to check for errors. 1239 | */ 1240 | size_t SdFile::write(const char* str) { 1241 | return write(str, strlen(str)); 1242 | } 1243 | #ifdef __AVR__ 1244 | //------------------------------------------------------------------------------ 1245 | /** 1246 | * Write a PROGMEM string to a file. 1247 | * 1248 | * Use SdFile::writeError to check for errors. 1249 | */ 1250 | void SdFile::write_P(PGM_P str) { 1251 | for (uint8_t c; (c = pgm_read_byte(str)); str++) write(c); 1252 | } 1253 | //------------------------------------------------------------------------------ 1254 | /** 1255 | * Write a PROGMEM string followed by CR/LF to a file. 1256 | * 1257 | * Use SdFile::writeError to check for errors. 1258 | */ 1259 | void SdFile::writeln_P(PGM_P str) { 1260 | write_P(str); 1261 | println(); 1262 | } 1263 | #endif 1264 | -------------------------------------------------------------------------------- /utility/SdInfo.h: -------------------------------------------------------------------------------- 1 | /* Arduino Sd2Card Library 2 | * Copyright (C) 2009 by William Greiman 3 | * 4 | * This file is part of the Arduino Sd2Card Library 5 | * 6 | * This Library is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This Library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with the Arduino Sd2Card Library. If not, see 18 | * . 19 | */ 20 | #ifndef SdInfo_h 21 | #define SdInfo_h 22 | #include 23 | // Based on the document: 24 | // 25 | // SD Specifications 26 | // Part 1 27 | // Physical Layer 28 | // Simplified Specification 29 | // Version 2.00 30 | // September 25, 2006 31 | // 32 | // www.sdcard.org/developers/tech/sdcard/pls/Simplified_Physical_Layer_Spec.pdf 33 | //------------------------------------------------------------------------------ 34 | // SD card commands 35 | /** GO_IDLE_STATE - init card in spi mode if CS low */ 36 | uint8_t const CMD0 = 0X00; 37 | /** SEND_IF_COND - verify SD Memory Card interface operating condition.*/ 38 | uint8_t const CMD8 = 0X08; 39 | /** SEND_CSD - read the Card Specific Data (CSD register) */ 40 | uint8_t const CMD9 = 0X09; 41 | /** SEND_CID - read the card identification information (CID register) */ 42 | uint8_t const CMD10 = 0X0A; 43 | /** SEND_STATUS - read the card status register */ 44 | uint8_t const CMD13 = 0X0D; 45 | /** READ_BLOCK - read a single data block from the card */ 46 | uint8_t const CMD17 = 0X11; 47 | /** WRITE_BLOCK - write a single data block to the card */ 48 | uint8_t const CMD24 = 0X18; 49 | /** WRITE_MULTIPLE_BLOCK - write blocks of data until a STOP_TRANSMISSION */ 50 | uint8_t const CMD25 = 0X19; 51 | /** ERASE_WR_BLK_START - sets the address of the first block to be erased */ 52 | uint8_t const CMD32 = 0X20; 53 | /** ERASE_WR_BLK_END - sets the address of the last block of the continuous 54 | range to be erased*/ 55 | uint8_t const CMD33 = 0X21; 56 | /** ERASE - erase all previously selected blocks */ 57 | uint8_t const CMD38 = 0X26; 58 | /** APP_CMD - escape for application specific command */ 59 | uint8_t const CMD55 = 0X37; 60 | /** READ_OCR - read the OCR register of a card */ 61 | uint8_t const CMD58 = 0X3A; 62 | /** SET_WR_BLK_ERASE_COUNT - Set the number of write blocks to be 63 | pre-erased before writing */ 64 | uint8_t const ACMD23 = 0X17; 65 | /** SD_SEND_OP_COMD - Sends host capacity support information and 66 | activates the card's initialization process */ 67 | uint8_t const ACMD41 = 0X29; 68 | //------------------------------------------------------------------------------ 69 | /** status for card in the ready state */ 70 | uint8_t const R1_READY_STATE = 0X00; 71 | /** status for card in the idle state */ 72 | uint8_t const R1_IDLE_STATE = 0X01; 73 | /** status bit for illegal command */ 74 | uint8_t const R1_ILLEGAL_COMMAND = 0X04; 75 | /** start data token for read or write single block*/ 76 | uint8_t const DATA_START_BLOCK = 0XFE; 77 | /** stop token for write multiple blocks*/ 78 | uint8_t const STOP_TRAN_TOKEN = 0XFD; 79 | /** start data token for write multiple blocks*/ 80 | uint8_t const WRITE_MULTIPLE_TOKEN = 0XFC; 81 | /** mask for data response tokens after a write block operation */ 82 | uint8_t const DATA_RES_MASK = 0X1F; 83 | /** write data accepted token */ 84 | uint8_t const DATA_RES_ACCEPTED = 0X05; 85 | //------------------------------------------------------------------------------ 86 | typedef struct CID { 87 | // byte 0 88 | uint8_t mid; // Manufacturer ID 89 | // byte 1-2 90 | char oid[2]; // OEM/Application ID 91 | // byte 3-7 92 | char pnm[5]; // Product name 93 | // byte 8 94 | unsigned prv_m : 4; // Product revision n.m 95 | unsigned prv_n : 4; 96 | // byte 9-12 97 | uint32_t psn; // Product serial number 98 | // byte 13 99 | unsigned mdt_year_high : 4; // Manufacturing date 100 | unsigned reserved : 4; 101 | // byte 14 102 | unsigned mdt_month : 4; 103 | unsigned mdt_year_low :4; 104 | // byte 15 105 | unsigned always1 : 1; 106 | unsigned crc : 7; 107 | }cid_t; 108 | //------------------------------------------------------------------------------ 109 | // CSD for version 1.00 cards 110 | typedef struct CSDV1 { 111 | // byte 0 112 | unsigned reserved1 : 6; 113 | unsigned csd_ver : 2; 114 | // byte 1 115 | uint8_t taac; 116 | // byte 2 117 | uint8_t nsac; 118 | // byte 3 119 | uint8_t tran_speed; 120 | // byte 4 121 | uint8_t ccc_high; 122 | // byte 5 123 | unsigned read_bl_len : 4; 124 | unsigned ccc_low : 4; 125 | // byte 6 126 | unsigned c_size_high : 2; 127 | unsigned reserved2 : 2; 128 | unsigned dsr_imp : 1; 129 | unsigned read_blk_misalign :1; 130 | unsigned write_blk_misalign : 1; 131 | unsigned read_bl_partial : 1; 132 | // byte 7 133 | uint8_t c_size_mid; 134 | // byte 8 135 | unsigned vdd_r_curr_max : 3; 136 | unsigned vdd_r_curr_min : 3; 137 | unsigned c_size_low :2; 138 | // byte 9 139 | unsigned c_size_mult_high : 2; 140 | unsigned vdd_w_cur_max : 3; 141 | unsigned vdd_w_curr_min : 3; 142 | // byte 10 143 | unsigned sector_size_high : 6; 144 | unsigned erase_blk_en : 1; 145 | unsigned c_size_mult_low : 1; 146 | // byte 11 147 | unsigned wp_grp_size : 7; 148 | unsigned sector_size_low : 1; 149 | // byte 12 150 | unsigned write_bl_len_high : 2; 151 | unsigned r2w_factor : 3; 152 | unsigned reserved3 : 2; 153 | unsigned wp_grp_enable : 1; 154 | // byte 13 155 | unsigned reserved4 : 5; 156 | unsigned write_partial : 1; 157 | unsigned write_bl_len_low : 2; 158 | // byte 14 159 | unsigned reserved5: 2; 160 | unsigned file_format : 2; 161 | unsigned tmp_write_protect : 1; 162 | unsigned perm_write_protect : 1; 163 | unsigned copy : 1; 164 | unsigned file_format_grp : 1; 165 | // byte 15 166 | unsigned always1 : 1; 167 | unsigned crc : 7; 168 | }csd1_t; 169 | //------------------------------------------------------------------------------ 170 | // CSD for version 2.00 cards 171 | typedef struct CSDV2 { 172 | // byte 0 173 | unsigned reserved1 : 6; 174 | unsigned csd_ver : 2; 175 | // byte 1 176 | uint8_t taac; 177 | // byte 2 178 | uint8_t nsac; 179 | // byte 3 180 | uint8_t tran_speed; 181 | // byte 4 182 | uint8_t ccc_high; 183 | // byte 5 184 | unsigned read_bl_len : 4; 185 | unsigned ccc_low : 4; 186 | // byte 6 187 | unsigned reserved2 : 4; 188 | unsigned dsr_imp : 1; 189 | unsigned read_blk_misalign :1; 190 | unsigned write_blk_misalign : 1; 191 | unsigned read_bl_partial : 1; 192 | // byte 7 193 | unsigned reserved3 : 2; 194 | unsigned c_size_high : 6; 195 | // byte 8 196 | uint8_t c_size_mid; 197 | // byte 9 198 | uint8_t c_size_low; 199 | // byte 10 200 | unsigned sector_size_high : 6; 201 | unsigned erase_blk_en : 1; 202 | unsigned reserved4 : 1; 203 | // byte 11 204 | unsigned wp_grp_size : 7; 205 | unsigned sector_size_low : 1; 206 | // byte 12 207 | unsigned write_bl_len_high : 2; 208 | unsigned r2w_factor : 3; 209 | unsigned reserved5 : 2; 210 | unsigned wp_grp_enable : 1; 211 | // byte 13 212 | unsigned reserved6 : 5; 213 | unsigned write_partial : 1; 214 | unsigned write_bl_len_low : 2; 215 | // byte 14 216 | unsigned reserved7: 2; 217 | unsigned file_format : 2; 218 | unsigned tmp_write_protect : 1; 219 | unsigned perm_write_protect : 1; 220 | unsigned copy : 1; 221 | unsigned file_format_grp : 1; 222 | // byte 15 223 | unsigned always1 : 1; 224 | unsigned crc : 7; 225 | }csd2_t; 226 | //------------------------------------------------------------------------------ 227 | // union of old and new style CSD register 228 | union csd_t { 229 | csd1_t v1; 230 | csd2_t v2; 231 | }; 232 | #endif // SdInfo_h 233 | -------------------------------------------------------------------------------- /utility/SdVolume.cpp: -------------------------------------------------------------------------------- 1 | /* Arduino SdFat Library 2 | * Copyright (C) 2009 by William Greiman 3 | * 4 | * This file is part of the Arduino SdFat Library 5 | * 6 | * This Library is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This Library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with the Arduino SdFat Library. If not, see 18 | * . 19 | */ 20 | #include "SdFat.h" 21 | //------------------------------------------------------------------------------ 22 | // raw block cache 23 | // init cacheBlockNumber_to invalid SD block number 24 | uint32_t SdVolume::cacheBlockNumber_ = 0XFFFFFFFF; 25 | cache_t SdVolume::cacheBuffer_; // 512 byte cache for Sd2Card 26 | Sd2Card* SdVolume::sdCard_; // pointer to SD card object 27 | uint8_t SdVolume::cacheDirty_ = 0; // cacheFlush() will write block if true 28 | uint32_t SdVolume::cacheMirrorBlock_ = 0; // mirror block for second FAT 29 | //------------------------------------------------------------------------------ 30 | // find a contiguous group of clusters 31 | uint8_t SdVolume::allocContiguous(uint32_t count, uint32_t* curCluster) { 32 | // start of group 33 | uint32_t bgnCluster; 34 | 35 | // flag to save place to start next search 36 | uint8_t setStart; 37 | 38 | // set search start cluster 39 | if (*curCluster) { 40 | // try to make file contiguous 41 | bgnCluster = *curCluster + 1; 42 | 43 | // don't save new start location 44 | setStart = false; 45 | } else { 46 | // start at likely place for free cluster 47 | bgnCluster = allocSearchStart_; 48 | 49 | // save next search start if one cluster 50 | setStart = 1 == count; 51 | } 52 | // end of group 53 | uint32_t endCluster = bgnCluster; 54 | 55 | // last cluster of FAT 56 | uint32_t fatEnd = clusterCount_ + 1; 57 | 58 | // search the FAT for free clusters 59 | for (uint32_t n = 0;; n++, endCluster++) { 60 | // can't find space checked all clusters 61 | if (n >= clusterCount_) return false; 62 | 63 | // past end - start from beginning of FAT 64 | if (endCluster > fatEnd) { 65 | bgnCluster = endCluster = 2; 66 | } 67 | uint32_t f; 68 | if (!fatGet(endCluster, &f)) return false; 69 | 70 | if (f != 0) { 71 | // cluster in use try next cluster as bgnCluster 72 | bgnCluster = endCluster + 1; 73 | } else if ((endCluster - bgnCluster + 1) == count) { 74 | // done - found space 75 | break; 76 | } 77 | } 78 | // mark end of chain 79 | if (!fatPutEOC(endCluster)) return false; 80 | 81 | // link clusters 82 | while (endCluster > bgnCluster) { 83 | if (!fatPut(endCluster - 1, endCluster)) return false; 84 | endCluster--; 85 | } 86 | if (*curCluster != 0) { 87 | // connect chains 88 | if (!fatPut(*curCluster, bgnCluster)) return false; 89 | } 90 | // return first cluster number to caller 91 | *curCluster = bgnCluster; 92 | 93 | // remember possible next free cluster 94 | if (setStart) allocSearchStart_ = bgnCluster + 1; 95 | 96 | return true; 97 | } 98 | //------------------------------------------------------------------------------ 99 | uint8_t SdVolume::cacheFlush(void) { 100 | if (cacheDirty_) { 101 | if (!sdCard_->writeBlock(cacheBlockNumber_, cacheBuffer_.data)) { 102 | return false; 103 | } 104 | // mirror FAT tables 105 | if (cacheMirrorBlock_) { 106 | if (!sdCard_->writeBlock(cacheMirrorBlock_, cacheBuffer_.data)) { 107 | return false; 108 | } 109 | cacheMirrorBlock_ = 0; 110 | } 111 | cacheDirty_ = 0; 112 | } 113 | return true; 114 | } 115 | //------------------------------------------------------------------------------ 116 | uint8_t SdVolume::cacheRawBlock(uint32_t blockNumber, uint8_t action) { 117 | if (cacheBlockNumber_ != blockNumber) { 118 | if (!cacheFlush()) return false; 119 | if (!sdCard_->readBlock(blockNumber, cacheBuffer_.data)) return false; 120 | cacheBlockNumber_ = blockNumber; 121 | } 122 | cacheDirty_ |= action; 123 | return true; 124 | } 125 | //------------------------------------------------------------------------------ 126 | // cache a zero block for blockNumber 127 | uint8_t SdVolume::cacheZeroBlock(uint32_t blockNumber) { 128 | if (!cacheFlush()) return false; 129 | 130 | // loop take less flash than memset(cacheBuffer_.data, 0, 512); 131 | for (uint16_t i = 0; i < 512; i++) { 132 | cacheBuffer_.data[i] = 0; 133 | } 134 | cacheBlockNumber_ = blockNumber; 135 | cacheSetDirty(); 136 | return true; 137 | } 138 | //------------------------------------------------------------------------------ 139 | // return the size in bytes of a cluster chain 140 | uint8_t SdVolume::chainSize(uint32_t cluster, uint32_t* size) const { 141 | uint32_t s = 0; 142 | do { 143 | if (!fatGet(cluster, &cluster)) return false; 144 | s += 512UL << clusterSizeShift_; 145 | } while (!isEOC(cluster)); 146 | *size = s; 147 | return true; 148 | } 149 | //------------------------------------------------------------------------------ 150 | // Fetch a FAT entry 151 | uint8_t SdVolume::fatGet(uint32_t cluster, uint32_t* value) const { 152 | if (cluster > (clusterCount_ + 1)) return false; 153 | uint32_t lba = fatStartBlock_; 154 | lba += fatType_ == 16 ? cluster >> 8 : cluster >> 7; 155 | if (lba != cacheBlockNumber_) { 156 | if (!cacheRawBlock(lba, CACHE_FOR_READ)) return false; 157 | } 158 | if (fatType_ == 16) { 159 | *value = cacheBuffer_.fat16[cluster & 0XFF]; 160 | } else { 161 | *value = cacheBuffer_.fat32[cluster & 0X7F] & FAT32MASK; 162 | } 163 | return true; 164 | } 165 | //------------------------------------------------------------------------------ 166 | // Store a FAT entry 167 | uint8_t SdVolume::fatPut(uint32_t cluster, uint32_t value) { 168 | // error if reserved cluster 169 | if (cluster < 2) return false; 170 | 171 | // error if not in FAT 172 | if (cluster > (clusterCount_ + 1)) return false; 173 | 174 | // calculate block address for entry 175 | uint32_t lba = fatStartBlock_; 176 | lba += fatType_ == 16 ? cluster >> 8 : cluster >> 7; 177 | 178 | if (lba != cacheBlockNumber_) { 179 | if (!cacheRawBlock(lba, CACHE_FOR_READ)) return false; 180 | } 181 | // store entry 182 | if (fatType_ == 16) { 183 | cacheBuffer_.fat16[cluster & 0XFF] = value; 184 | } else { 185 | cacheBuffer_.fat32[cluster & 0X7F] = value; 186 | } 187 | cacheSetDirty(); 188 | 189 | // mirror second FAT 190 | if (fatCount_ > 1) cacheMirrorBlock_ = lba + blocksPerFat_; 191 | return true; 192 | } 193 | //------------------------------------------------------------------------------ 194 | // free a cluster chain 195 | uint8_t SdVolume::freeChain(uint32_t cluster) { 196 | // clear free cluster location 197 | allocSearchStart_ = 2; 198 | 199 | do { 200 | uint32_t next; 201 | if (!fatGet(cluster, &next)) return false; 202 | 203 | // free cluster 204 | if (!fatPut(cluster, 0)) return false; 205 | 206 | cluster = next; 207 | } while (!isEOC(cluster)); 208 | 209 | return true; 210 | } 211 | //------------------------------------------------------------------------------ 212 | /** 213 | * Initialize a FAT volume. 214 | * 215 | * \param[in] dev The SD card where the volume is located. 216 | * 217 | * \param[in] part The partition to be used. Legal values for \a part are 218 | * 1-4 to use the corresponding partition on a device formatted with 219 | * a MBR, Master Boot Record, or zero if the device is formatted as 220 | * a super floppy with the FAT boot sector in block zero. 221 | * 222 | * \return The value one, true, is returned for success and 223 | * the value zero, false, is returned for failure. Reasons for 224 | * failure include not finding a valid partition, not finding a valid 225 | * FAT file system in the specified partition or an I/O error. 226 | */ 227 | uint8_t SdVolume::init(Sd2Card* dev, uint8_t part) { 228 | uint32_t volumeStartBlock = 0; 229 | sdCard_ = dev; 230 | // if part == 0 assume super floppy with FAT boot sector in block zero 231 | // if part > 0 assume mbr volume with partition table 232 | if (part) { 233 | if (part > 4)return false; 234 | if (!cacheRawBlock(volumeStartBlock, CACHE_FOR_READ)) return false; 235 | part_t* p = &cacheBuffer_.mbr.part[part-1]; 236 | if ((p->boot & 0X7F) !=0 || 237 | p->totalSectors < 100 || 238 | p->firstSector == 0) { 239 | // not a valid partition 240 | return false; 241 | } 242 | volumeStartBlock = p->firstSector; 243 | } 244 | if (!cacheRawBlock(volumeStartBlock, CACHE_FOR_READ)) return false; 245 | bpb_t* bpb = &cacheBuffer_.fbs.bpb; 246 | if (bpb->bytesPerSector != 512 || 247 | bpb->fatCount == 0 || 248 | bpb->reservedSectorCount == 0 || 249 | bpb->sectorsPerCluster == 0) { 250 | // not valid FAT volume 251 | return false; 252 | } 253 | fatCount_ = bpb->fatCount; 254 | blocksPerCluster_ = bpb->sectorsPerCluster; 255 | 256 | // determine shift that is same as multiply by blocksPerCluster_ 257 | clusterSizeShift_ = 0; 258 | while (blocksPerCluster_ != (1 << clusterSizeShift_)) { 259 | // error if not power of 2 260 | if (clusterSizeShift_++ > 7) return false; 261 | } 262 | blocksPerFat_ = bpb->sectorsPerFat16 ? 263 | bpb->sectorsPerFat16 : bpb->sectorsPerFat32; 264 | 265 | fatStartBlock_ = volumeStartBlock + bpb->reservedSectorCount; 266 | 267 | // count for FAT16 zero for FAT32 268 | rootDirEntryCount_ = bpb->rootDirEntryCount; 269 | 270 | // directory start for FAT16 dataStart for FAT32 271 | rootDirStart_ = fatStartBlock_ + bpb->fatCount * blocksPerFat_; 272 | 273 | // data start for FAT16 and FAT32 274 | dataStartBlock_ = rootDirStart_ + ((32 * bpb->rootDirEntryCount + 511)/512); 275 | 276 | // total blocks for FAT16 or FAT32 277 | uint32_t totalBlocks = bpb->totalSectors16 ? 278 | bpb->totalSectors16 : bpb->totalSectors32; 279 | // total data blocks 280 | clusterCount_ = totalBlocks - (dataStartBlock_ - volumeStartBlock); 281 | 282 | // divide by cluster size to get cluster count 283 | clusterCount_ >>= clusterSizeShift_; 284 | 285 | // FAT type is determined by cluster count 286 | if (clusterCount_ < 4085) { 287 | fatType_ = 12; 288 | } else if (clusterCount_ < 65525) { 289 | fatType_ = 16; 290 | } else { 291 | rootDirStart_ = bpb->fat32RootCluster; 292 | fatType_ = 32; 293 | } 294 | return true; 295 | } 296 | --------------------------------------------------------------------------------