Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
SdVolume.cpp
00001 /* Arduino SdFat Library 00002 * Copyright (C) 2009 by William Greiman 00003 * 00004 * This file is part of the Arduino SdFat Library 00005 * 00006 * This Library is free software: you can redistribute it and/or modify 00007 * it under the terms of the GNU General Public License as published by 00008 * the Free Software Foundation, either version 3 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * This Library is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with the Arduino SdFat Library. If not, see 00018 * <http://www.gnu.org/licenses/>. 00019 */ 00020 #include <SdFat.h> 00021 //------------------------------------------------------------------------------ 00022 // raw block cache 00023 // init cacheBlockNumber_to invalid SD block number 00024 uint32_t SdVolume::cacheBlockNumber_ = 0XFFFFFFFF; 00025 cache_t SdVolume::cacheBuffer_; // 512 byte cache for Sd2Card 00026 Sd2Card* SdVolume::sdCard_; // pointer to SD card object 00027 uint8_t SdVolume::cacheDirty_ = 0; // cacheFlush() will write block if true 00028 uint32_t SdVolume::cacheMirrorBlock_ = 0; // mirror block for second FAT 00029 //------------------------------------------------------------------------------ 00030 // find a contiguous group of clusters 00031 uint8_t SdVolume::allocContiguous(uint32_t count, uint32_t* curCluster) { 00032 // start of group 00033 uint32_t bgnCluster; 00034 00035 // flag to save place to start next search 00036 uint8_t setStart; 00037 00038 // set search start cluster 00039 if (*curCluster) { 00040 // try to make file contiguous 00041 bgnCluster = *curCluster + 1; 00042 00043 // don't save new start location 00044 setStart = false; 00045 } else { 00046 // start at likely place for free cluster 00047 bgnCluster = allocSearchStart_; 00048 00049 // save next search start if one cluster 00050 setStart = 1 == count; 00051 } 00052 // end of group 00053 uint32_t endCluster = bgnCluster; 00054 00055 // last cluster of FAT 00056 uint32_t fatEnd = clusterCount_ + 1; 00057 00058 // search the FAT for free clusters 00059 for (uint32_t n = 0;; n++, endCluster++) { 00060 // can't find space checked all clusters 00061 if (n >= clusterCount_) return false; 00062 00063 // past end - start from beginning of FAT 00064 if (endCluster > fatEnd) { 00065 bgnCluster = endCluster = 2; 00066 } 00067 uint32_t f; 00068 if (!fatGet(endCluster, &f)) return false; 00069 00070 if (f != 0) { 00071 // cluster in use try next cluster as bgnCluster 00072 bgnCluster = endCluster + 1; 00073 } else if ((endCluster - bgnCluster + 1) == count) { 00074 // done - found space 00075 break; 00076 } 00077 } 00078 // mark end of chain 00079 if (!fatPutEOC(endCluster)) return false; 00080 00081 // link clusters 00082 while (endCluster > bgnCluster) { 00083 if (!fatPut(endCluster - 1, endCluster)) return false; 00084 endCluster--; 00085 } 00086 if (*curCluster != 0) { 00087 // connect chains 00088 if (!fatPut(*curCluster, bgnCluster)) return false; 00089 } 00090 // return first cluster number to caller 00091 *curCluster = bgnCluster; 00092 00093 // remember possible next free cluster 00094 if (setStart) allocSearchStart_ = bgnCluster + 1; 00095 00096 return true; 00097 } 00098 //------------------------------------------------------------------------------ 00099 uint8_t SdVolume::cacheFlush(void) { 00100 if (cacheDirty_) { 00101 if (!sdCard_->writeBlock(cacheBlockNumber_, cacheBuffer_.data)) { 00102 return false; 00103 } 00104 // mirror FAT tables 00105 if (cacheMirrorBlock_) { 00106 if (!sdCard_->writeBlock(cacheMirrorBlock_, cacheBuffer_.data)) { 00107 return false; 00108 } 00109 cacheMirrorBlock_ = 0; 00110 } 00111 cacheDirty_ = 0; 00112 } 00113 return true; 00114 } 00115 //------------------------------------------------------------------------------ 00116 uint8_t SdVolume::cacheRawBlock(uint32_t blockNumber, uint8_t action) { 00117 if (cacheBlockNumber_ != blockNumber) { 00118 if (!cacheFlush()) return false; 00119 if (!sdCard_->readBlock(blockNumber, cacheBuffer_.data)) return false; 00120 cacheBlockNumber_ = blockNumber; 00121 } 00122 cacheDirty_ |= action; 00123 return true; 00124 } 00125 //------------------------------------------------------------------------------ 00126 // cache a zero block for blockNumber 00127 uint8_t SdVolume::cacheZeroBlock(uint32_t blockNumber) { 00128 if (!cacheFlush()) return false; 00129 00130 // loop take less flash than memset(cacheBuffer_.data, 0, 512); 00131 for (uint16_t i = 0; i < 512; i++) { 00132 cacheBuffer_.data[i] = 0; 00133 } 00134 cacheBlockNumber_ = blockNumber; 00135 cacheSetDirty(); 00136 return true; 00137 } 00138 //------------------------------------------------------------------------------ 00139 // return the size in bytes of a cluster chain 00140 uint8_t SdVolume::chainSize(uint32_t cluster, uint32_t* size) const { 00141 uint32_t s = 0; 00142 do { 00143 if (!fatGet(cluster, &cluster)) return false; 00144 s += 512UL << clusterSizeShift_; 00145 } while (!isEOC(cluster)); 00146 *size = s; 00147 return true; 00148 } 00149 //------------------------------------------------------------------------------ 00150 // Fetch a FAT entry 00151 uint8_t SdVolume::fatGet(uint32_t cluster, uint32_t* value) const { 00152 if (cluster > (clusterCount_ + 1)) return false; 00153 uint32_t lba = fatStartBlock_; 00154 lba += fatType_ == 16 ? cluster >> 8 : cluster >> 7; 00155 if (lba != cacheBlockNumber_) { 00156 if (!cacheRawBlock(lba, CACHE_FOR_READ)) return false; 00157 } 00158 if (fatType_ == 16) { 00159 *value = cacheBuffer_.fat16[cluster & 0XFF]; 00160 } else { 00161 *value = cacheBuffer_.fat32[cluster & 0X7F] & FAT32MASK; 00162 } 00163 return true; 00164 } 00165 //------------------------------------------------------------------------------ 00166 // Store a FAT entry 00167 uint8_t SdVolume::fatPut(uint32_t cluster, uint32_t value) { 00168 // error if reserved cluster 00169 if (cluster < 2) return false; 00170 00171 // error if not in FAT 00172 if (cluster > (clusterCount_ + 1)) return false; 00173 00174 // calculate block address for entry 00175 uint32_t lba = fatStartBlock_; 00176 lba += fatType_ == 16 ? cluster >> 8 : cluster >> 7; 00177 00178 if (lba != cacheBlockNumber_) { 00179 if (!cacheRawBlock(lba, CACHE_FOR_READ)) return false; 00180 } 00181 // store entry 00182 if (fatType_ == 16) { 00183 cacheBuffer_.fat16[cluster & 0XFF] = value; 00184 } else { 00185 cacheBuffer_.fat32[cluster & 0X7F] = value; 00186 } 00187 cacheSetDirty(); 00188 00189 // mirror second FAT 00190 if (fatCount_ > 1) cacheMirrorBlock_ = lba + blocksPerFat_; 00191 return true; 00192 } 00193 //------------------------------------------------------------------------------ 00194 // free a cluster chain 00195 uint8_t SdVolume::freeChain(uint32_t cluster) { 00196 // clear free cluster location 00197 allocSearchStart_ = 2; 00198 00199 do { 00200 uint32_t next; 00201 if (!fatGet(cluster, &next)) return false; 00202 00203 // free cluster 00204 if (!fatPut(cluster, 0)) return false; 00205 00206 cluster = next; 00207 } while (!isEOC(cluster)); 00208 00209 return true; 00210 } 00211 //------------------------------------------------------------------------------ 00212 /** 00213 * Initialize a FAT volume. 00214 * 00215 * \param[in] dev The SD card where the volume is located. 00216 * 00217 * \param[in] part The partition to be used. Legal values for \a part are 00218 * 1-4 to use the corresponding partition on a device formatted with 00219 * a MBR, Master Boot Record, or zero if the device is formatted as 00220 * a super floppy with the FAT boot sector in block zero. 00221 * 00222 * \return The value one, true, is returned for success and 00223 * the value zero, false, is returned for failure. Reasons for 00224 * failure include not finding a valid partition, not finding a valid 00225 * FAT file system in the specified partition or an I/O error. 00226 */ 00227 uint8_t SdVolume::init(Sd2Card* dev, uint8_t part) { 00228 uint32_t volumeStartBlock = 0; 00229 sdCard_ = dev; 00230 // if part == 0 assume super floppy with FAT boot sector in block zero 00231 // if part > 0 assume mbr volume with partition table 00232 if (part) { 00233 if (part > 4)return false; 00234 if (!cacheRawBlock(volumeStartBlock, CACHE_FOR_READ)) return false; 00235 part_t* p = &cacheBuffer_.mbr.part[part-1]; 00236 if ((p->boot & 0X7F) !=0 || 00237 p->totalSectors < 100 || 00238 p->firstSector == 0) { 00239 // not a valid partition 00240 return false; 00241 } 00242 volumeStartBlock = p->firstSector; 00243 } 00244 if (!cacheRawBlock(volumeStartBlock, CACHE_FOR_READ)) return false; 00245 bpb_t* bpb = &cacheBuffer_.fbs.bpb; 00246 if (bpb->bytesPerSector != 512 || 00247 bpb->fatCount == 0 || 00248 bpb->reservedSectorCount == 0 || 00249 bpb->sectorsPerCluster == 0) { 00250 // not valid FAT volume 00251 return false; 00252 } 00253 fatCount_ = bpb->fatCount; 00254 blocksPerCluster_ = bpb->sectorsPerCluster; 00255 00256 // determine shift that is same as multiply by blocksPerCluster_ 00257 clusterSizeShift_ = 0; 00258 while (blocksPerCluster_ != (1 << clusterSizeShift_)) { 00259 // error if not power of 2 00260 if (clusterSizeShift_++ > 7) return false; 00261 } 00262 blocksPerFat_ = bpb->sectorsPerFat16 ? 00263 bpb->sectorsPerFat16 : bpb->sectorsPerFat32; 00264 00265 fatStartBlock_ = volumeStartBlock + bpb->reservedSectorCount; 00266 00267 // count for FAT16 zero for FAT32 00268 rootDirEntryCount_ = bpb->rootDirEntryCount; 00269 00270 // directory start for FAT16 dataStart for FAT32 00271 rootDirStart_ = fatStartBlock_ + bpb->fatCount * blocksPerFat_; 00272 00273 // data start for FAT16 and FAT32 00274 dataStartBlock_ = rootDirStart_ + ((32 * bpb->rootDirEntryCount + 511)/512); 00275 00276 // total blocks for FAT16 or FAT32 00277 uint32_t totalBlocks = bpb->totalSectors16 ? 00278 bpb->totalSectors16 : bpb->totalSectors32; 00279 // total data blocks 00280 clusterCount_ = totalBlocks - (dataStartBlock_ - volumeStartBlock); 00281 00282 // divide by cluster size to get cluster count 00283 clusterCount_ >>= clusterSizeShift_; 00284 00285 // FAT type is determined by cluster count 00286 if (clusterCount_ < 4085) { 00287 fatType_ = 12; 00288 } else if (clusterCount_ < 65525) { 00289 fatType_ = 16; 00290 } else { 00291 rootDirStart_ = bpb->fat32RootCluster; 00292 fatType_ = 32; 00293 } 00294 return true; 00295 }
Generated on Thu Jul 14 2022 02:07:54 by
1.7.2