diff --git a/examples/RtcTimestampTest/RtcTimestampTest.ino b/examples/RtcTimestampTest/RtcTimestampTest.ino index 912a787c..76ec45f6 100644 --- a/examples/RtcTimestampTest/RtcTimestampTest.ino +++ b/examples/RtcTimestampTest/RtcTimestampTest.ino @@ -150,17 +150,17 @@ bool setRtc() { Serial.print(F("Input: ")); Serial.println(line); - y = strtol(line, &ptr, 0); + y = strtol(line, &ptr, 10); if (*ptr++ != '-' || y < 2000 || y > 2099) return error("year"); - m = strtol(ptr, &ptr, 0); + m = strtol(ptr, &ptr, 10); if (*ptr++ != '-' || m < 1 || m > 12) return error("month"); - d = strtol(ptr, &ptr, 0); + d = strtol(ptr, &ptr, 10); if (d < 1 || d > 31) return error("day"); - hh = strtol(ptr, &ptr, 0); + hh = strtol(ptr, &ptr, 10); if (*ptr++ != ':' || hh > 23) return error("hour"); - mm = strtol(ptr, &ptr, 0); + mm = strtol(ptr, &ptr, 10); if (*ptr++ != ':' || mm > 59) return error("minute"); - ss = strtol(ptr, &ptr, 0); + ss = strtol(ptr, &ptr, 10); if (ss > 59) return error("second"); rtc.adjust(DateTime(y, m, d, hh, mm, ss)); diff --git a/library.properties b/library.properties index 11374c6a..a327ea84 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=SdFat -version=2.0.2 +version=2.0.3 license=MIT author=Bill Greiman maintainer=Bill Greiman diff --git a/src/ExFatLib/ExFatFile.cpp b/src/ExFatLib/ExFatFile.cpp index b7dede25..6cecd8a4 100644 --- a/src/ExFatLib/ExFatFile.cpp +++ b/src/ExFatLib/ExFatFile.cpp @@ -647,16 +647,7 @@ int ExFatFile::read(void* buf, size_t count) { ns = maxNs; } n = ns << m_vol->bytesPerSectorShift(); - // Check for cache sector in read range. - if (sector <= m_vol->dataCacheSector() - && m_vol->dataCacheSector() < (sector + ns)) { - // Flush cache if cache sector is in the range. - if (!m_vol->dataCacheSync()) { - DBG_FAIL_MACRO; - goto fail; - } - } - if (!m_vol->readSectors(sector, dst, ns)) { + if (!m_vol->cacheSafeRead(sector, dst, ns)) { DBG_FAIL_MACRO; goto fail; } @@ -664,7 +655,7 @@ int ExFatFile::read(void* buf, size_t count) { } else { // read single sector n = m_vol->bytesPerSector(); - if (!m_vol->readSector(sector, dst)) { + if (!m_vol->cacheSafeRead(sector, dst)) { DBG_FAIL_MACRO; goto fail; } diff --git a/src/ExFatLib/ExFatFile.h b/src/ExFatLib/ExFatFile.h index 7e7241e1..457f550c 100644 --- a/src/ExFatLib/ExFatFile.h +++ b/src/ExFatLib/ExFatFile.h @@ -82,7 +82,6 @@ struct ExFatPos_t { uint64_t position; /** cluster for position */ uint32_t cluster; - ExFatPos_t() : position(0), cluster(0) {} }; //------------------------------------------------------------------------------ /** diff --git a/src/ExFatLib/ExFatFileWrite.cpp b/src/ExFatLib/ExFatFileWrite.cpp index bdf84125..88731ea0 100644 --- a/src/ExFatLib/ExFatFileWrite.cpp +++ b/src/ExFatLib/ExFatFileWrite.cpp @@ -747,24 +747,14 @@ size_t ExFatFile::write(const void* buf, size_t nbyte) { ns = maxNs; } n = ns << m_vol->bytesPerSectorShift(); - // Check for cache sector in write range. - if (sector <= m_vol->dataCacheSector() - && m_vol->dataCacheSector() < (sector + ns)) { - // Invalidate cache if cache sector is in the range. - m_vol->dataCacheInvalidate(); - } - if (!m_vol->writeSectors(sector, src, ns)) { - DBG_FAIL_MACRO; + if (!m_vol->cacheSafeWrite(sector, src, ns)) { + DBG_FAIL_MACRO; goto fail; } #endif // USE_MULTI_SECTOR_IO } else { - // use single sector write command n = m_vol->bytesPerSector(); - if (m_vol->dataCacheSector() == sector) { - m_vol->dataCacheInvalidate(); - } - if (!m_vol->writeSector(sector, src)) { + if (!m_vol->cacheSafeWrite(sector, src)) { DBG_FAIL_MACRO; goto fail; } diff --git a/src/ExFatLib/ExFatPartition.cpp b/src/ExFatLib/ExFatPartition.cpp index 9c34dd34..a86fd4e6 100644 --- a/src/ExFatLib/ExFatPartition.cpp +++ b/src/ExFatLib/ExFatPartition.cpp @@ -27,51 +27,6 @@ #include "ExFatVolume.h" #include "../common/FsStructs.h" //------------------------------------------------------------------------------ -uint8_t* FsCache::get(uint32_t sector, uint8_t option) { - if (!m_blockDev) { - DBG_FAIL_MACRO; - goto fail; - } - if (m_sector != sector) { - if (!sync()) { - DBG_FAIL_MACRO; - goto fail; - } - if (!(option & CACHE_OPTION_NO_READ)) { - if (!m_blockDev->readSector(sector, m_cacheBuffer)) { - DBG_FAIL_MACRO; - goto fail; - } - } - m_status = 0; - m_sector = sector; - } - m_status |= option & CACHE_STATUS_MASK; - return m_cacheBuffer; - - fail: - return nullptr; -} -//------------------------------------------------------------------------------ -void FsCache::invalidate() { - m_status = 0; - m_sector = 0XFFFFFFFF; -} -//------------------------------------------------------------------------------ -bool FsCache::sync() { - if (m_status & CACHE_STATUS_DIRTY) { - if (!m_blockDev->writeSector(m_sector, m_cacheBuffer)) { - DBG_FAIL_MACRO; - goto fail; - } - m_status &= ~CACHE_STATUS_DIRTY; - } - return true; - - fail: - return false; -} -//============================================================================== // return 0 if error, 1 if no space, else start cluster. uint32_t ExFatPartition::bitmapFind(uint32_t cluster, uint32_t count) { uint32_t start = cluster ? cluster - 2 : m_bitmapStart; diff --git a/src/ExFatLib/ExFatPartition.h b/src/ExFatLib/ExFatPartition.h index 4ca18a92..ef9adff1 100644 --- a/src/ExFatLib/ExFatPartition.h +++ b/src/ExFatLib/ExFatPartition.h @@ -30,86 +30,14 @@ */ #include "../common/SysCall.h" #include "../common/BlockDevice.h" +#include "../common/FsCache.h" #include "ExFatConfig.h" #include "ExFatTypes.h" /** Type for exFAT partition */ const uint8_t FAT_TYPE_EXFAT = 64; class ExFatFile; -//============================================================================== -/** - * \class FsCache - * \brief Sector cache. - */ -class FsCache { - public: - /** Cached sector is dirty */ - static const uint8_t CACHE_STATUS_DIRTY = 1; - /** Cache sector status bits */ - static const uint8_t CACHE_STATUS_MASK = CACHE_STATUS_DIRTY; - /** Sync existing sector but do not read new sector. */ - static const uint8_t CACHE_OPTION_NO_READ = 2; - /** Cache sector for read. */ - static const uint8_t CACHE_FOR_READ = 0; - /** Cache sector for write. */ - static const uint8_t CACHE_FOR_WRITE = CACHE_STATUS_DIRTY; - /** Reserve cache sector for write - do not read from sector device. */ - static const uint8_t CACHE_RESERVE_FOR_WRITE - = CACHE_STATUS_DIRTY | CACHE_OPTION_NO_READ; - FsCache() : m_blockDev(nullptr) { - invalidate(); - } - - /** \return Cache sector address. */ - uint8_t* cacheBuffer() { - return m_cacheBuffer; - } - /** \return Clear the cache and returns a pointer to the cache. */ - uint8_t* clear() { - if (isDirty() && !sync()) { - return nullptr; - } - invalidate(); - return m_cacheBuffer; - } - /** Set current sector dirty. */ - void dirty() { - m_status |= CACHE_STATUS_DIRTY; - } - /** Initialize the cache. - * \param[in] blockDev Block device for this partition. - */ - void init(BlockDevice* blockDev) { - m_blockDev = blockDev; - invalidate(); - } - /** Invalidate current cache sector. */ - void invalidate(); - /** \return dirty status */ - bool isDirty() { - return m_status & CACHE_STATUS_DIRTY; - } - /** \return Logical sector number for cached sector. */ - uint32_t sector() { - return m_sector; - } - /** Fill cache with sector data. - * \param[in] sector Sector to read. - * \param[in] option mode for cached sector. - * \return Address of cached sector. */ - uint8_t* get(uint32_t sector, uint8_t option); - /** Write current sector if dirty. - * \return true for success or false for failure. - */ - bool sync(); - - private: - uint8_t m_status; - BlockDevice* m_blockDev; - uint32_t m_sector; - uint8_t m_cacheBuffer[512]; -}; //============================================================================== /** * \class ExFatPartition @@ -233,20 +161,24 @@ class ExFatPartition { bool syncDevice() { return m_blockDev->syncDevice(); } + bool cacheSafeRead(uint32_t sector, uint8_t* dst) { + return m_dataCache.cacheSafeRead(sector, dst); + } + bool cacheSafeWrite(uint32_t sector, const uint8_t* src) { + return m_dataCache.cacheSafeWrite(sector, src); + } + bool cacheSafeRead(uint32_t sector, uint8_t* dst, size_t count) { + return m_dataCache.cacheSafeRead(sector, dst, count); + } + bool cacheSafeWrite(uint32_t sector, const uint8_t* src, size_t count) { + return m_dataCache.cacheSafeWrite(sector, src, count); + } bool readSector(uint32_t sector, uint8_t* dst) { return m_blockDev->readSector(sector, dst); } bool writeSector(uint32_t sector, const uint8_t* src) { return m_blockDev->writeSector(sector, src); } -#if USE_MULTI_SECTOR_IO - bool readSectors(uint32_t sector, uint8_t* dst, size_t count) { - return m_blockDev->readSectors(sector, dst, count); - } - bool writeSectors(uint32_t sector, const uint8_t* src, size_t count) { - return m_blockDev->writeSectors(sector, src, count); - } -#endif // USE_MULTI_SECTOR_IO //---------------------------------------------------------------------------- static const uint8_t m_bytesPerSectorShift = 9; static const uint16_t m_bytesPerSector = 512; diff --git a/src/FatLib/FatDbg.cpp b/src/FatLib/FatDbg.cpp index a1b4e978..164b4bdc 100644 --- a/src/FatLib/FatDbg.cpp +++ b/src/FatLib/FatDbg.cpp @@ -144,7 +144,7 @@ void FatPartition::dmpFat(print_t* pr, uint32_t start, uint32_t count) { uint32_t sector = m_fatStartSector + start; uint32_t cluster = nf*start; for (uint32_t i = 0; i < count; i++) { - cache_t* pc = cacheFetchFat(sector + i, FatCache::CACHE_FOR_READ); + cache_t* pc = cacheFetchFat(sector + i, FsCache::CACHE_FOR_READ); if (!pc) { pr->println(F("cache read failed")); return; diff --git a/src/FatLib/FatFile.cpp b/src/FatLib/FatFile.cpp index 1e066255..84f3546b 100644 --- a/src/FatLib/FatFile.cpp +++ b/src/FatLib/FatFile.cpp @@ -71,7 +71,7 @@ bool FatFile::addDirCluster() { goto fail; } sector = m_vol->clusterStartSector(m_curCluster); - pc = m_vol->cacheFetchData(sector, FatCache::CACHE_RESERVE_FOR_WRITE); + pc = m_vol->cacheFetchData(sector, FsCache::CACHE_RESERVE_FOR_WRITE); if (!pc) { DBG_FAIL_MACRO; goto fail; @@ -187,7 +187,7 @@ bool FatFile::dirEntry(DirFat_t* dst) { goto fail; } // read entry - dir = cacheDirEntry(FatCache::CACHE_FOR_READ); + dir = cacheDirEntry(FsCache::CACHE_FOR_READ); if (!dir) { DBG_FAIL_MACRO; goto fail; @@ -378,7 +378,7 @@ bool FatFile::mkdir(FatFile* parent, fname_t* fname) { goto fail; } // cache entry - should already be in cache due to sync() call - dir = cacheDirEntry(FatCache::CACHE_FOR_WRITE); + dir = cacheDirEntry(FsCache::CACHE_FOR_WRITE); if (!dir) { DBG_FAIL_MACRO; goto fail; @@ -395,7 +395,7 @@ bool FatFile::mkdir(FatFile* parent, fname_t* fname) { // cache sector for '.' and '..' sector = m_vol->clusterStartSector(m_firstCluster); - pc = m_vol->cacheFetchData(sector, FatCache::CACHE_FOR_WRITE); + pc = m_vol->cacheFetchData(sector, FsCache::CACHE_FOR_WRITE); if (!pc) { DBG_FAIL_MACRO; goto fail; @@ -786,7 +786,7 @@ int FatFile::read(void* buf, size_t nbyte) { n = toRead; } // read sector to cache and copy data to caller - pc = m_vol->cacheFetchData(sector, FatCache::CACHE_FOR_READ); + pc = m_vol->cacheFetchData(sector, FsCache::CACHE_FOR_READ); if (!pc) { DBG_FAIL_MACRO; goto fail; @@ -803,16 +803,7 @@ int FatFile::read(void* buf, size_t nbyte) { } } n = ns << m_vol->bytesPerSectorShift(); - // Check for cache sector in read range. - if (sector <= m_vol->cacheSectorNumber() - && m_vol->cacheSectorNumber() < (sector + ns)) { - // Flush cache if cache sector is in the range. - if (!m_vol->cacheSyncData()) { - DBG_FAIL_MACRO; - goto fail; - } - } - if (!m_vol->readSectors(sector, dst, ns)) { + if (!m_vol->cacheSafeRead(sector, dst, ns)) { DBG_FAIL_MACRO; goto fail; } @@ -820,7 +811,7 @@ int FatFile::read(void* buf, size_t nbyte) { } else { // read single sector n = m_vol->bytesPerSector(); - if (!m_vol->readSector(sector, dst)) { + if (!m_vol->cacheSafeRead(sector, dst)) { DBG_FAIL_MACRO; goto fail; } @@ -929,7 +920,7 @@ bool FatFile::rename(FatFile* dirFile, const char* newPath) { // sync() and cache directory entry sync(); oldFile = *this; - dir = cacheDirEntry(FatCache::CACHE_FOR_READ); + dir = cacheDirEntry(FsCache::CACHE_FOR_READ); if (!dir) { DBG_FAIL_MACRO; goto fail; @@ -962,7 +953,7 @@ bool FatFile::rename(FatFile* dirFile, const char* newPath) { file.m_flags = 0; // cache new directory entry - dir = cacheDirEntry(FatCache::CACHE_FOR_WRITE); + dir = cacheDirEntry(FsCache::CACHE_FOR_WRITE); if (!dir) { DBG_FAIL_MACRO; goto fail; @@ -976,7 +967,7 @@ bool FatFile::rename(FatFile* dirFile, const char* newPath) { if (dirCluster) { // get new dot dot uint32_t sector = m_vol->clusterStartSector(dirCluster); - pc = m_vol->cacheFetchData(sector, FatCache::CACHE_FOR_READ); + pc = m_vol->cacheFetchData(sector, FsCache::CACHE_FOR_READ); if (!pc) { DBG_FAIL_MACRO; goto fail; @@ -990,7 +981,7 @@ bool FatFile::rename(FatFile* dirFile, const char* newPath) { } // store new dot dot sector = m_vol->clusterStartSector(m_firstCluster); - pc = m_vol->cacheFetchData(sector, FatCache::CACHE_FOR_WRITE); + pc = m_vol->cacheFetchData(sector, FsCache::CACHE_FOR_WRITE); if (!pc) { DBG_FAIL_MACRO; goto fail; @@ -1200,7 +1191,7 @@ bool FatFile::sync() { return true; } if (m_flags & FILE_FLAG_DIR_DIRTY) { - DirFat_t* dir = cacheDirEntry(FatCache::CACHE_FOR_WRITE); + DirFat_t* dir = cacheDirEntry(FsCache::CACHE_FOR_WRITE); // check for deleted by another open file object if (!dir || dir->name[0] == FAT_NAME_DELETED) { DBG_FAIL_MACRO; @@ -1259,7 +1250,7 @@ bool FatFile::timestamp(uint8_t flags, uint16_t year, uint8_t month, DBG_FAIL_MACRO; goto fail; } - dir = cacheDirEntry(FatCache::CACHE_FOR_WRITE); + dir = cacheDirEntry(FsCache::CACHE_FOR_WRITE); if (!dir) { DBG_FAIL_MACRO; goto fail; @@ -1420,10 +1411,10 @@ size_t FatFile::write(const void* buf, size_t nbyte) { if (sectorOffset == 0 && (m_curPosition >= m_fileSize || m_flags & FILE_FLAG_PREALLOCATE)) { // start of new sector don't need to read into cache - cacheOption = FatCache::CACHE_RESERVE_FOR_WRITE; + cacheOption = FsCache::CACHE_RESERVE_FOR_WRITE; } else { // rewrite part of sector - cacheOption = FatCache::CACHE_FOR_WRITE; + cacheOption = FsCache::CACHE_FOR_WRITE; } pc = m_vol->cacheFetchData(sector, cacheOption); if (!pc) { @@ -1448,13 +1439,7 @@ size_t FatFile::write(const void* buf, size_t nbyte) { nSector = maxSectors; } n = nSector << m_vol->bytesPerSectorShift(); - // Check for cache sector in write range. - if (sector <= m_vol->cacheSectorNumber() - && m_vol->cacheSectorNumber() < (sector + nSector)) { - // Invalidate cache if cache sector is in the range. - m_vol->cacheInvalidate(); - } - if (!m_vol->writeSectors(sector, src, nSector)) { + if (!m_vol->cacheSafeWrite(sector, src, nSector)) { DBG_FAIL_MACRO; goto fail; } @@ -1462,10 +1447,7 @@ size_t FatFile::write(const void* buf, size_t nbyte) { } else { // use single sector write command n = m_vol->bytesPerSector(); - if (m_vol->cacheSectorNumber() == sector) { - m_vol->cacheInvalidate(); - } - if (!m_vol->writeSector(sector, src)) { + if (!m_vol->cacheSafeWrite(sector, src)) { DBG_FAIL_MACRO; goto fail; } diff --git a/src/FatLib/FatFile.h b/src/FatLib/FatFile.h index eeffdaa5..280f4cd8 100644 --- a/src/FatLib/FatFile.h +++ b/src/FatLib/FatFile.h @@ -70,7 +70,6 @@ struct FatPos_t { uint32_t position; /** cluster for position */ uint32_t cluster; - FatPos_t() : position(0), cluster(0) {} }; //------------------------------------------------------------------------------ /** Expression for path name separator. */ diff --git a/src/FatLib/FatFileLFN.cpp b/src/FatLib/FatFileLFN.cpp index 835bbb36..02ddd3d4 100644 --- a/src/FatLib/FatFileLFN.cpp +++ b/src/FatLib/FatFileLFN.cpp @@ -580,7 +580,7 @@ bool FatFile::remove() { goto fail; } // Cache directory entry. - dir = cacheDirEntry(FatCache::CACHE_FOR_WRITE); + dir = cacheDirEntry(FsCache::CACHE_FOR_WRITE); if (!dir) { DBG_FAIL_MACRO; goto fail; diff --git a/src/FatLib/FatFileSFN.cpp b/src/FatLib/FatFileSFN.cpp index ccf0f0e5..821a94cd 100644 --- a/src/FatLib/FatFileSFN.cpp +++ b/src/FatLib/FatFileSFN.cpp @@ -43,7 +43,7 @@ bool FatFile::getSFN(char* name) { return true; } // cache entry - dir = reinterpret_cast(cacheDirEntry(FatCache::CACHE_FOR_READ)); + dir = reinterpret_cast(cacheDirEntry(FsCache::CACHE_FOR_READ)); if (!dir) { DBG_FAIL_MACRO; goto fail; @@ -285,7 +285,7 @@ bool FatFile::remove() { goto fail; } // Cache directory entry. - dir = reinterpret_cast(cacheDirEntry(FatCache::CACHE_FOR_WRITE)); + dir = reinterpret_cast(cacheDirEntry(FsCache::CACHE_FOR_WRITE)); if (!dir) { DBG_FAIL_MACRO; goto fail; diff --git a/src/FatLib/FatFormatter.cpp b/src/FatLib/FatFormatter.cpp index 1ad018d3..0cbd7dc8 100644 --- a/src/FatLib/FatFormatter.cpp +++ b/src/FatLib/FatFormatter.cpp @@ -24,7 +24,7 @@ */ #include "FatFormatter.h" // Set nonzero to use calculated CHS in MBR. Should not be required. -#define USE_LBA_TO_CHS 0 +#define USE_LBA_TO_CHS 1 // Constants for file system structure optimized for flash. uint16_t const BU16 = 128; diff --git a/src/FatLib/FatPartition.cpp b/src/FatLib/FatPartition.cpp index c46bb51a..4b0a2fc7 100644 --- a/src/FatLib/FatPartition.cpp +++ b/src/FatLib/FatPartition.cpp @@ -28,51 +28,6 @@ #include "../common/FsStructs.h" #include "FatPartition.h" //------------------------------------------------------------------------------ -cache_t* FatCache::read(uint32_t sector, uint8_t option) { - if (m_lbn != sector) { - if (!sync()) { - DBG_FAIL_MACRO; - goto fail; - } - if (!(option & CACHE_OPTION_NO_READ)) { - if (!m_part->readSector(sector, m_buffer.data)) { - DBG_FAIL_MACRO; - goto fail; - } - } - m_status = 0; - m_lbn = sector; - } - m_status |= option & CACHE_STATUS_MASK; - return &m_buffer; - - fail: - - return nullptr; -} -//------------------------------------------------------------------------------ -bool FatCache::sync() { - if (m_status & CACHE_STATUS_DIRTY) { - if (!m_part->writeSector(m_lbn, m_buffer.data)) { - DBG_FAIL_MACRO; - goto fail; - } - // mirror second FAT - if (m_status & CACHE_STATUS_MIRROR_FAT) { - uint32_t sector = m_lbn + m_part->sectorsPerFat(); - if (!m_part->writeSector(sector, m_buffer.data)) { - DBG_FAIL_MACRO; - goto fail; - } - } - m_status &= ~CACHE_STATUS_DIRTY; - } - return true; - - fail: - return false; -} -//------------------------------------------------------------------------------ bool FatPartition::allocateCluster(uint32_t current, uint32_t* next) { uint32_t find; bool setStart; @@ -199,10 +154,6 @@ bool FatPartition::allocContiguous(uint32_t count, uint32_t* firstCluster) { return false; } //------------------------------------------------------------------------------ -uint32_t FatPartition::clusterStartSector(uint32_t cluster) const { - return m_dataStartSector + ((cluster - 2) << m_sectorsPerClusterShift); -} -//------------------------------------------------------------------------------ // Fetch a FAT entry - return -1 error, 0 EOC, else 1. int8_t FatPartition::fatGet(uint32_t cluster, uint32_t* value) { uint32_t sector; @@ -217,7 +168,7 @@ int8_t FatPartition::fatGet(uint32_t cluster, uint32_t* value) { if (fatType() == 32) { sector = m_fatStartSector + (cluster >> (m_bytesPerSectorShift - 2)); - pc = cacheFetchFat(sector, FatCache::CACHE_FOR_READ); + pc = cacheFetchFat(sector, FsCache::CACHE_FOR_READ); if (!pc) { DBG_FAIL_MACRO; goto fail; @@ -227,7 +178,7 @@ int8_t FatPartition::fatGet(uint32_t cluster, uint32_t* value) { } else if (fatType() == 16) { cluster &= 0XFFFF; sector = m_fatStartSector + (cluster >> (m_bytesPerSectorShift - 1) ); - pc = cacheFetchFat(sector, FatCache::CACHE_FOR_READ); + pc = cacheFetchFat(sector, FsCache::CACHE_FOR_READ); if (!pc) { DBG_FAIL_MACRO; goto fail; @@ -238,7 +189,7 @@ int8_t FatPartition::fatGet(uint32_t cluster, uint32_t* value) { uint16_t index = cluster; index += index >> 1; sector = m_fatStartSector + (index >> m_bytesPerSectorShift); - pc = cacheFetchFat(sector, FatCache::CACHE_FOR_READ); + pc = cacheFetchFat(sector, FsCache::CACHE_FOR_READ); if (!pc) { DBG_FAIL_MACRO; goto fail; @@ -247,7 +198,7 @@ int8_t FatPartition::fatGet(uint32_t cluster, uint32_t* value) { uint16_t tmp = pc->data[index]; index++; if (index == m_bytesPerSector) { - pc = cacheFetchFat(sector + 1, FatCache::CACHE_FOR_READ); + pc = cacheFetchFat(sector + 1, FsCache::CACHE_FOR_READ); if (!pc) { DBG_FAIL_MACRO; goto fail; @@ -283,7 +234,7 @@ bool FatPartition::fatPut(uint32_t cluster, uint32_t value) { if (fatType() == 32) { sector = m_fatStartSector + (cluster >> (m_bytesPerSectorShift - 2)); - pc = cacheFetchFat(sector, FatCache::CACHE_FOR_WRITE); + pc = cacheFetchFat(sector, FsCache::CACHE_FOR_WRITE); if (!pc) { DBG_FAIL_MACRO; goto fail; @@ -296,7 +247,7 @@ bool FatPartition::fatPut(uint32_t cluster, uint32_t value) { if (fatType() == 16) { cluster &= 0XFFFF; sector = m_fatStartSector + (cluster >> (m_bytesPerSectorShift - 1) ); - pc = cacheFetchFat(sector, FatCache::CACHE_FOR_WRITE); + pc = cacheFetchFat(sector, FsCache::CACHE_FOR_WRITE); if (!pc) { DBG_FAIL_MACRO; goto fail; @@ -310,7 +261,7 @@ bool FatPartition::fatPut(uint32_t cluster, uint32_t value) { uint16_t index = cluster; index += index >> 1; sector = m_fatStartSector + (index >> m_bytesPerSectorShift); - pc = cacheFetchFat(sector, FatCache::CACHE_FOR_WRITE); + pc = cacheFetchFat(sector, FsCache::CACHE_FOR_WRITE); if (!pc) { DBG_FAIL_MACRO; goto fail; @@ -326,7 +277,7 @@ bool FatPartition::fatPut(uint32_t cluster, uint32_t value) { if (index == m_bytesPerSector) { sector++; index = 0; - pc = cacheFetchFat(sector, FatCache::CACHE_FOR_WRITE); + pc = cacheFetchFat(sector, FsCache::CACHE_FOR_WRITE); if (!pc) { DBG_FAIL_MACRO; goto fail; @@ -402,7 +353,7 @@ int32_t FatPartition::freeClusterCount() { } else if (fatType() == 16 || fatType() == 32) { sector = m_fatStartSector; while (todo) { - cache_t* pc = cacheFetchFat(sector++, FatCache::CACHE_FOR_READ); + cache_t* pc = cacheFetchFat(sector++, FsCache::CACHE_FOR_READ); if (!pc) { DBG_FAIL_MACRO; goto fail; @@ -449,9 +400,9 @@ bool FatPartition::init(BlockDevice* dev, uint8_t part) { uint8_t tmp; m_fatType = 0; m_allocSearchStart = 1; - m_cache.init(this); + m_cache.init(dev); #if USE_SEPARATE_FAT_CACHE - m_fatCache.init(this); + m_fatCache.init(dev); #endif // USE_SEPARATE_FAT_CACHE // if part == 0 assume super floppy with FAT boot sector in sector zero // if part > 0 assume mbr volume with partition table @@ -461,7 +412,7 @@ bool FatPartition::init(BlockDevice* dev, uint8_t part) { goto fail; } mbr = reinterpret_cast - (cacheFetchData(0, FatCache::CACHE_FOR_READ)); + (cacheFetchData(0, FsCache::CACHE_FOR_READ)); MbrPart_t* mp = mbr->part + part - 1; if (!mbr || mp->type == 0 || (mp->boot != 0 && mp->boot != 0X80)) { @@ -471,9 +422,8 @@ bool FatPartition::init(BlockDevice* dev, uint8_t part) { volumeStartSector = getLe32(mp->relativeSectors); } pbs = reinterpret_cast - (cacheFetchData(volumeStartSector, FatCache::CACHE_FOR_READ)); + (cacheFetchData(volumeStartSector, FsCache::CACHE_FOR_READ)); bpb = reinterpret_cast(pbs->bpb); - if (!pbs || bpb->fatCount != 2 || getLe16(bpb->bytesPerSector) != 512) { DBG_FAIL_MACRO; goto fail; @@ -531,6 +481,10 @@ bool FatPartition::init(BlockDevice* dev, uint8_t part) { m_rootDirStart = getLe32(bpb->fat32RootCluster); m_fatType = 32; } + m_cache.setMirrorOffset(m_sectorsPerFat); +#if USE_SEPARATE_FAT_CACHE + m_fatCache.setMirrorOffset(m_sectorsPerFat); +#endif // USE_SEPARATE_FAT_CACHE return true; fail: diff --git a/src/FatLib/FatPartition.h b/src/FatLib/FatPartition.h index 5cdbc86c..5ef996d5 100644 --- a/src/FatLib/FatPartition.h +++ b/src/FatLib/FatPartition.h @@ -32,6 +32,7 @@ #include "FatLibConfig.h" #include "../common/SysCall.h" #include "../common/BlockDevice.h" +#include "../common/FsCache.h" #include "../common/FsStructs.h" /** Type for FAT12 partition */ @@ -43,12 +44,9 @@ const uint8_t FAT_TYPE_FAT16 = 16; /** Type for FAT12 partition */ const uint8_t FAT_TYPE_FAT32 = 32; -//------------------------------------------------------------------------------ -// Forward declaration of FatPartition. -class FatPartition; //------------------------------------------------------------------------------ /** - * \brief Cache for an raw data sector. + * \brief Cache type for a sector. */ union cache_t { /** Used to access cached file data sectors. */ @@ -58,74 +56,7 @@ union cache_t { /** Used to access cached FAT32 entries. */ uint32_t fat32[128]; /** Used to access cached directory entries. */ - DirFat_t dir[16]; -}; -//============================================================================== -/** - * \class FatCache - * \brief Sector cache. - */ -class FatCache { - public: - /** Cached sector is dirty */ - static const uint8_t CACHE_STATUS_DIRTY = 1; - /** Cashed sector is FAT entry and must be mirrored in second FAT. */ - static const uint8_t CACHE_STATUS_MIRROR_FAT = 2; - /** Cache sector status bits */ - static const uint8_t CACHE_STATUS_MASK - = CACHE_STATUS_DIRTY | CACHE_STATUS_MIRROR_FAT; - /** Sync existing sector but do not read new sector. */ - static const uint8_t CACHE_OPTION_NO_READ = 4; - /** Cache sector for read. */ - static const uint8_t CACHE_FOR_READ = 0; - /** Cache sector for write. */ - static const uint8_t CACHE_FOR_WRITE = CACHE_STATUS_DIRTY; - /** Reserve cache sector for write - do not read from sector device. */ - static const uint8_t CACHE_RESERVE_FOR_WRITE - = CACHE_STATUS_DIRTY | CACHE_OPTION_NO_READ; - /** \return Cache sector address. */ - cache_t* buffer() { - return &m_buffer; - } - /** Set current sector dirty. */ - void dirty() { - m_status |= CACHE_STATUS_DIRTY; - } - /** Initialize the cache. - * \param[in] vol FatPartition that owns this FatCache. - */ - void init(FatPartition *vol) { - m_part = vol; - invalidate(); - } - /** Invalidate current cache sector. */ - void invalidate() { - m_status = 0; - m_lbn = 0XFFFFFFFF; - } - /** \return dirty status */ - bool isDirty() { - return m_status & CACHE_STATUS_DIRTY; - } - /** \return Logical sector number for cached sector. */ - uint32_t sector() { - return m_lbn; - } - /** Read a sector into the cache. - * \param[in] sector Sector to read. - * \param[in] option mode for cached sector. - * \return Address of cached sector. */ - cache_t* read(uint32_t sector, uint8_t option); - /** Write current sector if dirty. - * \return true for success or false for failure. - */ - bool sync(); - - private: - uint8_t m_status; - FatPartition* m_part; - uint32_t m_lbn; - cache_t m_buffer; + DirFat_t dir[16]; }; //============================================================================== /** @@ -173,12 +104,8 @@ class FatPartition { /** Clear the cache and returns a pointer to the cache. Not for normal apps. * \return A pointer to the cache buffer or zero if an error occurs. */ - cache_t* cacheClear() { - if (!cacheSync()) { - return nullptr; - } - m_cache.invalidate(); - return m_cache.buffer(); + uint8_t* cacheClear() { + return m_cache.clear(); } /** \return The total number of clusters in the volume. */ uint32_t clusterCount() const { @@ -251,8 +178,6 @@ class FatPartition { #endif // DOXYGEN_SHOULD_SKIP_THIS //---------------------------------------------------------------------------- private: - /** FatCache allowed access to private members. */ - friend class FatCache; /** FatFile allowed access to private members. */ friend class FatFile; //---------------------------------------------------------------------------- @@ -274,6 +199,18 @@ class FatPartition { uint32_t m_rootDirStart; // Start sector FAT16, cluster FAT32. //---------------------------------------------------------------------------- // sector I/O functions. + bool cacheSafeRead(uint32_t sector, uint8_t* dst) { + return m_cache.cacheSafeRead(sector, dst); + } + bool cacheSafeRead(uint32_t sector, uint8_t* dst, size_t count) { + return m_cache.cacheSafeRead(sector, dst, count); + } + bool cacheSafeWrite(uint32_t sector, const uint8_t* dst) { + return m_cache.cacheSafeWrite(sector, dst); + } + bool cacheSafeWrite(uint32_t sector, const uint8_t* dst, size_t count) { + return m_cache.cacheSafeWrite(sector, dst, count); + } bool readSector(uint32_t sector, uint8_t* dst) { return m_blockDev->readSector(sector, dst); } @@ -283,14 +220,6 @@ class FatPartition { bool writeSector(uint32_t sector, const uint8_t* src) { return m_blockDev->writeSector(sector, src); } -#if USE_MULTI_SECTOR_IO - bool readSectors(uint32_t sector, uint8_t* dst, size_t ns) { - return m_blockDev->readSectors(sector, dst, ns); - } - bool writeSectors(uint32_t sector, const uint8_t* src, size_t ns) { - return m_blockDev->writeSectors(sector, src, ns); - } -#endif // USE_MULTI_SECTOR_IO #if MAINTAIN_FREE_CLUSTER_COUNT int32_t m_freeClusterCount; // Count of free clusters in volume. void setFreeClusterCount(int32_t value) { @@ -309,29 +238,28 @@ class FatPartition { (void)change; } #endif // MAINTAIN_FREE_CLUSTER_COUNT - // sector caches - FatCache m_cache; + FsCache m_cache; #if USE_SEPARATE_FAT_CACHE - FatCache m_fatCache; + FsCache m_fatCache; cache_t* cacheFetchFat(uint32_t sector, uint8_t options) { - return m_fatCache.read(sector, - options | FatCache::CACHE_STATUS_MIRROR_FAT); + options |= FsCache::CACHE_STATUS_MIRROR_FAT; + return reinterpret_cast(m_fatCache.get(sector, options)); } bool cacheSync() { return m_cache.sync() && m_fatCache.sync() && syncDevice(); } #else // USE_SEPARATE_FAT_CACHE cache_t* cacheFetchFat(uint32_t sector, uint8_t options) { - return cacheFetchData(sector, - options | FatCache::CACHE_STATUS_MIRROR_FAT); + options |= FsCache::CACHE_STATUS_MIRROR_FAT; + return cacheFetchData(sector, options); } bool cacheSync() { return m_cache.sync() && syncDevice(); } #endif // USE_SEPARATE_FAT_CACHE cache_t* cacheFetchData(uint32_t sector, uint8_t options) { - return m_cache.read(sector, options); + return reinterpret_cast(m_cache.get(sector, options)); } void cacheInvalidate() { m_cache.invalidate(); @@ -340,7 +268,7 @@ class FatPartition { return m_cache.sync(); } cache_t* cacheAddress() { - return m_cache.buffer(); + return reinterpret_cast(m_cache.cacheBuffer()); } uint32_t cacheSectorNumber() { return m_cache.sector(); @@ -354,7 +282,9 @@ class FatPartition { uint8_t sectorOfCluster(uint32_t position) const { return (position >> 9) & m_clusterSectorMask; } - uint32_t clusterStartSector(uint32_t cluster) const; + uint32_t clusterStartSector(uint32_t cluster) const { + return m_dataStartSector + ((cluster - 2) << m_sectorsPerClusterShift); + } int8_t fatGet(uint32_t cluster, uint32_t* value); bool fatPut(uint32_t cluster, uint32_t value); bool fatPutEOC(uint32_t cluster) { diff --git a/src/SdFat.h b/src/SdFat.h index b7855ede..c7c03f94 100644 --- a/src/SdFat.h +++ b/src/SdFat.h @@ -357,7 +357,7 @@ class SdFat32 : public SdBase { */ bool format(print_t* pr = nullptr) { FatFormatter fmt; - uint8_t* cache = reinterpret_cast(cacheClear()); + uint8_t* cache = cacheClear(); if (!cache) { return false; } @@ -378,7 +378,7 @@ class SdExFat : public SdBase { */ bool format(print_t* pr = nullptr) { ExFatFormatter fmt; - uint8_t* cache = reinterpret_cast(cacheClear()); + uint8_t* cache = cacheClear(); if (!cache) { return false; } diff --git a/src/common/BlockDeviceInterface.h b/src/common/BlockDeviceInterface.h index c478a16c..22e5804a 100644 --- a/src/common/BlockDeviceInterface.h +++ b/src/common/BlockDeviceInterface.h @@ -46,7 +46,7 @@ class BlockDeviceInterface { * \return true for success or false for failure. */ virtual bool readSector(uint32_t sector, uint8_t* dst) = 0; -#if USE_MULTI_SECTOR_IO + /** * Read multiple sectors. * @@ -56,7 +56,7 @@ class BlockDeviceInterface { * \return true for success or false for failure. */ virtual bool readSectors(uint32_t sector, uint8_t* dst, size_t ns) = 0; -#endif // USE_MULTI_SECTOR_IO + /** \return device size in sectors. */ virtual uint32_t sectorCount() = 0; @@ -73,7 +73,7 @@ class BlockDeviceInterface { * \return true for success or false for failure. */ virtual bool writeSector(uint32_t sector, const uint8_t* src) = 0; -#if USE_MULTI_SECTOR_IO + /** * Write multiple sectors. * @@ -83,6 +83,5 @@ class BlockDeviceInterface { * \return true for success or false for failure. */ virtual bool writeSectors(uint32_t sector, const uint8_t* src, size_t ns) = 0; -#endif // USE_MULTI_SECTOR_IO }; #endif // BlockDeviceInterface_h diff --git a/src/common/FsCache.cpp b/src/common/FsCache.cpp new file mode 100644 index 00000000..e19357e4 --- /dev/null +++ b/src/common/FsCache.cpp @@ -0,0 +1,74 @@ +/** + * Copyright (c) 2011-2020 Bill Greiman + * This file is part of the SdFat library for SD memory cards. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +#include "DebugMacros.h" +#include "FsCache.h" +//------------------------------------------------------------------------------ +uint8_t* FsCache::get(uint32_t sector, uint8_t option) { + if (!m_blockDev) { + DBG_FAIL_MACRO; + goto fail; + } + if (m_sector != sector) { + if (!sync()) { + DBG_FAIL_MACRO; + goto fail; + } + if (!(option & CACHE_OPTION_NO_READ)) { + if (!m_blockDev->readSector(sector, m_buffer)) { + DBG_FAIL_MACRO; + goto fail; + } + } + m_status = 0; + m_sector = sector; + } + m_status |= option & CACHE_STATUS_MASK; + return m_buffer; + + fail: + return nullptr; +} +//------------------------------------------------------------------------------ +bool FsCache::sync() { + if (m_status & CACHE_STATUS_DIRTY) { + if (!m_blockDev->writeSector(m_sector, m_buffer)) { + DBG_FAIL_MACRO; + goto fail; + } + // mirror second FAT + if (m_status & CACHE_STATUS_MIRROR_FAT) { + uint32_t sector = m_sector + m_mirrorOffset; + if (!m_blockDev->writeSector(sector, m_buffer)) { + DBG_FAIL_MACRO; + goto fail; + } + } + m_status &= ~CACHE_STATUS_DIRTY; + } + return true; + + fail: + return false; +} diff --git a/src/common/FsCache.h b/src/common/FsCache.h new file mode 100644 index 00000000..27aa9dac --- /dev/null +++ b/src/common/FsCache.h @@ -0,0 +1,184 @@ +/** + * Copyright (c) 2011-2020 Bill Greiman + * This file is part of the SdFat library for SD memory cards. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +#ifndef FsCache_h +#define FsCache_h +/** + * \file + * \brief Common cache code for exFAT and FAT. + */ +#include "SysCall.h" +#include "BlockDevice.h" +#include "DebugMacros.h" +/** + * \class FsCache + * \brief Sector cache. + */ +class FsCache { + public: + /** Cached sector is dirty */ + static const uint8_t CACHE_STATUS_DIRTY = 1; + /** Cashed sector is FAT entry and must be mirrored in second FAT. */ + static const uint8_t CACHE_STATUS_MIRROR_FAT = 2; + /** Cache sector status bits */ + static const uint8_t CACHE_STATUS_MASK = + CACHE_STATUS_DIRTY | CACHE_STATUS_MIRROR_FAT; + /** Sync existing sector but do not read new sector. */ + static const uint8_t CACHE_OPTION_NO_READ = 4; + /** Cache sector for read. */ + static const uint8_t CACHE_FOR_READ = 0; + /** Cache sector for write. */ + static const uint8_t CACHE_FOR_WRITE = CACHE_STATUS_DIRTY; + /** Reserve cache sector for write - do not read from sector device. */ + static const uint8_t CACHE_RESERVE_FOR_WRITE = + CACHE_STATUS_DIRTY | CACHE_OPTION_NO_READ; + //---------------------------------------------------------------------------- + /** \return Cache buffer address. */ + uint8_t* cacheBuffer() { + return m_buffer; + } + /** + * Cache safe read of a sector. + * + * \param[in] sector Logical sector to be read. + * \param[out] dst Pointer to the location that will receive the data. + * \return true for success or false for failure. + */ + bool cacheSafeRead(uint32_t sector, uint8_t* dst) { + if (isCached(sector)) { + memcpy(dst, m_buffer, 512); + return true; + } + return m_blockDev->readSector(sector, dst); + } + /** + * Cache safe read of multiple sectors. + * + * \param[in] sector Logical sector to be read. + * \param[in] count Number of sectors to be read. + * \param[out] dst Pointer to the location that will receive the data. + * \return true for success or false for failure. + */ + bool cacheSafeRead(uint32_t sector, uint8_t* dst, size_t count) { + if (isCached(sector, count) && !sync()) { + return false; + } + return m_blockDev->readSectors(sector, dst, count); + } + /** + * Cache safe write of a sectors. + * + * \param[in] sector Logical sector to be written. + * \param[in] src Pointer to the location of the data to be written. + * \return true for success or false for failure. + */ + bool cacheSafeWrite(uint32_t sector, const uint8_t* src) { + if (isCached(sector)) { + invalidate(); + } + return m_blockDev->writeSector(sector, src); + } + /** + * Cache safe write of multiple sectors. + * + * \param[in] sector Logical sector to be written. + * \param[in] src Pointer to the location of the data to be written. + * \param[in] count Number of sectors to be written. + * \return true for success or false for failure. + */ + bool cacheSafeWrite(uint32_t sector, const uint8_t* src, size_t count) { + if (isCached(sector, count)) { + invalidate(); + } + return m_blockDev->writeSectors(sector, src, count); + } + /** \return Clear the cache and returns a pointer to the cache. */ + uint8_t* clear() { + if (isDirty() && !sync()) { + return nullptr; + } + invalidate(); + return m_buffer; + } + /** Set current sector dirty. */ + void dirty() { + m_status |= CACHE_STATUS_DIRTY; + } + /** Initialize the cache. + * \param[in] blockDev Block device for this cache. + */ + void init(BlockDevice* blockDev) { + m_blockDev = blockDev; + invalidate(); + } + /** Invalidate current cache sector. */ + void invalidate() { + m_status = 0; + m_sector = 0XFFFFFFFF; + } + /** Check if a sector is in the cache. + * \param[in] sector Sector to checked. + * \return true if the sector is cached. + */ + bool isCached(uint32_t sector) {return sector == m_sector;} + /** Check if the cache contains a sector from a range. + * \param[in] sector Start sector of the range. + * \param[in] count Number of sectors in the range. + * \return true if a sector in the range is cached. + */ + bool isCached(uint32_t sector, size_t count) { + return sector <= m_sector && m_sector < (sector + count); + } + /** \return dirty status */ + bool isDirty() { + return m_status & CACHE_STATUS_DIRTY; + } + /** \return Logical sector number for cached sector. */ + uint32_t sector() { + return m_sector; + } + /** Set the offset to the second FAT for mirroring. + * \param[in] offset Sector offset to second FAT. + */ + void setMirrorOffset(uint32_t offset) { + m_mirrorOffset = offset; + } + /** Fill cache with sector data. + * \param[in] sector Sector to read. + * \param[in] option mode for cached sector. + * \return Address of cached sector. */ + uint8_t* get(uint32_t sector, uint8_t option); + /** Write current sector if dirty. + * \return true for success or false for failure. + */ + bool sync(); + + private: + uint8_t m_status; + BlockDevice* m_blockDev; + uint32_t m_mirrorOffset; + uint32_t m_sector; + uint8_t m_buffer[512]; +}; +#endif // FsCache_h diff --git a/src/common/FsDateTime.cpp b/src/common/FsDateTime.cpp index 5faae531..50e792a5 100644 --- a/src/common/FsDateTime.cpp +++ b/src/common/FsDateTime.cpp @@ -74,8 +74,7 @@ char* fsFmtTime(char* str, uint16_t time) { } //------------------------------------------------------------------------------ char* fsFmtTime(char* str, uint16_t time, uint8_t sec100) { - str = fsFmtField(str, sec100%100, 0); - str = fsFmtField(str, 2*(time & 31) + sec100/100, '.'); + str = fsFmtField(str, 2*(time & 31) + (sec100 < 100 ? 0 : 1), 0); *--str = ':'; return fsFmtTime(str, time); } @@ -138,8 +137,8 @@ size_t fsPrintDateTime(print_t* pr, uint32_t dateTime) { //------------------------------------------------------------------------------ size_t fsPrintDateTime(print_t* pr, uint32_t dateTime, uint8_t s100, int8_t tz) { - // Allow YYYY-MM-DD hh:mm:ss.ss UTC+hh:mm - char buf[sizeof("YYYY-MM-DD hh:mm:ss.ss UTC+hh:mm") -1]; + // Allow YYYY-MM-DD hh:mm:ss UTC+hh:mm + char buf[sizeof("YYYY-MM-DD hh:mm:ss UTC+hh:mm") -1]; char* str = buf + sizeof(buf); if (tz) { str = fsFmtTimeZone(str, tz); @@ -160,8 +159,8 @@ size_t fsPrintTime(print_t* pr, uint16_t time) { } //------------------------------------------------------------------------------ size_t fsPrintTime(print_t* pr, uint16_t time, uint8_t sec100) { - // Allow hh:mm:ss.ss - char buf[sizeof("hh:mm:ss.ss") -1]; + // Allow hh:mm:ss + char buf[sizeof("hh:mm:ss") -1]; char* str = buf + sizeof(buf); str = fsFmtTime(str, time, sec100); return pr->write(reinterpret_cast(str), buf + sizeof(buf) - str);