From e5a92b21937c42cf4768f10850247d8c730e35b1 Mon Sep 17 00:00:00 2001 From: Daniel Melendrez Date: Mon, 4 Mar 2024 23:28:33 +0000 Subject: [PATCH 1/2] Made it possible to print to any HardwareSerial object pointer, not only Serial --- src/utility/SdFat.h | 1011 +++++++++++++++++++++------------------- src/utility/SdFile.cpp | 845 +++++++++++++++++++++------------ 2 files changed, 1086 insertions(+), 770 deletions(-) diff --git a/src/utility/SdFat.h b/src/utility/SdFat.h index 46b880b..676c89b 100644 --- a/src/utility/SdFat.h +++ b/src/utility/SdFat.h @@ -23,12 +23,13 @@ \file SdFile and SdVolume classes */ -#if defined (__AVR__) || defined (__CPU_ARC__) - #include +#if defined(__AVR__) || defined(__CPU_ARC__) +#include #endif #include "Sd2Card.h" #include "FatStructs.h" #include +#include //------------------------------------------------------------------------------ /** Allow use of deprecated functions if non-zero @@ -40,18 +41,18 @@ 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 +#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() @@ -108,35 +109,43 @@ uint8_t const FAT_FILE_TYPE_SUBDIR = 4; 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) { +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) { +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) { +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) { +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) { +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) { +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) { +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) { +static inline uint8_t FAT_SECOND(uint16_t fatTime) +{ return 2 * (fatTime & 0X1F); } /** Default date for file timestamps is 1 Jan 2000 */ @@ -148,494 +157,558 @@ 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 +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: + \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; + \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 + // 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 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 + // 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. + 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); + 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, HardwareSerial *port = &Serial); + 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. + uint8_t openRoot(SdVolume *vol); + static void printDirName(const dir_t &dir, uint8_t width, HardwareSerial *port = &Serial); + static void printFatDate(uint16_t fatDate, HardwareSerial *port = &Serial); + static void printFatTime(uint16_t fatTime, HardwareSerial *port = &Serial); + static void printTwoDigits(uint8_t v, HardwareSerial *port = &Serial); + /** + 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. + \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. + 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); - } + \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: + 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; + /** \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) +// 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 +#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 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); + // 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 { +union cache_t +{ /** Used to access cached file data blocks. */ - uint8_t data[512]; + 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]; + dir_t dir[16]; /** Used to access a cached MasterBoot Record. */ - mbr_t mbr; + mbr_t mbr; /** Used to access to a cached FAT boot sector. */ - fbs_t fbs; + 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. +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. + \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); + \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 - } + // 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; + /** \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; + // 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); - } + 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 +#endif // SdFat_h diff --git a/src/utility/SdFile.cpp b/src/utility/SdFile.cpp index 18a1db6..168661f 100644 --- a/src/utility/SdFile.cpp +++ b/src/utility/SdFile.cpp @@ -19,26 +19,29 @@ */ #include "SdFat.h" #ifdef __AVR__ - #include +#include #endif #include //------------------------------------------------------------------------------ // callback function for date/time -void (*SdFile::dateTime_)(uint16_t* date, uint16_t* time) = NULL; +void (*SdFile::dateTime_)(uint16_t *date, uint16_t *time) = NULL; #if ALLOW_DEPRECATED_FUNCTIONS - // suppress cpplint warnings with NOLINT comment - void (*SdFile::oldDateTime_)(uint16_t& date, uint16_t& time) = NULL; // NOLINT -#endif // ALLOW_DEPRECATED_FUNCTIONS +// suppress cpplint warnings with NOLINT comment +void (*SdFile::oldDateTime_)(uint16_t &date, uint16_t &time) = NULL; // NOLINT +#endif // ALLOW_DEPRECATED_FUNCTIONS //------------------------------------------------------------------------------ // add a cluster to a file -uint8_t SdFile::addCluster() { - if (!vol_->allocContiguous(1, &curCluster_)) { +uint8_t SdFile::addCluster() +{ + if (!vol_->allocContiguous(1, &curCluster_)) + { return false; } // if first cluster of file link to directory entry - if (firstCluster_ == 0) { + if (firstCluster_ == 0) + { firstCluster_ = curCluster_; flags_ |= F_FILE_DIR_DIRTY; } @@ -48,15 +51,19 @@ uint8_t SdFile::addCluster() { //------------------------------------------------------------------------------ // Add a cluster to a directory file and zero the cluster. // return with first block of cluster in the cache -uint8_t SdFile::addDirCluster(void) { - if (!addCluster()) { +uint8_t SdFile::addDirCluster(void) +{ + if (!addCluster()) + { return false; } // zero data in cluster insure first cluster is in cache uint32_t block = vol_->clusterStartBlock(curCluster_); - for (uint8_t i = vol_->blocksPerCluster_; i != 0; i--) { - if (!SdVolume::cacheZeroBlock(block + i - 1)) { + for (uint8_t i = vol_->blocksPerCluster_; i != 0; i--) + { + if (!SdVolume::cacheZeroBlock(block + i - 1)) + { return false; } } @@ -67,8 +74,10 @@ uint8_t SdFile::addDirCluster(void) { //------------------------------------------------------------------------------ // cache a file's directory entry // return pointer to cached entry or null for failure -dir_t* SdFile::cacheDirEntry(uint8_t action) { - if (!SdVolume::cacheRawBlock(dirBlock_, action)) { +dir_t *SdFile::cacheDirEntry(uint8_t action) +{ + if (!SdVolume::cacheRawBlock(dirBlock_, action)) + { return NULL; } return SdVolume::cacheBuffer_.dir + dirIndex_; @@ -82,8 +91,10 @@ dir_t* SdFile::cacheDirEntry(uint8_t action) { the value zero, false, is returned for failure. Reasons for failure include no file is open or an I/O error. */ -uint8_t SdFile::close(void) { - if (!sync()) { +uint8_t SdFile::close(void) +{ + if (!sync()) + { return false; } type_ = FAT_FILE_TYPE_CLOSED; @@ -101,27 +112,32 @@ uint8_t SdFile::close(void) { Reasons for failure include file is not contiguous, file has zero length or an I/O error occurred. */ -uint8_t SdFile::contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock) { +uint8_t SdFile::contiguousRange(uint32_t *bgnBlock, uint32_t *endBlock) +{ // error if no blocks - if (firstCluster_ == 0) { + if (firstCluster_ == 0) + { return false; } - for (uint32_t c = firstCluster_; ; c++) { + for (uint32_t c = firstCluster_;; c++) + { uint32_t next; - if (!vol_->fatGet(c, &next)) { + if (!vol_->fatGet(c, &next)) + { return false; } // check for contiguous - if (next != (c + 1)) { + if (next != (c + 1)) + { // error if not end of chain - if (!vol_->isEOC(next)) { + if (!vol_->isEOC(next)) + { return false; } *bgnBlock = vol_->clusterStartBlock(firstCluster_); - *endBlock = vol_->clusterStartBlock(c) - + vol_->blocksPerCluster_ - 1; + *endBlock = vol_->clusterStartBlock(c) + vol_->blocksPerCluster_ - 1; return true; } } @@ -145,13 +161,16 @@ uint8_t SdFile::contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock) { directory is full or an I/O error. */ -uint8_t SdFile::createContiguous(SdFile* dirFile, - const char* fileName, uint32_t size) { +uint8_t SdFile::createContiguous(SdFile *dirFile, + const char *fileName, uint32_t size) +{ // don't allow zero length file - if (size == 0) { + if (size == 0) + { return false; } - if (!open(dirFile, fileName, O_CREAT | O_EXCL | O_RDWR)) { + if (!open(dirFile, fileName, O_CREAT | O_EXCL | O_RDWR)) + { return false; } @@ -159,7 +178,8 @@ uint8_t SdFile::createContiguous(SdFile* dirFile, uint32_t count = ((size - 1) >> (vol_->clusterSizeShift_ + 9)) + 1; // allocate clusters - if (!vol_->allocContiguous(count, &firstCluster_)) { + if (!vol_->allocContiguous(count, &firstCluster_)) + { remove(); return false; } @@ -178,15 +198,18 @@ uint8_t SdFile::createContiguous(SdFile* dirFile, \return The value one, true, is returned for success and the value zero, false, is returned for failure. */ -uint8_t SdFile::dirEntry(dir_t* dir) { +uint8_t SdFile::dirEntry(dir_t *dir) +{ // make sure fields on SD are correct - if (!sync()) { + if (!sync()) + { return false; } // read entry - dir_t* p = cacheDirEntry(SdVolume::CACHE_FOR_READ); - if (!p) { + dir_t *p = cacheDirEntry(SdVolume::CACHE_FOR_READ); + if (!p) + { return false; } @@ -202,13 +225,17 @@ uint8_t SdFile::dirEntry(dir_t* dir) { \param[in] dir The directory structure containing the name. \param[out] name A 13 byte char array for the formatted name. */ -void SdFile::dirName(const dir_t& dir, char* name) { +void SdFile::dirName(const dir_t &dir, char *name) +{ uint8_t j = 0; - for (uint8_t i = 0; i < 11; i++) { - if (dir.name[i] == ' ') { + for (uint8_t i = 0; i < 11; i++) + { + if (dir.name[i] == ' ') + { continue; } - if (i == 8) { + if (i == 8) + { name[j++] = '.'; } name[j++] = dir.name[i]; @@ -216,7 +243,7 @@ void SdFile::dirName(const dir_t& dir, char* name) { name[j] = 0; } //------------------------------------------------------------------------------ -/** List directory contents to Serial. +/** List directory contents to port-> \param[in] flags The inclusive OR of @@ -229,52 +256,62 @@ void SdFile::dirName(const dir_t& dir, char* name) { \param[in] indent Amount of space before file name. Used for recursive list to indicate subdirectory level. */ -void SdFile::ls(uint8_t flags, uint8_t indent) { - dir_t* p; +void SdFile::ls(uint8_t flags, uint8_t indent, HardwareSerial *port) +{ + dir_t *p; rewind(); - while ((p = readDirCache())) { + while ((p = readDirCache())) + { // done if past last used entry - if (p->name[0] == DIR_NAME_FREE) { + if (p->name[0] == DIR_NAME_FREE) + { break; } // skip deleted entry and entries for . and .. - if (p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') { + if (p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') + { continue; } // only list subdirectories and files - if (!DIR_IS_FILE_OR_SUBDIR(p)) { + if (!DIR_IS_FILE_OR_SUBDIR(p)) + { continue; } // print any indent spaces - for (int8_t i = 0; i < indent; i++) { - Serial.print(' '); + for (int8_t i = 0; i < indent; i++) + { + port->print(' '); } // print file name with possible blank fill - printDirName(*p, flags & (LS_DATE | LS_SIZE) ? 14 : 0); + printDirName(*p, flags & (LS_DATE | LS_SIZE) ? 14 : 0, port); // print modify date/time if requested - if (flags & LS_DATE) { + if (flags & LS_DATE) + { printFatDate(p->lastWriteDate); - Serial.print(' '); + port->print(' '); printFatTime(p->lastWriteTime); } // print size if requested - if (!DIR_IS_SUBDIR(p) && (flags & LS_SIZE)) { - Serial.print(' '); - Serial.print(p->fileSize); + if (!DIR_IS_SUBDIR(p) && (flags & LS_SIZE)) + { + port->print(' '); + port->print(p->fileSize); } - Serial.println(); + port->println(); // list subdirectory content if requested - if ((flags & LS_R) && DIR_IS_SUBDIR(p)) { + if ((flags & LS_R) && DIR_IS_SUBDIR(p)) + { uint16_t index = curPosition() / 32 - 1; SdFile s; - if (s.open(this, index, O_READ)) { + if (s.open(this, index, O_READ)) + { s.ls(flags, indent + 2); } seekSet(32 * (index + 1)); @@ -283,43 +320,55 @@ void SdFile::ls(uint8_t flags, uint8_t indent) { } //------------------------------------------------------------------------------ // format directory name field from a 8.3 name string -uint8_t SdFile::make83Name(const char* str, uint8_t* name) { +uint8_t SdFile::make83Name(const char *str, uint8_t *name) +{ uint8_t c; - uint8_t n = 7; // max index for part before dot + uint8_t n = 7; // max index for part before dot uint8_t i = 0; // blank fill name and extension - while (i < 11) { + while (i < 11) + { name[i++] = ' '; } i = 0; - while ((c = *str++) != '\0') { - if (c == '.') { - if (n == 10) { - return false; // only one dot allowed + while ((c = *str++) != '\0') + { + if (c == '.') + { + if (n == 10) + { + return false; // only one dot allowed } - n = 10; // max index for full 8.3 name - i = 8; // place for extension - } else { + n = 10; // max index for full 8.3 name + i = 8; // place for extension + } + else + { // illegal FAT characters uint8_t b; - #if defined(__AVR__) +#if defined(__AVR__) PGM_P p = PSTR("|<>^+=?/[];,*\"\\"); - while ((b = pgm_read_byte(p++))) if (b == c) { + while ((b = pgm_read_byte(p++))) + if (b == c) + { return false; } - #elif defined(__arm__) +#elif defined(__arm__) const uint8_t valid[] = "|<>^+=?/[];,*\"\\"; const uint8_t *p = valid; - while ((b = *p++)) if (b == c) { + while ((b = *p++)) + if (b == c) + { return false; } - #endif +#endif // check size and only allow ASCII printable characters - if (i > n || c < 0X21 || c > 0X7E) { + if (i > n || c < 0X21 || c > 0X7E) + { return false; } // only upper case allowed in 8.3 names - convert lower to upper - name[i++] = c < 'a' || c > 'z' ? c : c + ('A' - 'a'); + name[i++] = c < 'a' || c > 'z' ? c : c + ('A' - 'a'); } } // must have a file name, extension is optional @@ -338,11 +387,13 @@ uint8_t SdFile::make83Name(const char* str, uint8_t* name) { Reasons for failure include this SdFile is already open, \a dir is not a directory, \a dirName is invalid or already exists in \a dir. */ -uint8_t SdFile::makeDir(SdFile* dir, const char* dirName) { +uint8_t SdFile::makeDir(SdFile *dir, const char *dirName) +{ dir_t d; // create a normal file - if (!open(dir, dirName, O_CREAT | O_EXCL | O_RDWR)) { + if (!open(dir, dirName, O_CREAT | O_EXCL | O_RDWR)) + { return false; } @@ -351,18 +402,21 @@ uint8_t SdFile::makeDir(SdFile* dir, const char* dirName) { type_ = FAT_FILE_TYPE_SUBDIR; // allocate and zero first cluster - if (!addDirCluster()) { + if (!addDirCluster()) + { return false; } // force entry to SD - if (!sync()) { + if (!sync()) + { return false; } // cache entry - should already be in cache due to sync() call - dir_t* p = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); - if (!p) { + dir_t *p = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); + if (!p) + { return false; } @@ -371,14 +425,16 @@ uint8_t SdFile::makeDir(SdFile* dir, const char* dirName) { // make entry for '.' memcpy(&d, p, sizeof(d)); - for (uint8_t i = 1; i < 11; i++) { + for (uint8_t i = 1; i < 11; i++) + { d.name[i] = ' '; } d.name[0] = '.'; // cache block for '.' and '..' uint32_t block = vol_->clusterStartBlock(firstCluster_); - if (!SdVolume::cacheRawBlock(block, SdVolume::CACHE_FOR_WRITE)) { + if (!SdVolume::cacheRawBlock(block, SdVolume::CACHE_FOR_WRITE)) + { return false; } @@ -387,10 +443,13 @@ uint8_t SdFile::makeDir(SdFile* dir, const char* dirName) { // make entry for '..' d.name[1] = '.'; - if (dir->isRoot()) { + if (dir->isRoot()) + { d.firstClusterLow = 0; d.firstClusterHigh = 0; - } else { + } + else + { d.firstClusterLow = dir->firstCluster_ & 0XFFFF; d.firstClusterHigh = dir->firstCluster_ >> 16; } @@ -450,16 +509,19 @@ uint8_t SdFile::makeDir(SdFile* dir, const char* dirName) { a directory, \a fileName is invalid, the file does not exist or can't be opened in the access mode specified by oflag. */ -uint8_t SdFile::open(SdFile* dirFile, const char* fileName, uint8_t oflag) { +uint8_t SdFile::open(SdFile *dirFile, const char *fileName, uint8_t oflag) +{ uint8_t dname[11]; - dir_t* p; + dir_t *p; // error if already open - if (isOpen()) { + if (isOpen()) + { return false; } - if (!make83Name(fileName, dname)) { + if (!make83Name(fileName, dname)) + { return false; } vol_ = dirFile->vol_; @@ -469,27 +531,35 @@ uint8_t SdFile::open(SdFile* dirFile, const char* fileName, uint8_t oflag) { uint8_t emptyFound = false; // search for file - while (dirFile->curPosition_ < dirFile->fileSize_) { + while (dirFile->curPosition_ < dirFile->fileSize_) + { uint8_t index = 0XF & (dirFile->curPosition_ >> 5); p = dirFile->readDirCache(); - if (p == NULL) { + if (p == NULL) + { return false; } - if (p->name[0] == DIR_NAME_FREE || p->name[0] == DIR_NAME_DELETED) { + if (p->name[0] == DIR_NAME_FREE || p->name[0] == DIR_NAME_DELETED) + { // remember first empty slot - if (!emptyFound) { + if (!emptyFound) + { emptyFound = true; dirIndex_ = index; dirBlock_ = SdVolume::cacheBlockNumber_; } // done if no entries follow - if (p->name[0] == DIR_NAME_FREE) { + if (p->name[0] == DIR_NAME_FREE) + { break; } - } else if (!memcmp(dname, p->name, 11)) { + } + else if (!memcmp(dname, p->name, 11)) + { // don't open existing file if O_CREAT and O_EXCL - if ((oflag & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) { + if ((oflag & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) + { return false; } @@ -498,23 +568,30 @@ uint8_t SdFile::open(SdFile* dirFile, const char* fileName, uint8_t oflag) { } } // only create file if O_CREAT and O_WRITE - if ((oflag & (O_CREAT | O_WRITE)) != (O_CREAT | O_WRITE)) { + if ((oflag & (O_CREAT | O_WRITE)) != (O_CREAT | O_WRITE)) + { return false; } // cache found slot or add cluster if end of file - if (emptyFound) { + if (emptyFound) + { p = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); - if (!p) { + if (!p) + { return false; } - } else { - if (dirFile->type_ == FAT_FILE_TYPE_ROOT16) { + } + else + { + if (dirFile->type_ == FAT_FILE_TYPE_ROOT16) + { return false; } // add and zero cluster for dirFile - first cluster is in cache for write - if (!dirFile->addDirCluster()) { + if (!dirFile->addDirCluster()) + { return false; } @@ -527,10 +604,13 @@ uint8_t SdFile::open(SdFile* dirFile, const char* fileName, uint8_t oflag) { memcpy(p->name, dname, 11); // set timestamps - if (dateTime_) { + if (dateTime_) + { // call user function dateTime_(&p->creationDate, &p->creationTime); - } else { + } + else + { // use default date/time p->creationDate = FAT_DEFAULT_DATE; p->creationTime = FAT_DEFAULT_TIME; @@ -540,7 +620,8 @@ uint8_t SdFile::open(SdFile* dirFile, const char* fileName, uint8_t oflag) { p->lastWriteTime = p->creationTime; // force write of entry to SD - if (!SdVolume::cacheFlush()) { + if (!SdVolume::cacheFlush()) + { return false; } @@ -562,33 +643,39 @@ uint8_t SdFile::open(SdFile* dirFile, const char* fileName, uint8_t oflag) { See open() by fileName for definition of flags and return values. */ -uint8_t SdFile::open(SdFile* dirFile, uint16_t index, uint8_t oflag) { +uint8_t SdFile::open(SdFile *dirFile, uint16_t index, uint8_t oflag) +{ // error if already open - if (isOpen()) { + if (isOpen()) + { return false; } // don't open existing file if O_CREAT and O_EXCL - user call error - if ((oflag & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) { + if ((oflag & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) + { return false; } vol_ = dirFile->vol_; // seek to location of entry - if (!dirFile->seekSet(32 * index)) { + if (!dirFile->seekSet(32 * index)) + { return false; } // read entry into cache - dir_t* p = dirFile->readDirCache(); - if (p == NULL) { + dir_t *p = dirFile->readDirCache(); + if (p == NULL) + { return false; } // error if empty slot or '.' or '..' if (p->name[0] == DIR_NAME_FREE || - p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') { + p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') + { return false; } // open cached entry @@ -596,13 +683,16 @@ uint8_t SdFile::open(SdFile* dirFile, uint16_t index, uint8_t oflag) { } //------------------------------------------------------------------------------ // open a cached directory entry. Assumes vol_ is initializes -uint8_t SdFile::openCachedEntry(uint8_t dirIndex, uint8_t oflag) { +uint8_t SdFile::openCachedEntry(uint8_t dirIndex, uint8_t oflag) +{ // location of entry in cache - dir_t* p = SdVolume::cacheBuffer_.dir + dirIndex; + dir_t *p = SdVolume::cacheBuffer_.dir + dirIndex; // write or truncate is an error for a directory or read-only file - if (p->attributes & (DIR_ATT_READ_ONLY | DIR_ATT_DIRECTORY)) { - if (oflag & (O_WRITE | O_TRUNC)) { + if (p->attributes & (DIR_ATT_READ_ONLY | DIR_ATT_DIRECTORY)) + { + if (oflag & (O_WRITE | O_TRUNC)) + { return false; } } @@ -615,15 +705,21 @@ uint8_t SdFile::openCachedEntry(uint8_t dirIndex, uint8_t oflag) { firstCluster_ |= p->firstClusterLow; // make sure it is a normal file or subdirectory - if (DIR_IS_FILE(p)) { + if (DIR_IS_FILE(p)) + { fileSize_ = p->fileSize; type_ = FAT_FILE_TYPE_NORMAL; - } else if (DIR_IS_SUBDIR(p)) { - if (!vol_->chainSize(firstCluster_, &fileSize_)) { + } + else if (DIR_IS_SUBDIR(p)) + { + if (!vol_->chainSize(firstCluster_, &fileSize_)) + { return false; } type_ = FAT_FILE_TYPE_SUBDIR; - } else { + } + else + { return false; } // save open flags for read/write @@ -634,7 +730,8 @@ uint8_t SdFile::openCachedEntry(uint8_t dirIndex, uint8_t oflag) { curPosition_ = 0; // truncate file to zero length if requested - if (oflag & O_TRUNC) { + if (oflag & O_TRUNC) + { return truncate(0); } return true; @@ -650,23 +747,31 @@ uint8_t SdFile::openCachedEntry(uint8_t dirIndex, uint8_t oflag) { Reasons for failure include the FAT volume has not been initialized or it a FAT12 volume. */ -uint8_t SdFile::openRoot(SdVolume* vol) { +uint8_t SdFile::openRoot(SdVolume *vol) +{ // error if file is already open - if (isOpen()) { + if (isOpen()) + { return false; } - if (vol->fatType() == 16) { + if (vol->fatType() == 16) + { type_ = FAT_FILE_TYPE_ROOT16; firstCluster_ = 0; fileSize_ = 32 * vol->rootDirEntryCount(); - } else if (vol->fatType() == 32) { + } + else if (vol->fatType() == 32) + { type_ = FAT_FILE_TYPE_ROOT32; firstCluster_ = vol->rootDirStart(); - if (!vol->chainSize(firstCluster_, &fileSize_)) { + if (!vol->chainSize(firstCluster_, &fileSize_)) + { return false; } - } else { + } + else + { // volume is not initialized or FAT12 return false; } @@ -684,72 +789,81 @@ uint8_t SdFile::openRoot(SdVolume* vol) { return true; } //------------------------------------------------------------------------------ -/** %Print the name field of a directory entry in 8.3 format to Serial. +/** %Print the name field of a directory entry in 8.3 format to port-> \param[in] dir The directory structure containing the name. \param[in] width Blank fill name if length is less than \a width. */ -void SdFile::printDirName(const dir_t& dir, uint8_t width) { +void SdFile::printDirName(const dir_t &dir, uint8_t width, HardwareSerial *port) +{ uint8_t w = 0; - for (uint8_t i = 0; i < 11; i++) { - if (dir.name[i] == ' ') { + for (uint8_t i = 0; i < 11; i++) + { + if (dir.name[i] == ' ') + { continue; } - if (i == 8) { - Serial.print('.'); + if (i == 8) + { + port->print('.'); w++; } - Serial.write(dir.name[i]); + port->write(dir.name[i]); w++; } - if (DIR_IS_SUBDIR(&dir)) { - Serial.print('/'); + if (DIR_IS_SUBDIR(&dir)) + { + port->print('/'); w++; } - while (w < width) { - Serial.print(' '); + while (w < width) + { + port->print(' '); w++; } } //------------------------------------------------------------------------------ -/** %Print a directory date field to Serial. +/** %Print a directory date field to port-> Format is yyyy-mm-dd. \param[in] fatDate The date field from a directory entry. */ -void SdFile::printFatDate(uint16_t fatDate) { - Serial.print(FAT_YEAR(fatDate)); - Serial.print('-'); - printTwoDigits(FAT_MONTH(fatDate)); - Serial.print('-'); - printTwoDigits(FAT_DAY(fatDate)); +void SdFile::printFatDate(uint16_t fatDate, HardwareSerial *port) +{ + port->print(FAT_YEAR(fatDate)); + port->print('-'); + printTwoDigits(FAT_MONTH(fatDate), port); + port->print('-'); + printTwoDigits(FAT_DAY(fatDate), port); } //------------------------------------------------------------------------------ -/** %Print a directory time field to Serial. +/** %Print a directory time field to port-> Format is hh:mm:ss. \param[in] fatTime The time field from a directory entry. */ -void SdFile::printFatTime(uint16_t fatTime) { - printTwoDigits(FAT_HOUR(fatTime)); - Serial.print(':'); - printTwoDigits(FAT_MINUTE(fatTime)); - Serial.print(':'); - printTwoDigits(FAT_SECOND(fatTime)); +void SdFile::printFatTime(uint16_t fatTime, HardwareSerial *port) +{ + printTwoDigits(FAT_HOUR(fatTime), port); + port->print(':'); + printTwoDigits(FAT_MINUTE(fatTime), port); + port->print(':'); + printTwoDigits(FAT_SECOND(fatTime), port); } //------------------------------------------------------------------------------ -/** %Print a value as two digits to Serial. +/** %Print a value as two digits to port-> \param[in] v Value to be printed, 0 <= \a v <= 99 */ -void SdFile::printTwoDigits(uint8_t v) { +void SdFile::printTwoDigits(uint8_t v, HardwareSerial *port) +{ char str[3]; str[0] = '0' + v / 10; str[1] = '0' + v % 10; str[2] = 0; - Serial.print(str); + port->print(str); } //------------------------------------------------------------------------------ /** @@ -766,36 +880,48 @@ void SdFile::printTwoDigits(uint8_t v) { read() called before a file has been opened, corrupt file system or an I/O error occurred. */ -int16_t SdFile::read(void* buf, uint16_t nbyte) { - uint8_t* dst = reinterpret_cast(buf); +int16_t SdFile::read(void *buf, uint16_t nbyte) +{ + uint8_t *dst = reinterpret_cast(buf); // error if not open or write only - if (!isOpen() || !(flags_ & O_READ)) { + if (!isOpen() || !(flags_ & O_READ)) + { return -1; } // max bytes left in file - if (nbyte > (fileSize_ - curPosition_)) { + if (nbyte > (fileSize_ - curPosition_)) + { nbyte = fileSize_ - curPosition_; } // amount left to read uint16_t toRead = nbyte; - while (toRead > 0) { - uint32_t block; // raw device block number - uint16_t offset = curPosition_ & 0X1FF; // offset in block - if (type_ == FAT_FILE_TYPE_ROOT16) { + while (toRead > 0) + { + uint32_t block; // raw device block number + uint16_t offset = curPosition_ & 0X1FF; // offset in block + if (type_ == FAT_FILE_TYPE_ROOT16) + { block = vol_->rootDirStart() + (curPosition_ >> 9); - } else { + } + else + { uint8_t blockOfCluster = vol_->blockOfCluster(curPosition_); - if (offset == 0 && blockOfCluster == 0) { + if (offset == 0 && blockOfCluster == 0) + { // start of new cluster - if (curPosition_ == 0) { + if (curPosition_ == 0) + { // use first cluster in file curCluster_ = firstCluster_; - } else { + } + else + { // get next cluster from FAT - if (!vol_->fatGet(curCluster_, &curCluster_)) { + if (!vol_->fatGet(curCluster_, &curCluster_)) + { return -1; } } @@ -805,25 +931,32 @@ int16_t SdFile::read(void* buf, uint16_t nbyte) { uint16_t n = toRead; // amount to be read from current block - if (n > (512 - offset)) { + if (n > (512 - offset)) + { n = 512 - offset; } // no buffering needed if n == 512 or user requests no buffering if ((unbufferedRead() || n == 512) && - block != SdVolume::cacheBlockNumber_) { - if (!vol_->readData(block, offset, n, dst)) { + block != SdVolume::cacheBlockNumber_) + { + if (!vol_->readData(block, offset, n, dst)) + { return -1; } dst += n; - } else { + } + else + { // read block to cache and copy data to caller - if (!SdVolume::cacheRawBlock(block, SdVolume::CACHE_FOR_READ)) { + if (!SdVolume::cacheRawBlock(block, SdVolume::CACHE_FOR_READ)) + { return -1; } - uint8_t* src = SdVolume::cacheBuffer_.data + offset; - uint8_t* end = src + n; - while (src != end) { + uint8_t *src = SdVolume::cacheBuffer_.data + offset; + uint8_t *end = src + n; + while (src != end) + { *dst++ = *src++; } } @@ -844,24 +977,30 @@ int16_t SdFile::read(void* buf, uint16_t nbyte) { readDir() called before a directory has been opened, this is not a directory file or an I/O error occurred. */ -int8_t SdFile::readDir(dir_t* dir) { +int8_t SdFile::readDir(dir_t *dir) +{ int8_t n; // if not a directory file or miss-positioned return an error - if (!isDir() || (0X1F & curPosition_)) { + if (!isDir() || (0X1F & curPosition_)) + { return -1; } - while ((n = read(dir, sizeof(dir_t))) == sizeof(dir_t)) { + while ((n = read(dir, sizeof(dir_t))) == sizeof(dir_t)) + { // last entry if DIR_NAME_FREE - if (dir->name[0] == DIR_NAME_FREE) { + if (dir->name[0] == DIR_NAME_FREE) + { break; } // skip empty entries and entry for . and .. - if (dir->name[0] == DIR_NAME_DELETED || dir->name[0] == '.') { + if (dir->name[0] == DIR_NAME_DELETED || dir->name[0] == '.') + { continue; } // return if normal file or subdirectory - if (DIR_IS_FILE_OR_SUBDIR(dir)) { + if (DIR_IS_FILE_OR_SUBDIR(dir)) + { return n; } } @@ -871,9 +1010,11 @@ int8_t SdFile::readDir(dir_t* dir) { //------------------------------------------------------------------------------ // Read next directory entry into the cache // Assumes file is correctly positioned -dir_t* SdFile::readDirCache(void) { +dir_t *SdFile::readDirCache(void) +{ // error if not directory - if (!isDir()) { + if (!isDir()) + { return NULL; } @@ -881,7 +1022,8 @@ dir_t* SdFile::readDirCache(void) { uint8_t i = (curPosition_ >> 5) & 0XF; // use read to locate and cache block - if (read() < 0) { + if (read() < 0) + { return NULL; } @@ -906,15 +1048,18 @@ dir_t* SdFile::readDirCache(void) { Reasons for failure include the file read-only, is a directory, or an I/O error occurred. */ -uint8_t SdFile::remove(void) { +uint8_t SdFile::remove(void) +{ // free any clusters - will fail if read-only or directory - if (!truncate(0)) { + if (!truncate(0)) + { return false; } // cache directory entry - dir_t* d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); - if (!d) { + dir_t *d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); + if (!d) + { return false; } @@ -946,9 +1091,11 @@ uint8_t SdFile::remove(void) { \a dirFile is not a directory, \a fileName is not found or an I/O error occurred. */ -uint8_t SdFile::remove(SdFile* dirFile, const char* fileName) { +uint8_t SdFile::remove(SdFile *dirFile, const char *fileName) +{ SdFile file; - if (!file.open(dirFile, fileName, O_WRITE)) { + if (!file.open(dirFile, fileName, O_WRITE)) + { return false; } return file.remove(); @@ -969,30 +1116,37 @@ uint8_t SdFile::remove(SdFile* dirFile, const char* fileName) { Reasons for failure include the file is not a directory, is the root directory, is not empty, or an I/O error occurred. */ -uint8_t SdFile::rmDir(void) { +uint8_t SdFile::rmDir(void) +{ // must be open subdirectory - if (!isSubDir()) { + if (!isSubDir()) + { return false; } rewind(); // make sure directory is empty - while (curPosition_ < fileSize_) { - dir_t* p = readDirCache(); - if (p == NULL) { + while (curPosition_ < fileSize_) + { + dir_t *p = readDirCache(); + if (p == NULL) + { return false; } // done if past last used entry - if (p->name[0] == DIR_NAME_FREE) { + if (p->name[0] == DIR_NAME_FREE) + { break; } // skip empty slot or '.' or '..' - if (p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') { + if (p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') + { continue; } // error not empty - if (DIR_IS_FILE_OR_SUBDIR(p)) { + if (DIR_IS_FILE_OR_SUBDIR(p)) + { return false; } } @@ -1017,58 +1171,73 @@ uint8_t SdFile::rmDir(void) { \return The value one, true, is returned for success and the value zero, false, is returned for failure. */ -uint8_t SdFile::rmRfStar(void) { +uint8_t SdFile::rmRfStar(void) +{ rewind(); - while (curPosition_ < fileSize_) { + while (curPosition_ < fileSize_) + { SdFile f; // remember position uint16_t index = curPosition_ / 32; - dir_t* p = readDirCache(); - if (!p) { + dir_t *p = readDirCache(); + if (!p) + { return false; } // done if past last entry - if (p->name[0] == DIR_NAME_FREE) { + if (p->name[0] == DIR_NAME_FREE) + { break; } // skip empty slot or '.' or '..' - if (p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') { + if (p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') + { continue; } // skip if part of long file name or volume label in root - if (!DIR_IS_FILE_OR_SUBDIR(p)) { + if (!DIR_IS_FILE_OR_SUBDIR(p)) + { continue; } - if (!f.open(this, index, O_READ)) { + if (!f.open(this, index, O_READ)) + { return false; } - if (f.isSubDir()) { + if (f.isSubDir()) + { // recursively delete - if (!f.rmRfStar()) { + if (!f.rmRfStar()) + { return false; } - } else { + } + else + { // ignore read-only f.flags_ |= O_WRITE; - if (!f.remove()) { + if (!f.remove()) + { return false; } } // position to next entry if required - if (curPosition_ != (32u * (index + 1))) { - if (!seekSet(32u * (index + 1))) { + if (curPosition_ != (32u * (index + 1))) + { + if (!seekSet(32u * (index + 1))) + { return false; } } } // don't try to delete root - if (isRoot()) { + if (isRoot()) + { return true; } return rmDir(); @@ -1082,17 +1251,21 @@ uint8_t SdFile::rmRfStar(void) { \return The value one, true, is returned for success and the value zero, false, is returned for failure. */ -uint8_t SdFile::seekSet(uint32_t pos) { +uint8_t SdFile::seekSet(uint32_t pos) +{ // error if file not open or seek past end of file - if (!isOpen() || pos > fileSize_) { + if (!isOpen() || pos > fileSize_) + { return false; } - if (type_ == FAT_FILE_TYPE_ROOT16) { + if (type_ == FAT_FILE_TYPE_ROOT16) + { curPosition_ = pos; return true; } - if (pos == 0) { + if (pos == 0) + { // set position to start of file curCluster_ = 0; curPosition_ = 0; @@ -1102,15 +1275,20 @@ uint8_t SdFile::seekSet(uint32_t pos) { uint32_t nCur = (curPosition_ - 1) >> (vol_->clusterSizeShift_ + 9); uint32_t nNew = (pos - 1) >> (vol_->clusterSizeShift_ + 9); - if (nNew < nCur || curPosition_ == 0) { + if (nNew < nCur || curPosition_ == 0) + { // must follow chain from first cluster curCluster_ = firstCluster_; - } else { + } + else + { // advance from curPosition nNew -= nCur; } - while (nNew--) { - if (!vol_->fatGet(curCluster_, &curCluster_)) { + while (nNew--) + { + if (!vol_->fatGet(curCluster_, &curCluster_)) + { return false; } } @@ -1129,20 +1307,25 @@ uint8_t SdFile::seekSet(uint32_t pos) { Reasons for failure include a call to sync() before a file has been opened or an I/O error. */ -uint8_t SdFile::sync(uint8_t blocking) { +uint8_t SdFile::sync(uint8_t blocking) +{ // only allow open files and directories - if (!isOpen()) { + if (!isOpen()) + { return false; } - if (flags_ & F_FILE_DIR_DIRTY) { - dir_t* d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); - if (!d) { + if (flags_ & F_FILE_DIR_DIRTY) + { + dir_t *d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); + if (!d) + { return false; } // do not set filesize for dir files - if (!isDir()) { + if (!isDir()) + { d->fileSize = fileSize_; } @@ -1151,7 +1334,8 @@ uint8_t SdFile::sync(uint8_t blocking) { d->firstClusterHigh = firstCluster_ >> 16; // set modify time if user supplied a callback date/time function - if (dateTime_) { + if (dateTime_) + { dateTime_(&d->lastWriteDate, &d->lastWriteTime); d->lastAccessDate = d->lastWriteDate; } @@ -1159,7 +1343,8 @@ uint8_t SdFile::sync(uint8_t blocking) { flags_ &= ~F_FILE_DIR_DIRTY; } - if (!blocking) { + if (!blocking) + { flags_ &= ~F_FILE_NON_BLOCKING_WRITE; } @@ -1201,36 +1386,33 @@ uint8_t SdFile::sync(uint8_t blocking) { the value zero, false, is returned for failure. */ uint8_t SdFile::timestamp(uint8_t flags, uint16_t year, uint8_t month, - uint8_t day, uint8_t hour, uint8_t minute, uint8_t second) { - if (!isOpen() - || year < 1980 - || year > 2107 - || month < 1 - || month > 12 - || day < 1 - || day > 31 - || hour > 23 - || minute > 59 - || second > 59) { + uint8_t day, uint8_t hour, uint8_t minute, uint8_t second) +{ + if (!isOpen() || year < 1980 || year > 2107 || month < 1 || month > 12 || day < 1 || day > 31 || hour > 23 || minute > 59 || second > 59) + { return false; } - dir_t* d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); - if (!d) { + dir_t *d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE); + if (!d) + { return false; } uint16_t dirDate = FAT_DATE(year, month, day); uint16_t dirTime = FAT_TIME(hour, minute, second); - if (flags & T_ACCESS) { + if (flags & T_ACCESS) + { d->lastAccessDate = dirDate; } - if (flags & T_CREATE) { + if (flags & T_CREATE) + { d->creationDate = dirDate; d->creationTime = dirTime; // seems to be units of 1/100 second not 1/10 as Microsoft states d->creationTimeTenths = second & 1 ? 100 : 0; } - if (flags & T_WRITE) { + if (flags & T_WRITE) + { d->lastWriteDate = dirDate; d->lastWriteTime = dirTime; } @@ -1250,19 +1432,23 @@ uint8_t SdFile::timestamp(uint8_t flags, uint16_t year, uint8_t month, Reasons for failure include file is read only, file is a directory, \a length is greater than the current file size or an I/O error occurs. */ -uint8_t SdFile::truncate(uint32_t length) { +uint8_t SdFile::truncate(uint32_t length) +{ // error if not a normal file or read-only - if (!isFile() || !(flags_ & O_WRITE)) { + if (!isFile() || !(flags_ & O_WRITE)) + { return false; } // error if length is greater than current size - if (length > fileSize_) { + if (length > fileSize_) + { return false; } // fileSize and length are zero - nothing to do - if (fileSize_ == 0) { + if (fileSize_ == 0) + { return true; } @@ -1270,30 +1456,39 @@ uint8_t SdFile::truncate(uint32_t length) { uint32_t newPos = curPosition_ > length ? length : curPosition_; // position to last cluster in truncated file - if (!seekSet(length)) { + if (!seekSet(length)) + { return false; } - if (length == 0) { + if (length == 0) + { // free all clusters - if (!vol_->freeChain(firstCluster_)) { + if (!vol_->freeChain(firstCluster_)) + { return false; } firstCluster_ = 0; - } else { + } + else + { uint32_t toFree; - if (!vol_->fatGet(curCluster_, &toFree)) { + if (!vol_->fatGet(curCluster_, &toFree)) + { return false; } - if (!vol_->isEOC(toFree)) { + if (!vol_->isEOC(toFree)) + { // free extra clusters - if (!vol_->freeChain(toFree)) { + if (!vol_->freeChain(toFree)) + { return false; } // current cluster is end of chain - if (!vol_->fatPutEOC(curCluster_)) { + if (!vol_->fatPutEOC(curCluster_)) + { return false; } } @@ -1303,7 +1498,8 @@ uint8_t SdFile::truncate(uint32_t length) { // need to update directory entry flags_ |= F_FILE_DIR_DIRTY; - if (!sync()) { + if (!sync()) + { return false; } @@ -1327,9 +1523,10 @@ uint8_t SdFile::truncate(uint32_t length) { for a read-only file, device is full, a corrupt file system or an I/O error. */ -size_t SdFile::write(const void* buf, uint16_t nbyte) { +size_t SdFile::write(const void *buf, uint16_t nbyte) +{ // convert void* to uint8_t* - must be before goto statements - const uint8_t* src = reinterpret_cast(buf); + const uint8_t *src = reinterpret_cast(buf); // number of bytes left to write - must be before goto statements uint16_t nToWrite = nbyte; @@ -1337,42 +1534,59 @@ size_t SdFile::write(const void* buf, uint16_t nbyte) { uint8_t blocking = (flags_ & F_FILE_NON_BLOCKING_WRITE) == 0x00; // error if not a normal file or is read-only - if (!isFile() || !(flags_ & O_WRITE)) { + if (!isFile() || !(flags_ & O_WRITE)) + { goto writeErrorReturn; } // seek to end of file if append flag - if ((flags_ & O_APPEND) && curPosition_ != fileSize_) { - if (!seekEnd()) { + if ((flags_ & O_APPEND) && curPosition_ != fileSize_) + { + if (!seekEnd()) + { goto writeErrorReturn; } } - while (nToWrite > 0) { + while (nToWrite > 0) + { uint8_t blockOfCluster = vol_->blockOfCluster(curPosition_); uint16_t blockOffset = curPosition_ & 0X1FF; - if (blockOfCluster == 0 && blockOffset == 0) { + if (blockOfCluster == 0 && blockOffset == 0) + { // start of new cluster - if (curCluster_ == 0) { - if (firstCluster_ == 0) { + if (curCluster_ == 0) + { + if (firstCluster_ == 0) + { // allocate first cluster of file - if (!addCluster()) { + if (!addCluster()) + { goto writeErrorReturn; } - } else { + } + else + { curCluster_ = firstCluster_; } - } else { + } + else + { uint32_t next; - if (!vol_->fatGet(curCluster_, &next)) { + if (!vol_->fatGet(curCluster_, &next)) + { return false; } - if (vol_->isEOC(next)) { + if (vol_->isEOC(next)) + { // add cluster if at end of chain - if (!addCluster()) { + if (!addCluster()) + { goto writeErrorReturn; } - } else { + } + else + { curCluster_ = next; } } @@ -1381,56 +1595,73 @@ size_t SdFile::write(const void* buf, uint16_t nbyte) { uint16_t n = 512 - blockOffset; // lesser of space and amount to write - if (n > nToWrite) { + if (n > nToWrite) + { n = nToWrite; } // block for data write uint32_t block = vol_->clusterStartBlock(curCluster_) + blockOfCluster; - if (n == 512) { + if (n == 512) + { // full block - don't need to use cache // invalidate cache if block is in cache - if (SdVolume::cacheBlockNumber_ == block) { + if (SdVolume::cacheBlockNumber_ == block) + { SdVolume::cacheBlockNumber_ = 0XFFFFFFFF; } - if (!vol_->writeBlock(block, src, blocking)) { + if (!vol_->writeBlock(block, src, blocking)) + { goto writeErrorReturn; } src += 512; - } else { - if (blockOffset == 0 && curPosition_ >= fileSize_) { + } + else + { + if (blockOffset == 0 && curPosition_ >= fileSize_) + { // start of new block don't need to read into cache - if (!SdVolume::cacheFlush()) { + if (!SdVolume::cacheFlush()) + { goto writeErrorReturn; } SdVolume::cacheBlockNumber_ = block; SdVolume::cacheSetDirty(); - } else { + } + else + { // rewrite part of block - if (!SdVolume::cacheRawBlock(block, SdVolume::CACHE_FOR_WRITE)) { + if (!SdVolume::cacheRawBlock(block, SdVolume::CACHE_FOR_WRITE)) + { goto writeErrorReturn; } } - uint8_t* dst = SdVolume::cacheBuffer_.data + blockOffset; - uint8_t* end = dst + n; - while (dst != end) { + uint8_t *dst = SdVolume::cacheBuffer_.data + blockOffset; + uint8_t *end = dst + n; + while (dst != end) + { *dst++ = *src++; } } nToWrite -= n; curPosition_ += n; } - if (curPosition_ > fileSize_) { + if (curPosition_ > fileSize_) + { // update fileSize and insure sync will update dir entry fileSize_ = curPosition_; flags_ |= F_FILE_DIR_DIRTY; - } else if (dateTime_ && nbyte) { + } + else if (dateTime_ && nbyte) + { // insure sync will update modified date and time flags_ |= F_FILE_DIR_DIRTY; } - if (flags_ & O_SYNC) { - if (!sync()) { + if (flags_ & O_SYNC) + { + if (!sync()) + { goto writeErrorReturn; } } @@ -1438,7 +1669,7 @@ size_t SdFile::write(const void* buf, uint16_t nbyte) { writeErrorReturn: // return for write error - //writeError = true; + // writeError = true; setWriteError(); return 0; } @@ -1448,7 +1679,8 @@ size_t SdFile::write(const void* buf, uint16_t nbyte) { Use SdFile::writeError to check for errors. */ -size_t SdFile::write(uint8_t b) { +size_t SdFile::write(uint8_t b) +{ return write(&b, 1); } //------------------------------------------------------------------------------ @@ -1457,7 +1689,8 @@ size_t SdFile::write(uint8_t b) { Use SdFile::writeError to check for errors. */ -size_t SdFile::write(const char* str) { +size_t SdFile::write(const char *str) +{ return write(str, strlen(str)); } #ifdef __AVR__ @@ -1467,8 +1700,10 @@ size_t SdFile::write(const char* str) { Use SdFile::writeError to check for errors. */ -void SdFile::write_P(PGM_P str) { - for (uint8_t c; (c = pgm_read_byte(str)); str++) { +void SdFile::write_P(PGM_P str) +{ + for (uint8_t c; (c = pgm_read_byte(str)); str++) + { write(c); } } @@ -1478,7 +1713,8 @@ void SdFile::write_P(PGM_P str) { Use SdFile::writeError to check for errors. */ -void SdFile::writeln_P(PGM_P str) { +void SdFile::writeln_P(PGM_P str) +{ write_P(str); println(); } @@ -1489,30 +1725,37 @@ void SdFile::writeln_P(PGM_P str) { \return The number of bytes that can be written without blocking. */ -int SdFile::availableForWrite() { - if (!isFile() || !(flags_ & O_WRITE)) { +int SdFile::availableForWrite() +{ + if (!isFile() || !(flags_ & O_WRITE)) + { return 0; } // seek to end of file if append flag - if ((flags_ & O_APPEND) && curPosition_ != fileSize_) { - if (!seekEnd()) { + if ((flags_ & O_APPEND) && curPosition_ != fileSize_) + { + if (!seekEnd()) + { return 0; } } - if (vol_->isBusy()) { + if (vol_->isBusy()) + { return 0; } - if (flags_ & F_FILE_CLUSTER_ADDED) { + if (flags_ & F_FILE_CLUSTER_ADDED) + { // new cluster added, trigger a non-blocking sync sync(0); flags_ &= ~F_FILE_CLUSTER_ADDED; return 0; } - if (vol_->isCacheMirrorBlockDirty()) { + if (vol_->isCacheMirrorBlockDirty()) + { // cache mirror block is dirty, trigger a non-blocking sync vol_->cacheMirrorBlockFlush(0); return 0; From 03b49f038eebe053d3c25c3584523d8e02538dcb Mon Sep 17 00:00:00 2001 From: Daniel Melendrez Date: Thu, 14 Mar 2024 02:06:27 +0000 Subject: [PATCH 2/2] Updated printing FatDate and FatTime tot he HW Serial pointer --- src/utility/SdFile.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/utility/SdFile.cpp b/src/utility/SdFile.cpp index 168661f..bff0a1c 100644 --- a/src/utility/SdFile.cpp +++ b/src/utility/SdFile.cpp @@ -293,9 +293,9 @@ void SdFile::ls(uint8_t flags, uint8_t indent, HardwareSerial *port) // print modify date/time if requested if (flags & LS_DATE) { - printFatDate(p->lastWriteDate); + printFatDate(p->lastWriteDate, port); port->print(' '); - printFatTime(p->lastWriteTime); + printFatTime(p->lastWriteTime, port); } // print size if requested if (!DIR_IS_SUBDIR(p) && (flags & LS_SIZE))