utility
Embed:
(wiki syntax)
Show/hide line numbers
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