arduino stuffs
Diffstat (limited to 'libraries/SD/src/utility/SdFat.h')
| -rw-r--r-- | libraries/SD/src/utility/SdFat.h | 641 |
1 files changed, 641 insertions, 0 deletions
diff --git a/libraries/SD/src/utility/SdFat.h b/libraries/SD/src/utility/SdFat.h new file mode 100644 index 0000000..a17458d --- /dev/null +++ b/libraries/SD/src/utility/SdFat.h @@ -0,0 +1,641 @@ +/* Arduino SdFat Library + Copyright (C) 2009 by William Greiman + + This file is part of the Arduino SdFat Library + + This Library is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the Arduino SdFat Library. If not, see + <http://www.gnu.org/licenses/>. +*/ +#ifndef SdFat_h +#define SdFat_h +/** + \file + SdFile and SdVolume classes +*/ +#if defined (__AVR__) || defined (__CPU_ARC__) + #include <avr/pgmspace.h> +#endif +#include "Sd2Card.h" +#include "FatStructs.h" +#include <Print.h> +//------------------------------------------------------------------------------ +/** + Allow use of deprecated functions if non-zero +*/ +#define ALLOW_DEPRECATED_FUNCTIONS 1 +//------------------------------------------------------------------------------ +// forward declaration since SdVolume is used in SdFile +class SdVolume; +//============================================================================== +// SdFile class + +#ifdef O_RDONLY //ARDUINO_ARCH_MBED +#undef O_READ +#undef O_RDONLY +#undef O_WRITE +#undef O_WRONLY +#undef O_RDWR +#undef O_ACCMODE +#undef O_APPEND +#undef O_SYNC +#undef O_CREAT +#undef O_EXCL +#undef O_TRUNC +#endif + +// flags for ls() +/** ls() flag to print modify date */ +uint8_t const LS_DATE = 1; +/** ls() flag to print file size */ +uint8_t const LS_SIZE = 2; +/** ls() flag for recursive list of subdirectories */ +uint8_t const LS_R = 4; + +// use the gnu style oflag in open() +/** open() oflag for reading */ +uint8_t const O_READ = 0X01; +/** open() oflag - same as O_READ */ +uint8_t const O_RDONLY = O_READ; +/** open() oflag for write */ +uint8_t const O_WRITE = 0X02; +/** open() oflag - same as O_WRITE */ +uint8_t const O_WRONLY = O_WRITE; +/** open() oflag for reading and writing */ +uint8_t const O_RDWR = (O_READ | O_WRITE); +/** open() oflag mask for access modes */ +uint8_t const O_ACCMODE = (O_READ | O_WRITE); +/** The file offset shall be set to the end of the file prior to each write. */ +uint8_t const O_APPEND = 0X04; +/** synchronous writes - call sync() after each write */ +uint8_t const O_SYNC = 0X08; +/** create the file if nonexistent */ +uint8_t const O_CREAT = 0X10; +/** If O_CREAT and O_EXCL are set, open() shall fail if the file exists */ +uint8_t const O_EXCL = 0X20; +/** truncate the file to zero length */ +uint8_t const O_TRUNC = 0X40; + +// flags for timestamp +/** set the file's last access date */ +uint8_t const T_ACCESS = 1; +/** set the file's creation date and time */ +uint8_t const T_CREATE = 2; +/** Set the file's write date and time */ +uint8_t const T_WRITE = 4; +// values for type_ +/** This SdFile has not been opened. */ +uint8_t const FAT_FILE_TYPE_CLOSED = 0; +/** SdFile for a file */ +uint8_t const FAT_FILE_TYPE_NORMAL = 1; +/** SdFile for a FAT16 root directory */ +uint8_t const FAT_FILE_TYPE_ROOT16 = 2; +/** SdFile for a FAT32 root directory */ +uint8_t const FAT_FILE_TYPE_ROOT32 = 3; +/** SdFile for a subdirectory */ +uint8_t const FAT_FILE_TYPE_SUBDIR = 4; +/** Test value for directory type */ +uint8_t const FAT_FILE_TYPE_MIN_DIR = FAT_FILE_TYPE_ROOT16; + +/** date field for FAT directory entry */ +static inline uint16_t FAT_DATE(uint16_t year, uint8_t month, uint8_t day) { + return (year - 1980) << 9 | month << 5 | day; +} +/** year part of FAT directory date field */ +static inline uint16_t FAT_YEAR(uint16_t fatDate) { + return 1980 + (fatDate >> 9); +} +/** month part of FAT directory date field */ +static inline uint8_t FAT_MONTH(uint16_t fatDate) { + return (fatDate >> 5) & 0XF; +} +/** day part of FAT directory date field */ +static inline uint8_t FAT_DAY(uint16_t fatDate) { + return fatDate & 0X1F; +} +/** time field for FAT directory entry */ +static inline uint16_t FAT_TIME(uint8_t hour, uint8_t minute, uint8_t second) { + return hour << 11 | minute << 5 | second >> 1; +} +/** hour part of FAT directory time field */ +static inline uint8_t FAT_HOUR(uint16_t fatTime) { + return fatTime >> 11; +} +/** minute part of FAT directory time field */ +static inline uint8_t FAT_MINUTE(uint16_t fatTime) { + return (fatTime >> 5) & 0X3F; +} +/** second part of FAT directory time field */ +static inline uint8_t FAT_SECOND(uint16_t fatTime) { + return 2 * (fatTime & 0X1F); +} +/** Default date for file timestamps is 1 Jan 2000 */ +uint16_t const FAT_DEFAULT_DATE = ((2000 - 1980) << 9) | (1 << 5) | 1; +/** Default time for file timestamp is 1 am */ +uint16_t const FAT_DEFAULT_TIME = (1 << 11); +//------------------------------------------------------------------------------ +/** + \class SdFile + \brief Access FAT16 and FAT32 files on SD and SDHC cards. +*/ +class SdFile : public Print { + public: + /** Create an instance of SdFile. */ + SdFile(void) : type_(FAT_FILE_TYPE_CLOSED) {} + /** + writeError is set to true if an error occurs during a write(). + Set writeError to false before calling print() and/or write() and check + for true after calls to print() and/or write(). + */ + //bool writeError; + /** + Cancel unbuffered reads for this file. + See setUnbufferedRead() + */ + void clearUnbufferedRead(void) { + flags_ &= ~F_FILE_UNBUFFERED_READ; + } + uint8_t close(void); + uint8_t contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock); + uint8_t createContiguous(SdFile* dirFile, + const char* fileName, uint32_t size); + /** \return The current cluster number for a file or directory. */ + uint32_t curCluster(void) const { + return curCluster_; + } + /** \return The current position for a file or directory. */ + uint32_t curPosition(void) const { + return curPosition_; + } + /** + Set the date/time callback function + + \param[in] dateTime The user's call back function. The callback + function is of the form: + + \code + void dateTime(uint16_t* date, uint16_t* time) { + uint16_t year; + uint8_t month, day, hour, minute, second; + + // User gets date and time from GPS or real-time clock here + + // return date using FAT_DATE macro to format fields + * *date = FAT_DATE(year, month, day); + + // return time using FAT_TIME macro to format fields + * *time = FAT_TIME(hour, minute, second); + } + \endcode + + Sets the function that is called when a file is created or when + a file's directory entry is modified by sync(). All timestamps, + access, creation, and modify, are set when a file is created. + sync() maintains the last access date and last modify date/time. + + See the timestamp() function. + */ + static void dateTimeCallback( + void (*dateTime)(uint16_t* date, uint16_t* time)) { + dateTime_ = dateTime; + } + /** + Cancel the date/time callback function. + */ + static void dateTimeCallbackCancel(void) { + // use explicit zero since NULL is not defined for Sanguino + dateTime_ = 0; + } + /** \return Address of the block that contains this file's directory. */ + uint32_t dirBlock(void) const { + return dirBlock_; + } + uint8_t dirEntry(dir_t* dir); + /** \return Index of this file's directory in the block dirBlock. */ + uint8_t dirIndex(void) const { + return dirIndex_; + } + static void dirName(const dir_t& dir, char* name); + /** \return The total number of bytes in a file or directory. */ + uint32_t fileSize(void) const { + return fileSize_; + } + /** \return The first cluster number for a file or directory. */ + uint32_t firstCluster(void) const { + return firstCluster_; + } + /** \return True if this is a SdFile for a directory else false. */ + uint8_t isDir(void) const { + return type_ >= FAT_FILE_TYPE_MIN_DIR; + } + /** \return True if this is a SdFile for a file else false. */ + uint8_t isFile(void) const { + return type_ == FAT_FILE_TYPE_NORMAL; + } + /** \return True if this is a SdFile for an open file/directory else false. */ + uint8_t isOpen(void) const { + return type_ != FAT_FILE_TYPE_CLOSED; + } + /** \return True if this is a SdFile for a subdirectory else false. */ + uint8_t isSubDir(void) const { + return type_ == FAT_FILE_TYPE_SUBDIR; + } + /** \return True if this is a SdFile for the root directory. */ + uint8_t isRoot(void) const { + return type_ == FAT_FILE_TYPE_ROOT16 || type_ == FAT_FILE_TYPE_ROOT32; + } + void ls(uint8_t flags = 0, uint8_t indent = 0); + uint8_t makeDir(SdFile* dir, const char* dirName); + uint8_t open(SdFile* dirFile, uint16_t index, uint8_t oflag); + uint8_t open(SdFile* dirFile, const char* fileName, uint8_t oflag); + + uint8_t openRoot(SdVolume* vol); + static void printDirName(const dir_t& dir, uint8_t width); + static void printFatDate(uint16_t fatDate); + static void printFatTime(uint16_t fatTime); + static void printTwoDigits(uint8_t v); + /** + Read the next byte from a file. + + \return For success read returns the next byte in the file as an int. + If an error occurs or end of file is reached -1 is returned. + */ + int16_t read(void) { + uint8_t b; + return read(&b, 1) == 1 ? b : -1; + } + int16_t read(void* buf, uint16_t nbyte); + int8_t readDir(dir_t* dir); + static uint8_t remove(SdFile* dirFile, const char* fileName); + uint8_t remove(void); + /** Set the file's current position to zero. */ + void rewind(void) { + curPosition_ = curCluster_ = 0; + } + uint8_t rmDir(void); + uint8_t rmRfStar(void); + /** Set the files position to current position + \a pos. See seekSet(). */ + uint8_t seekCur(uint32_t pos) { + return seekSet(curPosition_ + pos); + } + /** + Set the files current position to end of file. Useful to position + a file for append. See seekSet(). + */ + uint8_t seekEnd(void) { + return seekSet(fileSize_); + } + uint8_t seekSet(uint32_t pos); + /** + Use unbuffered reads to access this file. Used with Wave + Shield ISR. Used with Sd2Card::partialBlockRead() in WaveRP. + + Not recommended for normal applications. + */ + void setUnbufferedRead(void) { + if (isFile()) { + flags_ |= F_FILE_UNBUFFERED_READ; + } + } + uint8_t timestamp(uint8_t flag, uint16_t year, uint8_t month, uint8_t day, + uint8_t hour, uint8_t minute, uint8_t second); + uint8_t sync(uint8_t blocking = 1); + /** Type of this SdFile. You should use isFile() or isDir() instead of type() + if possible. + + \return The file or directory type. + */ + uint8_t type(void) const { + return type_; + } + uint8_t truncate(uint32_t size); + /** \return Unbuffered read flag. */ + uint8_t unbufferedRead(void) const { + return flags_ & F_FILE_UNBUFFERED_READ; + } + /** \return SdVolume that contains this file. */ + SdVolume* volume(void) const { + return vol_; + } + size_t write(uint8_t b); + size_t write(const void* buf, uint16_t nbyte); + size_t write(const char* str); + #ifdef __AVR__ + void write_P(PGM_P str); + void writeln_P(PGM_P str); + #endif + int availableForWrite(void); + //------------------------------------------------------------------------------ + #if ALLOW_DEPRECATED_FUNCTIONS + // Deprecated functions - suppress cpplint warnings with NOLINT comment + /** \deprecated Use: + uint8_t SdFile::contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock); + */ + uint8_t contiguousRange(uint32_t& bgnBlock, uint32_t& endBlock) { // NOLINT + return contiguousRange(&bgnBlock, &endBlock); + } + /** \deprecated Use: + uint8_t SdFile::createContiguous(SdFile* dirFile, + const char* fileName, uint32_t size) + */ + uint8_t createContiguous(SdFile& dirFile, // NOLINT + const char* fileName, uint32_t size) { + return createContiguous(&dirFile, fileName, size); + } + + /** + \deprecated Use: + static void SdFile::dateTimeCallback( + void (*dateTime)(uint16_t* date, uint16_t* time)); + */ + static void dateTimeCallback( + void (*dateTime)(uint16_t& date, uint16_t& time)) { // NOLINT + oldDateTime_ = dateTime; + dateTime_ = dateTime ? oldToNew : 0; + } + /** \deprecated Use: uint8_t SdFile::dirEntry(dir_t* dir); */ + uint8_t dirEntry(dir_t& dir) { + return dirEntry(&dir); // NOLINT + } + /** \deprecated Use: + uint8_t SdFile::makeDir(SdFile* dir, const char* dirName); + */ + uint8_t makeDir(SdFile& dir, const char* dirName) { // NOLINT + return makeDir(&dir, dirName); + } + /** \deprecated Use: + uint8_t SdFile::open(SdFile* dirFile, const char* fileName, uint8_t oflag); + */ + uint8_t open(SdFile& dirFile, // NOLINT + const char* fileName, uint8_t oflag) { + return open(&dirFile, fileName, oflag); + } + /** \deprecated Do not use in new apps */ + uint8_t open(SdFile& dirFile, const char* fileName) { // NOLINT + return open(dirFile, fileName, O_RDWR); + } + /** \deprecated Use: + uint8_t SdFile::open(SdFile* dirFile, uint16_t index, uint8_t oflag); + */ + uint8_t open(SdFile& dirFile, uint16_t index, uint8_t oflag) { // NOLINT + return open(&dirFile, index, oflag); + } + /** \deprecated Use: uint8_t SdFile::openRoot(SdVolume* vol); */ + uint8_t openRoot(SdVolume& vol) { + return openRoot(&vol); // NOLINT + } + + /** \deprecated Use: int8_t SdFile::readDir(dir_t* dir); */ + int8_t readDir(dir_t& dir) { + return readDir(&dir); // NOLINT + } + /** \deprecated Use: + static uint8_t SdFile::remove(SdFile* dirFile, const char* fileName); + */ + static uint8_t remove(SdFile& dirFile, const char* fileName) { // NOLINT + return remove(&dirFile, fileName); + } + //------------------------------------------------------------------------------ + // rest are private + private: + static void (*oldDateTime_)(uint16_t& date, uint16_t& time); // NOLINT + static void oldToNew(uint16_t* date, uint16_t* time) { + uint16_t d; + uint16_t t; + oldDateTime_(d, t); + *date = d; + *time = t; + } + #endif // ALLOW_DEPRECATED_FUNCTIONS + private: + // bits defined in flags_ + // should be 0XF + static uint8_t const F_OFLAG = (O_ACCMODE | O_APPEND | O_SYNC); + // available bits + static uint8_t const F_FILE_NON_BLOCKING_WRITE = 0X10; + // a new cluster was added to the file + static uint8_t const F_FILE_CLUSTER_ADDED = 0X20; + // use unbuffered SD read + static uint8_t const F_FILE_UNBUFFERED_READ = 0X40; + // sync of directory entry required + static uint8_t const F_FILE_DIR_DIRTY = 0X80; + + // make sure F_OFLAG is ok + #if ((F_FILE_NON_BLOCKING_WRITE | F_FILE_CLUSTER_ADDED | F_FILE_UNBUFFERED_READ | F_FILE_DIR_DIRTY) & F_OFLAG) +#error flags_ bits conflict + #endif // flags_ bits + + // private data + uint8_t flags_; // See above for definition of flags_ bits + uint8_t type_; // type of file see above for values + uint32_t curCluster_; // cluster for current file position + uint32_t curPosition_; // current file position in bytes from beginning + uint32_t dirBlock_; // SD block that contains directory entry for file + uint8_t dirIndex_; // index of entry in dirBlock 0 <= dirIndex_ <= 0XF + uint32_t fileSize_; // file size in bytes + uint32_t firstCluster_; // first cluster of file + SdVolume* vol_; // volume where file is located + + // private functions + uint8_t addCluster(void); + uint8_t addDirCluster(void); + dir_t* cacheDirEntry(uint8_t action); + static void (*dateTime_)(uint16_t* date, uint16_t* time); + static uint8_t make83Name(const char* str, uint8_t* name); + uint8_t openCachedEntry(uint8_t cacheIndex, uint8_t oflags); + dir_t* readDirCache(void); +}; +//============================================================================== +// SdVolume class +/** + \brief Cache for an SD data block +*/ +union cache_t { + /** Used to access cached file data blocks. */ + uint8_t data[512]; + /** Used to access cached FAT16 entries. */ + uint16_t fat16[256]; + /** Used to access cached FAT32 entries. */ + uint32_t fat32[128]; + /** Used to access cached directory entries. */ + dir_t dir[16]; + /** Used to access a cached MasterBoot Record. */ + mbr_t mbr; + /** Used to access to a cached FAT boot sector. */ + fbs_t fbs; +}; +//------------------------------------------------------------------------------ +/** + \class SdVolume + \brief Access FAT16 and FAT32 volumes on SD and SDHC cards. +*/ +class SdVolume { + public: + /** Create an instance of SdVolume */ + SdVolume(void) : allocSearchStart_(2), fatType_(0) {} + /** Clear the cache and returns a pointer to the cache. Used by the WaveRP + recorder to do raw write to the SD card. Not for normal apps. + */ + static uint8_t* cacheClear(void) { + cacheFlush(); + cacheBlockNumber_ = 0XFFFFFFFF; + return cacheBuffer_.data; + } + /** + Initialize a FAT volume. Try partition one first then try super + floppy format. + + \param[in] dev The Sd2Card where the volume is located. + + \return The value one, true, is returned for success and + the value zero, false, is returned for failure. Reasons for + failure include not finding a valid partition, not finding a valid + FAT file system or an I/O error. + */ + uint8_t init(Sd2Card* dev) { + return init(dev, 1) ? true : init(dev, 0); + } + uint8_t init(Sd2Card* dev, uint8_t part); + + // inline functions that return volume info + /** \return The volume's cluster size in blocks. */ + uint8_t blocksPerCluster(void) const { + return blocksPerCluster_; + } + /** \return The number of blocks in one FAT. */ + uint32_t blocksPerFat(void) const { + return blocksPerFat_; + } + /** \return The total number of clusters in the volume. */ + uint32_t clusterCount(void) const { + return clusterCount_; + } + /** \return The shift count required to multiply by blocksPerCluster. */ + uint8_t clusterSizeShift(void) const { + return clusterSizeShift_; + } + /** \return The logical block number for the start of file data. */ + uint32_t dataStartBlock(void) const { + return dataStartBlock_; + } + /** \return The number of FAT structures on the volume. */ + uint8_t fatCount(void) const { + return fatCount_; + } + /** \return The logical block number for the start of the first FAT. */ + uint32_t fatStartBlock(void) const { + return fatStartBlock_; + } + /** \return The FAT type of the volume. Values are 12, 16 or 32. */ + uint8_t fatType(void) const { + return fatType_; + } + /** \return The number of entries in the root directory for FAT16 volumes. */ + uint32_t rootDirEntryCount(void) const { + return rootDirEntryCount_; + } + /** \return The logical block number for the start of the root directory + on FAT16 volumes or the first cluster number on FAT32 volumes. */ + uint32_t rootDirStart(void) const { + return rootDirStart_; + } + /** return a pointer to the Sd2Card object for this volume */ + static Sd2Card* sdCard(void) { + return sdCard_; + } + //------------------------------------------------------------------------------ + #if ALLOW_DEPRECATED_FUNCTIONS + // Deprecated functions - suppress cpplint warnings with NOLINT comment + /** \deprecated Use: uint8_t SdVolume::init(Sd2Card* dev); */ + uint8_t init(Sd2Card& dev) { + return init(&dev); // NOLINT + } + + /** \deprecated Use: uint8_t SdVolume::init(Sd2Card* dev, uint8_t vol); */ + uint8_t init(Sd2Card& dev, uint8_t part) { // NOLINT + return init(&dev, part); + } + #endif // ALLOW_DEPRECATED_FUNCTIONS + //------------------------------------------------------------------------------ + private: + // Allow SdFile access to SdVolume private data. + friend class SdFile; + + // value for action argument in cacheRawBlock to indicate read from cache + static uint8_t const CACHE_FOR_READ = 0; + // value for action argument in cacheRawBlock to indicate cache dirty + static uint8_t const CACHE_FOR_WRITE = 1; + + static cache_t cacheBuffer_; // 512 byte cache for device blocks + static uint32_t cacheBlockNumber_; // Logical number of block in the cache + static Sd2Card* sdCard_; // Sd2Card object for cache + static uint8_t cacheDirty_; // cacheFlush() will write block if true + static uint32_t cacheMirrorBlock_; // block number for mirror FAT + // + uint32_t allocSearchStart_; // start cluster for alloc search + uint8_t blocksPerCluster_; // cluster size in blocks + uint32_t blocksPerFat_; // FAT size in blocks + uint32_t clusterCount_; // clusters in one FAT + uint8_t clusterSizeShift_; // shift to convert cluster count to block count + uint32_t dataStartBlock_; // first data block number + uint8_t fatCount_; // number of FATs on volume + uint32_t fatStartBlock_; // start block for first FAT + uint8_t fatType_; // volume type (12, 16, OR 32) + uint16_t rootDirEntryCount_; // number of entries in FAT16 root dir + uint32_t rootDirStart_; // root start block for FAT16, cluster for FAT32 + //---------------------------------------------------------------------------- + uint8_t allocContiguous(uint32_t count, uint32_t* curCluster); + uint8_t blockOfCluster(uint32_t position) const { + return (position >> 9) & (blocksPerCluster_ - 1); + } + uint32_t clusterStartBlock(uint32_t cluster) const { + return dataStartBlock_ + ((cluster - 2) << clusterSizeShift_); + } + uint32_t blockNumber(uint32_t cluster, uint32_t position) const { + return clusterStartBlock(cluster) + blockOfCluster(position); + } + static uint8_t cacheFlush(uint8_t blocking = 1); + static uint8_t cacheMirrorBlockFlush(uint8_t blocking); + static uint8_t cacheRawBlock(uint32_t blockNumber, uint8_t action); + static void cacheSetDirty(void) { + cacheDirty_ |= CACHE_FOR_WRITE; + } + static uint8_t cacheZeroBlock(uint32_t blockNumber); + uint8_t chainSize(uint32_t beginCluster, uint32_t* size) const; + uint8_t fatGet(uint32_t cluster, uint32_t* value) const; + uint8_t fatPut(uint32_t cluster, uint32_t value); + uint8_t fatPutEOC(uint32_t cluster) { + return fatPut(cluster, 0x0FFFFFFF); + } + uint8_t freeChain(uint32_t cluster); + uint8_t isEOC(uint32_t cluster) const { + return cluster >= (fatType_ == 16 ? FAT16EOC_MIN : FAT32EOC_MIN); + } + uint8_t readBlock(uint32_t block, uint8_t* dst) { + return sdCard_->readBlock(block, dst); + } + uint8_t readData(uint32_t block, uint16_t offset, + uint16_t count, uint8_t* dst) { + return sdCard_->readData(block, offset, count, dst); + } + uint8_t writeBlock(uint32_t block, const uint8_t* dst, uint8_t blocking = 1) { + return sdCard_->writeBlock(block, dst, blocking); + } + uint8_t isBusy(void) { + return sdCard_->isBusy(); + } + uint8_t isCacheMirrorBlockDirty(void) { + return (cacheMirrorBlock_ != 0); + } +}; +#endif // SdFat_h |