|
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 |
|
23 #ifndef SdBaseFile_h |
|
24 #define SdBaseFile_h |
|
25 /** |
|
26 * \file |
|
27 * \brief SdBaseFile class |
|
28 */ |
|
29 #include "Marlin.h" |
|
30 #include "SdFatConfig.h" |
|
31 #include "SdVolume.h" |
|
32 //------------------------------------------------------------------------------ |
|
33 /** |
|
34 * \struct fpos_t |
|
35 * \brief internal type for istream |
|
36 * do not use in user apps |
|
37 */ |
|
38 struct fpos_t { |
|
39 /** stream position */ |
|
40 uint32_t position; |
|
41 /** cluster for position */ |
|
42 uint32_t cluster; |
|
43 fpos_t() : position(0), cluster(0) {} |
|
44 }; |
|
45 |
|
46 // use the gnu style oflag in open() |
|
47 /** open() oflag for reading */ |
|
48 uint8_t const O_READ = 0X01; |
|
49 /** open() oflag - same as O_IN */ |
|
50 uint8_t const O_RDONLY = O_READ; |
|
51 /** open() oflag for write */ |
|
52 uint8_t const O_WRITE = 0X02; |
|
53 /** open() oflag - same as O_WRITE */ |
|
54 uint8_t const O_WRONLY = O_WRITE; |
|
55 /** open() oflag for reading and writing */ |
|
56 uint8_t const O_RDWR = (O_READ | O_WRITE); |
|
57 /** open() oflag mask for access modes */ |
|
58 uint8_t const O_ACCMODE = (O_READ | O_WRITE); |
|
59 /** The file offset shall be set to the end of the file prior to each write. */ |
|
60 uint8_t const O_APPEND = 0X04; |
|
61 /** synchronous writes - call sync() after each write */ |
|
62 uint8_t const O_SYNC = 0X08; |
|
63 /** truncate the file to zero length */ |
|
64 uint8_t const O_TRUNC = 0X10; |
|
65 /** set the initial position at the end of the file */ |
|
66 uint8_t const O_AT_END = 0X20; |
|
67 /** create the file if nonexistent */ |
|
68 uint8_t const O_CREAT = 0X40; |
|
69 /** If O_CREAT and O_EXCL are set, open() shall fail if the file exists */ |
|
70 uint8_t const O_EXCL = 0X80; |
|
71 |
|
72 // SdBaseFile class static and const definitions |
|
73 // flags for ls() |
|
74 /** ls() flag to print modify date */ |
|
75 uint8_t const LS_DATE = 1; |
|
76 /** ls() flag to print file size */ |
|
77 uint8_t const LS_SIZE = 2; |
|
78 /** ls() flag for recursive list of subdirectories */ |
|
79 uint8_t const LS_R = 4; |
|
80 |
|
81 |
|
82 // flags for timestamp |
|
83 /** set the file's last access date */ |
|
84 uint8_t const T_ACCESS = 1; |
|
85 /** set the file's creation date and time */ |
|
86 uint8_t const T_CREATE = 2; |
|
87 /** Set the file's write date and time */ |
|
88 uint8_t const T_WRITE = 4; |
|
89 // values for type_ |
|
90 /** This file has not been opened. */ |
|
91 uint8_t const FAT_FILE_TYPE_CLOSED = 0; |
|
92 /** A normal file */ |
|
93 uint8_t const FAT_FILE_TYPE_NORMAL = 1; |
|
94 /** A FAT12 or FAT16 root directory */ |
|
95 uint8_t const FAT_FILE_TYPE_ROOT_FIXED = 2; |
|
96 /** A FAT32 root directory */ |
|
97 uint8_t const FAT_FILE_TYPE_ROOT32 = 3; |
|
98 /** A subdirectory file*/ |
|
99 uint8_t const FAT_FILE_TYPE_SUBDIR = 4; |
|
100 /** Test value for directory type */ |
|
101 uint8_t const FAT_FILE_TYPE_MIN_DIR = FAT_FILE_TYPE_ROOT_FIXED; |
|
102 |
|
103 /** date field for FAT directory entry |
|
104 * \param[in] year [1980,2107] |
|
105 * \param[in] month [1,12] |
|
106 * \param[in] day [1,31] |
|
107 * |
|
108 * \return Packed date for dir_t entry. |
|
109 */ |
|
110 static inline uint16_t FAT_DATE(uint16_t year, uint8_t month, uint8_t day) { |
|
111 return (year - 1980) << 9 | month << 5 | day; |
|
112 } |
|
113 /** year part of FAT directory date field |
|
114 * \param[in] fatDate Date in packed dir format. |
|
115 * |
|
116 * \return Extracted year [1980,2107] |
|
117 */ |
|
118 static inline uint16_t FAT_YEAR(uint16_t fatDate) { |
|
119 return 1980 + (fatDate >> 9); |
|
120 } |
|
121 /** month part of FAT directory date field |
|
122 * \param[in] fatDate Date in packed dir format. |
|
123 * |
|
124 * \return Extracted month [1,12] |
|
125 */ |
|
126 static inline uint8_t FAT_MONTH(uint16_t fatDate) { |
|
127 return (fatDate >> 5) & 0XF; |
|
128 } |
|
129 /** day part of FAT directory date field |
|
130 * \param[in] fatDate Date in packed dir format. |
|
131 * |
|
132 * \return Extracted day [1,31] |
|
133 */ |
|
134 static inline uint8_t FAT_DAY(uint16_t fatDate) { |
|
135 return fatDate & 0X1F; |
|
136 } |
|
137 /** time field for FAT directory entry |
|
138 * \param[in] hour [0,23] |
|
139 * \param[in] minute [0,59] |
|
140 * \param[in] second [0,59] |
|
141 * |
|
142 * \return Packed time for dir_t entry. |
|
143 */ |
|
144 static inline uint16_t FAT_TIME(uint8_t hour, uint8_t minute, uint8_t second) { |
|
145 return hour << 11 | minute << 5 | second >> 1; |
|
146 } |
|
147 /** hour part of FAT directory time field |
|
148 * \param[in] fatTime Time in packed dir format. |
|
149 * |
|
150 * \return Extracted hour [0,23] |
|
151 */ |
|
152 static inline uint8_t FAT_HOUR(uint16_t fatTime) { |
|
153 return fatTime >> 11; |
|
154 } |
|
155 /** minute part of FAT directory time field |
|
156 * \param[in] fatTime Time in packed dir format. |
|
157 * |
|
158 * \return Extracted minute [0,59] |
|
159 */ |
|
160 static inline uint8_t FAT_MINUTE(uint16_t fatTime) { |
|
161 return(fatTime >> 5) & 0X3F; |
|
162 } |
|
163 /** second part of FAT directory time field |
|
164 * Note second/2 is stored in packed time. |
|
165 * |
|
166 * \param[in] fatTime Time in packed dir format. |
|
167 * |
|
168 * \return Extracted second [0,58] |
|
169 */ |
|
170 static inline uint8_t FAT_SECOND(uint16_t fatTime) { |
|
171 return 2*(fatTime & 0X1F); |
|
172 } |
|
173 /** Default date for file timestamps is 1 Jan 2000 */ |
|
174 uint16_t const FAT_DEFAULT_DATE = ((2000 - 1980) << 9) | (1 << 5) | 1; |
|
175 /** Default time for file timestamp is 1 am */ |
|
176 uint16_t const FAT_DEFAULT_TIME = (1 << 11); |
|
177 //------------------------------------------------------------------------------ |
|
178 /** |
|
179 * \class SdBaseFile |
|
180 * \brief Base class for SdFile with Print and C++ streams. |
|
181 */ |
|
182 class SdBaseFile { |
|
183 public: |
|
184 /** Create an instance. */ |
|
185 SdBaseFile() : writeError(false), type_(FAT_FILE_TYPE_CLOSED) {} |
|
186 SdBaseFile(const char* path, uint8_t oflag); |
|
187 ~SdBaseFile() {if(isOpen()) close();} |
|
188 /** |
|
189 * writeError is set to true if an error occurs during a write(). |
|
190 * Set writeError to false before calling print() and/or write() and check |
|
191 * for true after calls to print() and/or write(). |
|
192 */ |
|
193 bool writeError; |
|
194 //---------------------------------------------------------------------------- |
|
195 // helpers for stream classes |
|
196 /** get position for streams |
|
197 * \param[out] pos struct to receive position |
|
198 */ |
|
199 void getpos(fpos_t* pos); |
|
200 /** set position for streams |
|
201 * \param[out] pos struct with value for new position |
|
202 */ |
|
203 void setpos(fpos_t* pos); |
|
204 //---------------------------------------------------------------------------- |
|
205 bool close(); |
|
206 bool contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock); |
|
207 bool createContiguous(SdBaseFile* dirFile, |
|
208 const char* path, uint32_t size); |
|
209 /** \return The current cluster number for a file or directory. */ |
|
210 uint32_t curCluster() const {return curCluster_;} |
|
211 /** \return The current position for a file or directory. */ |
|
212 uint32_t curPosition() const {return curPosition_;} |
|
213 /** \return Current working directory */ |
|
214 static SdBaseFile* cwd() {return cwd_;} |
|
215 /** Set the date/time callback function |
|
216 * |
|
217 * \param[in] dateTime The user's call back function. The callback |
|
218 * function is of the form: |
|
219 * |
|
220 * \code |
|
221 * void dateTime(uint16_t* date, uint16_t* time) { |
|
222 * uint16_t year; |
|
223 * uint8_t month, day, hour, minute, second; |
|
224 * |
|
225 * // User gets date and time from GPS or real-time clock here |
|
226 * |
|
227 * // return date using FAT_DATE macro to format fields |
|
228 * *date = FAT_DATE(year, month, day); |
|
229 * |
|
230 * // return time using FAT_TIME macro to format fields |
|
231 * *time = FAT_TIME(hour, minute, second); |
|
232 * } |
|
233 * \endcode |
|
234 * |
|
235 * Sets the function that is called when a file is created or when |
|
236 * a file's directory entry is modified by sync(). All timestamps, |
|
237 * access, creation, and modify, are set when a file is created. |
|
238 * sync() maintains the last access date and last modify date/time. |
|
239 * |
|
240 * See the timestamp() function. |
|
241 */ |
|
242 static void dateTimeCallback( |
|
243 void (*dateTime)(uint16_t* date, uint16_t* time)) { |
|
244 dateTime_ = dateTime; |
|
245 } |
|
246 /** Cancel the date/time callback function. */ |
|
247 static void dateTimeCallbackCancel() {dateTime_ = 0;} |
|
248 bool dirEntry(dir_t* dir); |
|
249 static void dirName(const dir_t& dir, char* name); |
|
250 bool exists(const char* name); |
|
251 int16_t fgets(char* str, int16_t num, char* delim = 0); |
|
252 /** \return The total number of bytes in a file or directory. */ |
|
253 uint32_t fileSize() const {return fileSize_;} |
|
254 /** \return The first cluster number for a file or directory. */ |
|
255 uint32_t firstCluster() const {return firstCluster_;} |
|
256 bool getFilename(char* name); |
|
257 /** \return True if this is a directory else false. */ |
|
258 bool isDir() const {return type_ >= FAT_FILE_TYPE_MIN_DIR;} |
|
259 /** \return True if this is a normal file else false. */ |
|
260 bool isFile() const {return type_ == FAT_FILE_TYPE_NORMAL;} |
|
261 /** \return True if this is an open file/directory else false. */ |
|
262 bool isOpen() const {return type_ != FAT_FILE_TYPE_CLOSED;} |
|
263 /** \return True if this is a subdirectory else false. */ |
|
264 bool isSubDir() const {return type_ == FAT_FILE_TYPE_SUBDIR;} |
|
265 /** \return True if this is the root directory. */ |
|
266 bool isRoot() const { |
|
267 return type_ == FAT_FILE_TYPE_ROOT_FIXED || type_ == FAT_FILE_TYPE_ROOT32; |
|
268 } |
|
269 void ls( uint8_t flags = 0, uint8_t indent = 0); |
|
270 bool mkdir(SdBaseFile* dir, const char* path, bool pFlag = true); |
|
271 // alias for backward compactability |
|
272 bool makeDir(SdBaseFile* dir, const char* path) { |
|
273 return mkdir(dir, path, false); |
|
274 } |
|
275 bool open(SdBaseFile* dirFile, uint16_t index, uint8_t oflag); |
|
276 bool open(SdBaseFile* dirFile, const char* path, uint8_t oflag); |
|
277 bool open(const char* path, uint8_t oflag = O_READ); |
|
278 bool openNext(SdBaseFile* dirFile, uint8_t oflag); |
|
279 bool openRoot(SdVolume* vol); |
|
280 int peek(); |
|
281 static void printFatDate(uint16_t fatDate); |
|
282 static void printFatTime( uint16_t fatTime); |
|
283 bool printName(); |
|
284 int16_t read(); |
|
285 int16_t read(void* buf, uint16_t nbyte); |
|
286 int8_t readDir(dir_t* dir); |
|
287 static bool remove(SdBaseFile* dirFile, const char* path); |
|
288 bool remove(); |
|
289 /** Set the file's current position to zero. */ |
|
290 void rewind() {seekSet(0);} |
|
291 bool rename(SdBaseFile* dirFile, const char* newPath); |
|
292 bool rmdir(); |
|
293 // for backward compatibility |
|
294 bool rmDir() {return rmdir();} |
|
295 bool rmRfStar(); |
|
296 /** Set the files position to current position + \a pos. See seekSet(). |
|
297 * \param[in] offset The new position in bytes from the current position. |
|
298 * \return true for success or false for failure. |
|
299 */ |
|
300 bool seekCur(int32_t offset) { |
|
301 return seekSet(curPosition_ + offset); |
|
302 } |
|
303 /** Set the files position to end-of-file + \a offset. See seekSet(). |
|
304 * \param[in] offset The new position in bytes from end-of-file. |
|
305 * \return true for success or false for failure. |
|
306 */ |
|
307 bool seekEnd(int32_t offset = 0) {return seekSet(fileSize_ + offset);} |
|
308 bool seekSet(uint32_t pos); |
|
309 bool sync(); |
|
310 bool timestamp(SdBaseFile* file); |
|
311 bool timestamp(uint8_t flag, uint16_t year, uint8_t month, uint8_t day, |
|
312 uint8_t hour, uint8_t minute, uint8_t second); |
|
313 /** Type of file. You should use isFile() or isDir() instead of type() |
|
314 * if possible. |
|
315 * |
|
316 * \return The file or directory type. |
|
317 */ |
|
318 uint8_t type() const {return type_;} |
|
319 bool truncate(uint32_t size); |
|
320 /** \return SdVolume that contains this file. */ |
|
321 SdVolume* volume() const {return vol_;} |
|
322 int16_t write(const void* buf, uint16_t nbyte); |
|
323 //------------------------------------------------------------------------------ |
|
324 private: |
|
325 // allow SdFat to set cwd_ |
|
326 friend class SdFat; |
|
327 // global pointer to cwd dir |
|
328 static SdBaseFile* cwd_; |
|
329 // data time callback function |
|
330 static void (*dateTime_)(uint16_t* date, uint16_t* time); |
|
331 // bits defined in flags_ |
|
332 // should be 0X0F |
|
333 static uint8_t const F_OFLAG = (O_ACCMODE | O_APPEND | O_SYNC); |
|
334 // sync of directory entry required |
|
335 static uint8_t const F_FILE_DIR_DIRTY = 0X80; |
|
336 |
|
337 // private data |
|
338 uint8_t flags_; // See above for definition of flags_ bits |
|
339 uint8_t fstate_; // error and eof indicator |
|
340 uint8_t type_; // type of file see above for values |
|
341 uint32_t curCluster_; // cluster for current file position |
|
342 uint32_t curPosition_; // current file position in bytes from beginning |
|
343 uint32_t dirBlock_; // block for this files directory entry |
|
344 uint8_t dirIndex_; // index of directory entry in dirBlock |
|
345 uint32_t fileSize_; // file size in bytes |
|
346 uint32_t firstCluster_; // first cluster of file |
|
347 SdVolume* vol_; // volume where file is located |
|
348 |
|
349 /** experimental don't use */ |
|
350 bool openParent(SdBaseFile* dir); |
|
351 // private functions |
|
352 bool addCluster(); |
|
353 bool addDirCluster(); |
|
354 dir_t* cacheDirEntry(uint8_t action); |
|
355 int8_t lsPrintNext( uint8_t flags, uint8_t indent); |
|
356 static bool make83Name(const char* str, uint8_t* name, const char** ptr); |
|
357 bool mkdir(SdBaseFile* parent, const uint8_t dname[11]); |
|
358 bool open(SdBaseFile* dirFile, const uint8_t dname[11], uint8_t oflag); |
|
359 bool openCachedEntry(uint8_t cacheIndex, uint8_t oflags); |
|
360 dir_t* readDirCache(); |
|
361 //------------------------------------------------------------------------------ |
|
362 // to be deleted |
|
363 static void printDirName( const dir_t& dir, |
|
364 uint8_t width, bool printSlash); |
|
365 //------------------------------------------------------------------------------ |
|
366 // Deprecated functions - suppress cpplint warnings with NOLINT comment |
|
367 #if ALLOW_DEPRECATED_FUNCTIONS && !defined(DOXYGEN) |
|
368 public: |
|
369 /** \deprecated Use: |
|
370 * bool contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock); |
|
371 * \param[out] bgnBlock the first block address for the file. |
|
372 * \param[out] endBlock the last block address for the file. |
|
373 * \return true for success or false for failure. |
|
374 */ |
|
375 bool contiguousRange(uint32_t& bgnBlock, uint32_t& endBlock) { // NOLINT |
|
376 return contiguousRange(&bgnBlock, &endBlock); |
|
377 } |
|
378 /** \deprecated Use: |
|
379 * bool createContiguous(SdBaseFile* dirFile, |
|
380 * const char* path, uint32_t size) |
|
381 * \param[in] dirFile The directory where the file will be created. |
|
382 * \param[in] path A path with a valid DOS 8.3 file name. |
|
383 * \param[in] size The desired file size. |
|
384 * \return true for success or false for failure. |
|
385 */ |
|
386 bool createContiguous(SdBaseFile& dirFile, // NOLINT |
|
387 const char* path, uint32_t size) { |
|
388 return createContiguous(&dirFile, path, size); |
|
389 } |
|
390 /** \deprecated Use: |
|
391 * static void dateTimeCallback( |
|
392 * void (*dateTime)(uint16_t* date, uint16_t* time)); |
|
393 * \param[in] dateTime The user's call back function. |
|
394 */ |
|
395 static void dateTimeCallback( |
|
396 void (*dateTime)(uint16_t& date, uint16_t& time)) { // NOLINT |
|
397 oldDateTime_ = dateTime; |
|
398 dateTime_ = dateTime ? oldToNew : 0; |
|
399 } |
|
400 /** \deprecated Use: bool dirEntry(dir_t* dir); |
|
401 * \param[out] dir Location for return of the file's directory entry. |
|
402 * \return true for success or false for failure. |
|
403 */ |
|
404 bool dirEntry(dir_t& dir) {return dirEntry(&dir);} // NOLINT |
|
405 /** \deprecated Use: |
|
406 * bool mkdir(SdBaseFile* dir, const char* path); |
|
407 * \param[in] dir An open SdFat instance for the directory that will contain |
|
408 * the new directory. |
|
409 * \param[in] path A path with a valid 8.3 DOS name for the new directory. |
|
410 * \return true for success or false for failure. |
|
411 */ |
|
412 bool mkdir(SdBaseFile& dir, const char* path) { // NOLINT |
|
413 return mkdir(&dir, path); |
|
414 } |
|
415 /** \deprecated Use: |
|
416 * bool open(SdBaseFile* dirFile, const char* path, uint8_t oflag); |
|
417 * \param[in] dirFile An open SdFat instance for the directory containing the |
|
418 * file to be opened. |
|
419 * \param[in] path A path with a valid 8.3 DOS name for the file. |
|
420 * \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive |
|
421 * OR of flags O_READ, O_WRITE, O_TRUNC, and O_SYNC. |
|
422 * \return true for success or false for failure. |
|
423 */ |
|
424 bool open(SdBaseFile& dirFile, // NOLINT |
|
425 const char* path, uint8_t oflag) { |
|
426 return open(&dirFile, path, oflag); |
|
427 } |
|
428 /** \deprecated Do not use in new apps |
|
429 * \param[in] dirFile An open SdFat instance for the directory containing the |
|
430 * file to be opened. |
|
431 * \param[in] path A path with a valid 8.3 DOS name for a file to be opened. |
|
432 * \return true for success or false for failure. |
|
433 */ |
|
434 bool open(SdBaseFile& dirFile, const char* path) { // NOLINT |
|
435 return open(dirFile, path, O_RDWR); |
|
436 } |
|
437 /** \deprecated Use: |
|
438 * bool open(SdBaseFile* dirFile, uint16_t index, uint8_t oflag); |
|
439 * \param[in] dirFile An open SdFat instance for the directory. |
|
440 * \param[in] index The \a index of the directory entry for the file to be |
|
441 * opened. The value for \a index is (directory file position)/32. |
|
442 * \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive |
|
443 * OR of flags O_READ, O_WRITE, O_TRUNC, and O_SYNC. |
|
444 * \return true for success or false for failure. |
|
445 */ |
|
446 bool open(SdBaseFile& dirFile, uint16_t index, uint8_t oflag) { // NOLINT |
|
447 return open(&dirFile, index, oflag); |
|
448 } |
|
449 /** \deprecated Use: bool openRoot(SdVolume* vol); |
|
450 * \param[in] vol The FAT volume containing the root directory to be opened. |
|
451 * \return true for success or false for failure. |
|
452 */ |
|
453 bool openRoot(SdVolume& vol) {return openRoot(&vol);} // NOLINT |
|
454 /** \deprecated Use: int8_t readDir(dir_t* dir); |
|
455 * \param[out] dir The dir_t struct that will receive the data. |
|
456 * \return bytes read for success zero for eof or -1 for failure. |
|
457 */ |
|
458 int8_t readDir(dir_t& dir) {return readDir(&dir);} // NOLINT |
|
459 /** \deprecated Use: |
|
460 * static uint8_t remove(SdBaseFile* dirFile, const char* path); |
|
461 * \param[in] dirFile The directory that contains the file. |
|
462 * \param[in] path The name of the file to be removed. |
|
463 * \return true for success or false for failure. |
|
464 */ |
|
465 static bool remove(SdBaseFile& dirFile, const char* path) { // NOLINT |
|
466 return remove(&dirFile, path); |
|
467 } |
|
468 //------------------------------------------------------------------------------ |
|
469 // rest are private |
|
470 private: |
|
471 static void (*oldDateTime_)(uint16_t& date, uint16_t& time); // NOLINT |
|
472 static void oldToNew(uint16_t* date, uint16_t* time) { |
|
473 uint16_t d; |
|
474 uint16_t t; |
|
475 oldDateTime_(d, t); |
|
476 *date = d; |
|
477 *time = t; |
|
478 } |
|
479 #endif // ALLOW_DEPRECATED_FUNCTIONS |
|
480 }; |
|
481 |
|
482 #endif // SdBaseFile_h |
|
483 #endif |