├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── examples ├── DirectoryFunctions │ └── DirectoryFunctions.cpp ├── LowLatencyLogger │ └── LowLatencyLogger.cpp ├── OpenNext │ └── OpenNext.cpp ├── ReadCsvArray │ └── ReadCsvArray.cpp ├── ReadCsvFields │ └── ReadCsvFields.cpp ├── SdFormatter │ └── SdFormatter.cpp ├── SdInfo │ └── SdInfo.cpp ├── Timestamp │ └── Timestamp.cpp ├── TryMeFirst │ └── TryMeFirst.cpp ├── VolumeFreeSpace │ └── VolumeFreeSpace.cpp └── bench │ └── bench.cpp ├── library.properties └── src ├── ArduinoFiles.h ├── ArduinoStream.h ├── FatApiConstants.h ├── FatFile.cpp ├── FatFile.h ├── FatFileLFN.cpp ├── FatFilePrint.cpp ├── FatFileSFN.cpp ├── FatFileSystem.h ├── FatLib.h ├── FatLibConfig.h ├── FatStructs.h ├── FatVolume.cpp ├── FatVolume.h ├── FmtNumber.cpp ├── FmtNumber.h ├── FreeStack.h ├── SdFat.cpp ├── SdFat.h ├── SdFat ├── ArduinoFiles.h ├── ArduinoStream.h ├── FatApiConstants.h ├── FatFile.h ├── FatFileSystem.h ├── FatLib.h ├── FatLibConfig.h ├── FatStructs.h ├── FatVolume.h ├── FmtNumber.h ├── FreeStack.h ├── SdFat.h ├── SdFatConfig.h ├── SdInfo.h ├── SdSpi.h ├── SdSpiCard.h ├── SoftSPIParticle.h ├── StdioStream.h ├── SysCall.h ├── SystemInclude.h ├── bufstream.h ├── fstream.h ├── ios.h ├── iostream.h ├── istream.h └── ostream.h ├── SdFatConfig.h ├── SdInfo.h ├── SdSpi.h ├── SdSpiCard.cpp ├── SdSpiCard.h ├── SdSpiParticle.cpp ├── SoftSPIParticle.h ├── StdioStream.cpp ├── StdioStream.h ├── SysCall.h ├── SystemInclude.h ├── bufstream.h ├── fstream.cpp ├── fstream.h ├── ios.h ├── iostream.h ├── istream.cpp ├── istream.h ├── ostream.cpp └── ostream.h /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear in the root of a volume 35 | .DocumentRevisions-V100 36 | .fseventsd 37 | .Spotlight-V100 38 | .TemporaryItems 39 | .Trashes 40 | .VolumeIcon.icns 41 | 42 | # Directories potentially created on remote AFP share 43 | .AppleDB 44 | .AppleDesktop 45 | Network Trash Folder 46 | Temporary Items 47 | .apdisk 48 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | About 2 | === 3 | SdFat-Particle is a port of the SdFat library for [Particle](https://www.particle.io/) development boards. 4 | 5 | The SdFat library provides read/write access to FAT16/FAT32 file systems on SD/SDHC flash cards. 6 | 7 | SdFat for Particle supports fast DMA access for all SPI interfaces on Particle devices. 8 | 9 | SdFat supports long filenames. 10 | 11 | 12 | ## Documentation 13 | 14 | Download the SdFat-Particle-doc repository from GitHub. 15 | 16 | https://github.com/greiman/SdFat-Particle-doc 17 | 18 | Please read the html documentation in the html folder by opening SdFat.html. 19 | 20 | Look at the classes tab for details about class member functions. 21 | 22 | 23 | ## Examples 24 | 25 | Please try the examples in the firmware/examples folder. 26 | 27 | Start with the TryMeFirst example. 28 | 29 | You can check the performance of your SD card with the bench example. 30 | 31 | Here is a list of example files I have tested on P1/photon. 32 | 33 | bench.cpp - Benchmark SD read/write speed. 34 | 35 | DirectoryFunctions.cpp - Demonstrate chdir(), ls(), mkdir(), and rmdir(). 36 | 37 | LowLatencyLogger.cpp - High speed binary data logger. 38 | 39 | OpenNext.cpp - Open all files in a directory. 40 | 41 | ReadCsvArray.cpp - Function to read an array from a csv file. 42 | 43 | ReadCsvFields.cpp - Function to read csv fields. 44 | 45 | SdFormatter.cpp - Format an SD card according to the SD standard. 46 | 47 | SdInfo.cpp - Display information about an SD card. 48 | 49 | Timestamp.cpp - Shows how to time-stamp files. 50 | 51 | TryMeFirst.cpp - A simple read/write example. 52 | 53 | VolumeFreeSpace.cpp - Determine free space in a volume. 54 | 55 | -------------------------------------------------------------------------------- /examples/DirectoryFunctions/DirectoryFunctions.cpp: -------------------------------------------------------------------------------- 1 | #include "SdFat.h" 2 | /* 3 | * Example use of chdir(), ls(), mkdir(), and rmdir(). 4 | */ 5 | 6 | // SD card chip select pin. 7 | const uint8_t SD_CHIP_SELECT = SS; 8 | //------------------------------------------------------------------------------ 9 | 10 | // File system object. 11 | SdFat sd; 12 | 13 | // Use for file creation in folders. 14 | SdFile file; 15 | 16 | // Create a Serial output stream. 17 | ArduinoOutStream cout(Serial); 18 | 19 | // Buffer for Serial input. 20 | char cinBuf[40]; 21 | 22 | // Create a serial input stream. 23 | ArduinoInStream cin(Serial, cinBuf, sizeof(cinBuf)); 24 | //============================================================================== 25 | // Error messages stored in flash. 26 | #define error(msg) sd.errorHalt(F(msg)) 27 | //------------------------------------------------------------------------------ 28 | void setup() { 29 | Serial.begin(9600); 30 | 31 | // Wait for USB Serial 32 | while (!Serial) { 33 | SysCall::yield(); 34 | } 35 | delay(1000); 36 | 37 | cout << F("Type any character to start\n"); 38 | // Wait for input line and discard. 39 | cin.readline(); 40 | cout << endl; 41 | 42 | // Initialize the SD card at SPI_HALF_SPEED to avoid bus errors with 43 | // breadboards. use SPI_FULL_SPEED for better performance. 44 | if (!sd.begin(SD_CHIP_SELECT, SPI_HALF_SPEED)) { 45 | sd.initErrorHalt(); 46 | } 47 | if (sd.exists("Folder1") 48 | || sd.exists("Folder1/file1.txt") 49 | || sd.exists("Folder1/File2.txt")) { 50 | error("Please remove existing Folder1, file1.txt, and File2.txt"); 51 | } 52 | int rootFileCount = 0; 53 | sd.vwd()->rewind(); 54 | while (file.openNext(sd.vwd(), O_READ)) { 55 | if (!file.isHidden()) { 56 | rootFileCount++; 57 | } 58 | file.close(); 59 | if (rootFileCount > 10) { 60 | error("Too many files in root. Please use an empty SD."); 61 | } 62 | } 63 | if (rootFileCount) { 64 | cout << F("\nPlease use an empty SD for best results.\n\n"); 65 | delay(1000); 66 | } 67 | // Create a new folder. 68 | if (!sd.mkdir("Folder1")) { 69 | error("Create Folder1 failed"); 70 | } 71 | cout << F("Created Folder1\n"); 72 | 73 | // Create a file in Folder1 using a path. 74 | if (!file.open("Folder1/file1.txt", O_CREAT | O_WRITE)) { 75 | error("create Folder1/file1.txt failed"); 76 | } 77 | file.close(); 78 | cout << F("Created Folder1/file1.txt\n"); 79 | 80 | // Change volume working directory to Folder1. 81 | if (!sd.chdir("Folder1")) { 82 | error("chdir failed for Folder1.\n"); 83 | } 84 | cout << F("chdir to Folder1\n"); 85 | 86 | // Create File2.txt in current directory. 87 | if (!file.open("File2.txt", O_CREAT | O_WRITE)) { 88 | error("create File2.txt failed"); 89 | } 90 | file.close(); 91 | cout << F("Created File2.txt in current directory\n"); 92 | 93 | cout << F("\nList of files on the SD.\n"); 94 | sd.ls("/", LS_R); 95 | 96 | // Remove files from current directory. 97 | if (!sd.remove("file1.txt") || !sd.remove("File2.txt")) { 98 | error("remove failed"); 99 | } 100 | cout << F("\nfile1.txt and File2.txt removed.\n"); 101 | 102 | // Change current directory to root. 103 | if (!sd.chdir()) { 104 | error("chdir to root failed.\n"); 105 | } 106 | 107 | cout << F("\nList of files on the SD.\n"); 108 | sd.ls(LS_R); 109 | 110 | // Remove Folder1. 111 | if (!sd.rmdir("Folder1")) { 112 | error("rmdir for Folder1 failed\n"); 113 | } 114 | 115 | cout << F("\nFolder1 removed.\n"); 116 | cout << F("\nList of files on the SD.\n"); 117 | sd.ls(LS_R); 118 | cout << F("Done!\n"); 119 | } 120 | //------------------------------------------------------------------------------ 121 | // Nothing happens in loop. 122 | void loop() {} -------------------------------------------------------------------------------- /examples/OpenNext/OpenNext.cpp: -------------------------------------------------------------------------------- 1 | #include "SdFat.h" 2 | /* 3 | * Print size, modify date/time, and name for all files in root. 4 | */ 5 | 6 | // SD default chip select pin. 7 | const uint8_t chipSelect = SS; 8 | 9 | // file system object 10 | SdFat sd; 11 | 12 | SdFile file; 13 | //------------------------------------------------------------------------------ 14 | void setup() { 15 | Serial.begin(9600); 16 | 17 | // Wait for USB Serial 18 | while (!Serial) { 19 | SysCall::yield(); 20 | } 21 | 22 | Serial.println("Type any character to start"); 23 | while (Serial.read() <= 0) { 24 | SysCall::yield(); 25 | } 26 | 27 | // initialize the SD card at SPI_HALF_SPEED to avoid bus errors with 28 | // breadboards. use SPI_FULL_SPEED for better performance. 29 | if (!sd.begin(chipSelect, SPI_HALF_SPEED)) { 30 | sd.initErrorHalt(); 31 | } 32 | 33 | // Open next file in root. The volume working directory, vwd, is root. 34 | // Warning, openNext starts at the current position of sd.vwd() so a 35 | // rewind may be neccessary in your application. 36 | sd.vwd()->rewind(); 37 | while (file.openNext(sd.vwd(), O_READ)) { 38 | file.printFileSize(&Serial); 39 | Serial.write(' '); 40 | file.printModifyDateTime(&Serial); 41 | Serial.write(' '); 42 | file.printName(&Serial); 43 | if (file.isDir()) { 44 | // Indicate a directory. 45 | Serial.write('/'); 46 | } 47 | Serial.println(); 48 | file.close(); 49 | } 50 | Serial.println("Done!"); 51 | } 52 | //------------------------------------------------------------------------------ 53 | void loop() {} 54 | -------------------------------------------------------------------------------- /examples/ReadCsvArray/ReadCsvArray.cpp: -------------------------------------------------------------------------------- 1 | #include "SdFat.h" 2 | // Read a two dimensional array from a CSV file. 3 | // 4 | #define CS_PIN SS 5 | 6 | // 5 X 4 array 7 | #define ROW_DIM 5 8 | #define COL_DIM 4 9 | 10 | SdFat SD; 11 | File file; 12 | 13 | /* 14 | * Read a file one field at a time. 15 | * 16 | * file - File to read. 17 | * 18 | * str - Character array for the field. 19 | * 20 | * size - Size of str array. 21 | * 22 | * delim - String containing field delimiters. 23 | * 24 | * return - length of field including terminating delimiter. 25 | * 26 | * Note, the last character of str will not be a delimiter if 27 | * a read error occurs, the field is too long, or the file 28 | * does not end with a delimiter. Consider this an error 29 | * if not at end-of-file. 30 | * 31 | */ 32 | size_t readField(File* file, char* str, size_t size, const char* delim) { 33 | char ch; 34 | size_t n = 0; 35 | while ((n + 1) < size && file->read(&ch, 1) == 1) { 36 | // Delete CR. 37 | if (ch == '\r') { 38 | continue; 39 | } 40 | str[n++] = ch; 41 | if (strchr(delim, ch)) { 42 | break; 43 | } 44 | } 45 | str[n] = '\0'; 46 | return n; 47 | } 48 | //------------------------------------------------------------------------------ 49 | #define errorHalt(msg) {Serial.println(F(msg)); SysCall::halt();} 50 | //------------------------------------------------------------------------------ 51 | void setup() { 52 | Serial.begin(9600); 53 | 54 | // Wait for USB Serial 55 | while (!Serial) { 56 | SysCall::yield(); 57 | } 58 | Serial.println("Type any character to start"); 59 | while (Serial.read() <= 0) { 60 | SysCall::yield(); 61 | } 62 | // Initialize the SD. 63 | if (!SD.begin(CS_PIN)) { 64 | errorHalt("begin failed"); 65 | } 66 | // Create or open the file. 67 | file = SD.open("READNUM.TXT", FILE_WRITE); 68 | if (!file) { 69 | errorHalt("open failed"); 70 | } 71 | // Rewind file so test data is not appended. 72 | file.rewind(); 73 | 74 | // Write test data. 75 | file.print(F( 76 | "11,12,13,14\r\n" 77 | "21,22,23,24\r\n" 78 | "31,32,33,34\r\n" 79 | "41,42,43,44\r\n" 80 | "51,52,53,54" // Allow missing endl at eof. 81 | )); 82 | 83 | // Rewind the file for read. 84 | file.rewind(); 85 | 86 | // Array for data. 87 | int array[ROW_DIM][COL_DIM]; 88 | int i = 0; // First array index. 89 | int j = 0; // Second array index 90 | size_t n; // Length of returned field with delimiter. 91 | char str[20]; // Must hold longest field with delimiter and zero byte. 92 | char *ptr; // Test for valid field. 93 | 94 | // Read the file and store the data. 95 | 96 | for (i = 0; i < ROW_DIM; i++) { 97 | for (j = 0; j < COL_DIM; j++) { 98 | n = readField(&file, str, sizeof(str), ",\n"); 99 | if (n == 0) { 100 | errorHalt("Too few lines"); 101 | } 102 | array[i][j] = strtol(str, &ptr, 10); 103 | if (ptr == str) { 104 | errorHalt("bad number"); 105 | } 106 | while (*ptr == ' ') { 107 | ptr++; 108 | } 109 | if (*ptr != ',' && *ptr != '\n' && *ptr != '\0') { 110 | errorHalt("extra characters in field"); 111 | } 112 | if (j < (COL_DIM-1) && str[n-1] != ',') { 113 | errorHalt("line with too few fields"); 114 | } 115 | } 116 | // Allow missing endl at eof. 117 | if (str[n-1] != '\n' && file.available()) { 118 | errorHalt("missing endl"); 119 | } 120 | } 121 | 122 | // Print the array. 123 | for (i = 0; i < ROW_DIM; i++) { 124 | for (j = 0; j < COL_DIM; j++) { 125 | if (j) { 126 | Serial.print(' '); 127 | } 128 | Serial.print(array[i][j]); 129 | } 130 | Serial.println(); 131 | } 132 | Serial.println("Done"); 133 | file.close(); 134 | } 135 | //------------------------------------------------------------------------------ 136 | void loop() { 137 | } 138 | 139 | -------------------------------------------------------------------------------- /examples/ReadCsvFields/ReadCsvFields.cpp: -------------------------------------------------------------------------------- 1 | #include "SdFat.h" 2 | // Function to read a CSV text file one field at a time. 3 | 4 | #define CS_PIN SS 5 | 6 | SdFat SD; 7 | File file; 8 | 9 | /* 10 | * Read a file one field at a time. 11 | * 12 | * file - File to read. 13 | * 14 | * str - Character array for the field. 15 | * 16 | * size - Size of str array. 17 | * 18 | * delim - String containing field delimiters. 19 | * 20 | * return - length of field including terminating delimiter. 21 | * 22 | * Note, the last character of str will not be a delimiter if 23 | * a read error occurs, the field is too long, or the file 24 | * does not end with a delimiter. Consider this an error 25 | * if not at end-of-file. 26 | * 27 | */ 28 | size_t readField(File* file, char* str, size_t size, const char* delim) { 29 | char ch; 30 | size_t n = 0; 31 | while ((n + 1) < size && file->read(&ch, 1) == 1) { 32 | // Delete CR. 33 | if (ch == '\r') { 34 | continue; 35 | } 36 | str[n++] = ch; 37 | if (strchr(delim, ch)) { 38 | break; 39 | } 40 | } 41 | str[n] = '\0'; 42 | return n; 43 | } 44 | //------------------------------------------------------------------------------ 45 | #define errorHalt(msg) {Serial.println(F(msg)); SysCall::halt();} 46 | //------------------------------------------------------------------------------ 47 | void setup() { 48 | Serial.begin(9600); 49 | 50 | // Wait for USB Serial 51 | while (!Serial) { 52 | SysCall::yield(); 53 | } 54 | Serial.println("Type any character to start"); 55 | while (Serial.read() <= 0) { 56 | SysCall::yield(); 57 | } 58 | 59 | // Initialize the SD. 60 | if (!SD.begin(CS_PIN)) errorHalt("begin failed"); 61 | 62 | // Create or open the file. 63 | file = SD.open("READTEST.TXT", FILE_WRITE); 64 | if (!file) errorHalt("open failed"); 65 | 66 | // Rewind file so test data is not appended. 67 | file.rewind(); 68 | 69 | // Write test data. 70 | file.print(F( 71 | "field_1_1,field_1_2,field_1_3\r\n" 72 | "field_2_1,field_2_2,field_2_3\r\n" 73 | "field_3_1,field_3_2\r\n" // missing a field 74 | "field_4_1,field_4_2,field_4_3\r\n" 75 | "field_5_1,field_5_2,field_5_3" // no delimiter 76 | )); 77 | 78 | // Rewind the file for read. 79 | file.rewind(); 80 | 81 | size_t n; // Length of returned field with delimiter. 82 | char str[20]; // Must hold longest field with delimiter and zero byte. 83 | 84 | // Read the file and print fields. 85 | while (true) { 86 | n = readField(&file, str, sizeof(str), ",\n"); 87 | 88 | // done if Error or at EOF. 89 | if (n == 0) break; 90 | 91 | // Print the type of delimiter. 92 | if (str[n-1] == ',' || str[n-1] == '\n') { 93 | Serial.print(str[n-1] == ',' ? F("comma: ") : F("endl: ")); 94 | 95 | // Remove the delimiter. 96 | str[n-1] = 0; 97 | } else { 98 | // At eof, too long, or read error. Too long is error. 99 | Serial.print(file.available() ? F("error: ") : F("eof: ")); 100 | } 101 | // Print the field. 102 | Serial.println(str); 103 | } 104 | file.close(); 105 | } 106 | //------------------------------------------------------------------------------ 107 | void loop() { 108 | } 109 | 110 | 111 | -------------------------------------------------------------------------------- /examples/SdInfo/SdInfo.cpp: -------------------------------------------------------------------------------- 1 | #include "SdFat.h" 2 | /* 3 | * This program attempts to initialize an SD card and analyze its structure. 4 | * Port of Arduino version. 5 | */ 6 | /* 7 | * SD chip select pin. 8 | * Default SD chip select is the SPI SS pin. 9 | */ 10 | const uint8_t SD_CHIP_SELECT = SS; 11 | /* 12 | * Set DISABLE_CHIP_SELECT to disable a second SPI device. 13 | * For example, with the Ethernet shield, set DISABLE_CHIP_SELECT 14 | * to 10 to disable the Ethernet controller. 15 | */ 16 | const int8_t DISABLE_CHIP_SELECT = -1; 17 | 18 | SdFat sd; 19 | 20 | // serial output steam 21 | ArduinoOutStream cout(Serial); 22 | 23 | // global for card size 24 | uint32_t cardSize; 25 | 26 | // global for card erase size 27 | uint32_t eraseSize; 28 | //------------------------------------------------------------------------------ 29 | void sdErrorMsg(const char* str) { 30 | cout << str << endl; 31 | if (sd.card()->errorCode()) { 32 | cout << F("SD errorCode: "); 33 | cout << hex << int(sd.card()->errorCode()) << endl; 34 | cout << F("SD errorData: "); 35 | cout << int(sd.card()->errorData()) << dec << endl; 36 | } 37 | } 38 | //------------------------------------------------------------------------------ 39 | uint8_t cidDmp() { 40 | cid_t cid; 41 | if (!sd.card()->readCID(&cid)) { 42 | sdErrorMsg("readCID failed"); 43 | return false; 44 | } 45 | cout << F("\nManufacturer ID: "); 46 | cout << hex << int(cid.mid) << dec << endl; 47 | cout << F("OEM ID: ") << cid.oid[0] << cid.oid[1] << endl; 48 | cout << F("Product: "); 49 | for (uint8_t i = 0; i < 5; i++) { 50 | cout << cid.pnm[i]; 51 | } 52 | cout << F("\nVersion: "); 53 | cout << int(cid.prv_n) << '.' << int(cid.prv_m) << endl; 54 | cout << F("Serial number: ") << hex << cid.psn << dec << endl; 55 | cout << F("Manufacturing date: "); 56 | cout << int(cid.mdt_month) << '/'; 57 | cout << (2000 + cid.mdt_year_low + 10 * cid.mdt_year_high) << endl; 58 | cout << endl; 59 | return true; 60 | } 61 | //------------------------------------------------------------------------------ 62 | uint8_t csdDmp() { 63 | csd_t csd; 64 | uint8_t eraseSingleBlock; 65 | if (!sd.card()->readCSD(&csd)) { 66 | sdErrorMsg("readCSD failed"); 67 | return false; 68 | } 69 | if (csd.v1.csd_ver == 0) { 70 | eraseSingleBlock = csd.v1.erase_blk_en; 71 | eraseSize = (csd.v1.sector_size_high << 1) | csd.v1.sector_size_low; 72 | } else if (csd.v2.csd_ver == 1) { 73 | eraseSingleBlock = csd.v2.erase_blk_en; 74 | eraseSize = (csd.v2.sector_size_high << 1) | csd.v2.sector_size_low; 75 | } else { 76 | cout << F("csd version error\n"); 77 | return false; 78 | } 79 | eraseSize++; 80 | cout << F("cardSize: ") << 0.000512*cardSize; 81 | cout << F(" MB (MB = 1,000,000 bytes)\n"); 82 | 83 | cout << F("flashEraseSize: ") << int(eraseSize) << F(" blocks\n"); 84 | cout << F("eraseSingleBlock: "); 85 | if (eraseSingleBlock) { 86 | cout << F("true\n"); 87 | } else { 88 | cout << F("false\n"); 89 | } 90 | return true; 91 | } 92 | //------------------------------------------------------------------------------ 93 | // print partition table 94 | uint8_t partDmp() { 95 | cache_t *p = sd.vol()->cacheClear(); 96 | if (!p) { 97 | sdErrorMsg("cacheClear failed"); 98 | return false; 99 | } 100 | if (!sd.card()->readBlock(0, p->data)) { 101 | sdErrorMsg("read MBR failed"); 102 | return false; 103 | } 104 | for (uint8_t ip = 1; ip < 5; ip++) { 105 | part_t *pt = &p->mbr.part[ip - 1]; 106 | if ((pt->boot & 0X7F) != 0 || pt->firstSector > cardSize) { 107 | cout << F("\nNo MBR. Assuming Super Floppy format.\n"); 108 | return true; 109 | } 110 | } 111 | cout << F("\nSD Partition Table\n"); 112 | cout << F("part,boot,type,start,length\n"); 113 | for (uint8_t ip = 1; ip < 5; ip++) { 114 | part_t *pt = &p->mbr.part[ip - 1]; 115 | cout << int(ip) << ',' << hex << int(pt->boot) << ',' << int(pt->type); 116 | cout << dec << ',' << pt->firstSector <<',' << pt->totalSectors << endl; 117 | } 118 | return true; 119 | } 120 | //------------------------------------------------------------------------------ 121 | void volDmp() { 122 | cout << F("\nVolume is FAT") << int(sd.vol()->fatType()) << endl; 123 | cout << F("blocksPerCluster: ") << int(sd.vol()->blocksPerCluster()) << endl; 124 | cout << F("clusterCount: ") << sd.vol()->clusterCount() << endl; 125 | cout << F("freeClusters: "); 126 | uint32_t volFree = sd.vol()->freeClusterCount(); 127 | cout << volFree << endl; 128 | float fs = 0.000512*volFree*sd.vol()->blocksPerCluster(); 129 | cout << F("freeSpace: ") << fs << F(" MB (MB = 1,000,000 bytes)\n"); 130 | cout << F("fatStartBlock: ") << sd.vol()->fatStartBlock() << endl; 131 | cout << F("fatCount: ") << int(sd.vol()->fatCount()) << endl; 132 | cout << F("blocksPerFat: ") << sd.vol()->blocksPerFat() << endl; 133 | cout << F("rootDirStart: ") << sd.vol()->rootDirStart() << endl; 134 | cout << F("dataStartBlock: ") << sd.vol()->dataStartBlock() << endl; 135 | if (sd.vol()->dataStartBlock() % eraseSize) { 136 | cout << F("Data area is not aligned on flash erase boundaries!\n"); 137 | cout << F("Download and use formatter from www.sdcard.org!\n"); 138 | } 139 | } 140 | //------------------------------------------------------------------------------ 141 | void setup() { 142 | Serial.begin(9600); 143 | 144 | // Wait for USB Serial 145 | while (!Serial) { 146 | SysCall::yield(); 147 | } 148 | 149 | // use uppercase in hex and use 0X base prefix 150 | cout << uppercase << showbase << endl; 151 | 152 | // F stores strings in flash to save RAM 153 | cout << F("SdFat version: ") << SD_FAT_VERSION << endl; 154 | if (DISABLE_CHIP_SELECT < 0) { 155 | cout << F( 156 | "\nAssuming the SD is the only SPI device.\n" 157 | "Edit DISABLE_CHIP_SELECT to disable another device.\n"); 158 | } else { 159 | cout << F("\nDisabling SPI device on pin "); 160 | cout << int(DISABLE_CHIP_SELECT) << endl; 161 | pinMode(DISABLE_CHIP_SELECT, OUTPUT); 162 | digitalWrite(DISABLE_CHIP_SELECT, HIGH); 163 | } 164 | cout << F("\nAssuming the SD chip select pin is: ") <= 0); 173 | 174 | // F stores strings in flash to save RAM 175 | cout << F("\ntype any character to start\n"); 176 | while (Serial.read() <= 0) { 177 | SysCall::yield(); 178 | } 179 | 180 | uint32_t t = millis(); 181 | // initialize the SD card at SPI_HALF_SPEED to avoid bus errors with 182 | // breadboards. use SPI_FULL_SPEED for better performance. 183 | if (!sd.cardBegin(SD_CHIP_SELECT, SPI_HALF_SPEED)) { 184 | sdErrorMsg("\ncardBegin failed"); 185 | return; 186 | } 187 | t = millis() - t; 188 | 189 | cardSize = sd.card()->cardSize(); 190 | if (cardSize == 0) { 191 | sdErrorMsg("cardSize failed"); 192 | return; 193 | } 194 | cout << F("\ninit time: ") << t << " ms" << endl; 195 | cout << F("\nCard type: "); 196 | switch (sd.card()->type()) { 197 | case SD_CARD_TYPE_SD1: 198 | cout << F("SD1\n"); 199 | break; 200 | 201 | case SD_CARD_TYPE_SD2: 202 | cout << F("SD2\n"); 203 | break; 204 | 205 | case SD_CARD_TYPE_SDHC: 206 | if (cardSize < 70000000) { 207 | cout << F("SDHC\n"); 208 | } else { 209 | cout << F("SDXC\n"); 210 | } 211 | break; 212 | 213 | default: 214 | cout << F("Unknown\n"); 215 | } 216 | if (!cidDmp()) { 217 | return; 218 | } 219 | if (!csdDmp()) { 220 | return; 221 | } 222 | uint32_t ocr; 223 | if (!sd.card()->readOCR(&ocr)) { 224 | sdErrorMsg("\nreadOCR failed"); 225 | return; 226 | } 227 | cout << F("OCR: ") << hex << ocr << dec << endl; 228 | if (!partDmp()) { 229 | return; 230 | } 231 | if (!sd.fsBegin()) { 232 | sdErrorMsg("\nFile System initialization failed.\n"); 233 | return; 234 | } 235 | volDmp(); 236 | } -------------------------------------------------------------------------------- /examples/Timestamp/Timestamp.cpp: -------------------------------------------------------------------------------- 1 | #include "SdFat.h" 2 | // Warning, Particle.timeSync() seems to take a while to happen. 3 | // You may want to set your time zone with Time.zone(offaet). 4 | /* 5 | * This program tests the dateTimeCallback() function 6 | * and the timestamp() function. 7 | */ 8 | SdFat sd; 9 | 10 | SdFile file; 11 | 12 | // Default SD chip select is SS pin 13 | const uint8_t chipSelect = SS; 14 | 15 | // create Serial stream 16 | ArduinoOutStream cout(Serial); 17 | //------------------------------------------------------------------------------ 18 | // store error strings in flash to save RAM 19 | #define error(s) sd.errorHalt(F(s)) 20 | //------------------------------------------------------------------------------ 21 | /* 22 | * User provided date time callback function. 23 | * See SdFile::dateTimeCallback() for usage. 24 | */ 25 | void dateTime(uint16_t* date, uint16_t* time) { 26 | // return date using FAT_DATE macro to format fields 27 | *date = FAT_DATE(Time.year(), Time.month(), Time.day()); 28 | 29 | // return time using FAT_TIME macro to format fields 30 | *time = FAT_TIME(Time.hour(), Time.minute(), Time.second()); 31 | } 32 | //------------------------------------------------------------------------------ 33 | /* 34 | * Function to print all timestamps. 35 | */ 36 | void printTimestamps(SdFile& f) { 37 | dir_t d; 38 | if (!f.dirEntry(&d)) { 39 | error("f.dirEntry failed"); 40 | } 41 | 42 | cout << F("Creation: "); 43 | f.printFatDate(d.creationDate); 44 | cout << ' '; 45 | f.printFatTime(d.creationTime); 46 | cout << endl; 47 | 48 | cout << F("Modify: "); 49 | f.printFatDate(d.lastWriteDate); 50 | cout <<' '; 51 | f.printFatTime(d.lastWriteTime); 52 | cout << endl; 53 | 54 | cout << F("Access: "); 55 | f.printFatDate(d.lastAccessDate); 56 | cout << endl; 57 | } 58 | //------------------------------------------------------------------------------ 59 | void setup(void) { 60 | Serial.begin(9600); 61 | // Wait for USB Serial 62 | while (!Serial) { 63 | SysCall::yield(); 64 | } 65 | cout << F("Type any character to start\n"); 66 | while (!Serial.available()) { 67 | SysCall::yield(); 68 | } 69 | 70 | // Request time sync so example works. 71 | Particle.syncTime(); 72 | 73 | // initialize the SD card at SPI_HALF_SPEED to avoid bus errors with 74 | // breadboards. use SPI_FULL_SPEED for better performance. 75 | if (!sd.begin(chipSelect, SPI_HALF_SPEED)) { 76 | sd.initErrorHalt(); 77 | } 78 | 79 | // remove files if they exist 80 | sd.remove("callback.txt"); 81 | sd.remove("default.txt"); 82 | sd.remove("stamp.txt"); 83 | 84 | // create a new file with default timestamps 85 | if (!file.open("default.txt", O_CREAT | O_WRITE)) { 86 | error("open default.txt failed"); 87 | } 88 | cout << F("\nOpen with default times.\n"); 89 | printTimestamps(file); 90 | 91 | // close file 92 | file.close(); 93 | /* 94 | * Test the date time callback function. 95 | * 96 | * dateTimeCallback() sets the function 97 | * that is called when a file is created 98 | * or when a file's directory entry is 99 | * modified by sync(). 100 | * 101 | * The callback can be disabled by the call 102 | * SdFile::dateTimeCallbackCancel() 103 | */ 104 | 105 | // set date time callback function 106 | SdFile::dateTimeCallback(dateTime); 107 | 108 | cout << F("\nDelay for 10 seconds to insure timeSync happens.\n"); 109 | for (int sec = 0; sec < 10; sec++) { 110 | delay(1000); 111 | cout << ' ' << Time.second(); 112 | } 113 | cout << endl; 114 | 115 | // create a new file with callback timestamps 116 | if (!file.open("callback.txt", O_CREAT | O_WRITE)) { 117 | error("open callback.txt failed"); 118 | } 119 | cout << F("\nOpen with callback times\n"); 120 | printTimestamps(file); 121 | 122 | cout << F("\nDelay for 10 seconds before writing to file.\n"); 123 | for (int sec = 0; sec < 10; sec++) { 124 | delay(1000); 125 | cout << ' ' << Time.second(); 126 | } 127 | cout << endl; 128 | 129 | // modify file by writing a byte 130 | file.write('t'); 131 | 132 | // force dir update 133 | file.sync(); 134 | 135 | cout << F("\nTimes after write\n"); 136 | printTimestamps(file); 137 | 138 | // close file 139 | file.close(); 140 | /* 141 | * Test timestamp() function 142 | * 143 | * Cancel callback so sync will not 144 | * change access/modify timestamp 145 | */ 146 | SdFile::dateTimeCallbackCancel(); 147 | 148 | // create a new file with default timestamps 149 | if (!file.open("stamp.txt", O_CREAT | O_WRITE)) { 150 | error("open stamp.txt failed"); 151 | } 152 | // set creation date time 153 | if (!file.timestamp(T_CREATE, 2014, 11, 10, 1, 2, 3)) { 154 | error("set create time failed"); 155 | } 156 | // set write/modification date time 157 | if (!file.timestamp(T_WRITE, 2014, 11, 11, 4, 5, 6)) { 158 | error("set write time failed"); 159 | } 160 | // set access date 161 | if (!file.timestamp(T_ACCESS, 2014, 11, 12, 7, 8, 9)) { 162 | error("set access time failed"); 163 | } 164 | cout << F("\nTimes after timestamp() calls\n"); 165 | printTimestamps(file); 166 | 167 | file.close(); 168 | cout << F("\nDone\n"); 169 | } 170 | 171 | void loop(void) {} 172 | -------------------------------------------------------------------------------- /examples/TryMeFirst/TryMeFirst.cpp: -------------------------------------------------------------------------------- 1 | #include "SdFat.h" 2 | 3 | // Pick an SPI configuration. 4 | // See SPI configuration section below (comments are for photon). 5 | #define SPI_CONFIGURATION 0 6 | //------------------------------------------------------------------------------ 7 | // Setup SPI configuration. 8 | #if SPI_CONFIGURATION == 0 9 | // Primary SPI with DMA 10 | // SCK => A3, MISO => A4, MOSI => A5, SS => A2 (default) 11 | SdFat sd; 12 | const uint8_t chipSelect = SS; 13 | #elif SPI_CONFIGURATION == 1 14 | // Secondary SPI with DMA 15 | // SCK => D4, MISO => D3, MOSI => D2, SS => D1 16 | SdFat sd(1); 17 | const uint8_t chipSelect = D1; 18 | #elif SPI_CONFIGURATION == 2 19 | // Primary SPI with Arduino SPI library style byte I/O. 20 | // SCK => A3, MISO => A4, MOSI => A5, SS => A2 (default) 21 | SdFatLibSpi sd; 22 | const uint8_t chipSelect = SS; 23 | #elif SPI_CONFIGURATION == 3 24 | // Software SPI. Use any digital pins. 25 | // MISO => D5, MOSI => D6, SCK => D7, SS => D0 26 | SdFatSoftSpi sd; 27 | const uint8_t chipSelect = D0; 28 | #endif // SPI_CONFIGURATION 29 | //------------------------------------------------------------------------------ 30 | 31 | File myFile; 32 | 33 | void setup() { 34 | Serial.begin(9600); 35 | // Wait for USB Serial 36 | while (!Serial) { 37 | SysCall::yield(); 38 | } 39 | 40 | Serial.println("Type any character to start"); 41 | while (Serial.read() <= 0) { 42 | SysCall::yield(); 43 | } 44 | 45 | // Initialize SdFat or print a detailed error message and halt 46 | // Use half speed like the native library. 47 | // Change to SPI_FULL_SPEED for more performance. 48 | if (!sd.begin(chipSelect, SPI_HALF_SPEED)) { 49 | sd.initErrorHalt(); 50 | } 51 | 52 | // open the file for write at end like the "Native SD library" 53 | if (!myFile.open("test.txt", O_RDWR | O_CREAT | O_AT_END)) { 54 | sd.errorHalt("opening test.txt for write failed"); 55 | } 56 | // if the file opened okay, write to it: 57 | Serial.print("Writing to test.txt..."); 58 | myFile.println("testing 1, 2, 3."); 59 | myFile.printf("fileSize: %d\n", myFile.fileSize()); 60 | 61 | // close the file: 62 | myFile.close(); 63 | Serial.println("done."); 64 | 65 | // re-open the file for reading: 66 | if (!myFile.open("test.txt", O_READ)) { 67 | sd.errorHalt("opening test.txt for read failed"); 68 | } 69 | Serial.println("test.txt content:"); 70 | 71 | // read from the file until there's nothing else in it: 72 | int data; 73 | while ((data = myFile.read()) >= 0) { 74 | Serial.write(data); 75 | } 76 | // close the file: 77 | myFile.close(); 78 | } 79 | 80 | void loop() { 81 | // nothing happens after setup 82 | } 83 | 84 | 85 | -------------------------------------------------------------------------------- /examples/VolumeFreeSpace/VolumeFreeSpace.cpp: -------------------------------------------------------------------------------- 1 | #include "SdFat.h" 2 | /* 3 | * This program demonstrates the freeClusterCount() call. 4 | */ 5 | /* 6 | * SD chip select pin. 7 | * Default SD chip select is the SPI SS pin. 8 | */ 9 | const uint8_t chipSelect = SS; 10 | 11 | #define TEST_FILE "Cluster.test" 12 | // file system 13 | SdFat sd; 14 | 15 | // test file 16 | SdFile file; 17 | 18 | // Serial output stream 19 | ArduinoOutStream cout(Serial); 20 | //------------------------------------------------------------------------------ 21 | void printFreeSpace() { 22 | cout << F("freeClusterCount() call time: "); 23 | uint32_t m = micros(); 24 | uint32_t volFree = sd.vol()->freeClusterCount(); 25 | cout << micros() - m << F(" micros\n"); 26 | cout << F("freeClusters: ") << volFree << setprecision(3) << endl; 27 | float fs = 0.000512*volFree*sd.vol()->blocksPerCluster(); 28 | cout << F("freeSpace: ") << fs << F(" MB (MB = 1,000,000 bytes)\n\n"); 29 | } 30 | //------------------------------------------------------------------------------ 31 | void setup() { 32 | Serial.begin(9600); 33 | // Wait for USB Serial 34 | while (!Serial) { 35 | SysCall::yield(); 36 | } 37 | 38 | if (!MAINTAIN_FREE_CLUSTER_COUNT) { 39 | cout << F("Please edit SdFatConfig.h and set\n"); 40 | cout << F("MAINTAIN_FREE_CLUSTER_COUNT nonzero for\n"); 41 | cout << F("maximum freeClusterCount() performance.\n\n"); 42 | } 43 | // F stores strings in flash to save RAM 44 | cout << F("Type any character to start\n"); 45 | while (Serial.read() <= 0) { 46 | SysCall::yield(); 47 | } 48 | 49 | // initialize the SD card at SPI_HALF_SPEED to avoid bus errors with 50 | // breadboards. use SPI_FULL_SPEED for better performance. 51 | if (!sd.begin(chipSelect, SPI_HALF_SPEED)) { 52 | sd.initErrorHalt(); 53 | } 54 | // Insure no TEST_FILE. 55 | sd.remove(TEST_FILE); 56 | 57 | cout << F("\nFirst call to freeClusterCount scans the FAT.\n\n"); 58 | printFreeSpace(); 59 | 60 | cout << F("Create and write to ") << TEST_FILE << endl; 61 | if (!file.open(TEST_FILE, O_WRITE | O_CREAT)) { 62 | sd.errorHalt(F("Create failed")); 63 | } 64 | file.print(F("Cause a cluster to be allocated")); 65 | file.close(); 66 | 67 | cout << F("\nSecond freeClusterCount call is faster if\n"); 68 | cout << F("MAINTAIN_FREE_CLUSTER_COUNT is nonzero.\n\n"); 69 | 70 | printFreeSpace(); 71 | 72 | cout << F("Remove ") << TEST_FILE << endl << endl; 73 | sd.remove(TEST_FILE); 74 | printFreeSpace(); 75 | } 76 | //------------------------------------------------------------------------------ 77 | void loop() {} -------------------------------------------------------------------------------- /examples/bench/bench.cpp: -------------------------------------------------------------------------------- 1 | #include "SdFat.h" 2 | // Use smaller transfer on Core. 3 | /* 4 | * This program is a simple binary read/write benchmark. 5 | * Port of Arduino version. 6 | */ 7 | // Size of read/write transfers. 8 | const size_t BUF_SIZE = 64*512; 9 | 10 | // File size in MB where MB = 1,000,000 bytes. 11 | const uint32_t FILE_SIZE_MB = 5; 12 | 13 | // Write pass count. 14 | const uint8_t WRITE_COUNT = 1; 15 | 16 | // Read pass count. 17 | const uint8_t READ_COUNT = 1; 18 | 19 | // Pick an SPI configuration. 20 | // See SPI configuration section below (comments are for photon). 21 | #define SPI_CONFIGURATION 0 22 | //============================================================================== 23 | // End of configuration constants. 24 | //------------------------------------------------------------------------------ 25 | // Setup SPI configuration. 26 | #if SPI_CONFIGURATION == 0 27 | // Primary SPI with DMA 28 | // SCK => A3, MISO => A4, MOSI => A5, SS => A2 (default) 29 | SdFat sd; 30 | const uint8_t chipSelect = SS; 31 | #elif SPI_CONFIGURATION == 1 32 | // Secondary SPI with DMA 33 | // SCK => D4, MISO => D3, MOSI => D2, SS => D1 34 | SdFat sd(1); 35 | const uint8_t chipSelect = D1; 36 | #elif SPI_CONFIGURATION == 2 37 | // Primary SPI with Arduino SPI library style byte I/O. 38 | // SCK => A3, MISO => A4, MOSI => A5, SS => A2 (default) 39 | SdFatLibSpi sd; 40 | const uint8_t chipSelect = SS; 41 | #elif SPI_CONFIGURATION == 3 42 | // Software SPI. Use any digital pins. 43 | // MISO => D5, MOSI => D6, SCK => D7, SS => D0 44 | SdFatSoftSpi sd; 45 | const uint8_t chipSelect = D0; 46 | #endif // SPI_CONFIGURATION 47 | //------------------------------------------------------------------------------ 48 | // File size in bytes. 49 | const uint32_t FILE_SIZE = 1000000UL*FILE_SIZE_MB; 50 | 51 | uint8_t buf[BUF_SIZE]; 52 | 53 | // test file 54 | SdFile file; 55 | 56 | // Serial output stream 57 | ArduinoOutStream cout(Serial); 58 | //------------------------------------------------------------------------------ 59 | // Store error strings in flash to save RAM. 60 | #define error(s) sd.errorHalt(F(s)) 61 | //------------------------------------------------------------------------------ 62 | void cidDmp() { 63 | cid_t cid; 64 | if (!sd.card()->readCID(&cid)) { 65 | error("readCID failed"); 66 | } 67 | cout << F("\nManufacturer ID: "); 68 | cout << hex << int(cid.mid) << dec << endl; 69 | cout << F("OEM ID: ") << cid.oid[0] << cid.oid[1] << endl; 70 | cout << F("Product: "); 71 | for (uint8_t i = 0; i < 5; i++) { 72 | cout << cid.pnm[i]; 73 | } 74 | cout << F("\nVersion: "); 75 | cout << int(cid.prv_n) << '.' << int(cid.prv_m) << endl; 76 | cout << F("Serial number: ") << hex << cid.psn << dec << endl; 77 | cout << F("Manufacturing date: "); 78 | cout << int(cid.mdt_month) << '/'; 79 | cout << (2000 + cid.mdt_year_low + 10 * cid.mdt_year_high) << endl; 80 | cout << endl; 81 | } 82 | //------------------------------------------------------------------------------ 83 | void setup() { 84 | Serial.begin(9600); 85 | 86 | // Wait for USB Serial 87 | while (!Serial) { 88 | SysCall::yield(); 89 | } 90 | delay(1000); 91 | cout << F("\nUse a freshly formatted SD for best performance.\n"); 92 | 93 | // use uppercase in hex and use 0X base prefix 94 | cout << uppercase << showbase << endl; 95 | } 96 | //------------------------------------------------------------------------------ 97 | void loop() { 98 | float s; 99 | uint32_t t; 100 | uint32_t maxLatency; 101 | uint32_t minLatency; 102 | uint32_t totalLatency; 103 | 104 | // discard any input 105 | do { 106 | delay(10); 107 | } while (Serial.read() >= 0); 108 | 109 | // F( stores strings in flash to save RAM 110 | cout << F("Type any character to start\n"); 111 | while (Serial.read() <= 0) { 112 | SysCall::yield(); 113 | } 114 | 115 | cout << F("FreeMemory: ") << System.freeMemory() << endl; 116 | 117 | // initialize the SD card at SPI_FULL_SPEED for best performance. 118 | // try SPI_HALF_SPEED if bus errors occur. 119 | if (!sd.begin(chipSelect, SPI_FULL_SPEED)) { 120 | sd.initErrorHalt(); 121 | } 122 | 123 | cout << F("Type is FAT") << int(sd.vol()->fatType()) << endl; 124 | cout << F("Card size: ") << sd.card()->cardSize()*512E-9; 125 | cout << F(" GB (GB = 1E9 bytes)") << endl; 126 | 127 | cidDmp(); 128 | 129 | // open or create file - truncate existing file. 130 | if (!file.open("bench.dat", O_CREAT | O_TRUNC | O_RDWR)) { 131 | error("open failed"); 132 | } 133 | 134 | // fill buf with known data 135 | for (uint16_t i = 0; i < (BUF_SIZE-2); i++) { 136 | buf[i] = 'A' + (i % 26); 137 | } 138 | buf[BUF_SIZE-2] = '\r'; 139 | buf[BUF_SIZE-1] = '\n'; 140 | 141 | cout << F("File size ") << FILE_SIZE_MB << F(" MB\n"); 142 | cout << F("Buffer size ") << BUF_SIZE << F(" bytes\n"); 143 | cout << F("Starting write test, please wait.") << endl << endl; 144 | 145 | // do write test 146 | uint32_t n = FILE_SIZE/sizeof(buf); 147 | cout < m) { 168 | minLatency = m; 169 | } 170 | totalLatency += m; 171 | } 172 | file.sync(); 173 | t = millis() - t; 174 | s = file.fileSize(); 175 | cout << s/t <<',' << maxLatency << ',' << minLatency; 176 | cout << ',' << totalLatency/n << endl; 177 | } 178 | cout << endl << F("Starting read test, please wait.") << endl; 179 | cout << endl < m) { 204 | minLatency = m; 205 | } 206 | totalLatency += m; 207 | if (buf[BUF_SIZE-1] != '\n') { 208 | error("data check"); 209 | } 210 | } 211 | s = file.fileSize(); 212 | t = millis() - t; 213 | cout << s/t <<',' << maxLatency << ',' << minLatency; 214 | cout << ',' << totalLatency/n << endl; 215 | } 216 | cout << endl << F("Done") << endl; 217 | file.close(); 218 | } -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=SdFat 2 | version=0.0.7 3 | license=GPL v3 4 | author=William Greiman 5 | sentence=An SD card library for Particle. 6 | category=Other 7 | url=https://github.com/greiman/SdFat-Particle 8 | repository=https://github.com/greiman/SdFat-Particle.git 9 | architectures=spark-core,particle-photon,particle-p1,particle-electron 10 | -------------------------------------------------------------------------------- /src/ArduinoFiles.h: -------------------------------------------------------------------------------- 1 | /* Arduino SdFat Library 2 | * Copyright (C) 2012 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 | * \file 22 | * \brief PrintFile class 23 | */ 24 | #ifndef ArduinoFiles_h 25 | #define ArduinoFiles_h 26 | #include "FatLibConfig.h" 27 | #if ENABLE_ARDUINO_FEATURES 28 | #include "FatFile.h" 29 | #include 30 | //------------------------------------------------------------------------------ 31 | /** Arduino SD.h style flag for open for read. */ 32 | #define FILE_READ O_READ 33 | /** Arduino SD.h style flag for open at EOF for read/write with create. */ 34 | #define FILE_WRITE (O_RDWR | O_CREAT | O_AT_END) 35 | //============================================================================== 36 | /** 37 | * \class PrintFile 38 | * \brief FatFile with Print. 39 | */ 40 | class PrintFile : public FatFile, public Print { 41 | public: 42 | PrintFile() {} 43 | /** Create a file object and open it in the current working directory. 44 | * 45 | * \param[in] path A path for a file to be opened. 46 | * 47 | * \param[in] oflag Values for \a oflag are constructed by a 48 | * bitwise-inclusive OR of open flags. see 49 | * FatFile::open(FatFile*, const char*, uint8_t). 50 | */ 51 | PrintFile(const char* path, uint8_t oflag) : FatFile(path, oflag) {} 52 | #if DESTRUCTOR_CLOSES_FILE 53 | ~PrintFile() {} 54 | #endif // DESTRUCTOR_CLOSES_FILE 55 | using FatFile::clearWriteError; 56 | using FatFile::getWriteError; 57 | using FatFile::read; 58 | using FatFile::write; 59 | /** \return number of bytes available from the current position to EOF 60 | * or INT_MAX if more than INT_MAX bytes are available. 61 | */ 62 | int available() { 63 | uint32_t n = FatFile::available(); 64 | return n > INT_MAX ? INT_MAX : n; 65 | } 66 | /** Ensure that any bytes written to the file are saved to the SD card. */ 67 | void flush() { 68 | FatFile::sync(); 69 | } 70 | /** Return the next available byte without consuming it. 71 | * 72 | * \return The byte if no error and not at eof else -1; 73 | */ 74 | int peek() { 75 | return FatFile::peek(); 76 | } 77 | /** Read the next byte from a file. 78 | * 79 | * \return For success return the next byte in the file as an int. 80 | * If an error occurs or end of file is reached return -1. 81 | */ 82 | // int read() { 83 | // return FatFile::read(); 84 | // } 85 | /** Write a byte to a file. Required by the Arduino Print class. 86 | * \param[in] b the byte to be written. 87 | * Use getWriteError to check for errors. 88 | * \return 1 for success and 0 for failure. 89 | */ 90 | size_t write(uint8_t b) { 91 | return FatFile::write(b); 92 | } 93 | /** Write data to an open file. Form required by Print. 94 | * 95 | * \note Data is moved to the cache but may not be written to the 96 | * storage device until sync() is called. 97 | * 98 | * \param[in] buf Pointer to the location of the data to be written. 99 | * 100 | * \param[in] size Number of bytes to write. 101 | * 102 | * \return For success write() returns the number of bytes written, always 103 | * \a nbyte. If an error occurs, write() returns -1. Possible errors 104 | * include write() is called before a file has been opened, write is called 105 | * for a read-only file, device is full, a corrupt file system or an 106 | * I/O error. 107 | */ 108 | size_t write(const uint8_t *buf, size_t size) { 109 | return FatFile::write(buf, size); 110 | } 111 | }; 112 | //============================================================================== 113 | /** 114 | * \class File 115 | * \brief Arduino SD.h style File API 116 | */ 117 | #if ARDUINO_FILE_USES_STREAM 118 | class File : public FatFile, public Stream { 119 | #else // ARDUINO_FILE_USES_STREAM 120 | class File : public FatFile, public Print { 121 | #endif // ARDUINO_FILE_USES_STREAM 122 | public: 123 | File() {} 124 | /** Create a file object and open it in the current working directory. 125 | * 126 | * \param[in] path A path with a valid 8.3 DOS name for a file to be opened. 127 | * 128 | * \param[in] oflag Values for \a oflag are constructed by a 129 | * bitwise-inclusive OR of open flags. see 130 | * FatFile::open(FatFile*, const char*, uint8_t). 131 | */ 132 | File(const char* path, uint8_t oflag) { 133 | open(path, oflag); 134 | } 135 | using FatFile::clearWriteError; 136 | using FatFile::getWriteError; 137 | using FatFile::read; 138 | using FatFile::write; 139 | /** The parenthesis operator. 140 | * 141 | * \return true if a file is open. 142 | */ 143 | operator bool() { 144 | return isOpen(); 145 | } 146 | /** \return number of bytes available from the current position to EOF 147 | * or INT_MAX if more than INT_MAX bytes are available. 148 | */ 149 | int available() { 150 | uint32_t n = FatFile::available(); 151 | return n > INT_MAX ? INT_MAX : n; 152 | } 153 | /** Ensure that any bytes written to the file are saved to the SD card. */ 154 | void flush() { 155 | FatFile::sync(); 156 | } 157 | /** This function reports if the current file is a directory or not. 158 | * \return true if the file is a directory. 159 | */ 160 | bool isDirectory() { 161 | return isDir(); 162 | } 163 | /** No longer implemented due to Long File Names. 164 | * 165 | * Use getName(char* name, size_t size). 166 | * \return a pointer to replacement suggestion. 167 | */ 168 | const char* name() const { 169 | return "use getName()"; 170 | } 171 | /** Return the next available byte without consuming it. 172 | * 173 | * \return The byte if no error and not at eof else -1; 174 | */ 175 | int peek() { 176 | return FatFile::peek(); 177 | } 178 | /** \return the current file position. */ 179 | uint32_t position() { 180 | return curPosition(); 181 | } 182 | /** Opens the next file or folder in a directory. 183 | * 184 | * \param[in] mode open mode flags. 185 | * \return a File object. 186 | */ 187 | File openNextFile(uint8_t mode = O_READ) { 188 | File tmpFile; 189 | tmpFile.openNext(this, mode); 190 | return tmpFile; 191 | } 192 | /** Read the next byte from a file. 193 | * 194 | * \return For success return the next byte in the file as an int. 195 | * If an error occurs or end of file is reached return -1. 196 | */ 197 | int read() { 198 | return FatFile::read(); 199 | } 200 | /** Rewind a file if it is a directory */ 201 | void rewindDirectory() { 202 | if (isDir()) { 203 | rewind(); 204 | } 205 | } 206 | /** 207 | * Seek to a new position in the file, which must be between 208 | * 0 and the size of the file (inclusive). 209 | * 210 | * \param[in] pos the new file position. 211 | * \return true for success else false. 212 | */ 213 | bool seek(uint32_t pos) { 214 | return seekSet(pos); 215 | } 216 | /** \return the file's size. */ 217 | uint32_t size() { 218 | return fileSize(); 219 | } 220 | /** Write a byte to a file. Required by the Arduino Print class. 221 | * \param[in] b the byte to be written. 222 | * Use getWriteError to check for errors. 223 | * \return 1 for success and 0 for failure. 224 | */ 225 | size_t write(uint8_t b) { 226 | return FatFile::write(b); 227 | } 228 | /** Write data to an open file. Form required by Print. 229 | * 230 | * \note Data is moved to the cache but may not be written to the 231 | * storage device until sync() is called. 232 | * 233 | * \param[in] buf Pointer to the location of the data to be written. 234 | * 235 | * \param[in] size Number of bytes to write. 236 | * 237 | * \return For success write() returns the number of bytes written, always 238 | * \a nbyte. If an error occurs, write() returns -1. Possible errors 239 | * include write() is called before a file has been opened, write is called 240 | * for a read-only file, device is full, a corrupt file system or an 241 | * I/O error. 242 | */ 243 | size_t write(const uint8_t *buf, size_t size) { 244 | return FatFile::write(buf, size); 245 | } 246 | }; 247 | #endif // ENABLE_ARDUINO_FEATURES 248 | #endif // ArduinoFiles_h 249 | -------------------------------------------------------------------------------- /src/ArduinoStream.h: -------------------------------------------------------------------------------- 1 | /* FatLib Library 2 | * Copyright (C) 2013 by William Greiman 3 | * 4 | * This file is part of the FatLib 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 FatLib Library. If not, see 18 | * . 19 | */ 20 | #ifndef ArduinoStream_h 21 | #define ArduinoStream_h 22 | /** 23 | * \file 24 | * \brief ArduinoInStream and ArduinoOutStream classes 25 | */ 26 | #include "FatLibConfig.h" 27 | #if ENABLE_ARDUINO_FEATURES 28 | #include "SysCall.h" 29 | #include "bufstream.h" 30 | //============================================================================== 31 | /** 32 | * \class ArduinoInStream 33 | * \brief Input stream for Arduino Stream objects 34 | */ 35 | class ArduinoInStream : public ibufstream { 36 | public: 37 | /** 38 | * Constructor 39 | * \param[in] hws hardware stream 40 | * \param[in] buf buffer for input line 41 | * \param[in] size size of input buffer 42 | */ 43 | ArduinoInStream(Stream &hws, char* buf, size_t size) { 44 | m_hw = &hws; 45 | m_line = buf; 46 | m_size = size; 47 | } 48 | /** read a line. */ 49 | void readline() { 50 | size_t i = 0; 51 | uint32_t t; 52 | m_line[0] = '\0'; 53 | while (!m_hw->available()) { 54 | SysCall::yield(); 55 | } 56 | 57 | while (1) { 58 | t = millis(); 59 | while (!m_hw->available()) { 60 | if ((millis() - t) > 10) { 61 | goto done; 62 | } 63 | } 64 | if (i >= (m_size - 1)) { 65 | setstate(failbit); 66 | return; 67 | } 68 | m_line[i++] = m_hw->read(); 69 | m_line[i] = '\0'; 70 | } 71 | done: 72 | init(m_line); 73 | } 74 | 75 | protected: 76 | /** Internal - do not use. 77 | * \param[in] off 78 | * \param[in] way 79 | * \return true/false. 80 | */ 81 | bool seekoff(off_type off, seekdir way) { 82 | (void)off; 83 | (void)way; 84 | return false; 85 | } 86 | /** Internal - do not use. 87 | * \param[in] pos 88 | * \return true/false. 89 | */ 90 | bool seekpos(pos_type pos) { 91 | (void)pos; 92 | return false; 93 | } 94 | 95 | private: 96 | char *m_line; 97 | size_t m_size; 98 | Stream* m_hw; 99 | }; 100 | //============================================================================== 101 | /** 102 | * \class ArduinoOutStream 103 | * \brief Output stream for Arduino Print objects 104 | */ 105 | class ArduinoOutStream : public ostream { 106 | public: 107 | /** constructor 108 | * 109 | * \param[in] pr Print object for this ArduinoOutStream. 110 | */ 111 | explicit ArduinoOutStream(Print& pr) : m_pr(&pr) {} 112 | 113 | protected: 114 | /// @cond SHOW_PROTECTED 115 | /** 116 | * Internal do not use 117 | * \param[in] c 118 | */ 119 | void putch(char c) { 120 | if (c == '\n') { 121 | m_pr->write('\r'); 122 | } 123 | m_pr->write(c); 124 | } 125 | void putstr(const char* str) { 126 | m_pr->write(str); 127 | } 128 | bool seekoff(off_type off, seekdir way) { 129 | (void)off; 130 | (void)way; 131 | return false; 132 | } 133 | bool seekpos(pos_type pos) { 134 | (void)pos; 135 | return false; 136 | } 137 | bool sync() { 138 | return true; 139 | } 140 | pos_type tellpos() { 141 | return 0; 142 | } 143 | /// @endcond 144 | private: 145 | ArduinoOutStream() {} 146 | Print* m_pr; 147 | }; 148 | #endif // ENABLE_ARDUINO_FEATURES 149 | #endif // ArduinoStream_h 150 | -------------------------------------------------------------------------------- /src/FatApiConstants.h: -------------------------------------------------------------------------------- 1 | /* FatLib Library 2 | * Copyright (C) 2013 by William Greiman 3 | * 4 | * This file is part of the FatLib 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 FatLib Library. If not, see 18 | * . 19 | */ 20 | #ifndef FatApiConstants_h 21 | #define FatApiConstants_h 22 | //------------------------------------------------------------------------------ 23 | // use the gnu style oflag in open() 24 | /** open() oflag for reading */ 25 | uint8_t const O_READ = 0X01; 26 | /** open() oflag - same as O_IN */ 27 | uint8_t const O_RDONLY = O_READ; 28 | /** open() oflag for write */ 29 | uint8_t const O_WRITE = 0X02; 30 | /** open() oflag - same as O_WRITE */ 31 | uint8_t const O_WRONLY = O_WRITE; 32 | /** open() oflag for reading and writing */ 33 | uint8_t const O_RDWR = (O_READ | O_WRITE); 34 | /** open() oflag mask for access modes */ 35 | uint8_t const O_ACCMODE = (O_READ | O_WRITE); 36 | /** The file offset shall be set to the end of the file prior to each write. */ 37 | uint8_t const O_APPEND = 0X04; 38 | /** synchronous writes - call sync() after each write */ 39 | uint8_t const O_SYNC = 0X08; 40 | /** truncate the file to zero length */ 41 | uint8_t const O_TRUNC = 0X10; 42 | /** set the initial position at the end of the file */ 43 | uint8_t const O_AT_END = 0X20; 44 | /** create the file if nonexistent */ 45 | uint8_t const O_CREAT = 0X40; 46 | /** If O_CREAT and O_EXCL are set, open() shall fail if the file exists */ 47 | uint8_t const O_EXCL = 0X80; 48 | 49 | // FatFile class static and const definitions 50 | // flags for ls() 51 | /** ls() flag for list all files including hidden. */ 52 | uint8_t const LS_A = 1; 53 | /** ls() flag to print modify. date */ 54 | uint8_t const LS_DATE = 2; 55 | /** ls() flag to print file size. */ 56 | uint8_t const LS_SIZE = 4; 57 | /** ls() flag for recursive list of subdirectories */ 58 | uint8_t const LS_R = 8; 59 | 60 | // flags for timestamp 61 | /** set the file's last access date */ 62 | uint8_t const T_ACCESS = 1; 63 | /** set the file's creation date and time */ 64 | uint8_t const T_CREATE = 2; 65 | /** Set the file's write date and time */ 66 | uint8_t const T_WRITE = 4; 67 | #endif // FatApiConstants_h 68 | -------------------------------------------------------------------------------- /src/FatFilePrint.cpp: -------------------------------------------------------------------------------- 1 | /* FatLib Library 2 | * Copyright (C) 2012 by William Greiman 3 | * 4 | * This file is part of the FatLib 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 FatLib Library. If not, see 18 | * . 19 | */ 20 | #include 21 | #include "FatFile.h" 22 | #include "FmtNumber.h" 23 | //------------------------------------------------------------------------------ 24 | // print uint8_t with width 2 25 | static void print2u(print_t* pr, uint8_t v) { 26 | char c0 = '?'; 27 | char c1 = '?'; 28 | if (v < 100) { 29 | c1 = v/10; 30 | c0 = v - 10*c1 + '0'; 31 | c1 += '0'; 32 | } 33 | pr->write(c1); 34 | pr->write(c0); 35 | } 36 | //------------------------------------------------------------------------------ 37 | static void printU32(print_t* pr, uint32_t v) { 38 | char buf[11]; 39 | char* ptr = buf + sizeof(buf); 40 | *--ptr = 0; 41 | pr->write(fmtDec(v, ptr)); 42 | } 43 | //------------------------------------------------------------------------------ 44 | static void printHex(print_t* pr, uint8_t w, uint16_t h) { 45 | char buf[5]; 46 | char* ptr = buf + sizeof(buf); 47 | *--ptr = 0; 48 | for (uint8_t i = 0; i < w; i++) { 49 | char c = h & 0XF; 50 | *--ptr = c < 10 ? c + '0' : c + 'A' - 10; 51 | h >>= 4; 52 | } 53 | pr->write(ptr); 54 | } 55 | //------------------------------------------------------------------------------ 56 | void FatFile::dmpFile(print_t* pr, uint32_t pos, size_t n) { 57 | char text[17]; 58 | text[16] = 0; 59 | if (n >= 0XFFF0) { 60 | n = 0XFFF0; 61 | } 62 | if (!seekSet(pos)) { 63 | return; 64 | } 65 | for (size_t i = 0; i <= n; i++) { 66 | if ((i & 15) == 0) { 67 | if (i) { 68 | pr->write(' '); 69 | pr->write(text); 70 | if (i == n) { 71 | break; 72 | } 73 | } 74 | pr->write('\r'); 75 | pr->write('\n'); 76 | if (i >= n) { 77 | break; 78 | } 79 | printHex(pr, 4, i); 80 | pr->write(' '); 81 | } 82 | int16_t h = read(); 83 | if (h < 0) { 84 | break; 85 | } 86 | pr->write(' '); 87 | printHex(pr, 2, h); 88 | text[i&15] = ' ' <= h && h < 0X7F ? h : '.'; 89 | } 90 | pr->write('\r'); 91 | pr->write('\n'); 92 | } 93 | //------------------------------------------------------------------------------ 94 | void FatFile::ls(print_t* pr, uint8_t flags, uint8_t indent) { 95 | FatFile file; 96 | rewind(); 97 | while (file.openNext(this, O_READ)) { 98 | // indent for dir level 99 | if (!file.isHidden() || (flags & LS_A)) { 100 | for (uint8_t i = 0; i < indent; i++) { 101 | pr->write(' '); 102 | } 103 | if (flags & LS_DATE) { 104 | file.printModifyDateTime(pr); 105 | pr->write(' '); 106 | } 107 | if (flags & LS_SIZE) { 108 | file.printFileSize(pr); 109 | pr->write(' '); 110 | } 111 | file.printName(pr); 112 | if (file.isDir()) { 113 | pr->write('/'); 114 | } 115 | pr->write('\r'); 116 | pr->write('\n'); 117 | if ((flags & LS_R) && file.isDir()) { 118 | file.ls(pr, flags, indent + 2); 119 | } 120 | } 121 | file.close(); 122 | } 123 | } 124 | //------------------------------------------------------------------------------ 125 | bool FatFile::printCreateDateTime(print_t* pr) { 126 | dir_t dir; 127 | if (!dirEntry(&dir)) { 128 | DBG_FAIL_MACRO; 129 | goto fail; 130 | } 131 | printFatDate(pr, dir.creationDate); 132 | pr->write(' '); 133 | printFatTime(pr, dir.creationTime); 134 | return true; 135 | 136 | fail: 137 | return false; 138 | } 139 | //------------------------------------------------------------------------------ 140 | void FatFile::printFatDate(print_t* pr, uint16_t fatDate) { 141 | printU32(pr, FAT_YEAR(fatDate)); 142 | pr->write('-'); 143 | print2u(pr, FAT_MONTH(fatDate)); 144 | pr->write('-'); 145 | print2u(pr, FAT_DAY(fatDate)); 146 | } 147 | //------------------------------------------------------------------------------ 148 | void FatFile::printFatTime(print_t* pr, uint16_t fatTime) { 149 | print2u(pr, FAT_HOUR(fatTime)); 150 | pr->write(':'); 151 | print2u(pr, FAT_MINUTE(fatTime)); 152 | pr->write(':'); 153 | print2u(pr, FAT_SECOND(fatTime)); 154 | } 155 | //------------------------------------------------------------------------------ 156 | /** Template for FatFile::printField() */ 157 | template 158 | static int printFieldT(FatFile* file, char sign, Type value, char term) { 159 | char buf[3*sizeof(Type) + 3]; 160 | char* str = &buf[sizeof(buf)]; 161 | 162 | if (term) { 163 | *--str = term; 164 | if (term == '\n') { 165 | *--str = '\r'; 166 | } 167 | } 168 | #ifdef OLD_FMT 169 | do { 170 | Type m = value; 171 | value /= 10; 172 | *--str = '0' + m - 10*value; 173 | } while (value); 174 | #else // OLD_FMT 175 | str = fmtDec(value, str); 176 | #endif // OLD_FMT 177 | if (sign) { 178 | *--str = sign; 179 | } 180 | return file->write(str, &buf[sizeof(buf)] - str); 181 | } 182 | //------------------------------------------------------------------------------ 183 | 184 | int FatFile::printField(float value, char term, uint8_t prec) { 185 | char buf[24]; 186 | char* str = &buf[sizeof(buf)]; 187 | if (term) { 188 | *--str = term; 189 | if (term == '\n') { 190 | *--str = '\r'; 191 | } 192 | } 193 | str = fmtFloat(value, str, prec); 194 | return write(str, buf + sizeof(buf) - str); 195 | } 196 | //------------------------------------------------------------------------------ 197 | int FatFile::printField(uint16_t value, char term) { 198 | return printFieldT(this, 0, value, term); 199 | } 200 | //------------------------------------------------------------------------------ 201 | int FatFile::printField(int16_t value, char term) { 202 | char sign = 0; 203 | if (value < 0) { 204 | sign = '-'; 205 | value = -value; 206 | } 207 | return printFieldT(this, sign, (uint16_t)value, term); 208 | } 209 | //------------------------------------------------------------------------------ 210 | int FatFile::printField(uint32_t value, char term) { 211 | return printFieldT(this, 0, value, term); 212 | } 213 | //------------------------------------------------------------------------------ 214 | int FatFile::printField(int32_t value, char term) { 215 | char sign = 0; 216 | if (value < 0) { 217 | sign = '-'; 218 | value = -value; 219 | } 220 | return printFieldT(this, sign, (uint32_t)value, term); 221 | } 222 | //------------------------------------------------------------------------------ 223 | bool FatFile::printModifyDateTime(print_t* pr) { 224 | dir_t dir; 225 | if (!dirEntry(&dir)) { 226 | DBG_FAIL_MACRO; 227 | goto fail; 228 | } 229 | printFatDate(pr, dir.lastWriteDate); 230 | pr->write(' '); 231 | printFatTime(pr, dir.lastWriteTime); 232 | return true; 233 | 234 | fail: 235 | return false; 236 | } 237 | 238 | //------------------------------------------------------------------------------ 239 | size_t FatFile::printFileSize(print_t* pr) { 240 | char buf[11]; 241 | char *ptr = buf + sizeof(buf); 242 | *--ptr = 0; 243 | ptr = fmtDec(fileSize(), ptr); 244 | while (ptr > buf) { 245 | *--ptr = ' '; 246 | } 247 | return pr->write(buf); 248 | } 249 | -------------------------------------------------------------------------------- /src/FatFileSFN.cpp: -------------------------------------------------------------------------------- 1 | /* FatLib Library 2 | * Copyright (C) 2012 by William Greiman 3 | * 4 | * This file is part of the FatLib 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 FatLib Library. If not, see 18 | * . 19 | */ 20 | #include "FatFile.h" 21 | #include "FatFileSystem.h" 22 | //------------------------------------------------------------------------------ 23 | bool FatFile::getSFN(char* name) { 24 | dir_t* dir; 25 | if (!isOpen()) { 26 | DBG_FAIL_MACRO; 27 | goto fail; 28 | } 29 | if (isRoot()) { 30 | name[0] = '/'; 31 | name[1] = '\0'; 32 | return true; 33 | } 34 | // cache entry 35 | dir = cacheDirEntry(FatCache::CACHE_FOR_READ); 36 | if (!dir) { 37 | DBG_FAIL_MACRO; 38 | goto fail; 39 | } 40 | // format name 41 | dirName(dir, name); 42 | return true; 43 | 44 | fail: 45 | return false; 46 | } 47 | //------------------------------------------------------------------------------ 48 | size_t FatFile::printSFN(print_t* pr) { 49 | char name[13]; 50 | if (!getSFN(name)) { 51 | DBG_FAIL_MACRO; 52 | goto fail; 53 | } 54 | return pr->write(name); 55 | 56 | fail: 57 | return 0; 58 | } 59 | #if !USE_LONG_FILE_NAMES 60 | //------------------------------------------------------------------------------ 61 | bool FatFile::getName(char* name, size_t size) { 62 | return size < 13 ? 0 : getSFN(name); 63 | } 64 | //------------------------------------------------------------------------------ 65 | // format directory name field from a 8.3 name string 66 | bool FatFile::parsePathName(const char* path, fname_t* fname, 67 | const char** ptr) { 68 | uint8_t uc = 0; 69 | uint8_t lc = 0; 70 | uint8_t bit = FNAME_FLAG_LC_BASE; 71 | // blank fill name and extension 72 | for (uint8_t i = 0; i < 11; i++) { 73 | fname->sfn[i] = ' '; 74 | } 75 | 76 | for (uint8_t i = 0, n = 7;; path++) { 77 | uint8_t c = *path; 78 | if (c == 0 || isDirSeparator(c)) { 79 | // Done. 80 | break; 81 | } 82 | if (c == '.' && n == 7) { 83 | n = 10; // max index for full 8.3 name 84 | i = 8; // place for extension 85 | 86 | // bit for extension. 87 | bit = FNAME_FLAG_LC_EXT; 88 | } else { 89 | if (!legal83Char(c) || i > n) { 90 | DBG_FAIL_MACRO; 91 | goto fail; 92 | } 93 | if ('a' <= c && c <= 'z') { 94 | c += 'A' - 'a'; 95 | lc |= bit; 96 | } else if ('A' <= c && c <= 'Z') { 97 | uc |= bit; 98 | } 99 | fname->sfn[i++] = c; 100 | } 101 | } 102 | // must have a file name, extension is optional 103 | if (fname->sfn[0] == ' ') { 104 | DBG_FAIL_MACRO; 105 | goto fail; 106 | } 107 | // Set base-name and extension bits. 108 | fname->flags = lc & uc ? 0 : lc; 109 | while (isDirSeparator(*path)) { 110 | path++; 111 | } 112 | *ptr = path; 113 | return true; 114 | 115 | fail: 116 | return false; 117 | } 118 | //------------------------------------------------------------------------------ 119 | // open with filename in fname 120 | #define SFN_OPEN_USES_CHKSUM 0 121 | bool FatFile::open(FatFile* dirFile, fname_t* fname, uint8_t oflag) { 122 | bool emptyFound = false; 123 | #if SFN_OPEN_USES_CHKSUM 124 | uint8_t chksum; 125 | #endif 126 | uint8_t lfnOrd = 0; 127 | uint16_t emptyIndex; 128 | uint16_t index = 0; 129 | dir_t* dir; 130 | ldir_t* ldir; 131 | 132 | dirFile->rewind(); 133 | while (1) { 134 | if (!emptyFound) { 135 | emptyIndex = index; 136 | } 137 | dir = dirFile->readDirCache(true); 138 | if (!dir) { 139 | if (dirFile->getError()) { 140 | DBG_FAIL_MACRO; 141 | goto fail; 142 | } 143 | // At EOF if no error. 144 | break; 145 | } 146 | if (dir->name[0] == DIR_NAME_FREE) { 147 | emptyFound = true; 148 | break; 149 | } 150 | if (dir->name[0] == DIR_NAME_DELETED) { 151 | lfnOrd = 0; 152 | emptyFound = true; 153 | } else if (DIR_IS_FILE_OR_SUBDIR(dir)) { 154 | if (!memcmp(fname->sfn, dir->name, 11)) { 155 | // don't open existing file if O_EXCL 156 | if (oflag & O_EXCL) { 157 | DBG_FAIL_MACRO; 158 | goto fail; 159 | } 160 | #if SFN_OPEN_USES_CHKSUM 161 | if (lfnOrd && chksum != lfnChecksum(dir->name)) { 162 | DBG_FAIL_MACRO; 163 | goto fail; 164 | } 165 | #endif // SFN_OPEN_USES_CHKSUM 166 | if (!openCachedEntry(dirFile, index, oflag, lfnOrd)) { 167 | DBG_FAIL_MACRO; 168 | goto fail; 169 | } 170 | return true; 171 | } else { 172 | lfnOrd = 0; 173 | } 174 | } else if (DIR_IS_LONG_NAME(dir)) { 175 | ldir = reinterpret_cast(dir); 176 | if (ldir->ord & LDIR_ORD_LAST_LONG_ENTRY) { 177 | lfnOrd = ldir->ord & 0X1F; 178 | #if SFN_OPEN_USES_CHKSUM 179 | chksum = ldir->chksum; 180 | #endif // SFN_OPEN_USES_CHKSUM 181 | } 182 | } else { 183 | lfnOrd = 0; 184 | } 185 | index++; 186 | } 187 | // don't create unless O_CREAT and O_WRITE 188 | if (!(oflag & O_CREAT) || !(oflag & O_WRITE)) { 189 | DBG_FAIL_MACRO; 190 | goto fail; 191 | } 192 | if (emptyFound) { 193 | index = emptyIndex; 194 | } else { 195 | if (!dirFile->addDirCluster()) { 196 | DBG_FAIL_MACRO; 197 | goto fail; 198 | } 199 | } 200 | if (!dirFile->seekSet(32UL*index)) { 201 | DBG_FAIL_MACRO; 202 | goto fail; 203 | } 204 | dir = dirFile->readDirCache(); 205 | if (!dir) { 206 | DBG_FAIL_MACRO; 207 | goto fail; 208 | } 209 | // initialize as empty file 210 | memset(dir, 0, sizeof(dir_t)); 211 | memcpy(dir->name, fname->sfn, 11); 212 | 213 | // Set base-name and extension lower case bits. 214 | dir->reservedNT = (DIR_NT_LC_BASE | DIR_NT_LC_EXT) & fname->flags; 215 | 216 | // set timestamps 217 | if (m_dateTime) { 218 | // call user date/time function 219 | m_dateTime(&dir->creationDate, &dir->creationTime); 220 | } else { 221 | // use default date/time 222 | dir->creationDate = FAT_DEFAULT_DATE; 223 | dir->creationTime = FAT_DEFAULT_TIME; 224 | } 225 | dir->lastAccessDate = dir->creationDate; 226 | dir->lastWriteDate = dir->creationDate; 227 | dir->lastWriteTime = dir->creationTime; 228 | 229 | // Force write of entry to device. 230 | dirFile->m_vol->cacheDirty(); 231 | 232 | // open entry in cache. 233 | return openCachedEntry(dirFile, index, oflag, 0); 234 | 235 | fail: 236 | return false; 237 | } 238 | //------------------------------------------------------------------------------ 239 | size_t FatFile::printName(print_t* pr) { 240 | return printSFN(pr); 241 | } 242 | //------------------------------------------------------------------------------ 243 | bool FatFile::remove() { 244 | dir_t* dir; 245 | // Can't remove if LFN or not open for write. 246 | if (!isFile() || isLFN() || !(m_flags & O_WRITE)) { 247 | DBG_FAIL_MACRO; 248 | goto fail; 249 | } 250 | // Free any clusters. 251 | if (m_firstCluster && !m_vol->freeChain(m_firstCluster)) { 252 | DBG_FAIL_MACRO; 253 | goto fail; 254 | } 255 | // Cache directory entry. 256 | dir = cacheDirEntry(FatCache::CACHE_FOR_WRITE); 257 | if (!dir) { 258 | DBG_FAIL_MACRO; 259 | goto fail; 260 | } 261 | // Mark entry deleted. 262 | dir->name[0] = DIR_NAME_DELETED; 263 | 264 | // Set this file closed. 265 | m_attr = FILE_ATTR_CLOSED; 266 | 267 | // Write entry to device. 268 | return m_vol->cacheSync(); 269 | 270 | fail: 271 | return false; 272 | } 273 | #endif // !USE_LONG_FILE_NAMES 274 | -------------------------------------------------------------------------------- /src/FatFileSystem.h: -------------------------------------------------------------------------------- 1 | /* FatLib Library 2 | * Copyright (C) 2013 by William Greiman 3 | * 4 | * This file is part of the FatLib 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 FatLib Library. If not, see 18 | * . 19 | */ 20 | #ifndef FatFileSystem_h 21 | #define FatFileSystem_h 22 | #include "FatVolume.h" 23 | #include "FatFile.h" 24 | #include "ArduinoFiles.h" 25 | /** 26 | * \file 27 | * \brief FatFileSystem class 28 | */ 29 | //------------------------------------------------------------------------------ 30 | /** 31 | * \class FatFileSystem 32 | * \brief Integration class for the FatLib library. 33 | */ 34 | class FatFileSystem : public FatVolume { 35 | public: 36 | /** 37 | * Initialize an FatFileSystem object. 38 | * \param[in] part partition to initialize. 39 | * \return The value true is returned for success and 40 | * the value false is returned for failure. 41 | */ 42 | bool begin(uint8_t part = 0) { 43 | vwd()->close(); 44 | return (part ? init(part) : init(1) || init(0)) 45 | && vwd()->openRoot(this) && FatFile::setCwd(vwd()); 46 | } 47 | #if ENABLE_ARDUINO_FEATURES 48 | /** List the directory contents of the volume working directory to Serial. 49 | * 50 | * \param[in] flags The inclusive OR of 51 | * 52 | * LS_DATE - %Print file modification date 53 | * 54 | * LS_SIZE - %Print file size. 55 | * 56 | * LS_R - Recursive list of subdirectories. 57 | */ 58 | void ls(uint8_t flags = 0) { 59 | ls(&Serial, flags); 60 | } 61 | /** List the directory contents of a directory to Serial. 62 | * 63 | * \param[in] path directory to list. 64 | * 65 | * \param[in] flags The inclusive OR of 66 | * 67 | * LS_DATE - %Print file modification date 68 | * 69 | * LS_SIZE - %Print file size. 70 | * 71 | * LS_R - Recursive list of subdirectories. 72 | */ 73 | void ls(const char* path, uint8_t flags = 0) { 74 | ls(&Serial, path, flags); 75 | } 76 | /** open a file 77 | * 78 | * \param[in] path location of file to be opened. 79 | * \param[in] mode open mode flags. 80 | * \return a File object. 81 | */ 82 | File open(const char *path, uint8_t mode = FILE_READ) { 83 | File tmpFile; 84 | tmpFile.open(vwd(), path, mode); 85 | return tmpFile; 86 | } 87 | #endif // ENABLE_ARDUINO_FEATURES 88 | /** Change a volume's working directory to root 89 | * 90 | * Changes the volume's working directory to the SD's root directory. 91 | * Optionally set the current working directory to the volume's 92 | * working directory. 93 | * 94 | * \param[in] set_cwd Set the current working directory to this volume's 95 | * working directory if true. 96 | * 97 | * \return The value true is returned for success and 98 | * the value false is returned for failure. 99 | */ 100 | bool chdir(bool set_cwd = false) { 101 | vwd()->close(); 102 | return vwd()->openRoot(this) && (set_cwd ? FatFile::setCwd(vwd()) : true); 103 | } 104 | /** Change a volume's working directory 105 | * 106 | * Changes the volume working directory to the \a path subdirectory. 107 | * Optionally set the current working directory to the volume's 108 | * working directory. 109 | * 110 | * Example: If the volume's working directory is "/DIR", chdir("SUB") 111 | * will change the volume's working directory from "/DIR" to "/DIR/SUB". 112 | * 113 | * If path is "/", the volume's working directory will be changed to the 114 | * root directory 115 | * 116 | * \param[in] path The name of the subdirectory. 117 | * 118 | * \param[in] set_cwd Set the current working directory to this volume's 119 | * working directory if true. 120 | * 121 | * \return The value true is returned for success and 122 | * the value false is returned for failure. 123 | */ 124 | //---------------------------------------------------------------------------- 125 | bool chdir(const char *path, bool set_cwd = false) { 126 | FatFile dir; 127 | if (path[0] == '/' && path[1] == '\0') { 128 | return chdir(set_cwd); 129 | } 130 | if (!dir.open(vwd(), path, O_READ)) { 131 | goto fail; 132 | } 133 | if (!dir.isDir()) { 134 | goto fail; 135 | } 136 | // *m_vwd = dir; 137 | m_vwd = dir; 138 | if (set_cwd) { 139 | FatFile::setCwd(vwd()); 140 | } 141 | return true; 142 | 143 | fail: 144 | return false; 145 | } 146 | //---------------------------------------------------------------------------- 147 | /** Set the current working directory to a volume's working directory. 148 | * 149 | * This is useful with multiple SD cards. 150 | * 151 | * The current working directory is changed to this 152 | * volume's working directory. 153 | * 154 | * This is like the Windows/DOS \: command. 155 | */ 156 | void chvol() { 157 | FatFile::setCwd(vwd()); 158 | } 159 | //---------------------------------------------------------------------------- 160 | /** 161 | * Test for the existence of a file. 162 | * 163 | * \param[in] path Path of the file to be tested for. 164 | * 165 | * \return true if the file exists else false. 166 | */ 167 | bool exists(const char* path) { 168 | return vwd()->exists(path); 169 | } 170 | //---------------------------------------------------------------------------- 171 | /** List the directory contents of the volume working directory. 172 | * 173 | * \param[in] pr Print stream for list. 174 | * 175 | * \param[in] flags The inclusive OR of 176 | * 177 | * LS_DATE - %Print file modification date 178 | * 179 | * LS_SIZE - %Print file size. 180 | * 181 | * LS_R - Recursive list of subdirectories. 182 | */ 183 | void ls(print_t* pr, uint8_t flags) { 184 | vwd()->ls(pr, flags); 185 | } 186 | //---------------------------------------------------------------------------- 187 | /** List the directory contents of a directory. 188 | * 189 | * \param[in] pr Print stream for list. 190 | * 191 | * \param[in] path directory to list. 192 | * 193 | * \param[in] flags The inclusive OR of 194 | * 195 | * LS_DATE - %Print file modification date 196 | * 197 | * LS_SIZE - %Print file size. 198 | * 199 | * LS_R - Recursive list of subdirectories. 200 | */ 201 | void ls(print_t* pr, const char* path, uint8_t flags) { 202 | FatFile dir; 203 | dir.open(vwd(), path, O_READ); 204 | dir.ls(pr, flags); 205 | } 206 | //---------------------------------------------------------------------------- 207 | /** Make a subdirectory in the volume working directory. 208 | * 209 | * \param[in] path A path with a valid 8.3 DOS name for the subdirectory. 210 | * 211 | * \param[in] pFlag Create missing parent directories if true. 212 | * 213 | * \return The value true is returned for success and 214 | * the value false is returned for failure. 215 | */ 216 | bool mkdir(const char* path, bool pFlag = true) { 217 | FatFile sub; 218 | return sub.mkdir(vwd(), path, pFlag); 219 | } 220 | //---------------------------------------------------------------------------- 221 | /** Remove a file from the volume working directory. 222 | * 223 | * \param[in] path A path with a valid 8.3 DOS name for the file. 224 | * 225 | * \return The value true is returned for success and 226 | * the value false is returned for failure. 227 | */ 228 | bool remove(const char* path) { 229 | return FatFile::remove(vwd(), path); 230 | } 231 | //---------------------------------------------------------------------------- 232 | /** Rename a file or subdirectory. 233 | * 234 | * \param[in] oldPath Path name to the file or subdirectory to be renamed. 235 | * 236 | * \param[in] newPath New path name of the file or subdirectory. 237 | * 238 | * The \a newPath object must not exist before the rename call. 239 | * 240 | * The file to be renamed must not be open. The directory entry may be 241 | * moved and file system corruption could occur if the file is accessed by 242 | * a file object that was opened before the rename() call. 243 | * 244 | * \return The value true is returned for success and 245 | * the value false is returned for failure. 246 | */ 247 | bool rename(const char *oldPath, const char *newPath) { 248 | FatFile file; 249 | if (!file.open(vwd(), oldPath, O_READ)) { 250 | return false; 251 | } 252 | return file.rename(vwd(), newPath); 253 | } 254 | //---------------------------------------------------------------------------- 255 | /** Remove a subdirectory from the volume's working directory. 256 | * 257 | * \param[in] path A path with a valid 8.3 DOS name for the subdirectory. 258 | * 259 | * The subdirectory file will be removed only if it is empty. 260 | * 261 | * \return The value true is returned for success and 262 | * the value false is returned for failure. 263 | */ 264 | bool rmdir(const char* path) { 265 | FatFile sub; 266 | if (!sub.open(vwd(), path, O_READ)) { 267 | return false; 268 | } 269 | return sub.rmdir(); 270 | } 271 | //---------------------------------------------------------------------------- 272 | /** Truncate a file to a specified length. The current file position 273 | * will be maintained if it is less than or equal to \a length otherwise 274 | * it will be set to end of file. 275 | * 276 | * \param[in] path A path with a valid 8.3 DOS name for the file. 277 | * \param[in] length The desired length for the file. 278 | * 279 | * \return The value true is returned for success and 280 | * the value false is returned for failure. 281 | */ 282 | bool truncate(const char* path, uint32_t length) { 283 | FatFile file; 284 | if (!file.open(vwd(), path, O_WRITE)) { 285 | return false; 286 | } 287 | return file.truncate(length); 288 | } 289 | /** \return a pointer to the FatVolume object. */ 290 | FatVolume* vol() { 291 | return this; 292 | } 293 | /** \return a pointer to the volume working directory. */ 294 | FatFile* vwd() { 295 | return &m_vwd; 296 | } 297 | /** Wipe all data from the volume. You must reinitialize the volume before 298 | * accessing it again. 299 | * \param[in] pr print stream for status dots. 300 | * \return true for success else false. 301 | */ 302 | bool wipe(print_t* pr = 0) { 303 | vwd()->close(); 304 | return FatVolume::wipe(pr); 305 | } 306 | 307 | private: 308 | FatFile m_vwd; 309 | }; 310 | #endif // FatFileSystem_h 311 | -------------------------------------------------------------------------------- /src/FatLib.h: -------------------------------------------------------------------------------- 1 | /* FatLib Library 2 | * Copyright (C) 2013 by William Greiman 3 | * 4 | * This file is part of the FatLib 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 FatLib Library. If not, see 18 | * . 19 | */ 20 | #ifndef FatLib_h 21 | #define FatLib_h 22 | #include "ArduinoFiles.h" 23 | #include "ArduinoStream.h" 24 | #include "FatFileSystem.h" 25 | #include "FatLibConfig.h" 26 | #include "FatVolume.h" 27 | #include "FatFile.h" 28 | #include "StdioStream.h" 29 | #include "fstream.h" 30 | //------------------------------------------------------------------------------ 31 | /** FatFileSystem version YYYYMMDD */ 32 | #define FAT_LIB_VERSION 20150131 33 | #endif // FatLib_h 34 | -------------------------------------------------------------------------------- /src/FatLibConfig.h: -------------------------------------------------------------------------------- 1 | /* FatLib Library 2 | * Copyright (C) 2013 by William Greiman 3 | * 4 | * This file is part of the FatLib 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 FatLib Library. If not, see 18 | * . 19 | */ 20 | /** 21 | * \file 22 | * \brief configuration definitions 23 | */ 24 | #ifndef FatLibConfig_h 25 | #define FatLibConfig_h 26 | #include 27 | // Allow this file to override defaults. 28 | #include "SdFatConfig.h" 29 | 30 | #ifdef __AVR__ 31 | #include 32 | #endif // __AVR__ 33 | //------------------------------------------------------------------------------ 34 | /** 35 | * Set USE_LONG_FILE_NAMES nonzero to use long file names (LFN). 36 | * Long File Name are limited to a maximum length of 255 characters. 37 | * 38 | * This implementation allows 7-bit characters in the range 39 | * 0X20 to 0X7E. The following characters are not allowed: 40 | * 41 | * < (less than) 42 | * > (greater than) 43 | * : (colon) 44 | * " (double quote) 45 | * / (forward slash) 46 | * \ (backslash) 47 | * | (vertical bar or pipe) 48 | * ? (question mark) 49 | * * (asterisk) 50 | * 51 | */ 52 | #ifndef USE_LONG_FILE_NAMES 53 | #define USE_LONG_FILE_NAMES 1 54 | #endif // USE_LONG_FILE_NAMES 55 | //------------------------------------------------------------------------------ 56 | /** 57 | * Set ARDUINO_FILE_USES_STREAM nonzero to use Stream as the base class 58 | * for the Arduino File class. If ARDUINO_FILE_USES_STREAM is zero, Print 59 | * will be used as the base class for the Arduino File class. 60 | * 61 | * You can save some flash if you do not use Stream input functions such as 62 | * find(), findUntil(), readBytesUntil(), readString(), readStringUntil(), 63 | * parseInt(), and parsefloat(). 64 | */ 65 | #ifndef ARDUINO_FILE_USES_STREAM 66 | #define ARDUINO_FILE_USES_STREAM 1 67 | #endif // ARDUINO_FILE_USES_STREAM 68 | //------------------------------------------------------------------------------ 69 | /** 70 | * Set USE_SEPARATE_FAT_CACHE non-zero to use a second 512 byte cache 71 | * for FAT table entries. Improves performance for large writes that 72 | * are not a multiple of 512 bytes. 73 | */ 74 | #ifndef USE_SEPARATE_FAT_CACHE 75 | #ifdef __arm__ 76 | #define USE_SEPARATE_FAT_CACHE 1 77 | #else // __arm__ 78 | #define USE_SEPARATE_FAT_CACHE 0 79 | #endif // __arm__ 80 | #endif // USE_SEPARATE_FAT_CACHE 81 | //------------------------------------------------------------------------------ 82 | /** 83 | * Set USE_MULTI_BLOCK_IO non-zero to use multi-block SD read/write. 84 | * 85 | * Don't use mult-block read/write on small AVR boards. 86 | */ 87 | #ifndef USE_MULTI_BLOCK_IO 88 | #if defined(RAMEND) && RAMEND < 3000 89 | #define USE_MULTI_BLOCK_IO 0 90 | #else // RAMEND 91 | #define USE_MULTI_BLOCK_IO 1 92 | #endif // RAMEND 93 | #endif // USE_MULTI_BLOCK_IO 94 | //------------------------------------------------------------------------------ 95 | /** 96 | * Set DESTRUCTOR_CLOSES_FILE non-zero to close a file in its destructor. 97 | * 98 | * Causes use of lots of heap in ARM. 99 | */ 100 | #ifndef DESTRUCTOR_CLOSES_FILE 101 | #define DESTRUCTOR_CLOSES_FILE 0 102 | #endif // DESTRUCTOR_CLOSES_FILE 103 | //------------------------------------------------------------------------------ 104 | /** 105 | * Call flush for endl if ENDL_CALLS_FLUSH is non-zero 106 | * 107 | * The standard for iostreams is to call flush. This is very costly for 108 | * SdFat. Each call to flush causes 2048 bytes of I/O to the SD. 109 | * 110 | * SdFat has a single 512 byte buffer for I/O so it must write the current 111 | * data block to the SD, read the directory block from the SD, update the 112 | * directory entry, write the directory block to the SD and read the data 113 | * block back into the buffer. 114 | * 115 | * The SD flash memory controller is not designed for this many rewrites 116 | * so performance may be reduced by more than a factor of 100. 117 | * 118 | * If ENDL_CALLS_FLUSH is zero, you must call flush and/or close to force 119 | * all data to be written to the SD. 120 | */ 121 | #ifndef ENDL_CALLS_FLUSH 122 | #define ENDL_CALLS_FLUSH 0 123 | #endif // ENDL_CALLS_FLUSH 124 | //------------------------------------------------------------------------------ 125 | /** 126 | * Allow FAT12 volumes if FAT12_SUPPORT is non-zero. 127 | * FAT12 has not been well tested. 128 | */ 129 | #ifndef FAT12_SUPPORT 130 | #define FAT12_SUPPORT 0 131 | #endif // FAT12_SUPPORT 132 | //------------------------------------------------------------------------------ 133 | /** 134 | * Enable Extra features for Arduino. 135 | */ 136 | #ifndef ENABLE_ARDUINO_FEATURES 137 | #if defined(ARDUINO) || defined(PLATFORM_ID) || defined(DOXYGEN) 138 | #define ENABLE_ARDUINO_FEATURES 1 139 | #else // #if defined(ARDUINO) || defined(DOXYGEN) 140 | #define ENABLE_ARDUINO_FEATURES 0 141 | #endif // defined(ARDUINO) || defined(DOXYGEN) 142 | #endif // ENABLE_ARDUINO_FEATURES 143 | #endif // FatLibConfig_h 144 | -------------------------------------------------------------------------------- /src/FmtNumber.h: -------------------------------------------------------------------------------- 1 | /* FatLib Library 2 | * Copyright (C) 2013 by William Greiman 3 | * 4 | * This file is part of the FatLib 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 FatLib Library. If not, see 18 | * . 19 | */ 20 | #ifndef FmtNumber_h 21 | #define FmtNumber_h 22 | // #include 23 | inline bool isDigit(char c) { 24 | return '0' <= c && c <= '9'; 25 | } 26 | inline bool isSpace(char c) { 27 | return c == ' ' || (0X9 <= c && c <= 0XD); 28 | } 29 | #include 30 | #include 31 | char* fmtDec(uint16_t n, char* p); 32 | char* fmtDec(uint32_t n, char* p); 33 | char* fmtFloat(float value, char* p, uint8_t prec); 34 | char* fmtFloat(float value, char* ptr, uint8_t prec, char expChar); 35 | char* fmtHex(uint32_t n, char* p); 36 | float scale10(float v, int8_t n); 37 | float scanFloat(const char* str, char** ptr); 38 | #endif // FmtNumber_h 39 | -------------------------------------------------------------------------------- /src/FreeStack.h: -------------------------------------------------------------------------------- 1 | /* Arduino SdFat Library 2 | * Copyright (C) 2015 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 FreeStack_h 21 | #define FreeStack_h 22 | /** 23 | * \file 24 | * \brief FreeStack() function. 25 | */ 26 | 27 | #if defined(__AVR__) || defined(DOXYGEN) 28 | /** boundary between stack and heap. */ 29 | extern char *__brkval; 30 | /** End of bss section.*/ 31 | extern char __bss_end; 32 | /** Amount of free stack space. 33 | * \return The number of free bytes. 34 | */ 35 | static int FreeStack() { 36 | char top; 37 | return __brkval ? &top - __brkval : &top - &__bss_end; 38 | } 39 | #elif defined(PLATFORM_ID) // Particle board 40 | static int FreeStack() { 41 | return System.freeMemory(); 42 | } 43 | #elif defined(__arm__) 44 | extern "C" char* sbrk(int incr); 45 | static int FreeStack() { 46 | char top; 47 | return &top - reinterpret_cast(sbrk(0)); 48 | } 49 | 50 | #else 51 | #warning FreeStack is not defined for this system. 52 | static int FreeStack() { 53 | return 0; 54 | } 55 | #endif 56 | #endif // FreeStack_h 57 | -------------------------------------------------------------------------------- /src/SdFat.cpp: -------------------------------------------------------------------------------- 1 | /* Arduino SdFat Library 2 | * Copyright (C) 2012 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 | void SdFatBase::errorHalt(Print* pr) { 23 | errorPrint(pr); 24 | SysCall::halt(); 25 | } 26 | //------------------------------------------------------------------------------ 27 | void SdFatBase::errorHalt(Print* pr, char const* msg) { 28 | errorPrint(pr, msg); 29 | SysCall::halt(); 30 | } 31 | //------------------------------------------------------------------------------ 32 | void SdFatBase::errorPrint(Print* pr) { 33 | if (!cardErrorCode()) { 34 | return; 35 | } 36 | pr->print(F("SD errorCode: 0X")); 37 | pr->print(cardErrorCode(), HEX); 38 | pr->print(F(",0X")); 39 | pr->println(cardErrorData(), HEX); 40 | } 41 | //------------------------------------------------------------------------------ 42 | void SdFatBase::errorPrint(Print* pr, char const* msg) { 43 | pr->print(F("error: ")); 44 | pr->println(msg); 45 | errorPrint(pr); 46 | } 47 | //------------------------------------------------------------------------------ 48 | void SdFatBase::initErrorHalt(Print* pr) { 49 | initErrorPrint(pr); 50 | SysCall::halt(); 51 | } 52 | //------------------------------------------------------------------------------ 53 | void SdFatBase::initErrorHalt(Print* pr, char const *msg) { 54 | pr->println(msg); 55 | initErrorHalt(pr); 56 | } 57 | //------------------------------------------------------------------------------ 58 | void SdFatBase::initErrorPrint(Print* pr) { 59 | if (cardErrorCode()) { 60 | pr->println(F("Can't access SD card. Do not reformat.")); 61 | if (cardErrorCode() == SD_CARD_ERROR_CMD0) { 62 | pr->println(F("No card, wrong chip select pin, or SPI problem?")); 63 | } 64 | errorPrint(pr); 65 | } else if (vol()->fatType() == 0) { 66 | pr->println(F("Invalid format, reformat SD.")); 67 | } else if (!vwd()->isOpen()) { 68 | pr->println(F("Can't open root directory.")); 69 | } else { 70 | pr->println(F("No error found.")); 71 | } 72 | } 73 | //------------------------------------------------------------------------------ 74 | void SdFatBase::initErrorPrint(Print* pr, char const *msg) { 75 | pr->println(msg); 76 | initErrorPrint(pr); 77 | } 78 | #if defined(ARDUINO) || defined(DOXYGEN) 79 | //------------------------------------------------------------------------------ 80 | void SdFatBase::errorPrint(Print* pr, const __FlashStringHelper* msg) { 81 | pr->print(F("error: ")); 82 | pr->println(msg); 83 | errorPrint(pr); 84 | } 85 | //------------------------------------------------------------------------------ 86 | void SdFatBase::errorHalt(Print* pr, const __FlashStringHelper* msg) { 87 | errorPrint(pr, msg); 88 | SysCall::halt(); 89 | } 90 | //------------------------------------------------------------------------------ 91 | void SdFatBase::initErrorHalt(Print* pr, const __FlashStringHelper* msg) { 92 | pr->println(msg); 93 | initErrorHalt(pr); 94 | } 95 | //------------------------------------------------------------------------------ 96 | void SdFatBase::initErrorPrint(Print* pr, const __FlashStringHelper* msg) { 97 | pr->println(msg); 98 | initErrorPrint(pr); 99 | } 100 | #endif // defined(ARDUINO) || defined(DOXYGEN) 101 | -------------------------------------------------------------------------------- /src/SdFat.h: -------------------------------------------------------------------------------- 1 | /* Arduino SdFat Library 2 | * Copyright (C) 2012 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 | * \brief SdFat class 25 | */ 26 | #include "SdSpiCard.h" 27 | #include "FatLib.h" 28 | //------------------------------------------------------------------------------ 29 | /** SdFat version YYYYMMDD */ 30 | #define SD_FAT_VERSION 20170302 31 | //============================================================================== 32 | /** 33 | * \class SdBaseFile 34 | * \brief Class for backward compatibility. 35 | */ 36 | class SdBaseFile : public FatFile { 37 | public: 38 | SdBaseFile() {} 39 | /** Create a file object and open it in the current working directory. 40 | * 41 | * \param[in] path A path for a file to be opened. 42 | * 43 | * \param[in] oflag Values for \a oflag are constructed by a 44 | * bitwise-inclusive OR of open flags. see 45 | * FatFile::open(FatFile*, const char*, uint8_t). 46 | */ 47 | SdBaseFile(const char* path, uint8_t oflag) : FatFile(path, oflag) {} 48 | }; 49 | #if ENABLE_ARDUINO_FEATURES 50 | /** 51 | * \class SdFile 52 | * \brief Class for backward compatibility. 53 | */ 54 | class SdFile : public PrintFile { 55 | public: 56 | SdFile() {} 57 | /** Create a file object and open it in the current working directory. 58 | * 59 | * \param[in] path A path for a file to be opened. 60 | * 61 | * \param[in] oflag Values for \a oflag are constructed by a 62 | * bitwise-inclusive OR of open flags. see 63 | * FatFile::open(FatFile*, const char*, uint8_t). 64 | */ 65 | SdFile(const char* path, uint8_t oflag) : PrintFile(path, oflag) {} 66 | }; 67 | #endif // #if ENABLE_ARDUINO_FEATURES 68 | /** 69 | * \class SdFatBase 70 | * \brief Virtual base class for %SdFat library. 71 | */ 72 | class SdFatBase : public FatFileSystem { 73 | public: 74 | /** Initialize SD card and file system. 75 | * \param[in] spi SPI object for the card. 76 | * \param[in] csPin SD card chip select pin. 77 | * \param[in] divisor SPI divisor. 78 | * \return true for success else false. 79 | */ 80 | bool begin(SdSpiCard::m_spi_t* spi, uint8_t csPin = SS, uint8_t divisor = 2) { 81 | return m_sdCard.begin(spi, csPin, divisor) && 82 | FatFileSystem::begin(); 83 | } 84 | /** \return Pointer to SD card object */ 85 | SdSpiCard *card() { 86 | return &m_sdCard; 87 | } 88 | /** \return card error code */ 89 | uint8_t cardErrorCode() { 90 | return m_sdCard.errorCode(); 91 | } 92 | /** \return card error data */ 93 | uint8_t cardErrorData() { 94 | return m_sdCard.errorData(); 95 | } 96 | /** %Print any SD error code to Serial and halt. */ 97 | void errorHalt() { 98 | errorHalt(&Serial); 99 | } 100 | /** %Print any SD error code and halt. 101 | * 102 | * \param[in] pr Print destination. 103 | */ 104 | void errorHalt(Print* pr); 105 | /** %Print msg, any SD error code and halt. 106 | * 107 | * \param[in] msg Message to print. 108 | */ 109 | void errorHalt(char const* msg) { 110 | errorHalt(&Serial, msg); 111 | } 112 | /** %Print msg, any SD error code, and halt. 113 | * 114 | * \param[in] pr Print destination. 115 | * \param[in] msg Message to print. 116 | */ 117 | void errorHalt(Print* pr, char const* msg); 118 | 119 | /** %Print any SD error code to Serial */ 120 | void errorPrint() { 121 | errorPrint(&Serial); 122 | } 123 | /** %Print any SD error code. 124 | * \param[in] pr Print device. 125 | */ 126 | void errorPrint(Print* pr); 127 | /** %Print msg, any SD error code. 128 | * 129 | * \param[in] msg Message to print. 130 | */ 131 | void errorPrint(const char* msg) { 132 | errorPrint(&Serial, msg); 133 | } 134 | /** %Print msg, any SD error code. 135 | * 136 | * \param[in] pr Print destination. 137 | * \param[in] msg Message to print. 138 | */ 139 | void errorPrint(Print* pr, char const* msg); 140 | 141 | /** Diagnostic call to initialize FatFileSystem - use for 142 | * diagnostic purposes only. 143 | * \return true for success else false. 144 | */ 145 | bool fsBegin() { 146 | return FatFileSystem::begin(); 147 | } 148 | /** %Print any SD error code and halt. */ 149 | void initErrorHalt() { 150 | initErrorHalt(&Serial); 151 | } 152 | /** %Print error details and halt after begin fails. 153 | * 154 | * \param[in] pr Print destination. 155 | */ 156 | void initErrorHalt(Print* pr); 157 | /**Print message, error details, and halt after SdFat::init() fails. 158 | * 159 | * \param[in] msg Message to print. 160 | */ 161 | void initErrorHalt(char const *msg) { 162 | initErrorHalt(&Serial, msg); 163 | } 164 | /**Print message, error details, and halt after SdFatBase::init() fails. 165 | * \param[in] pr Print device. 166 | * \param[in] msg Message to print. 167 | */ 168 | void initErrorHalt(Print* pr, char const *msg); 169 | 170 | /** Print error details after SdFat::init() fails. */ 171 | void initErrorPrint() { 172 | initErrorPrint(&Serial); 173 | } 174 | /** Print error details after SdFatBase::init() fails. 175 | * 176 | * \param[in] pr Print destination. 177 | */ 178 | void initErrorPrint(Print* pr); 179 | /**Print message and error details and halt after SdFat::init() fails. 180 | * 181 | * \param[in] msg Message to print. 182 | */ 183 | void initErrorPrint(char const *msg) { 184 | initErrorPrint(&Serial, msg); 185 | } 186 | /**Print message and error details and halt after SdFatBase::init() fails. 187 | * 188 | * \param[in] pr Print destination. 189 | * \param[in] msg Message to print. 190 | */ 191 | void initErrorPrint(Print* pr, char const *msg); 192 | #if defined(ARDUINO) || defined(DOXYGEN) 193 | /** %Print msg, any SD error code, and halt. 194 | * 195 | * \param[in] msg Message to print. 196 | */ 197 | void errorHalt(const __FlashStringHelper* msg) { 198 | errorHalt(&Serial, msg); 199 | } 200 | /** %Print msg, any SD error code, and halt. 201 | * 202 | * \param[in] pr Print destination. 203 | * \param[in] msg Message to print. 204 | */ 205 | void errorHalt(Print* pr, const __FlashStringHelper* msg); 206 | /** %Print msg, any SD error code. 207 | * 208 | * \param[in] msg Message to print. 209 | */ 210 | void errorPrint(const __FlashStringHelper* msg) { 211 | errorPrint(&Serial, msg); 212 | } 213 | /** %Print msg, any SD error code. 214 | * 215 | * \param[in] pr Print destination. 216 | * \param[in] msg Message to print. 217 | */ 218 | void errorPrint(Print* pr, const __FlashStringHelper* msg); 219 | /**Print message, error details, and halt after SdFat::init() fails. 220 | * 221 | * \param[in] msg Message to print. 222 | */ 223 | void initErrorHalt(const __FlashStringHelper* msg) { 224 | initErrorHalt(&Serial, msg); 225 | } 226 | /**Print message, error details, and halt after SdFatBase::init() fails. 227 | * \param[in] pr Print device for message. 228 | * \param[in] msg Message to print. 229 | */ 230 | void initErrorHalt(Print* pr, const __FlashStringHelper* msg); 231 | /**Print message and error details and halt after SdFat::init() fails. 232 | * 233 | * \param[in] msg Message to print. 234 | */ 235 | void initErrorPrint(const __FlashStringHelper* msg) { 236 | initErrorPrint(&Serial, msg); 237 | } 238 | /**Print message and error details and halt after SdFatBase::init() fails. 239 | * 240 | * \param[in] pr Print destination. 241 | * \param[in] msg Message to print. 242 | */ 243 | void initErrorPrint(Print* pr, const __FlashStringHelper* msg); 244 | #endif // defined(ARDUINO) || defined(DOXYGEN) 245 | 246 | private: 247 | 248 | bool readBlock(uint32_t block, uint8_t* dst) { 249 | return m_sdCard.readBlock(block, dst); 250 | } 251 | bool writeBlock(uint32_t block, const uint8_t* src) { 252 | return m_sdCard.writeBlock(block, src); 253 | } 254 | bool readBlocks(uint32_t block, uint8_t* dst, size_t n) { 255 | return m_sdCard.readBlocks(block, dst, n); 256 | } 257 | bool writeBlocks(uint32_t block, const uint8_t* src, size_t n) { 258 | return m_sdCard.writeBlocks(block, src, n); 259 | } 260 | SdSpiCard m_sdCard; 261 | }; 262 | //============================================================================== 263 | /** 264 | * \class SdFat 265 | * \brief Main file system class for %SdFat library. 266 | */ 267 | class SdFat : public SdFatBase { 268 | public: 269 | #if IMPLEMENT_SPI_INTERFACE_SELECTION 270 | SdFat() { 271 | m_spi.setSpiIf(0); 272 | } 273 | explicit SdFat(uint8_t spiIf) { 274 | m_spi.setSpiIf(spiIf < SPI_INTERFACE_COUNT ? spiIf : 0); 275 | } 276 | #endif // IMPLEMENT_SPI_INTERFACE_SELECTION 277 | 278 | /** Initialize SD card and file system. 279 | * 280 | * \param[in] csPin SD card chip select pin. 281 | * \param[in] divisor SPI divisor. 282 | * \return true for success else false. 283 | */ 284 | bool begin(uint8_t csPin = SS, uint8_t divisor = 2) { 285 | return SdFatBase::begin(&m_spi, csPin, divisor); 286 | } 287 | /** Diagnostic call to initialize SD card - use for diagnostic purposes only. 288 | * \param[in] csPin SD card chip select pin. 289 | * \param[in] divisor SPI divisor. 290 | * \return true for success else false. 291 | */ 292 | bool cardBegin(uint8_t csPin = SS, uint8_t divisor = 2) { 293 | return card()->begin(&m_spi, csPin, divisor); 294 | } 295 | 296 | private: 297 | SpiDefault_t m_spi; 298 | }; 299 | //============================================================================== 300 | #if SD_SPI_CONFIGURATION >= 3 || defined(DOXYGEN) 301 | /** 302 | * \class SdFatLibSpi 303 | * \brief SdFat class using the standard Arduino SPI library. 304 | */ 305 | class SdFatLibSpi: public SdFatBase { 306 | public: 307 | /** Initialize SD card and file system. 308 | * 309 | * \param[in] csPin SD card chip select pin. 310 | * \param[in] divisor SPI divisor. 311 | * \return true for success else false. 312 | */ 313 | bool begin(uint8_t csPin = SS, uint8_t divisor = 2) { 314 | return SdFatBase::begin(&m_spi, csPin, divisor); 315 | } 316 | /** Diagnostic call to initialize SD card - use for diagnostic purposes only. 317 | * \param[in] csPin SD card chip select pin. 318 | * \param[in] divisor SPI divisor. 319 | * \return true for success else false. 320 | */ 321 | bool cardBegin(uint8_t csPin = SS, uint8_t divisor = 2) { 322 | return card()->begin(&m_spi, csPin, divisor); 323 | } 324 | 325 | private: 326 | SdSpiLib m_spi; 327 | }; 328 | //============================================================================== 329 | /** 330 | * \class SdFatSoftSpi 331 | * \brief SdFat class using software SPI. 332 | */ 333 | template 334 | class SdFatSoftSpi : public SdFatBase { 335 | public: 336 | /** Initialize SD card and file system. 337 | * 338 | * \param[in] csPin SD card chip select pin. 339 | * \param[in] divisor SPI divisor. 340 | * \return true for success else false. 341 | */ 342 | bool begin(uint8_t csPin = SS, uint8_t divisor = 2) { 343 | return SdFatBase::begin(&m_spi, csPin, divisor); 344 | } 345 | /** Diagnostic call to initialize SD card - use for diagnostic purposes only. 346 | * \param[in] csPin SD card chip select pin. 347 | * \param[in] divisor SPI divisor. 348 | * \return true for success else false. 349 | */ 350 | bool cardBegin(uint8_t csPin = SS, uint8_t divisor = 2) { 351 | return card()->begin(&m_spi, csPin, divisor); 352 | } 353 | 354 | private: 355 | SdSpiSoft m_spi; 356 | }; 357 | #endif /// SD_SPI_CONFIGURATION >= 3 || defined(DOXYGEN) 358 | #endif // SdFat_h 359 | -------------------------------------------------------------------------------- /src/SdFat/ArduinoFiles.h: -------------------------------------------------------------------------------- 1 | #include "../ArduinoFiles.h" -------------------------------------------------------------------------------- /src/SdFat/ArduinoStream.h: -------------------------------------------------------------------------------- 1 | #include "../ArduinoStream.h" -------------------------------------------------------------------------------- /src/SdFat/FatApiConstants.h: -------------------------------------------------------------------------------- 1 | #include "../FatApiConstants.h" -------------------------------------------------------------------------------- /src/SdFat/FatFile.h: -------------------------------------------------------------------------------- 1 | #include "../FatFile.h" -------------------------------------------------------------------------------- /src/SdFat/FatFileSystem.h: -------------------------------------------------------------------------------- 1 | #include "../FatFileSystem.h" -------------------------------------------------------------------------------- /src/SdFat/FatLib.h: -------------------------------------------------------------------------------- 1 | #include "../FatLib.h" -------------------------------------------------------------------------------- /src/SdFat/FatLibConfig.h: -------------------------------------------------------------------------------- 1 | #include "../FatLibConfig.h" -------------------------------------------------------------------------------- /src/SdFat/FatStructs.h: -------------------------------------------------------------------------------- 1 | #include "../FatStructs.h" -------------------------------------------------------------------------------- /src/SdFat/FatVolume.h: -------------------------------------------------------------------------------- 1 | #include "../FatVolume.h" -------------------------------------------------------------------------------- /src/SdFat/FmtNumber.h: -------------------------------------------------------------------------------- 1 | #include "../FmtNumber.h" -------------------------------------------------------------------------------- /src/SdFat/FreeStack.h: -------------------------------------------------------------------------------- 1 | #include "../FreeStack.h" -------------------------------------------------------------------------------- /src/SdFat/SdFat.h: -------------------------------------------------------------------------------- 1 | #include "../SdFat.h" -------------------------------------------------------------------------------- /src/SdFat/SdFatConfig.h: -------------------------------------------------------------------------------- 1 | #include "../SdFatConfig.h" -------------------------------------------------------------------------------- /src/SdFat/SdInfo.h: -------------------------------------------------------------------------------- 1 | #include "../SdInfo.h" -------------------------------------------------------------------------------- /src/SdFat/SdSpi.h: -------------------------------------------------------------------------------- 1 | #include "../SdSpi.h" -------------------------------------------------------------------------------- /src/SdFat/SdSpiCard.h: -------------------------------------------------------------------------------- 1 | #include "../SdSpiCard.h" -------------------------------------------------------------------------------- /src/SdFat/SoftSPIParticle.h: -------------------------------------------------------------------------------- 1 | #include "../SoftSPIParticle.h" -------------------------------------------------------------------------------- /src/SdFat/StdioStream.h: -------------------------------------------------------------------------------- 1 | #include "../StdioStream.h" -------------------------------------------------------------------------------- /src/SdFat/SysCall.h: -------------------------------------------------------------------------------- 1 | #include "../SysCall.h" -------------------------------------------------------------------------------- /src/SdFat/SystemInclude.h: -------------------------------------------------------------------------------- 1 | #include "../SystemInclude.h" -------------------------------------------------------------------------------- /src/SdFat/bufstream.h: -------------------------------------------------------------------------------- 1 | #include "../bufstream.h" -------------------------------------------------------------------------------- /src/SdFat/fstream.h: -------------------------------------------------------------------------------- 1 | #include "../fstream.h" -------------------------------------------------------------------------------- /src/SdFat/ios.h: -------------------------------------------------------------------------------- 1 | #include "../ios.h" -------------------------------------------------------------------------------- /src/SdFat/iostream.h: -------------------------------------------------------------------------------- 1 | #include "../iostream.h" -------------------------------------------------------------------------------- /src/SdFat/istream.h: -------------------------------------------------------------------------------- 1 | #include "../istream.h" -------------------------------------------------------------------------------- /src/SdFat/ostream.h: -------------------------------------------------------------------------------- 1 | #include "../ostream.h" -------------------------------------------------------------------------------- /src/SdFatConfig.h: -------------------------------------------------------------------------------- 1 | /* Arduino SdFat Library 2 | * Copyright (C) 2012 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 | * \file 22 | * \brief configuration definitions 23 | */ 24 | #ifndef SdFatConfig_h 25 | #define SdFatConfig_h 26 | #include 27 | #ifdef __AVR__ 28 | #include 29 | #endif // __AVR__ 30 | //------------------------------------------------------------------------------ 31 | /** 32 | * Set USE_LONG_FILE_NAMES nonzero to use long file names (LFN). 33 | * Long File Name are limited to a maximum length of 255 characters. 34 | * 35 | * This implementation allows 7-bit characters in the range 36 | * 0X20 to 0X7E except the following characters are not allowed: 37 | * 38 | * < (less than) 39 | * > (greater than) 40 | * : (colon) 41 | * " (double quote) 42 | * / (forward slash) 43 | * \ (backslash) 44 | * | (vertical bar or pipe) 45 | * ? (question mark) 46 | * * (asterisk) 47 | * 48 | */ 49 | #define USE_LONG_FILE_NAMES 1 50 | //------------------------------------------------------------------------------ 51 | /** 52 | * Set ARDUINO_FILE_USES_STREAM nonzero to use Stream as the base class 53 | * for the Arduino File class. If ARDUINO_FILE_USES_STREAM is zero, Print 54 | * will be used as the base class for the Arduino File class. 55 | * 56 | * You can save some flash if you do not use Stream input functions such as 57 | * find(), findUntil(), readBytesUntil(), readString(), readStringUntil(), 58 | * parseInt(), and parseFloat(). 59 | */ 60 | #define ARDUINO_FILE_USES_STREAM 1 61 | //------------------------------------------------------------------------------ 62 | /** 63 | * The symbol SD_SPI_CONFIGURATION defines SPI access to the SD card. 64 | * 65 | * IF SD_SPI_CONFIGUTATION is define to be zero, only the SdFat class 66 | * is define and SdFat uses a fast custom SPI implementation if avaiable. 67 | * If SD_HAS_CUSTOM_SPI is zero, the standard SPI library is used. 68 | * 69 | * If SD_SPI_CONFIGURATION is define to be one, only the SdFat class is 70 | * define and SdFat uses the standard Arduino SPI.h library. 71 | * 72 | * If SD_SPI_CONFIGURATION is define to be two, only the SdFat class is 73 | * define and SdFat uses software SPI on the pins defined below. 74 | * 75 | * If SD_SPI_CONFIGURATION is define to be three, the three classes, SdFat, 76 | * SdFatLibSpi, and SdFatSoftSpi are defined. SdFat uses the fast 77 | * custom SPI implementation. SdFatLibSpi uses the standard Arduino SPI 78 | * library. SdFatSoftSpi is a template class that uses Software SPI. The 79 | * template parameters define the software SPI pins. See the ThreeCard 80 | * example for simultaneous use of all three classes. 81 | */ 82 | #define SD_SPI_CONFIGURATION 3 83 | //------------------------------------------------------------------------------ 84 | /** 85 | * If SD_SPI_CONFIGURATION is defined to be two, these definitions 86 | * will define the pins used for software SPI. 87 | * 88 | * The default definition allows Uno shields to be used on other boards. 89 | */ 90 | /** Software SPI Master Out Slave In pin */ 91 | uint8_t const SOFT_SPI_MOSI_PIN = 11; 92 | /** Software SPI Master In Slave Out pin */ 93 | uint8_t const SOFT_SPI_MISO_PIN = 12; 94 | /** Software SPI Clock pin */ 95 | uint8_t const SOFT_SPI_SCK_PIN = 13; 96 | //------------------------------------------------------------------------------ 97 | /** 98 | * Set MAINTAIN_FREE_CLUSTER_COUNT nonzero to keep the count of free clusters 99 | * updated. This will increase the speed of the freeClusterCount() call 100 | * after the first call. Extra flash will be required. 101 | */ 102 | #define MAINTAIN_FREE_CLUSTER_COUNT 1 103 | //------------------------------------------------------------------------------ 104 | /** 105 | * To enable SD card CRC checking set USE_SD_CRC nonzero. 106 | * 107 | * Set USE_SD_CRC to 1 to use a smaller slower CRC-CCITT function. 108 | * 109 | * Set USE_SD_CRC to 2 to used a larger faster table driven CRC-CCITT function. 110 | */ 111 | #define USE_SD_CRC 0 112 | //------------------------------------------------------------------------------ 113 | /** 114 | * Set ENABLE_SPI_TRANSACTIONS nonzero to enable the SPI transaction feature 115 | * of the standard Arduino SPI library. You must include SPI.h in your 116 | * programs when ENABLE_SPI_TRANSACTIONS is nonzero. 117 | */ 118 | #define ENABLE_SPI_TRANSACTIONS 0 119 | //------------------------------------------------------------------------------ 120 | /** 121 | * Set FAT12_SUPPORT nonzero to enable use if FAT12 volumes. 122 | * FAT12 has not been well tested and requires additional flash. 123 | */ 124 | #define FAT12_SUPPORT 0 125 | //------------------------------------------------------------------------------ 126 | /** 127 | * Set DESTRUCTOR_CLOSES_FILE nonzero to close a file in its destructor. 128 | * 129 | * Causes use of lots of heap in ARM. 130 | */ 131 | #define DESTRUCTOR_CLOSES_FILE 0 132 | //------------------------------------------------------------------------------ 133 | /** 134 | * Call flush for endl if ENDL_CALLS_FLUSH is nonzero 135 | * 136 | * The standard for iostreams is to call flush. This is very costly for 137 | * SdFat. Each call to flush causes 2048 bytes of I/O to the SD. 138 | * 139 | * SdFat has a single 512 byte buffer for SD I/O so it must write the current 140 | * data block to the SD, read the directory block from the SD, update the 141 | * directory entry, write the directory block to the SD and read the data 142 | * block back into the buffer. 143 | * 144 | * The SD flash memory controller is not designed for this many rewrites 145 | * so performance may be reduced by more than a factor of 100. 146 | * 147 | * If ENDL_CALLS_FLUSH is zero, you must call flush and/or close to force 148 | * all data to be written to the SD. 149 | */ 150 | #define ENDL_CALLS_FLUSH 0 151 | //------------------------------------------------------------------------------ 152 | /** 153 | * SPI SCK divisor for SD initialization commands. 154 | * or greater 155 | */ 156 | #ifdef __AVR__ 157 | const uint8_t SPI_SCK_INIT_DIVISOR = 64; 158 | #else 159 | const uint8_t SPI_SCK_INIT_DIVISOR = 128; 160 | #endif 161 | //------------------------------------------------------------------------------ 162 | /** 163 | * Set USE_SEPARATE_FAT_CACHE nonzero to use a second 512 byte cache 164 | * for FAT table entries. This improves performance for large writes 165 | * that are not a multiple of 512 bytes. 166 | */ 167 | #ifdef __arm__ 168 | #define USE_SEPARATE_FAT_CACHE 1 169 | #else // __arm__ 170 | #define USE_SEPARATE_FAT_CACHE 0 171 | #endif // __arm__ 172 | //------------------------------------------------------------------------------ 173 | /** 174 | * Set USE_MULTI_BLOCK_IO nonzero to use multi-block SD read/write. 175 | * 176 | * Don't use mult-block read/write on small AVR boards. 177 | */ 178 | #if defined(RAMEND) && RAMEND < 3000 179 | #define USE_MULTI_BLOCK_IO 0 180 | #else // RAMEND 181 | #define USE_MULTI_BLOCK_IO 1 182 | #endif // RAMEND 183 | //------------------------------------------------------------------------------ 184 | /** 185 | * Determine the default SPI configuration. 186 | */ 187 | #if defined(__AVR__)\ 188 | || defined(__SAM3X8E__) || defined(__SAM3X8H__)\ 189 | || (defined(__arm__) && defined(CORE_TEENSY))\ 190 | || defined(__STM32F1__)\ 191 | || defined(PLATFORM_ID)\ 192 | || defined(DOXYGEN) 193 | // Use custom fast implementation. 194 | #define SD_HAS_CUSTOM_SPI 1 195 | #else // SD_HAS_CUSTOM_SPI 196 | // Use standard SPI library. 197 | #define SD_HAS_CUSTOM_SPI 0 198 | #endif // SD_HAS_CUSTOM_SPI 199 | //----------------------------------------------------------------------------- 200 | /** 201 | * Number of hardware interfaces. 202 | */ 203 | #if defined(PLATFORM_ID) 204 | #if Wiring_SPI1 && Wiring_SPI2 205 | #define SPI_INTERFACE_COUNT 3 206 | #elif Wiring_SPI1 207 | #define SPI_INTERFACE_COUNT 2 208 | #endif // Wiring_SPI1 && Wiring_SPI2 209 | #endif // defined(PLATFORM_ID) 210 | // default is one 211 | #ifndef SPI_INTERFACE_COUNT 212 | #define SPI_INTERFACE_COUNT 1 213 | #endif // SPI_INTERFACE_COUNT 214 | //------------------------------------------------------------------------------ 215 | /** 216 | * Check if API to select HW SPI interface is needed. 217 | */ 218 | #if SPI_INTERFACE_COUNT > 1 && SD_HAS_CUSTOM_SPI\ 219 | && SD_SPI_CONFIGURATION != 1 && SD_SPI_CONFIGURATION != 2 220 | #define IMPLEMENT_SPI_INTERFACE_SELECTION 1 221 | #else // SPI_INTERFACE_COUNT > 1 222 | #define IMPLEMENT_SPI_INTERFACE_SELECTION 0 223 | #endif // SPI_INTERFACE_COUNT > 1 224 | #endif // SdFatConfig_h 225 | -------------------------------------------------------------------------------- /src/SdSpiCard.h: -------------------------------------------------------------------------------- 1 | /* Arduino SdSpiCard Library 2 | * Copyright (C) 2012 by William Greiman 3 | * 4 | * This file is part of the Arduino SdSpiCard 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 SdSpiCard Library. If not, see 18 | * . 19 | */ 20 | #ifndef SpiCard_h 21 | #define SpiCard_h 22 | /** 23 | * \file 24 | * \brief SdSpiCard class for V2 SD/SDHC cards 25 | */ 26 | #include "SystemInclude.h" 27 | #include "SdFatConfig.h" 28 | #include "SdInfo.h" 29 | #include "SdSpi.h" 30 | //============================================================================== 31 | /** 32 | * \class SdSpiCard 33 | * \brief Raw access to SD and SDHC flash memory cards via SPI protocol. 34 | */ 35 | class SdSpiCard { 36 | public: 37 | /** typedef for SPI class. */ 38 | #if SD_SPI_CONFIGURATION < 3 39 | typedef SpiDefault_t m_spi_t; 40 | #else // SD_SPI_CONFIGURATION < 3 41 | typedef SdSpiBase m_spi_t; 42 | #endif // SD_SPI_CONFIGURATION < 3 43 | /** Construct an instance of SdSpiCard. */ 44 | SdSpiCard() : m_selected(false), 45 | m_errorCode(SD_CARD_ERROR_INIT_NOT_CALLED), m_type(0) {} 46 | /** Initialize the SD card. 47 | * \param[in] spi SPI object. 48 | * \param[in] chipSelectPin SD chip select pin. 49 | * \param[in] sckDivisor SPI clock divisor. 50 | * \return true for success else false. 51 | */ 52 | bool begin(m_spi_t* spi, uint8_t chipSelectPin = SS, 53 | uint8_t sckDivisor = SPI_FULL_SPEED); 54 | /** 55 | * Determine the size of an SD flash memory card. 56 | * 57 | * \return The number of 512 byte data blocks in the card 58 | * or zero if an error occurs. 59 | */ 60 | uint32_t cardSize(); 61 | /** Set the SD chip select pin high, send a dummy byte, and call SPI endTransaction. 62 | * 63 | * This function should only be called by programs doing raw I/O to the SD. 64 | */ 65 | void chipSelectHigh(); 66 | /** Set the SD chip select pin low and call SPI beginTransaction. 67 | * 68 | * This function should only be called by programs doing raw I/O to the SD. 69 | */ 70 | void chipSelectLow(); 71 | /** Erase a range of blocks. 72 | * 73 | * \param[in] firstBlock The address of the first block in the range. 74 | * \param[in] lastBlock The address of the last block in the range. 75 | * 76 | * \note This function requests the SD card to do a flash erase for a 77 | * range of blocks. The data on the card after an erase operation is 78 | * either 0 or 1, depends on the card vendor. The card must support 79 | * single block erase. 80 | * 81 | * \return The value true is returned for success and 82 | * the value false is returned for failure. 83 | */ 84 | bool erase(uint32_t firstBlock, uint32_t lastBlock); 85 | /** Determine if card supports single block erase. 86 | * 87 | * \return true is returned if single block erase is supported. 88 | * false is returned if single block erase is not supported. 89 | */ 90 | bool eraseSingleBlockEnable(); 91 | /** 92 | * Set SD error code. 93 | * \param[in] code value for error code. 94 | */ 95 | void error(uint8_t code) { 96 | m_errorCode = code; 97 | } 98 | /** 99 | * \return code for the last error. See SdSpiCard.h for a list of error codes. 100 | */ 101 | int errorCode() const { 102 | return m_errorCode; 103 | } 104 | /** \return error data for last error. */ 105 | int errorData() const { 106 | return m_status; 107 | } 108 | /** 109 | * Check for busy. MISO low indicates the card is busy. 110 | * 111 | * \return true if busy else false. 112 | */ 113 | bool isBusy(); 114 | /** 115 | * Read a 512 byte block from an SD card. 116 | * 117 | * \param[in] block Logical block to be read. 118 | * \param[out] dst Pointer to the location that will receive the data. 119 | * \return The value true is returned for success and 120 | * the value false is returned for failure. 121 | */ 122 | bool readBlock(uint32_t block, uint8_t* dst); 123 | /** 124 | * Read multiple 512 byte blocks from an SD card. 125 | * 126 | * \param[in] block Logical block to be read. 127 | * \param[in] count Number of blocks to be read. 128 | * \param[out] dst Pointer to the location that will receive the data. 129 | * \return The value true is returned for success and 130 | * the value false is returned for failure. 131 | */ 132 | bool readBlocks(uint32_t block, uint8_t* dst, size_t count); 133 | /** 134 | * Read a card's CID register. The CID contains card identification 135 | * information such as Manufacturer ID, Product name, Product serial 136 | * number and Manufacturing date. 137 | * 138 | * \param[out] cid pointer to area for returned data. 139 | * 140 | * \return true for success or false for failure. 141 | */ 142 | bool readCID(cid_t* cid) { 143 | return readRegister(CMD10, cid); 144 | } 145 | /** 146 | * Read a card's CSD register. The CSD contains Card-Specific Data that 147 | * provides information regarding access to the card's contents. 148 | * 149 | * \param[out] csd pointer to area for returned data. 150 | * 151 | * \return true for success or false for failure. 152 | */ 153 | bool readCSD(csd_t* csd) { 154 | return readRegister(CMD9, csd); 155 | } 156 | /** Read one data block in a multiple block read sequence 157 | * 158 | * \param[out] dst Pointer to the location for the data to be read. 159 | * 160 | * \return The value true is returned for success and 161 | * the value false is returned for failure. 162 | */ 163 | bool readData(uint8_t *dst); 164 | /** Read OCR register. 165 | * 166 | * \param[out] ocr Value of OCR register. 167 | * \return true for success else false. 168 | */ 169 | bool readOCR(uint32_t* ocr); 170 | /** Start a read multiple blocks sequence. 171 | * 172 | * \param[in] blockNumber Address of first block in sequence. 173 | * 174 | * \note This function is used with readData() and readStop() for optimized 175 | * multiple block reads. SPI chipSelect must be low for the entire sequence. 176 | * 177 | * \return The value true is returned for success and 178 | * the value false is returned for failure. 179 | */ 180 | bool readStart(uint32_t blockNumber); 181 | /** End a read multiple blocks sequence. 182 | * 183 | * \return The value true is returned for success and 184 | * the value false is returned for failure. 185 | */ 186 | bool readStop(); 187 | /** Return SCK divisor. 188 | * 189 | * \return Requested SCK divisor. 190 | */ 191 | uint8_t sckDivisor() { 192 | return m_sckDivisor; 193 | } 194 | /** \return the SD chip select status, true if slected else false. */ 195 | bool selected() {return m_selected;} 196 | /** Return the card type: SD V1, SD V2 or SDHC 197 | * \return 0 - SD V1, 1 - SD V2, or 3 - SDHC. 198 | */ 199 | int type() const { 200 | return m_type; 201 | } 202 | /** 203 | * Writes a 512 byte block to an SD card. 204 | * 205 | * \param[in] blockNumber Logical block to be written. 206 | * \param[in] src Pointer to the location of the data to be written. 207 | * \return The value true is returned for success and 208 | * the value false is returned for failure. 209 | */ 210 | bool writeBlock(uint32_t blockNumber, const uint8_t* src); 211 | /** 212 | * Write multiple 512 byte blocks to an SD card. 213 | * 214 | * \param[in] block Logical block to be written. 215 | * \param[in] count Number of blocks to be written. 216 | * \param[in] src Pointer to the location of the data to be written. 217 | * \return The value true is returned for success and 218 | * the value false is returned for failure. 219 | */ 220 | bool writeBlocks(uint32_t block, const uint8_t* src, size_t count); 221 | /** Write one data block in a multiple block write sequence. 222 | * \param[in] src Pointer to the location of the data to be written. 223 | * \return The value true is returned for success and 224 | * the value false is returned for failure. 225 | */ 226 | bool writeData(const uint8_t* src); 227 | /** Start a write multiple blocks sequence. 228 | * 229 | * \param[in] blockNumber Address of first block in sequence. 230 | * \param[in] eraseCount The number of blocks to be pre-erased. 231 | * 232 | * \note This function is used with writeData() and writeStop() 233 | * for optimized multiple block writes. 234 | * 235 | * \return The value true is returned for success and 236 | * the value false is returned for failure. 237 | */ 238 | bool writeStart(uint32_t blockNumber, uint32_t eraseCount); 239 | /** End a write multiple blocks sequence. 240 | * 241 | * \return The value true is returned for success and 242 | * the value false is returned for failure. 243 | */ 244 | bool writeStop(); 245 | 246 | private: 247 | // private functions 248 | uint8_t cardAcmd(uint8_t cmd, uint32_t arg) { 249 | cardCommand(CMD55, 0); 250 | return cardCommand(cmd, arg); 251 | } 252 | uint8_t cardCommand(uint8_t cmd, uint32_t arg); 253 | bool readData(uint8_t* dst, size_t count); 254 | bool readRegister(uint8_t cmd, void* buf); 255 | void type(uint8_t value) { 256 | m_type = value; 257 | } 258 | bool waitNotBusy(uint16_t timeoutMillis); 259 | bool writeData(uint8_t token, const uint8_t* src); 260 | void spiBegin(uint8_t chipSelectPin) { 261 | m_spi->begin(chipSelectPin); 262 | } 263 | void spiBeginTransaction(uint8_t spiDivisor) { 264 | m_spi->beginTransaction(spiDivisor); 265 | } 266 | void spiEndTransaction() { 267 | m_spi->endTransaction(); 268 | } 269 | uint8_t spiReceive() { 270 | return m_spi->receive(); 271 | } 272 | uint8_t spiReceive(uint8_t* buf, size_t n) { 273 | return m_spi->receive(buf, n); 274 | } 275 | void spiSend(uint8_t data) { 276 | m_spi->send(data); 277 | } 278 | void spiSend(const uint8_t* buf, size_t n) { 279 | m_spi->send(buf, n); 280 | } 281 | m_spi_t* m_spi; 282 | bool m_selected; 283 | uint8_t m_chipSelectPin; 284 | uint8_t m_errorCode; 285 | uint8_t m_sckDivisor; 286 | uint8_t m_status; 287 | uint8_t m_type; 288 | }; 289 | //============================================================================== 290 | /** 291 | * \class Sd2Card 292 | * \brief Raw access to SD and SDHC card using default SPI library. 293 | */ 294 | class Sd2Card : public SdSpiCard { 295 | public: 296 | /** Initialize the SD card. 297 | * \param[in] chipSelectPin SD chip select pin. 298 | * \param[in] sckDivisor SPI clock divisor. 299 | * \return true for success else false. 300 | */ 301 | bool begin(uint8_t chipSelectPin = SS, uint8_t sckDivisor = 2) { 302 | return SdSpiCard::begin(&m_spi, chipSelectPin, sckDivisor); 303 | } 304 | /** Initialize the SD card. Obsolete form. 305 | * \param[in] chipSelectPin SD chip select pin. 306 | * \param[in] sckDivisor SPI clock divisor. 307 | * \return true for success else false. 308 | */ 309 | bool init(uint8_t sckDivisor = 2, uint8_t chipSelectPin = SS) { 310 | return begin(chipSelectPin, sckDivisor); 311 | } 312 | 313 | private: 314 | bool begin(m_spi_t* spi, uint8_t chipSelectPin = SS, 315 | uint8_t sckDivisor = SPI_FULL_SPEED) { 316 | (void)spi; 317 | (void)chipSelectPin; 318 | (void)sckDivisor; 319 | return false; 320 | } 321 | SpiDefault_t m_spi; 322 | }; 323 | #endif // SpiCard_h 324 | -------------------------------------------------------------------------------- /src/SdSpiParticle.cpp: -------------------------------------------------------------------------------- 1 | /* Arduino SdFat Library 2 | * Copyright (C) 2016 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 "SdSpi.h" 21 | #if defined(PLATFORM_ID) 22 | 23 | static uint32_t bugDelay = 0; // fix for SPI DMA bug. 24 | 25 | static volatile bool SPI_DMA_TransferCompleted = false; 26 | 27 | static SPIClass* const spiPtr[] = { 28 | &SPI 29 | #if Wiring_SPI1 30 | , &SPI1 31 | #if Wiring_SPI2 32 | , &SPI2 33 | #endif // Wiring_SPI2 34 | #endif // Wiring_SPI1 35 | }; 36 | #if SPI_INTERFACE_COUNT == 1 37 | const uint8_t m_spiIf = 0; 38 | #endif 39 | //----------------------------------------------------------------------------- 40 | void SD_SPI_DMA_TransferComplete_Callback(void) { 41 | SPI_DMA_TransferCompleted = true; 42 | } 43 | //------------------------------------------------------------------------------ 44 | void SdSpi::begin(uint8_t chipSelectPin) { 45 | spiPtr[m_spiIf]->begin(chipSelectPin); 46 | } 47 | //------------------------------------------------------------------------------ 48 | void SdSpi::beginTransaction(uint8_t divisor) { 49 | spiPtr[m_spiIf]->setBitOrder(MSBFIRST); 50 | spiPtr[m_spiIf]->setDataMode(SPI_MODE0); 51 | #ifndef SPI_CLOCK_DIV128 52 | spiPtr[m_spiIf]->setClockDivider(divisor); 53 | #else // SPI_CLOCK_DIV128 54 | int v; 55 | if (divisor <= 2) { 56 | v = SPI_CLOCK_DIV2; 57 | } else if (divisor <= 4) { 58 | v = SPI_CLOCK_DIV4; 59 | } else if (divisor <= 8) { 60 | v = SPI_CLOCK_DIV8; 61 | } else if (divisor <= 16) { 62 | v = SPI_CLOCK_DIV16; 63 | } else if (divisor <= 32) { 64 | v = SPI_CLOCK_DIV32; 65 | } else if (divisor <= 64) { 66 | v = SPI_CLOCK_DIV64; 67 | } else { 68 | v = SPI_CLOCK_DIV128; 69 | } 70 | spiPtr[m_spiIf]->setClockDivider(v); 71 | #endif // SPI_CLOCK_DIV128 72 | // delay for SPI transfer done callback too soon bug. 73 | bugDelay = 24*divisor*(1 + m_spiIf)/60; 74 | } 75 | //----------------------------------------------------------------------------- 76 | void SdSpi::endTransaction() { 77 | } 78 | //----------------------------------------------------------------------------- 79 | /** SPI receive a byte */ 80 | uint8_t SdSpi::receive() { 81 | return spiPtr[m_spiIf]->transfer(0xFF); 82 | } 83 | //----------------------------------------------------------------------------- 84 | uint8_t SdSpi::receive(uint8_t* buf, size_t n) { 85 | SPI_DMA_TransferCompleted = false; 86 | spiPtr[m_spiIf]->transfer(0, buf, n, SD_SPI_DMA_TransferComplete_Callback); 87 | while (!SPI_DMA_TransferCompleted) {} 88 | if (bugDelay) { 89 | delayMicroseconds(bugDelay); 90 | } 91 | return 0; 92 | } 93 | //----------------------------------------------------------------------------- 94 | /** SPI send a byte */ 95 | void SdSpi::send(uint8_t b) { 96 | spiPtr[m_spiIf]->transfer(b); 97 | } 98 | //----------------------------------------------------------------------------- 99 | void SdSpi::send(const uint8_t* buf , size_t n) { 100 | SPI_DMA_TransferCompleted = false; 101 | 102 | spiPtr[m_spiIf]->transfer(const_cast(buf), 0, n, 103 | SD_SPI_DMA_TransferComplete_Callback); 104 | 105 | while (!SPI_DMA_TransferCompleted) {} 106 | if (bugDelay) { 107 | delayMicroseconds(bugDelay); 108 | } 109 | } 110 | #endif // defined(PLATFORM_ID) 111 | -------------------------------------------------------------------------------- /src/SoftSPIParticle.h: -------------------------------------------------------------------------------- 1 | /* Arduino DigitalIO Library 2 | * Copyright (C) 2013 by William Greiman 3 | * 4 | * This file is part of the Arduino DigitalIO 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 DigitalIO Library. If not, see 18 | * . 19 | */ 20 | /** 21 | * @file 22 | * @brief Software SPI. 23 | * 24 | * @defgroup softSPI Software SPI 25 | * @details Software SPI Template Class. 26 | * @{ 27 | */ 28 | #ifndef SoftSPIParticle_h 29 | #define SoftSPIParticle_h 30 | #if defined(PLATFORM_ID) 31 | #include "application.h" 32 | //------------------------------------------------------------------------------ 33 | /** Nop for timing. */ 34 | #define nop asm volatile ("nop\n\t") 35 | //------------------------------------------------------------------------------ 36 | #define fastDigitalRead(pin) pinReadFast(pin) 37 | #define fastDigitalWrite(pin, level) digitalWriteFast(pin, level) 38 | //------------------------------------------------------------------------------ 39 | /** 40 | * @class SoftSPI 41 | * @brief Fast software SPI. 42 | */ 43 | template 44 | class SoftSPI { 45 | public: 46 | //---------------------------------------------------------------------------- 47 | /** Initialize SoftSPI pins. */ 48 | void begin() { 49 | pinMode(MisoPin, INPUT); 50 | pinMode(MosiPin, OUTPUT); 51 | pinMode(SckPin, OUTPUT); 52 | fastDigitalWrite(MosiPin, !MODE_CPHA(Mode)); 53 | fastDigitalWrite(SckPin, MODE_CPOL(Mode)); 54 | } 55 | //---------------------------------------------------------------------------- 56 | /** Soft SPI receive byte. 57 | * @return Data byte received. 58 | */ 59 | inline __attribute__((always_inline)) 60 | uint8_t receive() { 61 | uint8_t data = 0; 62 | receiveBit(7, &data); 63 | receiveBit(6, &data); 64 | receiveBit(5, &data); 65 | receiveBit(4, &data); 66 | receiveBit(3, &data); 67 | receiveBit(2, &data); 68 | receiveBit(1, &data); 69 | receiveBit(0, &data); 70 | return data; 71 | } 72 | //---------------------------------------------------------------------------- 73 | /** Soft SPI send byte. 74 | * @param[in] data Data byte to send. 75 | */ 76 | inline __attribute__((always_inline)) 77 | void send(uint8_t data) { 78 | sendBit(7, data); 79 | sendBit(6, data); 80 | sendBit(5, data); 81 | sendBit(4, data); 82 | sendBit(3, data); 83 | sendBit(2, data); 84 | sendBit(1, data); 85 | sendBit(0, data); 86 | } 87 | //---------------------------------------------------------------------------- 88 | /** Soft SPI transfer byte. 89 | * @param[in] txData Data byte to send. 90 | * @return Data byte received. 91 | */ 92 | inline __attribute__((always_inline)) 93 | uint8_t transfer(uint8_t txData) { 94 | uint8_t rxData = 0; 95 | transferBit(7, &rxData, txData); 96 | transferBit(6, &rxData, txData); 97 | transferBit(5, &rxData, txData); 98 | transferBit(4, &rxData, txData); 99 | transferBit(3, &rxData, txData); 100 | transferBit(2, &rxData, txData); 101 | transferBit(1, &rxData, txData); 102 | transferBit(0, &rxData, txData); 103 | return rxData; 104 | } 105 | 106 | private: 107 | //---------------------------------------------------------------------------- 108 | inline __attribute__((always_inline)) 109 | bool MODE_CPHA(uint8_t mode) {return (mode & 1) != 0;} 110 | inline __attribute__((always_inline)) 111 | bool MODE_CPOL(uint8_t mode) {return (mode & 2) != 0;} 112 | inline __attribute__((always_inline)) 113 | void receiveBit(uint8_t bit, uint8_t* data) { 114 | if (MODE_CPHA(Mode)) { 115 | fastDigitalWrite(SckPin, !MODE_CPOL(Mode)); 116 | } 117 | nop; 118 | nop; 119 | fastDigitalWrite(SckPin, 120 | MODE_CPHA(Mode) ? MODE_CPOL(Mode) : !MODE_CPOL(Mode)); 121 | if (fastDigitalRead(MisoPin)) *data |= 1 << bit; 122 | if (!MODE_CPHA(Mode)) { 123 | fastDigitalWrite(SckPin, MODE_CPOL(Mode)); 124 | } 125 | } 126 | //---------------------------------------------------------------------------- 127 | inline __attribute__((always_inline)) 128 | void sendBit(uint8_t bit, uint8_t data) { 129 | if (MODE_CPHA(Mode)) { 130 | fastDigitalWrite(SckPin, !MODE_CPOL(Mode)); 131 | } 132 | fastDigitalWrite(MosiPin, data & (1 << bit)); 133 | fastDigitalWrite(SckPin, 134 | MODE_CPHA(Mode) ? MODE_CPOL(Mode) : !MODE_CPOL(Mode)); 135 | nop; 136 | nop; 137 | if (!MODE_CPHA(Mode)) { 138 | fastDigitalWrite(SckPin, MODE_CPOL(Mode)); 139 | } 140 | } 141 | //---------------------------------------------------------------------------- 142 | inline __attribute__((always_inline)) 143 | void transferBit(uint8_t bit, uint8_t* rxData, uint8_t txData) { 144 | if (MODE_CPHA(Mode)) { 145 | fastDigitalWrite(SckPin, !MODE_CPOL(Mode)); 146 | } 147 | fastDigitalWrite(MosiPin, txData & (1 << bit)); 148 | fastDigitalWrite(SckPin, 149 | MODE_CPHA(Mode) ? MODE_CPOL(Mode) : !MODE_CPOL(Mode)); 150 | if (fastDigitalRead(MisoPin)) *rxData |= 1 << bit; 151 | if (!MODE_CPHA(Mode)) { 152 | fastDigitalWrite(SckPin, MODE_CPOL(Mode)); 153 | } 154 | } 155 | //---------------------------------------------------------------------------- 156 | }; 157 | #endif // #if defined(PLATFORM_ID) 158 | #endif // SoftSPIParticle_h 159 | /** @} */ 160 | -------------------------------------------------------------------------------- /src/SysCall.h: -------------------------------------------------------------------------------- 1 | /* FatLib Library 2 | * Copyright (C) 2013 by William Greiman 3 | * 4 | * This file is part of the FatLib 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 FatLib Library. If not, see 18 | * . 19 | */ 20 | #ifndef SysCall_h 21 | #define SysCall_h 22 | /** 23 | * \file 24 | * \brief SysCall class 25 | */ 26 | #if defined(PLATFORM_ID) // Only defined if a Particle device 27 | #include "application.h" 28 | #else // defined(PLATFORM_ID) 29 | #error "Unknown system" 30 | #endif // defined(PLATFORM_ID) 31 | #ifndef F 32 | /** Define macro for strings stored in flash. */ 33 | #define F(str) (str) 34 | #endif // F 35 | /** 36 | * \class SysCall 37 | * \brief SysCall - Class to wrap system calls. 38 | */ 39 | class SysCall { 40 | public: 41 | /** Halt execution of this thread. */ 42 | static void halt() { 43 | while (1) { 44 | yield(); 45 | } 46 | } 47 | /** Yield to other threads. */ 48 | static void yield(); 49 | }; 50 | 51 | #if defined(PLATFORM_ID) // Only defined if a Particle device 52 | inline void SysCall::yield() { 53 | Particle.process(); 54 | } 55 | #else // defined(PLATFORM_ID) 56 | inline void SysCall::yield() {} 57 | #endif // defined(PLATFORM_ID) 58 | 59 | #endif // SysCall_h 60 | -------------------------------------------------------------------------------- /src/SystemInclude.h: -------------------------------------------------------------------------------- 1 | /* Arduino SdFat Library 2 | * Copyright (C) 2016 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 SystemInclude_h 21 | #define SystemInclude_h 22 | #if defined(PLATFORM_ID) // Only defined if a Particle device 23 | #include "SysCall.h" 24 | #else // System type 25 | #error Unknown System. 26 | #endif // System type 27 | #endif // SystemInclude_h 28 | -------------------------------------------------------------------------------- /src/bufstream.h: -------------------------------------------------------------------------------- 1 | /* FatLib Library 2 | * Copyright (C) 2013 by William Greiman 3 | * 4 | * This file is part of the FatLib 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 FatLib Library. If not, see 18 | * . 19 | */ 20 | #ifndef bufstream_h 21 | #define bufstream_h 22 | /** 23 | * \file 24 | * \brief \ref ibufstream and \ref obufstream classes 25 | */ 26 | #include 27 | #include "iostream.h" 28 | //============================================================================== 29 | /** 30 | * \class ibufstream 31 | * \brief parse a char string 32 | */ 33 | class ibufstream : public istream { 34 | public: 35 | /** Constructor */ 36 | ibufstream() : m_buf(0), m_len(0) {} 37 | /** Constructor 38 | * \param[in] str pointer to string to be parsed 39 | * Warning: The string will not be copied so must stay in scope. 40 | */ 41 | explicit ibufstream(const char* str) { 42 | init(str); 43 | } 44 | /** Initialize an ibufstream 45 | * \param[in] str pointer to string to be parsed 46 | * Warning: The string will not be copied so must stay in scope. 47 | */ 48 | void init(const char* str) { 49 | m_buf = str; 50 | m_len = strlen(m_buf); 51 | m_pos = 0; 52 | clear(); 53 | } 54 | 55 | protected: 56 | /// @cond SHOW_PROTECTED 57 | int16_t getch() { 58 | if (m_pos < m_len) { 59 | return m_buf[m_pos++]; 60 | } 61 | setstate(eofbit); 62 | return -1; 63 | } 64 | void getpos(FatPos_t *pos) { 65 | pos->position = m_pos; 66 | } 67 | bool seekoff(off_type off, seekdir way) { 68 | (void)off; 69 | (void)way; 70 | return false; 71 | } 72 | bool seekpos(pos_type pos) { 73 | if (pos < m_len) { 74 | m_pos = pos; 75 | return true; 76 | } 77 | return false; 78 | } 79 | void setpos(FatPos_t *pos) { 80 | m_pos = pos->position; 81 | } 82 | pos_type tellpos() { 83 | return m_pos; 84 | } 85 | /// @endcond 86 | private: 87 | const char* m_buf; 88 | size_t m_len; 89 | size_t m_pos; 90 | }; 91 | //============================================================================== 92 | /** 93 | * \class obufstream 94 | * \brief format a char string 95 | */ 96 | class obufstream : public ostream { 97 | public: 98 | /** constructor */ 99 | obufstream() : m_in(0) {} 100 | /** Constructor 101 | * \param[in] buf buffer for formatted string 102 | * \param[in] size buffer size 103 | */ 104 | obufstream(char *buf, size_t size) { 105 | init(buf, size); 106 | } 107 | /** Initialize an obufstream 108 | * \param[in] buf buffer for formatted string 109 | * \param[in] size buffer size 110 | */ 111 | void init(char *buf, size_t size) { 112 | m_buf = buf; 113 | buf[0] = '\0'; 114 | m_size = size; 115 | m_in = 0; 116 | } 117 | /** \return a pointer to the buffer */ 118 | char* buf() { 119 | return m_buf; 120 | } 121 | /** \return the length of the formatted string */ 122 | size_t length() { 123 | return m_in; 124 | } 125 | 126 | protected: 127 | /// @cond SHOW_PROTECTED 128 | void putch(char c) { 129 | if (m_in >= (m_size - 1)) { 130 | setstate(badbit); 131 | return; 132 | } 133 | m_buf[m_in++] = c; 134 | m_buf[m_in] = '\0'; 135 | } 136 | void putstr(const char *str) { 137 | while (*str) { 138 | putch(*str++); 139 | } 140 | } 141 | bool seekoff(off_type off, seekdir way) { 142 | (void)off; 143 | (void)way; 144 | return false; 145 | } 146 | bool seekpos(pos_type pos) { 147 | if (pos > m_in) { 148 | return false; 149 | } 150 | m_in = pos; 151 | m_buf[m_in] = '\0'; 152 | return true; 153 | } 154 | bool sync() { 155 | return true; 156 | } 157 | 158 | pos_type tellpos() { 159 | return m_in; 160 | } 161 | /// @endcond 162 | private: 163 | char *m_buf; 164 | size_t m_size; 165 | size_t m_in; 166 | }; 167 | #endif // bufstream_h 168 | -------------------------------------------------------------------------------- /src/fstream.cpp: -------------------------------------------------------------------------------- 1 | /* FatLib Library 2 | * Copyright (C) 2013 by William Greiman 3 | * 4 | * This file is part of the FatLib 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 FatLib Library. If not, see 18 | * . 19 | */ 20 | #include "fstream.h" 21 | //============================================================================== 22 | /// @cond SHOW_PROTECTED 23 | int16_t FatStreamBase::getch() { 24 | uint8_t c; 25 | int8_t s = read(&c, 1); 26 | if (s != 1) { 27 | if (s < 0) { 28 | setstate(badbit); 29 | } else { 30 | setstate(eofbit); 31 | } 32 | return -1; 33 | } 34 | if (c != '\r' || (getmode() & ios::binary)) { 35 | return c; 36 | } 37 | s = read(&c, 1); 38 | if (s == 1 && c == '\n') { 39 | return c; 40 | } 41 | if (s == 1) { 42 | seekCur(-1); 43 | } 44 | return '\r'; 45 | } 46 | //------------------------------------------------------------------------------ 47 | void FatStreamBase::open(const char* path, ios::openmode mode) { 48 | uint8_t flags; 49 | switch (mode & (app | in | out | trunc)) { 50 | case app | in: 51 | case app | in | out: 52 | flags = O_RDWR | O_APPEND | O_CREAT; 53 | break; 54 | 55 | case app: 56 | case app | out: 57 | flags = O_WRITE | O_APPEND | O_CREAT; 58 | break; 59 | 60 | case in: 61 | flags = O_READ; 62 | break; 63 | 64 | case in | out: 65 | flags = O_RDWR; 66 | break; 67 | 68 | case in | out | trunc: 69 | flags = O_RDWR | O_TRUNC | O_CREAT; 70 | break; 71 | 72 | case out: 73 | case out | trunc: 74 | flags = O_WRITE | O_TRUNC | O_CREAT; 75 | break; 76 | 77 | default: 78 | goto fail; 79 | } 80 | if (mode & ios::ate) { 81 | flags |= O_AT_END; 82 | } 83 | if (!FatFile::open(path, flags)) { 84 | goto fail; 85 | } 86 | setmode(mode); 87 | clear(); 88 | return; 89 | 90 | fail: 91 | FatFile::close(); 92 | setstate(failbit); 93 | return; 94 | } 95 | //------------------------------------------------------------------------------ 96 | void FatStreamBase::putch(char c) { 97 | if (c == '\n' && !(getmode() & ios::binary)) { 98 | write('\r'); 99 | } 100 | write(c); 101 | if (getWriteError()) { 102 | setstate(badbit); 103 | } 104 | } 105 | //------------------------------------------------------------------------------ 106 | void FatStreamBase::putstr(const char* str) { 107 | size_t n = 0; 108 | while (1) { 109 | char c = str[n]; 110 | if (c == '\0' || (c == '\n' && !(getmode() & ios::binary))) { 111 | if (n > 0) { 112 | write(str, n); 113 | } 114 | if (c == '\0') { 115 | break; 116 | } 117 | write('\r'); 118 | str += n; 119 | n = 0; 120 | } 121 | n++; 122 | } 123 | if (getWriteError()) { 124 | setstate(badbit); 125 | } 126 | } 127 | //------------------------------------------------------------------------------ 128 | /** Internal do not use 129 | * \param[in] off 130 | * \param[in] way 131 | */ 132 | bool FatStreamBase::seekoff(off_type off, seekdir way) { 133 | pos_type pos; 134 | switch (way) { 135 | case beg: 136 | pos = off; 137 | break; 138 | 139 | case cur: 140 | pos = curPosition() + off; 141 | break; 142 | 143 | case end: 144 | pos = fileSize() + off; 145 | break; 146 | 147 | default: 148 | return false; 149 | } 150 | return seekpos(pos); 151 | } 152 | //------------------------------------------------------------------------------ 153 | /** Internal do not use 154 | * \param[in] pos 155 | */ 156 | bool FatStreamBase::seekpos(pos_type pos) { 157 | return seekSet(pos); 158 | } 159 | //------------------------------------------------------------------------------ 160 | int FatStreamBase::write(const void* buf, size_t n) { 161 | return FatFile::write(buf, n); 162 | } 163 | //------------------------------------------------------------------------------ 164 | void FatStreamBase::write(char c) { 165 | write(&c, 1); 166 | } 167 | /// @endcond 168 | -------------------------------------------------------------------------------- /src/fstream.h: -------------------------------------------------------------------------------- 1 | /* FatLib Library 2 | * Copyright (C) 2013 by William Greiman 3 | * 4 | * This file is part of the FatLib 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 FatLib Library. If not, see 18 | * . 19 | */ 20 | #ifndef fstream_h 21 | #define fstream_h 22 | /** 23 | * \file 24 | * \brief \ref fstream, \ref ifstream, and \ref ofstream classes 25 | */ 26 | #include "FatFile.h" 27 | #include "iostream.h" 28 | //============================================================================== 29 | /** 30 | * \class FatStreamBase 31 | * \brief Base class for C++ style streams 32 | */ 33 | class FatStreamBase : protected FatFile, virtual public ios { 34 | protected: 35 | /// @cond SHOW_PROTECTED 36 | int16_t getch(); 37 | void putch(char c); 38 | void putstr(const char *str); 39 | void open(const char* path, ios::openmode mode); 40 | /** Internal do not use 41 | * \return mode 42 | */ 43 | ios::openmode getmode() { 44 | return m_mode; 45 | } 46 | /** Internal do not use 47 | * \param[in] mode 48 | */ 49 | void setmode(ios::openmode mode) { 50 | m_mode = mode; 51 | } 52 | bool seekoff(off_type off, seekdir way); 53 | bool seekpos(pos_type pos); 54 | int write(const void* buf, size_t n); 55 | void write(char c); 56 | /// @endcond 57 | private: 58 | ios::openmode m_mode; 59 | }; 60 | //============================================================================== 61 | /** 62 | * \class fstream 63 | * \brief file input/output stream. 64 | */ 65 | class fstream : public iostream, FatStreamBase { 66 | public: 67 | using iostream::peek; 68 | fstream() {} 69 | /** Constructor with open 70 | * 71 | * \param[in] path path to open 72 | * \param[in] mode open mode 73 | */ 74 | explicit fstream(const char* path, openmode mode = in | out) { 75 | open(path, mode); 76 | } 77 | #if DESTRUCTOR_CLOSES_FILE 78 | ~fstream() {} 79 | #endif // DESTRUCTOR_CLOSES_FILE 80 | /** Clear state and writeError 81 | * \param[in] state new state for stream 82 | */ 83 | void clear(iostate state = goodbit) { 84 | ios::clear(state); 85 | FatFile::clearWriteError(); 86 | } 87 | /** Close a file and force cached data and directory information 88 | * to be written to the storage device. 89 | */ 90 | void close() { 91 | FatFile::close(); 92 | } 93 | /** Open a fstream 94 | * \param[in] path file to open 95 | * \param[in] mode open mode 96 | * 97 | * Valid open modes are (at end, ios::ate, and/or ios::binary may be added): 98 | * 99 | * ios::in - Open file for reading. 100 | * 101 | * ios::out or ios::out | ios::trunc - Truncate to 0 length, if existent, 102 | * or create a file for writing only. 103 | * 104 | * ios::app or ios::out | ios::app - Append; open or create file for 105 | * writing at end-of-file. 106 | * 107 | * ios::in | ios::out - Open file for update (reading and writing). 108 | * 109 | * ios::in | ios::out | ios::trunc - Truncate to zero length, if existent, 110 | * or create file for update. 111 | * 112 | * ios::in | ios::app or ios::in | ios::out | ios::app - Append; open or 113 | * create text file for update, writing at end of file. 114 | */ 115 | void open(const char* path, openmode mode = in | out) { 116 | FatStreamBase::open(path, mode); 117 | } 118 | /** \return True if stream is open else false. */ 119 | bool is_open() { 120 | return FatFile::isOpen(); 121 | } 122 | 123 | protected: 124 | /// @cond SHOW_PROTECTED 125 | /** Internal - do not use 126 | * \return 127 | */ 128 | int16_t getch() { 129 | return FatStreamBase::getch(); 130 | } 131 | /** Internal - do not use 132 | * \param[out] pos 133 | */ 134 | void getpos(FatPos_t* pos) { 135 | FatFile::getpos(pos); 136 | } 137 | /** Internal - do not use 138 | * \param[in] c 139 | */ 140 | void putch(char c) { 141 | FatStreamBase::putch(c); 142 | } 143 | /** Internal - do not use 144 | * \param[in] str 145 | */ 146 | void putstr(const char *str) { 147 | FatStreamBase::putstr(str); 148 | } 149 | /** Internal - do not use 150 | * \param[in] pos 151 | */ 152 | bool seekoff(off_type off, seekdir way) { 153 | return FatStreamBase::seekoff(off, way); 154 | } 155 | bool seekpos(pos_type pos) { 156 | return FatStreamBase::seekpos(pos); 157 | } 158 | void setpos(FatPos_t* pos) { 159 | FatFile::setpos(pos); 160 | } 161 | bool sync() { 162 | return FatStreamBase::sync(); 163 | } 164 | pos_type tellpos() { 165 | return FatStreamBase::curPosition(); 166 | } 167 | /// @endcond 168 | }; 169 | //============================================================================== 170 | /** 171 | * \class ifstream 172 | * \brief file input stream. 173 | */ 174 | class ifstream : public istream, FatStreamBase { 175 | public: 176 | using istream::peek; 177 | ifstream() {} 178 | /** Constructor with open 179 | * \param[in] path file to open 180 | * \param[in] mode open mode 181 | */ 182 | explicit ifstream(const char* path, openmode mode = in) { 183 | open(path, mode); 184 | } 185 | #if DESTRUCTOR_CLOSES_FILE 186 | ~ifstream() {} 187 | #endif // DESTRUCTOR_CLOSES_FILE 188 | /** Close a file and force cached data and directory information 189 | * to be written to the storage device. 190 | */ 191 | void close() { 192 | FatFile::close(); 193 | } 194 | /** \return True if stream is open else false. */ 195 | bool is_open() { 196 | return FatFile::isOpen(); 197 | } 198 | /** Open an ifstream 199 | * \param[in] path file to open 200 | * \param[in] mode open mode 201 | * 202 | * \a mode See fstream::open() for valid modes. 203 | */ 204 | void open(const char* path, openmode mode = in) { 205 | FatStreamBase::open(path, mode | in); 206 | } 207 | 208 | protected: 209 | /// @cond SHOW_PROTECTED 210 | /** Internal - do not use 211 | * \return 212 | */ 213 | int16_t getch() { 214 | return FatStreamBase::getch(); 215 | } 216 | /** Internal - do not use 217 | * \param[out] pos 218 | */ 219 | void getpos(FatPos_t* pos) { 220 | FatFile::getpos(pos); 221 | } 222 | /** Internal - do not use 223 | * \param[in] pos 224 | */ 225 | bool seekoff(off_type off, seekdir way) { 226 | return FatStreamBase::seekoff(off, way); 227 | } 228 | bool seekpos(pos_type pos) { 229 | return FatStreamBase::seekpos(pos); 230 | } 231 | void setpos(FatPos_t* pos) { 232 | FatFile::setpos(pos); 233 | } 234 | pos_type tellpos() { 235 | return FatStreamBase::curPosition(); 236 | } 237 | /// @endcond 238 | }; 239 | //============================================================================== 240 | /** 241 | * \class ofstream 242 | * \brief file output stream. 243 | */ 244 | class ofstream : public ostream, FatStreamBase { 245 | public: 246 | ofstream() {} 247 | /** Constructor with open 248 | * \param[in] path file to open 249 | * \param[in] mode open mode 250 | */ 251 | explicit ofstream(const char* path, ios::openmode mode = out) { 252 | open(path, mode); 253 | } 254 | #if DESTRUCTOR_CLOSES_FILE 255 | ~ofstream() {} 256 | #endif // DESTRUCTOR_CLOSES_FILE 257 | /** Clear state and writeError 258 | * \param[in] state new state for stream 259 | */ 260 | void clear(iostate state = goodbit) { 261 | ios::clear(state); 262 | FatFile::clearWriteError(); 263 | } 264 | /** Close a file and force cached data and directory information 265 | * to be written to the storage device. 266 | */ 267 | void close() { 268 | FatFile::close(); 269 | } 270 | /** Open an ofstream 271 | * \param[in] path file to open 272 | * \param[in] mode open mode 273 | * 274 | * \a mode See fstream::open() for valid modes. 275 | */ 276 | void open(const char* path, openmode mode = out) { 277 | FatStreamBase::open(path, mode | out); 278 | } 279 | /** \return True if stream is open else false. */ 280 | bool is_open() { 281 | return FatFile::isOpen(); 282 | } 283 | 284 | protected: 285 | /// @cond SHOW_PROTECTED 286 | /** 287 | * Internal do not use 288 | * \param[in] c 289 | */ 290 | void putch(char c) { 291 | FatStreamBase::putch(c); 292 | } 293 | void putstr(const char* str) { 294 | FatStreamBase::putstr(str); 295 | } 296 | bool seekoff(off_type off, seekdir way) { 297 | return FatStreamBase::seekoff(off, way); 298 | } 299 | bool seekpos(pos_type pos) { 300 | return FatStreamBase::seekpos(pos); 301 | } 302 | /** 303 | * Internal do not use 304 | * \param[in] b 305 | */ 306 | bool sync() { 307 | return FatStreamBase::sync(); 308 | } 309 | pos_type tellpos() { 310 | return FatStreamBase::curPosition(); 311 | } 312 | /// @endcond 313 | }; 314 | //------------------------------------------------------------------------------ 315 | #endif // fstream_h 316 | -------------------------------------------------------------------------------- /src/ios.h: -------------------------------------------------------------------------------- 1 | /* FatLib Library 2 | * Copyright (C) 2013 by William Greiman 3 | * 4 | * This file is part of the FatLib 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 FatLib Library. If not, see 18 | * . 19 | */ 20 | #ifndef ios_h 21 | #define ios_h 22 | #include "FatFile.h" 23 | /** 24 | * \file 25 | * \brief \ref ios_base and \ref ios classes 26 | */ 27 | //============================================================================== 28 | /** 29 | * \class ios_base 30 | * \brief Base class for all streams 31 | */ 32 | class ios_base { 33 | public: 34 | /** typedef for iostate bitmask */ 35 | typedef unsigned char iostate; 36 | // State flags. 37 | /** iostate for no flags */ 38 | static const iostate goodbit = 0x00; 39 | /** iostate bad bit for a nonrecoverable error. */ 40 | static const iostate badbit = 0X01; 41 | /** iostate bit for end of file reached */ 42 | static const iostate eofbit = 0x02; 43 | /** iostate fail bit for nonfatal error */ 44 | static const iostate failbit = 0X04; 45 | /** 46 | * unsigned size that can represent maximum file size. 47 | * (violates spec - should be signed) 48 | */ 49 | typedef uint32_t streamsize; 50 | /** type for absolute seek position */ 51 | typedef uint32_t pos_type; 52 | /** type for relative seek offset */ 53 | typedef int32_t off_type; 54 | 55 | /** enumerated type for the direction of relative seeks */ 56 | enum seekdir { 57 | /** seek relative to the beginning of the stream */ 58 | beg, 59 | /** seek relative to the current stream position */ 60 | cur, 61 | /** seek relative to the end of the stream */ 62 | end 63 | }; 64 | /** type for format flags */ 65 | typedef unsigned int fmtflags; 66 | /** left adjust fields */ 67 | static const fmtflags left = 0x0001; 68 | /** right adjust fields */ 69 | static const fmtflags right = 0x0002; 70 | /** fill between sign/base prefix and number */ 71 | static const fmtflags internal = 0x0004; 72 | /** base 10 flag*/ 73 | static const fmtflags dec = 0x0008; 74 | /** base 16 flag */ 75 | static const fmtflags hex = 0x0010; 76 | /** base 8 flag */ 77 | static const fmtflags oct = 0x0020; 78 | // static const fmtflags fixed = 0x0040; 79 | // static const fmtflags scientific = 0x0080; 80 | /** use strings true/false for bool */ 81 | static const fmtflags boolalpha = 0x0100; 82 | /** use prefix 0X for hex and 0 for oct */ 83 | static const fmtflags showbase = 0x0200; 84 | /** always show '.' for floating numbers */ 85 | static const fmtflags showpoint = 0x0400; 86 | /** show + sign for nonnegative numbers */ 87 | static const fmtflags showpos = 0x0800; 88 | /** skip initial white space */ 89 | static const fmtflags skipws = 0x1000; 90 | // static const fmtflags unitbuf = 0x2000; 91 | /** use uppercase letters in number representations */ 92 | static const fmtflags uppercase = 0x4000; 93 | /** mask for adjustfield */ 94 | static const fmtflags adjustfield = left | right | internal; 95 | /** mask for basefield */ 96 | static const fmtflags basefield = dec | hex | oct; 97 | // static const fmtflags floatfield = scientific | fixed; 98 | //---------------------------------------------------------------------------- 99 | /** typedef for iostream open mode */ 100 | typedef uint8_t openmode; 101 | 102 | // Openmode flags. 103 | /** seek to end before each write */ 104 | static const openmode app = 0X4; 105 | /** open and seek to end immediately after opening */ 106 | static const openmode ate = 0X8; 107 | /** perform input and output in binary mode (as opposed to text mode) */ 108 | static const openmode binary = 0X10; 109 | /** open for input */ 110 | static const openmode in = 0X20; 111 | /** open for output */ 112 | static const openmode out = 0X40; 113 | /** truncate an existing stream when opening */ 114 | static const openmode trunc = 0X80; 115 | //---------------------------------------------------------------------------- 116 | ios_base() : m_fill(' '), m_fmtflags(dec | right | skipws) 117 | , m_precision(2), m_width(0) {} 118 | /** \return fill character */ 119 | char fill() { 120 | return m_fill; 121 | } 122 | /** Set fill character 123 | * \param[in] c new fill character 124 | * \return old fill character 125 | */ 126 | char fill(char c) { 127 | char r = m_fill; 128 | m_fill = c; 129 | return r; 130 | } 131 | /** \return format flags */ 132 | fmtflags flags() const { 133 | return m_fmtflags; 134 | } 135 | /** set format flags 136 | * \param[in] fl new flag 137 | * \return old flags 138 | */ 139 | fmtflags flags(fmtflags fl) { 140 | fmtflags tmp = m_fmtflags; 141 | m_fmtflags = fl; 142 | return tmp; 143 | } 144 | /** \return precision */ 145 | int precision() const { 146 | return m_precision; 147 | } 148 | /** set precision 149 | * \param[in] n new precision 150 | * \return old precision 151 | */ 152 | int precision(unsigned int n) { 153 | int r = m_precision; 154 | m_precision = n; 155 | return r; 156 | } 157 | /** set format flags 158 | * \param[in] fl new flags to be or'ed in 159 | * \return old flags 160 | */ 161 | fmtflags setf(fmtflags fl) { 162 | fmtflags r = m_fmtflags; 163 | m_fmtflags |= fl; 164 | return r; 165 | } 166 | /** modify format flags 167 | * \param[in] mask flags to be removed 168 | * \param[in] fl flags to be set after mask bits have been cleared 169 | * \return old flags 170 | */ 171 | fmtflags setf(fmtflags fl, fmtflags mask) { 172 | fmtflags r = m_fmtflags; 173 | m_fmtflags &= ~mask; 174 | m_fmtflags |= fl; 175 | return r; 176 | } 177 | /** clear format flags 178 | * \param[in] fl flags to be cleared 179 | * \return old flags 180 | */ 181 | void unsetf(fmtflags fl) { 182 | m_fmtflags &= ~fl; 183 | } 184 | /** \return width */ 185 | unsigned width() { 186 | return m_width; 187 | } 188 | /** set width 189 | * \param[in] n new width 190 | * \return old width 191 | */ 192 | unsigned width(unsigned n) { 193 | unsigned r = m_width; 194 | m_width = n; 195 | return r; 196 | } 197 | 198 | protected: 199 | /** \return current number base */ 200 | uint8_t flagsToBase() { 201 | uint8_t f = flags() & basefield; 202 | return f == oct ? 8 : f != hex ? 10 : 16; 203 | } 204 | 205 | private: 206 | char m_fill; 207 | fmtflags m_fmtflags; 208 | unsigned char m_precision; 209 | unsigned int m_width; 210 | }; 211 | //------------------------------------------------------------------------------ 212 | /** function for boolalpha manipulator 213 | * \param[in] str The stream 214 | * \return The stream 215 | */ 216 | inline ios_base& boolalpha(ios_base& str) { 217 | str.setf(ios_base::boolalpha); 218 | return str; 219 | } 220 | /** function for dec manipulator 221 | * \param[in] str The stream 222 | * \return The stream 223 | */ 224 | inline ios_base& dec(ios_base& str) { 225 | str.setf(ios_base::dec, ios_base::basefield); 226 | return str; 227 | } 228 | /** function for hex manipulator 229 | * \param[in] str The stream 230 | * \return The stream 231 | */ 232 | inline ios_base& hex(ios_base& str) { 233 | str.setf(ios_base::hex, ios_base::basefield); 234 | return str; 235 | } 236 | /** function for internal manipulator 237 | * \param[in] str The stream 238 | * \return The stream 239 | */ 240 | inline ios_base& internal(ios_base& str) { 241 | str.setf(ios_base::internal, ios_base::adjustfield); 242 | return str; 243 | } 244 | /** function for left manipulator 245 | * \param[in] str The stream 246 | * \return The stream 247 | */ 248 | inline ios_base& left(ios_base& str) { 249 | str.setf(ios_base::left, ios_base::adjustfield); 250 | return str; 251 | } 252 | /** function for noboolalpha manipulator 253 | * \param[in] str The stream 254 | * \return The stream 255 | */ 256 | inline ios_base& noboolalpha(ios_base& str) { 257 | str.unsetf(ios_base::boolalpha); 258 | return str; 259 | } 260 | /** function for noshowbase manipulator 261 | * \param[in] str The stream 262 | * \return The stream 263 | */ 264 | inline ios_base& noshowbase(ios_base& str) { 265 | str.unsetf(ios_base::showbase); 266 | return str; 267 | } 268 | /** function for noshowpoint manipulator 269 | * \param[in] str The stream 270 | * \return The stream 271 | */ 272 | inline ios_base& noshowpoint(ios_base& str) { 273 | str.unsetf(ios_base::showpoint); 274 | return str; 275 | } 276 | /** function for noshowpos manipulator 277 | * \param[in] str The stream 278 | * \return The stream 279 | */ 280 | inline ios_base& noshowpos(ios_base& str) { 281 | str.unsetf(ios_base::showpos); 282 | return str; 283 | } 284 | /** function for noskipws manipulator 285 | * \param[in] str The stream 286 | * \return The stream 287 | */ 288 | inline ios_base& noskipws(ios_base& str) { 289 | str.unsetf(ios_base::skipws); 290 | return str; 291 | } 292 | /** function for nouppercase manipulator 293 | * \param[in] str The stream 294 | * \return The stream 295 | */ 296 | inline ios_base& nouppercase(ios_base& str) { 297 | str.unsetf(ios_base::uppercase); 298 | return str; 299 | } 300 | /** function for oct manipulator 301 | * \param[in] str The stream 302 | * \return The stream 303 | */ 304 | inline ios_base& oct(ios_base& str) { 305 | str.setf(ios_base::oct, ios_base::basefield); 306 | return str; 307 | } 308 | /** function for right manipulator 309 | * \param[in] str The stream 310 | * \return The stream 311 | */ 312 | inline ios_base& right(ios_base& str) { 313 | str.setf(ios_base::right, ios_base::adjustfield); 314 | return str; 315 | } 316 | /** function for showbase manipulator 317 | * \param[in] str The stream 318 | * \return The stream 319 | */ 320 | inline ios_base& showbase(ios_base& str) { 321 | str.setf(ios_base::showbase); 322 | return str; 323 | } 324 | /** function for showpos manipulator 325 | * \param[in] str The stream 326 | * \return The stream 327 | */ 328 | inline ios_base& showpos(ios_base& str) { 329 | str.setf(ios_base::showpos); 330 | return str; 331 | } 332 | /** function for showpoint manipulator 333 | * \param[in] str The stream 334 | * \return The stream 335 | */ 336 | inline ios_base& showpoint(ios_base& str) { 337 | str.setf(ios_base::showpoint); 338 | return str; 339 | } 340 | /** function for skipws manipulator 341 | * \param[in] str The stream 342 | * \return The stream 343 | */ 344 | inline ios_base& skipws(ios_base& str) { 345 | str.setf(ios_base::skipws); 346 | return str; 347 | } 348 | /** function for uppercase manipulator 349 | * \param[in] str The stream 350 | * \return The stream 351 | */ 352 | inline ios_base& uppercase(ios_base& str) { 353 | str.setf(ios_base::uppercase); 354 | return str; 355 | } 356 | //============================================================================== 357 | /** 358 | * \class ios 359 | * \brief Error and state information for all streams 360 | */ 361 | class ios : public ios_base { 362 | public: 363 | /** Create ios with no error flags set */ 364 | ios() : m_iostate(0) {} 365 | 366 | /** \return null pointer if fail() is true. */ 367 | operator const void*() const { 368 | return !fail() ? reinterpret_cast(this) : 0; 369 | } 370 | /** \return true if fail() else false. */ 371 | bool operator!() const { 372 | return fail(); 373 | } 374 | /** \return The iostate flags for this file. */ 375 | iostate rdstate() const { 376 | return m_iostate; 377 | } 378 | /** \return True if no iostate flags are set else false. */ 379 | bool good() const { 380 | return m_iostate == goodbit; 381 | } 382 | /** \return true if end of file has been reached else false. 383 | * 384 | * Warning: An empty file returns false before the first read. 385 | * 386 | * Moral: eof() is only useful in combination with fail(), to find out 387 | * whether EOF was the cause for failure 388 | */ 389 | bool eof() const { 390 | return m_iostate & eofbit; 391 | } 392 | /** \return true if any iostate bit other than eof are set else false. */ 393 | bool fail() const { 394 | return m_iostate & (failbit | badbit); 395 | } 396 | /** \return true if bad bit is set else false. */ 397 | bool bad() const { 398 | return m_iostate & badbit; 399 | } 400 | /** Clear iostate bits. 401 | * 402 | * \param[in] state The flags you want to set after clearing all flags. 403 | **/ 404 | void clear(iostate state = goodbit) { 405 | m_iostate = state; 406 | } 407 | /** Set iostate bits. 408 | * 409 | * \param[in] state Bitts to set. 410 | **/ 411 | void setstate(iostate state) { 412 | m_iostate |= state; 413 | } 414 | 415 | private: 416 | iostate m_iostate; 417 | }; 418 | #endif // ios_h 419 | -------------------------------------------------------------------------------- /src/iostream.h: -------------------------------------------------------------------------------- 1 | /* FatLib Library 2 | * Copyright (C) 2013 by William Greiman 3 | * 4 | * This file is part of the FatLib 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 FatLib Library. If not, see 18 | * . 19 | */ 20 | #ifndef iostream_h 21 | #define iostream_h 22 | /** 23 | * \file 24 | * \brief \ref iostream class 25 | */ 26 | #include "istream.h" 27 | #include "ostream.h" 28 | /** Skip white space 29 | * \param[in] is the Stream 30 | * \return The stream 31 | */ 32 | inline istream& ws(istream& is) { 33 | is.skipWhite(); 34 | return is; 35 | } 36 | /** insert endline 37 | * \param[in] os The Stream 38 | * \return The stream 39 | */ 40 | inline ostream& endl(ostream& os) { 41 | os.put('\n'); 42 | #if ENDL_CALLS_FLUSH 43 | os.flush(); 44 | #endif // ENDL_CALLS_FLUSH 45 | return os; 46 | } 47 | /** flush manipulator 48 | * \param[in] os The stream 49 | * \return The stream 50 | */ 51 | inline ostream& flush(ostream& os) { 52 | os.flush(); 53 | return os; 54 | } 55 | /** 56 | * \struct setfill 57 | * \brief type for setfill manipulator 58 | */ 59 | struct setfill { 60 | /** fill character */ 61 | char c; 62 | /** constructor 63 | * 64 | * \param[in] arg new fill character 65 | */ 66 | explicit setfill(char arg) : c(arg) {} 67 | }; 68 | /** setfill manipulator 69 | * \param[in] os the stream 70 | * \param[in] arg set setfill object 71 | * \return the stream 72 | */ 73 | inline ostream &operator<< (ostream &os, const setfill &arg) { 74 | os.fill(arg.c); 75 | return os; 76 | } 77 | /** setfill manipulator 78 | * \param[in] obj the stream 79 | * \param[in] arg set setfill object 80 | * \return the stream 81 | */ 82 | inline istream &operator>>(istream &obj, const setfill &arg) { 83 | obj.fill(arg.c); 84 | return obj; 85 | } 86 | //------------------------------------------------------------------------------ 87 | /** \struct setprecision 88 | * \brief type for setprecision manipulator 89 | */ 90 | struct setprecision { 91 | /** precision */ 92 | unsigned int p; 93 | /** constructor 94 | * \param[in] arg new precision 95 | */ 96 | explicit setprecision(unsigned int arg) : p(arg) {} 97 | }; 98 | /** setprecision manipulator 99 | * \param[in] os the stream 100 | * \param[in] arg set setprecision object 101 | * \return the stream 102 | */ 103 | inline ostream &operator<< (ostream &os, const setprecision &arg) { 104 | os.precision(arg.p); 105 | return os; 106 | } 107 | /** setprecision manipulator 108 | * \param[in] is the stream 109 | * \param[in] arg set setprecision object 110 | * \return the stream 111 | */ 112 | inline istream &operator>>(istream &is, const setprecision &arg) { 113 | is.precision(arg.p); 114 | return is; 115 | } 116 | //------------------------------------------------------------------------------ 117 | /** \struct setw 118 | * \brief type for setw manipulator 119 | */ 120 | struct setw { 121 | /** width */ 122 | unsigned w; 123 | /** constructor 124 | * \param[in] arg new width 125 | */ 126 | explicit setw(unsigned arg) : w(arg) {} 127 | }; 128 | /** setw manipulator 129 | * \param[in] os the stream 130 | * \param[in] arg set setw object 131 | * \return the stream 132 | */ 133 | inline ostream &operator<< (ostream &os, const setw &arg) { 134 | os.width(arg.w); 135 | return os; 136 | } 137 | /** setw manipulator 138 | * \param[in] is the stream 139 | * \param[in] arg set setw object 140 | * \return the stream 141 | */ 142 | inline istream &operator>>(istream &is, const setw &arg) { 143 | is.width(arg.w); 144 | return is; 145 | } 146 | //============================================================================== 147 | /** 148 | * \class iostream 149 | * \brief Input/Output stream 150 | */ 151 | class iostream : public istream, public ostream { 152 | }; 153 | #endif // iostream_h 154 | -------------------------------------------------------------------------------- /src/istream.cpp: -------------------------------------------------------------------------------- 1 | /* FatLib Library 2 | * Copyright (C) 2013 by William Greiman 3 | * 4 | * This file is part of the FatLib 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 FatLib Library. If not, see 18 | * . 19 | */ 20 | // #include 21 | #include 22 | #include 23 | #include "istream.h" 24 | //------------------------------------------------------------------------------ 25 | int istream::get() { 26 | int c; 27 | m_gcount = 0; 28 | c = getch(); 29 | if (c < 0) { 30 | setstate(failbit); 31 | } else { 32 | m_gcount = 1; 33 | } 34 | return c; 35 | } 36 | //------------------------------------------------------------------------------ 37 | istream& istream::get(char& c) { 38 | int tmp = get(); 39 | if (tmp >= 0) { 40 | c = tmp; 41 | } 42 | return *this; 43 | } 44 | //------------------------------------------------------------------------------ 45 | istream& istream::get(char *str, streamsize n, char delim) { 46 | int c; 47 | FatPos_t pos; 48 | m_gcount = 0; 49 | while ((m_gcount + 1) < n) { 50 | c = getch(&pos); 51 | if (c < 0) { 52 | break; 53 | } 54 | if (c == delim) { 55 | setpos(&pos); 56 | break; 57 | } 58 | str[m_gcount++] = c; 59 | } 60 | if (n > 0) { 61 | str[m_gcount] = '\0'; 62 | } 63 | if (m_gcount == 0) { 64 | setstate(failbit); 65 | } 66 | return *this; 67 | } 68 | //------------------------------------------------------------------------------ 69 | void istream::getBool(bool *b) { 70 | if ((flags() & boolalpha) == 0) { 71 | getNumber(b); 72 | return; 73 | } 74 | #ifdef __AVR__ 75 | PGM_P truePtr = PSTR("true"); 76 | PGM_P falsePtr = PSTR("false"); 77 | #else // __AVR__ 78 | const char* truePtr = "true"; 79 | const char* falsePtr = "false"; 80 | #endif // __AVR 81 | const uint8_t true_len = 4; 82 | const uint8_t false_len = 5; 83 | bool trueOk = true; 84 | bool falseOk = true; 85 | uint8_t i = 0; 86 | int c = readSkip(); 87 | while (1) { 88 | #ifdef __AVR__ 89 | falseOk = falseOk && c == pgm_read_byte(falsePtr + i); 90 | trueOk = trueOk && c == pgm_read_byte(truePtr + i); 91 | #else // __AVR__ 92 | falseOk = falseOk && c == falsePtr[i]; 93 | trueOk = trueOk && c == truePtr[i]; 94 | #endif // __AVR__ 95 | if (trueOk == false && falseOk == false) { 96 | break; 97 | } 98 | i++; 99 | if (trueOk && i == true_len) { 100 | *b = true; 101 | return; 102 | } 103 | if (falseOk && i == false_len) { 104 | *b = false; 105 | return; 106 | } 107 | c = getch(); 108 | } 109 | setstate(failbit); 110 | } 111 | //------------------------------------------------------------------------------ 112 | void istream::getChar(char* ch) { 113 | int16_t c = readSkip(); 114 | if (c < 0) { 115 | setstate(failbit); 116 | } else { 117 | *ch = c; 118 | } 119 | } 120 | //------------------------------------------------------------------------------ 121 | // 122 | // http://www.exploringbinary.com/category/numbers-in-computers/ 123 | // 124 | int16_t const EXP_LIMIT = 100; 125 | static const uint32_t uint32_max = (uint32_t)-1; 126 | bool istream::getDouble(double* value) { 127 | bool got_digit = false; 128 | bool got_dot = false; 129 | bool neg; 130 | int16_t c; 131 | bool expNeg = false; 132 | int16_t exp = 0; 133 | int16_t fracExp = 0; 134 | uint32_t frac = 0; 135 | FatPos_t endPos; 136 | double pow10; 137 | double v; 138 | 139 | getpos(&endPos); 140 | c = readSkip(); 141 | neg = c == '-'; 142 | if (c == '-' || c == '+') { 143 | c = getch(); 144 | } 145 | while (1) { 146 | if (isdigit(c)) { 147 | got_digit = true; 148 | if (frac < uint32_max/10) { 149 | frac = frac * 10 + (c - '0'); 150 | if (got_dot) { 151 | fracExp--; 152 | } 153 | } else { 154 | if (!got_dot) { 155 | fracExp++; 156 | } 157 | } 158 | } else if (!got_dot && c == '.') { 159 | got_dot = true; 160 | } else { 161 | break; 162 | } 163 | if (fracExp < -EXP_LIMIT || fracExp > EXP_LIMIT) { 164 | goto fail; 165 | } 166 | c = getch(&endPos); 167 | } 168 | if (!got_digit) { 169 | goto fail; 170 | } 171 | if (c == 'e' || c == 'E') { 172 | c = getch(); 173 | expNeg = c == '-'; 174 | if (c == '-' || c == '+') { 175 | c = getch(); 176 | } 177 | while (isdigit(c)) { 178 | if (exp > EXP_LIMIT) { 179 | goto fail; 180 | } 181 | exp = exp * 10 + (c - '0'); 182 | c = getch(&endPos); 183 | } 184 | } 185 | v = static_cast(frac); 186 | exp = expNeg ? fracExp - exp : fracExp + exp; 187 | expNeg = exp < 0; 188 | if (expNeg) { 189 | exp = -exp; 190 | } 191 | pow10 = 10.0; 192 | while (exp) { 193 | if (exp & 1) { 194 | if (expNeg) { 195 | // check for underflow 196 | if (v < FLT_MIN * pow10 && frac != 0) { 197 | goto fail; 198 | } 199 | v /= pow10; 200 | } else { 201 | // check for overflow 202 | if (v > FLT_MAX / pow10) { 203 | goto fail; 204 | } 205 | v *= pow10; 206 | } 207 | } 208 | pow10 *= pow10; 209 | exp >>= 1; 210 | } 211 | setpos(&endPos); 212 | *value = neg ? -v : v; 213 | return true; 214 | 215 | fail: 216 | // error restore position to last good place 217 | setpos(&endPos); 218 | setstate(failbit); 219 | return false; 220 | } 221 | //------------------------------------------------------------------------------ 222 | 223 | istream& istream::getline(char *str, streamsize n, char delim) { 224 | FatPos_t pos; 225 | int c; 226 | m_gcount = 0; 227 | if (n > 0) { 228 | str[0] = '\0'; 229 | } 230 | while (1) { 231 | c = getch(&pos); 232 | if (c < 0) { 233 | break; 234 | } 235 | if (c == delim) { 236 | m_gcount++; 237 | break; 238 | } 239 | if ((m_gcount + 1) >= n) { 240 | setpos(&pos); 241 | setstate(failbit); 242 | break; 243 | } 244 | str[m_gcount++] = c; 245 | str[m_gcount] = '\0'; 246 | } 247 | if (m_gcount == 0) { 248 | setstate(failbit); 249 | } 250 | return *this; 251 | } 252 | //------------------------------------------------------------------------------ 253 | bool istream::getNumber(uint32_t posMax, uint32_t negMax, uint32_t* num) { 254 | int16_t c; 255 | int8_t any = 0; 256 | int8_t have_zero = 0; 257 | uint8_t neg; 258 | uint32_t val = 0; 259 | uint32_t cutoff; 260 | uint8_t cutlim; 261 | FatPos_t endPos; 262 | uint8_t f = flags() & basefield; 263 | uint8_t base = f == oct ? 8 : f != hex ? 10 : 16; 264 | getpos(&endPos); 265 | c = readSkip(); 266 | 267 | neg = c == '-' ? 1 : 0; 268 | if (c == '-' || c == '+') { 269 | c = getch(); 270 | } 271 | 272 | if (base == 16 && c == '0') { // TESTSUITE 273 | c = getch(&endPos); 274 | if (c == 'X' || c == 'x') { 275 | c = getch(); 276 | // remember zero in case no hex digits follow x/X 277 | have_zero = 1; 278 | } else { 279 | any = 1; 280 | } 281 | } 282 | // set values for overflow test 283 | cutoff = neg ? negMax : posMax; 284 | cutlim = cutoff % base; 285 | cutoff /= base; 286 | 287 | while (1) { 288 | if (isdigit(c)) { 289 | c -= '0'; 290 | } else if (isalpha(c)) { 291 | c -= isupper(c) ? 'A' - 10 : 'a' - 10; 292 | } else { 293 | break; 294 | } 295 | if (c >= base) { 296 | break; 297 | } 298 | if (val > cutoff || (val == cutoff && c > cutlim)) { 299 | // indicate overflow error 300 | any = -1; 301 | break; 302 | } 303 | val = val * base + c; 304 | c = getch(&endPos); 305 | any = 1; 306 | } 307 | setpos(&endPos); 308 | if (any > 0 || (have_zero && any >= 0)) { 309 | *num = neg ? -val : val; 310 | return true; 311 | } 312 | setstate(failbit); 313 | return false; 314 | } 315 | //------------------------------------------------------------------------------ 316 | void istream::getStr(char *str) { 317 | FatPos_t pos; 318 | uint16_t i = 0; 319 | uint16_t m = width() ? width() - 1 : 0XFFFE; 320 | if (m != 0) { 321 | getpos(&pos); 322 | int c = readSkip(); 323 | 324 | while (i < m) { 325 | if (c < 0) { 326 | break; 327 | } 328 | if (isspace(c)) { 329 | setpos(&pos); 330 | break; 331 | } 332 | str[i++] = c; 333 | c = getch(&pos); 334 | } 335 | } 336 | str[i] = '\0'; 337 | if (i == 0) { 338 | setstate(failbit); 339 | } 340 | width(0); 341 | } 342 | //------------------------------------------------------------------------------ 343 | istream& istream::ignore(streamsize n, int delim) { 344 | int c; 345 | m_gcount = 0; 346 | while (m_gcount < n) { 347 | c = getch(); 348 | if (c < 0) { 349 | break; 350 | } 351 | m_gcount++; 352 | if (c == delim) { 353 | break; 354 | } 355 | } 356 | return *this; 357 | } 358 | //------------------------------------------------------------------------------ 359 | int istream::peek() { 360 | int16_t c; 361 | FatPos_t pos; 362 | m_gcount = 0; 363 | getpos(&pos); 364 | c = getch(); 365 | if (c < 0) { 366 | if (!bad()) { 367 | setstate(eofbit); 368 | } 369 | } else { 370 | setpos(&pos); 371 | } 372 | return c; 373 | } 374 | //------------------------------------------------------------------------------ 375 | int16_t istream::readSkip() { 376 | int16_t c; 377 | do { 378 | c = getch(); 379 | } while (isspace(c) && (flags() & skipws)); 380 | return c; 381 | } 382 | //------------------------------------------------------------------------------ 383 | /** used to implement ws() */ 384 | void istream::skipWhite() { 385 | int c; 386 | FatPos_t pos; 387 | do { 388 | c = getch(&pos); 389 | } while (isspace(c)); 390 | setpos(&pos); 391 | } 392 | -------------------------------------------------------------------------------- /src/istream.h: -------------------------------------------------------------------------------- 1 | /* FatLib Library 2 | * Copyright (C) 2013 by William Greiman 3 | * 4 | * This file is part of the FatLib 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 FatLib Library. If not, see 18 | * . 19 | */ 20 | #ifndef istream_h 21 | #define istream_h 22 | /** 23 | * \file 24 | * \brief \ref istream class 25 | */ 26 | #include "ios.h" 27 | 28 | /** 29 | * \class istream 30 | * \brief Input Stream 31 | */ 32 | class istream : public virtual ios { 33 | public: 34 | istream() {} 35 | /** call manipulator 36 | * \param[in] pf function to call 37 | * \return the stream 38 | */ 39 | istream& operator>>(istream& (*pf)(istream& str)) { 40 | return pf(*this); 41 | } 42 | /** call manipulator 43 | * \param[in] pf function to call 44 | * \return the stream 45 | */ 46 | istream& operator>>(ios_base& (*pf)(ios_base& str)) { 47 | pf(*this); 48 | return *this; 49 | } 50 | /** call manipulator 51 | * \param[in] pf function to call 52 | * \return the stream 53 | */ 54 | istream& operator>>(ios& (*pf)(ios& str)) { 55 | pf(*this); 56 | return *this; 57 | } 58 | /** 59 | * Extract a character string 60 | * \param[out] str location to store the string. 61 | * \return Is always *this. Failure is indicated by the state of *this. 62 | */ 63 | istream& operator>>(char *str) { 64 | getStr(str); 65 | return *this; 66 | } 67 | /** 68 | * Extract a character 69 | * \param[out] ch location to store the character. 70 | * \return Is always *this. Failure is indicated by the state of *this. 71 | */ 72 | istream& operator>>(char& ch) { 73 | getChar(&ch); 74 | return *this; 75 | } 76 | /** 77 | * Extract a character string 78 | * \param[out] str location to store the string. 79 | * \return Is always *this. Failure is indicated by the state of *this. 80 | */ 81 | istream& operator>>(signed char *str) { 82 | getStr(reinterpret_cast(str)); 83 | return *this; 84 | } 85 | /** 86 | * Extract a character 87 | * \param[out] ch location to store the character. 88 | * \return Is always *this. Failure is indicated by the state of *this. 89 | */ 90 | istream& operator>>(signed char& ch) { 91 | getChar(reinterpret_cast(&ch)); 92 | return *this; 93 | } 94 | /** 95 | * Extract a character string 96 | * \param[out] str location to store the string. 97 | * \return Is always *this. Failure is indicated by the state of *this. 98 | */ 99 | istream& operator>>(unsigned char *str) { 100 | getStr(reinterpret_cast(str)); 101 | return *this; 102 | } 103 | /** 104 | * Extract a character 105 | * \param[out] ch location to store the character. 106 | * \return Is always *this. Failure is indicated by the state of *this. 107 | */ 108 | istream& operator>>(unsigned char& ch) { 109 | getChar(reinterpret_cast(&ch)); 110 | return *this; 111 | } 112 | /** 113 | * Extract a value of type bool. 114 | * \param[out] arg location to store the value. 115 | * \return Is always *this. Failure is indicated by the state of *this. 116 | */ 117 | istream& operator>>(bool& arg) { 118 | getBool(&arg); 119 | return *this; 120 | } 121 | /** 122 | * Extract a value of type short. 123 | * \param[out] arg location to store the value. 124 | * \return Is always *this. Failure is indicated by the state of *this. 125 | */ 126 | istream &operator>>(short& arg) { // NOLINT 127 | getNumber(&arg); 128 | return *this; 129 | } 130 | /** 131 | * Extract a value of type unsigned short. 132 | * \param[out] arg location to store the value. 133 | * \return Is always *this. Failure is indicated by the state of *this. 134 | */ 135 | istream &operator>>(unsigned short& arg) { // NOLINT 136 | getNumber(&arg); 137 | return *this; 138 | } 139 | /** 140 | * Extract a value of type int. 141 | * \param[out] arg location to store the value. 142 | * \return Is always *this. Failure is indicated by the state of *this. 143 | */ 144 | istream &operator>>(int& arg) { 145 | getNumber(&arg); 146 | return *this; 147 | } 148 | /** 149 | * Extract a value of type unsigned int. 150 | * \param[out] arg location to store the value. 151 | * \return Is always *this. Failure is indicated by the state of *this. 152 | */ 153 | istream &operator>>(unsigned int& arg) { 154 | getNumber(&arg); 155 | return *this; 156 | } 157 | /** 158 | * Extract a value of type long. 159 | * \param[out] arg location to store the value. 160 | * \return Is always *this. Failure is indicated by the state of *this. 161 | */ 162 | istream &operator>>(long& arg) { // NOLINT 163 | getNumber(&arg); 164 | return *this; 165 | } 166 | /** 167 | * Extract a value of type unsigned long. 168 | * \param[out] arg location to store the value. 169 | * \return Is always *this. Failure is indicated by the state of *this. 170 | */ 171 | istream &operator>>(unsigned long& arg) { // NOLINT 172 | getNumber(&arg); 173 | return *this; 174 | } 175 | /** 176 | * Extract a value of type double. 177 | * \param[out] arg location to store the value. 178 | * \return Is always *this. Failure is indicated by the state of *this. 179 | */ 180 | istream &operator>> (double& arg) { 181 | getDouble(&arg); 182 | return *this; 183 | } 184 | /** 185 | * Extract a value of type float. 186 | * \param[out] arg location to store the value. 187 | * \return Is always *this. Failure is indicated by the state of *this. 188 | */ 189 | istream &operator>> (float& arg) { 190 | double v; 191 | getDouble(&v); 192 | arg = v; 193 | return *this; 194 | } 195 | /** 196 | * Extract a value of type void*. 197 | * \param[out] arg location to store the value. 198 | * \return Is always *this. Failure is indicated by the state of *this. 199 | */ 200 | istream& operator>> (void*& arg) { 201 | uint32_t val; 202 | getNumber(&val); 203 | arg = reinterpret_cast(val); 204 | return *this; 205 | } 206 | /** 207 | * \return The number of characters extracted by the last unformatted 208 | * input function. 209 | */ 210 | streamsize gcount() const { 211 | return m_gcount; 212 | } 213 | /** 214 | * Extract a character if one is available. 215 | * 216 | * \return The character or -1 if a failure occurs. A failure is indicated 217 | * by the stream state. 218 | */ 219 | int get(); 220 | /** 221 | * Extract a character if one is available. 222 | * 223 | * \param[out] ch location to receive the extracted character. 224 | * 225 | * \return always returns *this. A failure is indicated by the stream state. 226 | */ 227 | istream& get(char& ch); 228 | /** 229 | * Extract characters. 230 | * 231 | * \param[out] str Location to receive extracted characters. 232 | * \param[in] n Size of str. 233 | * \param[in] delim Delimiter 234 | * 235 | * Characters are extracted until extraction fails, n is less than 1, 236 | * n-1 characters are extracted, or the next character equals 237 | * \a delim (delim is not extracted). If no characters are extracted 238 | * failbit is set. If end-of-file occurs the eofbit is set. 239 | * 240 | * \return always returns *this. A failure is indicated by the stream state. 241 | */ 242 | istream& get(char *str, streamsize n, char delim = '\n'); 243 | /** 244 | * Extract characters 245 | * 246 | * \param[out] str Location to receive extracted characters. 247 | * \param[in] n Size of str. 248 | * \param[in] delim Delimiter 249 | * 250 | * Characters are extracted until extraction fails, 251 | * the next character equals \a delim (delim is extracted), or n-1 252 | * characters are extracted. 253 | * 254 | * The failbit is set if no characters are extracted or n-1 characters 255 | * are extracted. If end-of-file occurs the eofbit is set. 256 | * 257 | * \return always returns *this. A failure is indicated by the stream state. 258 | */ 259 | istream& getline(char *str, streamsize n, char delim = '\n'); 260 | /** 261 | * Extract characters and discard them. 262 | * 263 | * \param[in] n maximum number of characters to ignore. 264 | * \param[in] delim Delimiter. 265 | * 266 | * Characters are extracted until extraction fails, \a n characters 267 | * are extracted, or the next input character equals \a delim 268 | * (the delimiter is extracted). If end-of-file occurs the eofbit is set. 269 | * 270 | * Failures are indicated by the state of the stream. 271 | * 272 | * \return *this 273 | * 274 | */ 275 | istream& ignore(streamsize n = 1, int delim = -1); 276 | /** 277 | * Return the next available character without consuming it. 278 | * 279 | * \return The character if the stream state is good else -1; 280 | * 281 | */ 282 | int peek(); 283 | // istream& read(char *str, streamsize count); 284 | // streamsize readsome(char *str, streamsize count); 285 | /** 286 | * \return the stream position 287 | */ 288 | pos_type tellg() { 289 | return tellpos(); 290 | } 291 | /** 292 | * Set the stream position 293 | * \param[in] pos The absolute position in which to move the read pointer. 294 | * \return Is always *this. Failure is indicated by the state of *this. 295 | */ 296 | istream& seekg(pos_type pos) { 297 | if (!seekpos(pos)) { 298 | setstate(failbit); 299 | } 300 | return *this; 301 | } 302 | /** 303 | * Set the stream position. 304 | * 305 | * \param[in] off An offset to move the read pointer relative to way. 306 | * \a off is a signed 32-bit int so the offset is limited to +- 2GB. 307 | * \param[in] way One of ios::beg, ios::cur, or ios::end. 308 | * \return Is always *this. Failure is indicated by the state of *this. 309 | */ 310 | istream& seekg(off_type off, seekdir way) { 311 | if (!seekoff(off, way)) { 312 | setstate(failbit); 313 | } 314 | return *this; 315 | } 316 | void skipWhite(); 317 | 318 | protected: 319 | /// @cond SHOW_PROTECTED 320 | /** 321 | * Internal - do not use 322 | * \return 323 | */ 324 | virtual int16_t getch() = 0; 325 | /** 326 | * Internal - do not use 327 | * \param[out] pos 328 | * \return 329 | */ 330 | int16_t getch(FatPos_t* pos) { 331 | getpos(pos); 332 | return getch(); 333 | } 334 | /** 335 | * Internal - do not use 336 | * \param[out] pos 337 | */ 338 | virtual void getpos(FatPos_t* pos) = 0; 339 | /** 340 | * Internal - do not use 341 | * \param[in] pos 342 | */ 343 | virtual bool seekoff(off_type off, seekdir way) = 0; 344 | virtual bool seekpos(pos_type pos) = 0; 345 | virtual void setpos(FatPos_t* pos) = 0; 346 | virtual pos_type tellpos() = 0; 347 | 348 | /// @endcond 349 | private: 350 | void getBool(bool *b); 351 | void getChar(char* ch); 352 | bool getDouble(double* value); 353 | template void getNumber(T* value); 354 | bool getNumber(uint32_t posMax, uint32_t negMax, uint32_t* num); 355 | void getStr(char *str); 356 | int16_t readSkip(); 357 | 358 | size_t m_gcount; 359 | }; 360 | //------------------------------------------------------------------------------ 361 | template 362 | void istream::getNumber(T* value) { 363 | uint32_t tmp; 364 | if ((T)-1 < 0) { 365 | // number is signed, max positive value 366 | uint32_t const m = ((uint32_t)-1) >> (33 - sizeof(T) * 8); 367 | // max absolute value of negative number is m + 1. 368 | if (getNumber(m, m + 1, &tmp)) { 369 | *value = (T)tmp; 370 | } 371 | } else { 372 | // max unsigned value for T 373 | uint32_t const m = (T)-1; 374 | if (getNumber(m, m, &tmp)) { 375 | *value = (T)tmp; 376 | } 377 | } 378 | } 379 | #endif // istream_h 380 | -------------------------------------------------------------------------------- /src/ostream.cpp: -------------------------------------------------------------------------------- 1 | /* FatLib Library 2 | * Copyright (C) 2013 by William Greiman 3 | * 4 | * This file is part of the FatLib 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 FatLib Library. If not, see 18 | * . 19 | */ 20 | #include 21 | #include "ostream.h" 22 | #ifndef PSTR 23 | #define PSTR(x) x 24 | #endif 25 | //------------------------------------------------------------------------------ 26 | void ostream::do_fill(unsigned len) { 27 | for (; len < width(); len++) { 28 | putch(fill()); 29 | } 30 | width(0); 31 | } 32 | //------------------------------------------------------------------------------ 33 | void ostream::fill_not_left(unsigned len) { 34 | if ((flags() & adjustfield) != left) { 35 | do_fill(len); 36 | } 37 | } 38 | //------------------------------------------------------------------------------ 39 | char* ostream::fmtNum(uint32_t n, char *ptr, uint8_t base) { 40 | char a = flags() & uppercase ? 'A' - 10 : 'a' - 10; 41 | do { 42 | uint32_t m = n; 43 | n /= base; 44 | char c = m - base * n; 45 | *--ptr = c < 10 ? c + '0' : c + a; 46 | } while (n); 47 | return ptr; 48 | } 49 | //------------------------------------------------------------------------------ 50 | void ostream::putBool(bool b) { 51 | if (flags() & boolalpha) { 52 | if (b) { 53 | putPgm(PSTR("true")); 54 | } else { 55 | putPgm(PSTR("false")); 56 | } 57 | } else { 58 | putChar(b ? '1' : '0'); 59 | } 60 | } 61 | //------------------------------------------------------------------------------ 62 | void ostream::putChar(char c) { 63 | fill_not_left(1); 64 | putch(c); 65 | do_fill(1); 66 | } 67 | //------------------------------------------------------------------------------ 68 | void ostream::putDouble(double n) { 69 | uint8_t nd = precision(); 70 | double round = 0.5; 71 | char sign; 72 | char buf[13]; // room for sign, 10 digits, '.', and zero byte 73 | char *end = buf + sizeof(buf) - 1; 74 | char *str = end; 75 | // terminate string 76 | *end = '\0'; 77 | 78 | // get sign and make nonnegative 79 | if (n < 0.0) { 80 | sign = '-'; 81 | n = -n; 82 | } else { 83 | sign = flags() & showpos ? '+' : '\0'; 84 | } 85 | // check for larger than uint32_t 86 | if (n > 4.0E9) { 87 | putPgm(PSTR("BIG FLT")); 88 | return; 89 | } 90 | // round up and separate int and fraction parts 91 | for (uint8_t i = 0; i < nd; ++i) { 92 | round *= 0.1; 93 | } 94 | n += round; 95 | uint32_t intPart = n; 96 | double fractionPart = n - intPart; 97 | 98 | // format intPart and decimal point 99 | if (nd || (flags() & showpoint)) { 100 | *--str = '.'; 101 | } 102 | str = fmtNum(intPart, str, 10); 103 | 104 | // calculate length for fill 105 | uint8_t len = sign ? 1 : 0; 106 | len += nd + end - str; 107 | 108 | // extract adjust field 109 | fmtflags adj = flags() & adjustfield; 110 | if (adj == internal) { 111 | if (sign) { 112 | putch(sign); 113 | } 114 | do_fill(len); 115 | } else { 116 | // do fill for internal or right 117 | fill_not_left(len); 118 | if (sign) { 119 | *--str = sign; 120 | } 121 | } 122 | putstr(str); 123 | // output fraction 124 | while (nd-- > 0) { 125 | fractionPart *= 10.0; 126 | int digit = static_cast(fractionPart); 127 | putch(digit + '0'); 128 | fractionPart -= digit; 129 | } 130 | // do fill if not done above 131 | do_fill(len); 132 | } 133 | //------------------------------------------------------------------------------ 134 | void ostream::putNum(int32_t n) { 135 | bool neg = n < 0 && flagsToBase() == 10; 136 | if (neg) { 137 | n = -n; 138 | } 139 | putNum(n, neg); 140 | } 141 | //------------------------------------------------------------------------------ 142 | void ostream::putNum(uint32_t n, bool neg) { 143 | char buf[13]; 144 | char* end = buf + sizeof(buf) - 1; 145 | char* num; 146 | char* str; 147 | uint8_t base = flagsToBase(); 148 | *end = '\0'; 149 | str = num = fmtNum(n, end, base); 150 | if (base == 10) { 151 | if (neg) { 152 | *--str = '-'; 153 | } else if (flags() & showpos) { 154 | *--str = '+'; 155 | } 156 | } else if (flags() & showbase) { 157 | if (flags() & hex) { 158 | *--str = flags() & uppercase ? 'X' : 'x'; 159 | } 160 | *--str = '0'; 161 | } 162 | uint8_t len = end - str; 163 | fmtflags adj = flags() & adjustfield; 164 | if (adj == internal) { 165 | while (str < num) { 166 | putch(*str++); 167 | } 168 | } 169 | if (adj != left) { 170 | do_fill(len); 171 | } 172 | putstr(str); 173 | do_fill(len); 174 | } 175 | //------------------------------------------------------------------------------ 176 | void ostream::putPgm(const char* str) { 177 | int n; 178 | for (n = 0; pgm_read_byte(&str[n]); n++) {} 179 | fill_not_left(n); 180 | for (uint8_t c; (c = pgm_read_byte(str)); str++) { 181 | putch(c); 182 | } 183 | do_fill(n); 184 | } 185 | //------------------------------------------------------------------------------ 186 | void ostream::putStr(const char *str) { 187 | unsigned n = strlen(str); 188 | fill_not_left(n); 189 | putstr(str); 190 | do_fill(n); 191 | } 192 | -------------------------------------------------------------------------------- /src/ostream.h: -------------------------------------------------------------------------------- 1 | /* FatLib Library 2 | * Copyright (C) 2013 by William Greiman 3 | * 4 | * This file is part of the FatLib 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 FatLib Library. If not, see 18 | * . 19 | */ 20 | #ifndef ostream_h 21 | #define ostream_h 22 | /** 23 | * \file 24 | * \brief \ref ostream class 25 | */ 26 | #include "ios.h" 27 | //============================================================================== 28 | /** 29 | * \class ostream 30 | * \brief Output Stream 31 | */ 32 | class ostream : public virtual ios { 33 | public: 34 | ostream() {} 35 | 36 | /** call manipulator 37 | * \param[in] pf function to call 38 | * \return the stream 39 | */ 40 | ostream& operator<< (ostream& (*pf)(ostream& str)) { 41 | return pf(*this); 42 | } 43 | /** call manipulator 44 | * \param[in] pf function to call 45 | * \return the stream 46 | */ 47 | ostream& operator<< (ios_base& (*pf)(ios_base& str)) { 48 | pf(*this); 49 | return *this; 50 | } 51 | /** Output bool 52 | * \param[in] arg value to output 53 | * \return the stream 54 | */ 55 | ostream &operator<< (bool arg) { 56 | putBool(arg); 57 | return *this; 58 | } 59 | /** Output string 60 | * \param[in] arg string to output 61 | * \return the stream 62 | */ 63 | ostream &operator<< (const char *arg) { 64 | putStr(arg); 65 | return *this; 66 | } 67 | /** Output string 68 | * \param[in] arg string to output 69 | * \return the stream 70 | */ 71 | ostream &operator<< (const signed char *arg) { 72 | putStr((const char*)arg); 73 | return *this; 74 | } 75 | /** Output string 76 | * \param[in] arg string to output 77 | * \return the stream 78 | */ 79 | ostream &operator<< (const unsigned char *arg) { 80 | putStr((const char*)arg); 81 | return *this; 82 | } 83 | /** Output character 84 | * \param[in] arg character to output 85 | * \return the stream 86 | */ 87 | ostream &operator<< (char arg) { 88 | putChar(arg); 89 | return *this; 90 | } 91 | /** Output character 92 | * \param[in] arg character to output 93 | * \return the stream 94 | */ 95 | ostream &operator<< (signed char arg) { 96 | putChar(static_cast(arg)); 97 | return *this; 98 | } 99 | /** Output character 100 | * \param[in] arg character to output 101 | * \return the stream 102 | */ 103 | ostream &operator<< (unsigned char arg) { 104 | putChar(static_cast(arg)); 105 | return *this; 106 | } 107 | /** Output double 108 | * \param[in] arg value to output 109 | * \return the stream 110 | */ 111 | ostream &operator<< (double arg) { 112 | putDouble(arg); 113 | return *this; 114 | } 115 | /** Output float 116 | * \param[in] arg value to output 117 | * \return the stream 118 | */ 119 | ostream &operator<< (float arg) { 120 | putDouble(arg); 121 | return *this; 122 | } 123 | /** Output signed short 124 | * \param[in] arg value to output 125 | * \return the stream 126 | */ 127 | ostream &operator<< (short arg) { // NOLINT 128 | putNum((int32_t)arg); 129 | return *this; 130 | } 131 | /** Output unsigned short 132 | * \param[in] arg value to output 133 | * \return the stream 134 | */ 135 | ostream &operator<< (unsigned short arg) { // NOLINT 136 | putNum((uint32_t)arg); 137 | return *this; 138 | } 139 | /** Output signed int 140 | * \param[in] arg value to output 141 | * \return the stream 142 | */ 143 | ostream &operator<< (int arg) { 144 | putNum((int32_t)arg); 145 | return *this; 146 | } 147 | /** Output unsigned int 148 | * \param[in] arg value to output 149 | * \return the stream 150 | */ 151 | ostream &operator<< (unsigned int arg) { 152 | putNum((uint32_t)arg); 153 | return *this; 154 | } 155 | /** Output signed long 156 | * \param[in] arg value to output 157 | * \return the stream 158 | */ 159 | ostream &operator<< (long arg) { // NOLINT 160 | putNum((int32_t)arg); 161 | return *this; 162 | } 163 | /** Output unsigned long 164 | * \param[in] arg value to output 165 | * \return the stream 166 | */ 167 | ostream &operator<< (unsigned long arg) { // NOLINT 168 | putNum((uint32_t)arg); 169 | return *this; 170 | } 171 | /** Output pointer 172 | * \param[in] arg value to output 173 | * \return the stream 174 | */ 175 | ostream& operator<< (const void* arg) { 176 | putNum(reinterpret_cast(arg)); 177 | return *this; 178 | } 179 | #if (defined(ARDUINO) && ENABLE_ARDUINO_FEATURES) || defined(DOXYGEN) 180 | /** Output a string from flash using the Arduino F() macro. 181 | * \param[in] arg pointing to flash string 182 | * \return the stream 183 | */ 184 | ostream &operator<< (const __FlashStringHelper *arg) { 185 | putPgm(reinterpret_cast(arg)); 186 | return *this; 187 | } 188 | #endif // (defined(ARDUINO) && ENABLE_ARDUINO_FEATURES) || defined(DOXYGEN) 189 | /** 190 | * Puts a character in a stream. 191 | * 192 | * The unformatted output function inserts the element \a ch. 193 | * It returns *this. 194 | * 195 | * \param[in] ch The character 196 | * \return A reference to the ostream object. 197 | */ 198 | ostream& put(char ch) { 199 | putch(ch); 200 | return *this; 201 | } 202 | // ostream& write(char *str, streamsize count); 203 | /** 204 | * Flushes the buffer associated with this stream. The flush function 205 | * calls the sync function of the associated file. 206 | * \return A reference to the ostream object. 207 | */ 208 | ostream& flush() { 209 | if (!sync()) { 210 | setstate(badbit); 211 | } 212 | return *this; 213 | } 214 | /** 215 | * \return the stream position 216 | */ 217 | pos_type tellp() { 218 | return tellpos(); 219 | } 220 | /** 221 | * Set the stream position 222 | * \param[in] pos The absolute position in which to move the write pointer. 223 | * \return Is always *this. Failure is indicated by the state of *this. 224 | */ 225 | ostream& seekp(pos_type pos) { 226 | if (!seekpos(pos)) { 227 | setstate(failbit); 228 | } 229 | return *this; 230 | } 231 | /** 232 | * Set the stream position. 233 | * 234 | * \param[in] off An offset to move the write pointer relative to way. 235 | * \a off is a signed 32-bit int so the offset is limited to +- 2GB. 236 | * \param[in] way One of ios::beg, ios::cur, or ios::end. 237 | * \return Is always *this. Failure is indicated by the state of *this. 238 | */ 239 | ostream& seekp(off_type off, seekdir way) { 240 | if (!seekoff(off, way)) { 241 | setstate(failbit); 242 | } 243 | return *this; 244 | } 245 | 246 | protected: 247 | /// @cond SHOW_PROTECTED 248 | /** Put character with binary/text conversion 249 | * \param[in] ch character to write 250 | */ 251 | virtual void putch(char ch) = 0; 252 | virtual void putstr(const char *str) = 0; 253 | virtual bool seekoff(off_type pos, seekdir way) = 0; 254 | virtual bool seekpos(pos_type pos) = 0; 255 | virtual bool sync() = 0; 256 | 257 | virtual pos_type tellpos() = 0; 258 | /// @endcond 259 | private: 260 | void do_fill(unsigned len); 261 | void fill_not_left(unsigned len); 262 | char* fmtNum(uint32_t n, char *ptr, uint8_t base); 263 | void putBool(bool b); 264 | void putChar(char c); 265 | void putDouble(double n); 266 | void putNum(uint32_t n, bool neg = false); 267 | void putNum(int32_t n); 268 | void putPgm(const char* str); 269 | void putStr(const char* str); 270 | }; 271 | #endif // ostream_h 272 | --------------------------------------------------------------------------------