|
1 /* Arduino SdFat Library |
|
2 * Copyright (C) 2009 by William Greiman |
|
3 * |
|
4 * This file is part of the Arduino SdFat Library |
|
5 * |
|
6 * This Library is free software: you can redistribute it and/or modify |
|
7 * it under the terms of the GNU General Public License as published by |
|
8 * the Free Software Foundation, either version 3 of the License, or |
|
9 * (at your option) any later version. |
|
10 * |
|
11 * This Library is distributed in the hope that it will be useful, |
|
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
14 * GNU General Public License for more details. |
|
15 * |
|
16 * You should have received a copy of the GNU General Public License |
|
17 * along with the Arduino SdFat Library. If not, see |
|
18 * <http://www.gnu.org/licenses/>. |
|
19 */ |
|
20 #include "Marlin.h" |
|
21 #ifdef SDSUPPORT |
|
22 #ifndef SdVolume_h |
|
23 #define SdVolume_h |
|
24 /** |
|
25 * \file |
|
26 * \brief SdVolume class |
|
27 */ |
|
28 #include "SdFatConfig.h" |
|
29 #include "Sd2Card.h" |
|
30 #include "SdFatStructs.h" |
|
31 |
|
32 //============================================================================== |
|
33 // SdVolume class |
|
34 /** |
|
35 * \brief Cache for an SD data block |
|
36 */ |
|
37 union cache_t { |
|
38 /** Used to access cached file data blocks. */ |
|
39 uint8_t data[512]; |
|
40 /** Used to access cached FAT16 entries. */ |
|
41 uint16_t fat16[256]; |
|
42 /** Used to access cached FAT32 entries. */ |
|
43 uint32_t fat32[128]; |
|
44 /** Used to access cached directory entries. */ |
|
45 dir_t dir[16]; |
|
46 /** Used to access a cached Master Boot Record. */ |
|
47 mbr_t mbr; |
|
48 /** Used to access to a cached FAT boot sector. */ |
|
49 fat_boot_t fbs; |
|
50 /** Used to access to a cached FAT32 boot sector. */ |
|
51 fat32_boot_t fbs32; |
|
52 /** Used to access to a cached FAT32 FSINFO sector. */ |
|
53 fat32_fsinfo_t fsinfo; |
|
54 }; |
|
55 //------------------------------------------------------------------------------ |
|
56 /** |
|
57 * \class SdVolume |
|
58 * \brief Access FAT16 and FAT32 volumes on SD and SDHC cards. |
|
59 */ |
|
60 class SdVolume { |
|
61 public: |
|
62 /** Create an instance of SdVolume */ |
|
63 SdVolume() : fatType_(0) {} |
|
64 /** Clear the cache and returns a pointer to the cache. Used by the WaveRP |
|
65 * recorder to do raw write to the SD card. Not for normal apps. |
|
66 * \return A pointer to the cache buffer or zero if an error occurs. |
|
67 */ |
|
68 cache_t* cacheClear() { |
|
69 if (!cacheFlush()) return 0; |
|
70 cacheBlockNumber_ = 0XFFFFFFFF; |
|
71 return &cacheBuffer_; |
|
72 } |
|
73 /** Initialize a FAT volume. Try partition one first then try super |
|
74 * floppy format. |
|
75 * |
|
76 * \param[in] dev The Sd2Card where the volume is located. |
|
77 * |
|
78 * \return The value one, true, is returned for success and |
|
79 * the value zero, false, is returned for failure. Reasons for |
|
80 * failure include not finding a valid partition, not finding a valid |
|
81 * FAT file system or an I/O error. |
|
82 */ |
|
83 bool init(Sd2Card* dev) { return init(dev, 1) ? true : init(dev, 0);} |
|
84 bool init(Sd2Card* dev, uint8_t part); |
|
85 |
|
86 // inline functions that return volume info |
|
87 /** \return The volume's cluster size in blocks. */ |
|
88 uint8_t blocksPerCluster() const {return blocksPerCluster_;} |
|
89 /** \return The number of blocks in one FAT. */ |
|
90 uint32_t blocksPerFat() const {return blocksPerFat_;} |
|
91 /** \return The total number of clusters in the volume. */ |
|
92 uint32_t clusterCount() const {return clusterCount_;} |
|
93 /** \return The shift count required to multiply by blocksPerCluster. */ |
|
94 uint8_t clusterSizeShift() const {return clusterSizeShift_;} |
|
95 /** \return The logical block number for the start of file data. */ |
|
96 uint32_t dataStartBlock() const {return dataStartBlock_;} |
|
97 /** \return The number of FAT structures on the volume. */ |
|
98 uint8_t fatCount() const {return fatCount_;} |
|
99 /** \return The logical block number for the start of the first FAT. */ |
|
100 uint32_t fatStartBlock() const {return fatStartBlock_;} |
|
101 /** \return The FAT type of the volume. Values are 12, 16 or 32. */ |
|
102 uint8_t fatType() const {return fatType_;} |
|
103 int32_t freeClusterCount(); |
|
104 /** \return The number of entries in the root directory for FAT16 volumes. */ |
|
105 uint32_t rootDirEntryCount() const {return rootDirEntryCount_;} |
|
106 /** \return The logical block number for the start of the root directory |
|
107 on FAT16 volumes or the first cluster number on FAT32 volumes. */ |
|
108 uint32_t rootDirStart() const {return rootDirStart_;} |
|
109 /** Sd2Card object for this volume |
|
110 * \return pointer to Sd2Card object. |
|
111 */ |
|
112 Sd2Card* sdCard() {return sdCard_;} |
|
113 /** Debug access to FAT table |
|
114 * |
|
115 * \param[in] n cluster number. |
|
116 * \param[out] v value of entry |
|
117 * \return true for success or false for failure |
|
118 */ |
|
119 bool dbgFat(uint32_t n, uint32_t* v) {return fatGet(n, v);} |
|
120 //------------------------------------------------------------------------------ |
|
121 private: |
|
122 // Allow SdBaseFile access to SdVolume private data. |
|
123 friend class SdBaseFile; |
|
124 |
|
125 // value for dirty argument in cacheRawBlock to indicate read from cache |
|
126 static bool const CACHE_FOR_READ = false; |
|
127 // value for dirty argument in cacheRawBlock to indicate write to cache |
|
128 static bool const CACHE_FOR_WRITE = true; |
|
129 |
|
130 #if USE_MULTIPLE_CARDS |
|
131 cache_t cacheBuffer_; // 512 byte cache for device blocks |
|
132 uint32_t cacheBlockNumber_; // Logical number of block in the cache |
|
133 Sd2Card* sdCard_; // Sd2Card object for cache |
|
134 bool cacheDirty_; // cacheFlush() will write block if true |
|
135 uint32_t cacheMirrorBlock_; // block number for mirror FAT |
|
136 #else // USE_MULTIPLE_CARDS |
|
137 static cache_t cacheBuffer_; // 512 byte cache for device blocks |
|
138 static uint32_t cacheBlockNumber_; // Logical number of block in the cache |
|
139 static Sd2Card* sdCard_; // Sd2Card object for cache |
|
140 static bool cacheDirty_; // cacheFlush() will write block if true |
|
141 static uint32_t cacheMirrorBlock_; // block number for mirror FAT |
|
142 #endif // USE_MULTIPLE_CARDS |
|
143 uint32_t allocSearchStart_; // start cluster for alloc search |
|
144 uint8_t blocksPerCluster_; // cluster size in blocks |
|
145 uint32_t blocksPerFat_; // FAT size in blocks |
|
146 uint32_t clusterCount_; // clusters in one FAT |
|
147 uint8_t clusterSizeShift_; // shift to convert cluster count to block count |
|
148 uint32_t dataStartBlock_; // first data block number |
|
149 uint8_t fatCount_; // number of FATs on volume |
|
150 uint32_t fatStartBlock_; // start block for first FAT |
|
151 uint8_t fatType_; // volume type (12, 16, OR 32) |
|
152 uint16_t rootDirEntryCount_; // number of entries in FAT16 root dir |
|
153 uint32_t rootDirStart_; // root start block for FAT16, cluster for FAT32 |
|
154 //---------------------------------------------------------------------------- |
|
155 bool allocContiguous(uint32_t count, uint32_t* curCluster); |
|
156 uint8_t blockOfCluster(uint32_t position) const { |
|
157 return (position >> 9) & (blocksPerCluster_ - 1);} |
|
158 uint32_t clusterStartBlock(uint32_t cluster) const { |
|
159 return dataStartBlock_ + ((cluster - 2) << clusterSizeShift_);} |
|
160 uint32_t blockNumber(uint32_t cluster, uint32_t position) const { |
|
161 return clusterStartBlock(cluster) + blockOfCluster(position);} |
|
162 cache_t *cache() {return &cacheBuffer_;} |
|
163 uint32_t cacheBlockNumber() {return cacheBlockNumber_;} |
|
164 #if USE_MULTIPLE_CARDS |
|
165 bool cacheFlush(); |
|
166 bool cacheRawBlock(uint32_t blockNumber, bool dirty); |
|
167 #else // USE_MULTIPLE_CARDS |
|
168 static bool cacheFlush(); |
|
169 static bool cacheRawBlock(uint32_t blockNumber, bool dirty); |
|
170 #endif // USE_MULTIPLE_CARDS |
|
171 // used by SdBaseFile write to assign cache to SD location |
|
172 void cacheSetBlockNumber(uint32_t blockNumber, bool dirty) { |
|
173 cacheDirty_ = dirty; |
|
174 cacheBlockNumber_ = blockNumber; |
|
175 } |
|
176 void cacheSetDirty() {cacheDirty_ |= CACHE_FOR_WRITE;} |
|
177 bool chainSize(uint32_t beginCluster, uint32_t* size); |
|
178 bool fatGet(uint32_t cluster, uint32_t* value); |
|
179 bool fatPut(uint32_t cluster, uint32_t value); |
|
180 bool fatPutEOC(uint32_t cluster) { |
|
181 return fatPut(cluster, 0x0FFFFFFF); |
|
182 } |
|
183 bool freeChain(uint32_t cluster); |
|
184 bool isEOC(uint32_t cluster) const { |
|
185 if (FAT12_SUPPORT && fatType_ == 12) return cluster >= FAT12EOC_MIN; |
|
186 if (fatType_ == 16) return cluster >= FAT16EOC_MIN; |
|
187 return cluster >= FAT32EOC_MIN; |
|
188 } |
|
189 bool readBlock(uint32_t block, uint8_t* dst) { |
|
190 return sdCard_->readBlock(block, dst);} |
|
191 bool writeBlock(uint32_t block, const uint8_t* dst) { |
|
192 return sdCard_->writeBlock(block, dst); |
|
193 } |
|
194 //------------------------------------------------------------------------------ |
|
195 // Deprecated functions - suppress cpplint warnings with NOLINT comment |
|
196 #if ALLOW_DEPRECATED_FUNCTIONS && !defined(DOXYGEN) |
|
197 public: |
|
198 /** \deprecated Use: bool SdVolume::init(Sd2Card* dev); |
|
199 * \param[in] dev The SD card where the volume is located. |
|
200 * \return true for success or false for failure. |
|
201 */ |
|
202 bool init(Sd2Card& dev) {return init(&dev);} // NOLINT |
|
203 /** \deprecated Use: bool SdVolume::init(Sd2Card* dev, uint8_t vol); |
|
204 * \param[in] dev The SD card where the volume is located. |
|
205 * \param[in] part The partition to be used. |
|
206 * \return true for success or false for failure. |
|
207 */ |
|
208 bool init(Sd2Card& dev, uint8_t part) { // NOLINT |
|
209 return init(&dev, part); |
|
210 } |
|
211 #endif // ALLOW_DEPRECATED_FUNCTIONS |
|
212 }; |
|
213 #endif // SdVolume |
|
214 #endif |