ESP3D  3.0
Firmware for ESP boards connected to 3D Printer
sd_native_esp8266.cpp
Go to the documentation of this file.
1 /*
2 sd_native_esp8266.cpp - ESP3D sd support class
3 
4  Copyright (c) 2014 Luc Lebosse. All rights reserved.
5 
6  This library is free software; you can redistribute it and/or
7  modify it under the terms of the GNU Lesser General Public
8  License as published by the Free Software Foundation; either
9  version 2.1 of the License, or (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 GNU
14  Lesser General Public License for more details.
15 
16  You should have received a copy of the GNU Lesser General Public
17  License along with this library; if not, write to the Free Software
18  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20 #include "../../../include/esp3d_config.h"
21 #if defined (ARDUINO_ARCH_ESP8266) && defined(SD_DEVICE)
22 #if (SD_DEVICE == ESP_SD_NATIVE) || (SD_DEVICE == ESP_SDFAT)
23 #define FS_NO_GLOBALS
24 #include "../esp_sd.h"
25 #include "../../../core/genLinkedList.h"
26 #include "../../../core/settings_esp3d.h"
27 #define NO_GLOBAL_SD
28 #include "SdFat.h"
29 extern sdfat::File tSDFile_handle[ESP_MAX_SD_OPENHANDLE];
30 using namespace sdfat;
31 
32 SdFat SD;
33 
34 void dateTime (uint16_t* date, uint16_t* dtime)
35 {
36  struct tm tmstruct;
37  time_t now;
38  time (&now);
39  localtime_r (&now, &tmstruct);
40  *date = FAT_DATE ( (tmstruct.tm_year) + 1900, ( tmstruct.tm_mon) + 1, tmstruct.tm_mday);
41  *dtime = FAT_TIME (tmstruct.tm_hour, tmstruct.tm_min, tmstruct.tm_sec);
42 }
43 
44 time_t getDateTimeFile(sdfat::File & filehandle)
45 {
46  static time_t dt = 0;
47  struct tm timefile;
48  dir_t d;
49  if(filehandle) {
50  if (filehandle.dirEntry(&d)) {
51  timefile.tm_year = FAT_YEAR(d.lastWriteDate) - 1900;
52  timefile.tm_mon = FAT_MONTH(d.lastWriteDate) - 1;
53  timefile.tm_mday = FAT_DAY(d.lastWriteDate);
54  timefile.tm_hour = FAT_HOUR(d.lastWriteTime);
55  timefile.tm_min = FAT_MINUTE(d.lastWriteTime);
56  timefile.tm_sec = FAT_SECOND(d.lastWriteTime);
57  timefile.tm_isdst = -1;
58  dt = mktime(&timefile);
59  if (dt == -1) {
60  log_esp3d("mktime failed");
61  }
62  } else {
63  log_esp3d("stat file failed");
64  }
65  } else {
66  log_esp3d("check file for stat failed");
67  }
68  return dt;
69 }
70 
71 uint8_t ESP_SD::getState(bool refresh)
72 {
73 #if defined(ESP_SD_DETECT_PIN) && ESP_SD_DETECT_PIN != -1
74  //no need to go further if SD detect is not correct
75  if (!((digitalRead (ESP_SD_DETECT_PIN) == ESP_SD_DETECT_VALUE) ? true : false)) {
76  _state = ESP_SDCARD_NOT_PRESENT;
77  return _state;
78  }
79 #endif //ESP_SD_DETECT_PIN
80  //if busy doing something return state
81  if (!((_state == ESP_SDCARD_NOT_PRESENT) || _state == ESP_SDCARD_IDLE)) {
82  return _state;
83  }
84  if (!refresh) {
85  return _state; //to avoid refresh=true + busy to reset SD and waste time
86  }
87  //SD is idle or not detected, let see if still the case
88  _state = ESP_SDCARD_NOT_PRESENT;
89  //refresh content if card was removed
90  if (SD.begin((ESP_SD_CS_PIN == -1)?SS:ESP_SD_CS_PIN, SD_SCK_HZ(F_CPU/_spi_speed_divider))) {
91  if (SD.card()->cardSize() > 0 ) {
92  _state = ESP_SDCARD_IDLE;
93  }
94  }
95  return _state;
96 }
97 
98 bool ESP_SD::begin()
99 {
100  _started = true;
101  _state = ESP_SDCARD_NOT_PRESENT;
102  _spi_speed_divider = Settings_ESP3D::read_byte(ESP_SD_SPEED_DIV);
103  //sanity check
104  if (_spi_speed_divider <= 0) {
105  _spi_speed_divider = 1;
106  }
107 #ifdef SD_TIMESTAMP_FEATURE
108  //set callback to get time on files on SD
109  SdFile::dateTimeCallback (dateTime);
110 #endif //SD_TIMESTAMP_FEATURE
111  if (getState(true) == ESP_SDCARD_IDLE) {
112  freeBytes();
113  }
114  return _started;
115 }
116 
117 void ESP_SD::end()
118 {
119  _state = ESP_SDCARD_NOT_PRESENT;
120  _started = false;
121 }
122 
123 uint64_t ESP_SD::totalBytes()
124 {
125  uint64_t volTotal = SD.vol()->clusterCount();
126  uint8_t blocks = SD.vol()->blocksPerCluster();
127  return volTotal * blocks * 512;
128 }
129 
130 uint64_t ESP_SD::usedBytes()
131 {
132  return totalBytes() - freeBytes();
133 }
134 
135 uint64_t ESP_SD::freeBytes()
136 {
137  static uint64_t volFree;
138  if (_sizechanged) {
139  volFree = SD.vol()->freeClusterCount();
140  _sizechanged = false;
141  }
142  uint8_t blocks = SD.vol()->blocksPerCluster();
143  return volFree * blocks * 512;
144 }
145 
146 bool ESP_SD::rename(const char *oldpath, const char *newpath)
147 {
148  return SD.rename(oldpath,newpath);
149 }
150 
151 // strings needed in file system structures
152 #define noName "NO NAME "
153 #define fat16str "FAT16 "
154 #define fat32str "FAT32 "
155 // constants for file system structure
156 #define BU16 128
157 #define BU32 8192
158 #define ERASE_SIZE 262144L;
159 
160 //------------------------------------------------------------------------------
161 // write cached block to the card
162 uint8_t writeCache(uint32_t lbn, Sd2Card & card, cache_t & cache)
163 {
164  return card.writeBlock(lbn, cache.data);
165 }
166 
167 //------------------------------------------------------------------------------
168 // initialize appropriate sizes for SD capacity
169 bool initSizes(uint32_t cardCapacityMB, uint8_t & sectorsPerCluster, uint8_t & numberOfHeads, uint8_t & sectorsPerTrack)
170 {
171  if (cardCapacityMB <= 6) {
172  return false;
173  } else if (cardCapacityMB <= 16) {
174  sectorsPerCluster = 2;
175  } else if (cardCapacityMB <= 32) {
176  sectorsPerCluster = 4;
177  } else if (cardCapacityMB <= 64) {
178  sectorsPerCluster = 8;
179  } else if (cardCapacityMB <= 128) {
180  sectorsPerCluster = 16;
181  } else if (cardCapacityMB <= 1024) {
182  sectorsPerCluster = 32;
183  } else if (cardCapacityMB <= 32768) {
184  sectorsPerCluster = 64;
185  } else {
186  // SDXC cards
187  sectorsPerCluster = 128;
188  }
189 
190  // set fake disk geometry
191  sectorsPerTrack = cardCapacityMB <= 256 ? 32 : 63;
192 
193  if (cardCapacityMB <= 16) {
194  numberOfHeads = 2;
195  } else if (cardCapacityMB <= 32) {
196  numberOfHeads = 4;
197  } else if (cardCapacityMB <= 128) {
198  numberOfHeads = 8;
199  } else if (cardCapacityMB <= 504) {
200  numberOfHeads = 16;
201  } else if (cardCapacityMB <= 1008) {
202  numberOfHeads = 32;
203  } else if (cardCapacityMB <= 2016) {
204  numberOfHeads = 64;
205  } else if (cardCapacityMB <= 4032) {
206  numberOfHeads = 128;
207  } else {
208  numberOfHeads = 255;
209  }
210  return true;
211 }
212 
213 //------------------------------------------------------------------------------
214 // zero cache and optionally set the sector signature
215 void clearCache(uint8_t addSig, cache_t & cache)
216 {
217  memset(&cache, 0, sizeof(cache));
218  if (addSig) {
219  cache.mbr.mbrSig0 = BOOTSIG0;
220  cache.mbr.mbrSig1 = BOOTSIG1;
221  }
222 }
223 //------------------------------------------------------------------------------
224 // zero FAT and root dir area on SD
225 bool clearFatDir(uint32_t bgn, uint32_t count, Sd2Card & card, cache_t & cache, ESP3DOutput * output)
226 {
227  clearCache(false, cache);
228  if (!card.writeStart(bgn, count)) {
229  return false;
230  }
231  for (uint32_t i = 0; i < count; i++) {
232  if ((i & 0XFF) == 0) {
233  if (output) {
234  output->print(".");
235  }
236  }
237  if (!card.writeData(cache.data)) {
238  return false;
239  }
240  }
241  if (!card.writeStop()) {
242  return false;
243  }
244  return true;
245 }
246 
247 //------------------------------------------------------------------------------
248 // return cylinder number for a logical block number
249 uint16_t lbnToCylinder(uint32_t lbn, uint8_t numberOfHeads, uint8_t sectorsPerTrack)
250 {
251  return lbn / (numberOfHeads * sectorsPerTrack);
252 }
253 //------------------------------------------------------------------------------
254 // return head number for a logical block number
255 uint8_t lbnToHead(uint32_t lbn, uint8_t numberOfHeads, uint8_t sectorsPerTrack)
256 {
257  return (lbn % (numberOfHeads * sectorsPerTrack)) / sectorsPerTrack;
258 }
259 //------------------------------------------------------------------------------
260 // return sector number for a logical block number
261 uint8_t lbnToSector(uint32_t lbn, uint8_t sectorsPerTrack)
262 {
263  return (lbn % sectorsPerTrack) + 1;
264 }
265 
266 //------------------------------------------------------------------------------
267 // format and write the Master Boot Record
268 bool writeMbr(Sd2Card & card, cache_t & cache, uint8_t partType, uint32_t relSector, uint32_t partSize, uint8_t numberOfHeads, uint8_t sectorsPerTrack)
269 {
270  clearCache(true, cache);
271  part_t* p = cache.mbr.part;
272  p->boot = 0;
273  uint16_t c = lbnToCylinder(relSector, numberOfHeads, sectorsPerTrack);
274  if (c > 1023) {
275  return false;
276  }
277  p->beginCylinderHigh = c >> 8;
278  p->beginCylinderLow = c & 0XFF;
279  p->beginHead = lbnToHead(relSector, numberOfHeads, sectorsPerTrack);
280  p->beginSector = lbnToSector(relSector, sectorsPerTrack);
281  p->type = partType;
282  uint32_t endLbn = relSector + partSize - 1;
283  c = lbnToCylinder(endLbn,numberOfHeads, sectorsPerTrack);
284  if (c <= 1023) {
285  p->endCylinderHigh = c >> 8;
286  p->endCylinderLow = c & 0XFF;
287  p->endHead = lbnToHead(endLbn, numberOfHeads, sectorsPerTrack);
288  p->endSector = lbnToSector(endLbn, sectorsPerTrack);
289  } else {
290  // Too big flag, c = 1023, h = 254, s = 63
291  p->endCylinderHigh = 3;
292  p->endCylinderLow = 255;
293  p->endHead = 254;
294  p->endSector = 63;
295  }
296  p->firstSector = relSector;
297  p->totalSectors = partSize;
298  if (!writeCache(0, card, cache)) {
299  return false;
300  }
301  return true;
302 }
303 
304 //------------------------------------------------------------------------------
305 // generate serial number from card size and micros since boot
306 uint32_t volSerialNumber(uint32_t cardSizeBlocks)
307 {
308  return (cardSizeBlocks << 8) + micros();
309 }
310 
311 // format the SD as FAT16
312 bool makeFat16(uint32_t & dataStart, Sd2Card & card, cache_t & cache, uint8_t numberOfHeads, uint8_t sectorsPerTrack, uint32_t cardSizeBlocks, uint8_t sectorsPerCluster, uint32_t &relSector, uint32_t partSize, uint8_t & partType, uint32_t &fatSize, uint32_t &fatStart, uint16_t reservedSectors, ESP3DOutput * output)
313 {
314  uint32_t nc;
315  for (dataStart = 2 * BU16;; dataStart += BU16) {
316  nc = (cardSizeBlocks - dataStart)/sectorsPerCluster;
317  fatSize = (nc + 2 + 255)/256;
318  uint32_t r = BU16 + 1 + 2 * fatSize + 32;
319  if (dataStart < r) {
320  continue;
321  }
322  relSector = dataStart - r + BU16;
323  break;
324  }
325  // check valid cluster count for FAT16 volume
326  if (nc < 4085 || nc >= 65525) {
327  return false;
328  }
329  reservedSectors = 1;
330  fatStart = relSector + reservedSectors;
331  partSize = nc * sectorsPerCluster + 2 * fatSize + reservedSectors + 32;
332  if (partSize < 32680) {
333  partType = 0X01;
334  } else if (partSize < 65536) {
335  partType = 0X04;
336  } else {
337  partType = 0X06;
338  }
339  // write MBR
340  if (!writeMbr(card, cache, partType, relSector, partSize, numberOfHeads, sectorsPerTrack)) {
341  return false;
342  }
343  clearCache(true, cache);
344  fat_boot_t* pb = &cache.fbs;
345  pb->jump[0] = 0XEB;
346  pb->jump[1] = 0X00;
347  pb->jump[2] = 0X90;
348  for (uint8_t i = 0; i < sizeof(pb->oemId); i++) {
349  pb->oemId[i] = ' ';
350  }
351  pb->bytesPerSector = 512;
352  pb->sectorsPerCluster = sectorsPerCluster;
353  pb->reservedSectorCount = reservedSectors;
354  pb->fatCount = 2;
355  pb->rootDirEntryCount = 512;
356  pb->mediaType = 0XF8;
357  pb->sectorsPerFat16 = fatSize;
358  pb->sectorsPerTrack = sectorsPerTrack;
359  pb->headCount = numberOfHeads;
360  pb->hidddenSectors = relSector;
361  pb->totalSectors32 = partSize;
362  pb->driveNumber = 0X80;
363  pb->bootSignature = EXTENDED_BOOT_SIG;
364  pb->volumeSerialNumber = volSerialNumber(cardSizeBlocks);
365  memcpy(pb->volumeLabel, noName, sizeof(pb->volumeLabel));
366  memcpy(pb->fileSystemType, fat16str, sizeof(pb->fileSystemType));
367  // write partition boot sector
368  if (!writeCache(relSector, card, cache)) {
369  return false;
370  }
371  // clear FAT and root directory
372  clearFatDir(fatStart, dataStart - fatStart, card, cache, output);
373  clearCache(false, cache);
374  cache.fat16[0] = 0XFFF8;
375  cache.fat16[1] = 0XFFFF;
376  // write first block of FAT and backup for reserved clusters
377  if (!writeCache(fatStart, card, cache)
378  || !writeCache(fatStart + fatSize, card, cache)) {
379  return false;
380  }
381  return true;
382 }
383 
384 // format the SD as FAT32
385 bool makeFat32(uint32_t & dataStart, Sd2Card & card, cache_t & cache, uint8_t numberOfHeads, uint8_t sectorsPerTrack, uint32_t cardSizeBlocks, uint8_t sectorsPerCluster, uint32_t &relSector, uint32_t partSize, uint8_t & partType, uint32_t &fatSize, uint32_t &fatStart, uint16_t reservedSectors, ESP3DOutput * output)
386 {
387  uint32_t nc;
388  relSector = BU32;
389  for (dataStart = 2 * BU32;; dataStart += BU32) {
390  nc = (cardSizeBlocks - dataStart)/sectorsPerCluster;
391  fatSize = (nc + 2 + 127)/128;
392  uint32_t r = relSector + 9 + 2 * fatSize;
393  if (dataStart >= r) {
394  break;
395  }
396  }
397  // error if too few clusters in FAT32 volume
398  if (nc < 65525) {
399  return false;
400  }
401  reservedSectors = dataStart - relSector - 2 * fatSize;
402  fatStart = relSector + reservedSectors;
403  partSize = nc * sectorsPerCluster + dataStart - relSector;
404  // type depends on address of end sector
405  // max CHS has lbn = 16450560 = 1024*255*63
406  if ((relSector + partSize) <= 16450560) {
407  // FAT32
408  partType = 0X0B;
409  } else {
410  // FAT32 with INT 13
411  partType = 0X0C;
412  }
413  if (!writeMbr(card, cache, partType, relSector, partSize, numberOfHeads, sectorsPerTrack)) {
414  return false;
415  }
416  clearCache(true, cache);
417 
418  fat32_boot_t* pb = &cache.fbs32;
419  pb->jump[0] = 0XEB;
420  pb->jump[1] = 0X00;
421  pb->jump[2] = 0X90;
422  for (uint8_t i = 0; i < sizeof(pb->oemId); i++) {
423  pb->oemId[i] = ' ';
424  }
425  pb->bytesPerSector = 512;
426  pb->sectorsPerCluster = sectorsPerCluster;
427  pb->reservedSectorCount = reservedSectors;
428  pb->fatCount = 2;
429  pb->mediaType = 0XF8;
430  pb->sectorsPerTrack = sectorsPerTrack;
431  pb->headCount = numberOfHeads;
432  pb->hidddenSectors = relSector;
433  pb->totalSectors32 = partSize;
434  pb->sectorsPerFat32 = fatSize;
435  pb->fat32RootCluster = 2;
436  pb->fat32FSInfo = 1;
437  pb->fat32BackBootBlock = 6;
438  pb->driveNumber = 0X80;
439  pb->bootSignature = EXTENDED_BOOT_SIG;
440  pb->volumeSerialNumber = volSerialNumber(cardSizeBlocks);
441  memcpy(pb->volumeLabel, noName, sizeof(pb->volumeLabel));
442  memcpy(pb->fileSystemType, fat32str, sizeof(pb->fileSystemType));
443  // write partition boot sector and backup
444  if (!writeCache(relSector, card, cache)
445  || !writeCache(relSector + 6, card, cache)) {
446  return false;
447  }
448  clearCache(true, cache);
449  // write extra boot area and backup
450  if (!writeCache(relSector + 2, card, cache)
451  || !writeCache(relSector + 8, card, cache)) {
452  return false;
453  }
454  fat32_fsinfo_t* pf = &cache.fsinfo;
455  pf->leadSignature = FSINFO_LEAD_SIG;
456  pf->structSignature = FSINFO_STRUCT_SIG;
457  pf->freeCount = 0XFFFFFFFF;
458  pf->nextFree = 0XFFFFFFFF;
459  // write FSINFO sector and backup
460  if (!writeCache(relSector + 1, card, cache)
461  || !writeCache(relSector + 7, card, cache)) {
462  return false;
463  }
464  clearFatDir(fatStart, 2 * fatSize + sectorsPerCluster, card, cache, output);
465  clearCache(false, cache);
466  cache.fat32[0] = 0x0FFFFFF8;
467  cache.fat32[1] = 0x0FFFFFFF;
468  cache.fat32[2] = 0x0FFFFFFF;
469  // write first block of FAT and backup for reserved clusters
470  if (!writeCache(fatStart, card, cache)
471  || !writeCache(fatStart + fatSize, card, cache)) {
472  return false;
473  }
474  return true;
475 }
476 
477 bool eraseCard(Sd2Card & card, cache_t & cache, uint32_t cardSizeBlocks, ESP3DOutput * output)
478 {
479  uint32_t firstBlock = 0;
480  uint32_t lastBlock;
481  uint16_t n = 0;
482  if (output) {
483  output->printMSG("Erasing ", false);
484  }
485  do {
486  lastBlock = firstBlock + ERASE_SIZE - 1;
487  if (lastBlock >= cardSizeBlocks) {
488  lastBlock = cardSizeBlocks - 1;
489  }
490  if (!card.erase(firstBlock, lastBlock)) {
491  return false;
492  }
493  if (output) {
494  output->print(".");
495  }
496  firstBlock += ERASE_SIZE;
497  } while (firstBlock < cardSizeBlocks);
498 
499  if (!card.readBlock(0, cache.data)) {
500  return false;
501  }
502  if (output) {
503  output->printLN("");
504  }
505  return true;
506 }
507 
508 bool formatCard(uint32_t & dataStart, Sd2Card & card,
509  cache_t & cache, uint8_t numberOfHeads,
510  uint8_t sectorsPerTrack, uint32_t cardSizeBlocks,
511  uint8_t sectorsPerCluster, uint32_t &relSector,
512  uint32_t partSize, uint8_t & partType,
513  uint32_t &fatSize, uint32_t &fatStart,
514  uint32_t cardCapacityMB, uint16_t reservedSectors, ESP3DOutput * output)
515 {
516  initSizes(cardCapacityMB, sectorsPerCluster, numberOfHeads, sectorsPerTrack);
517  if (card.type() != SD_CARD_TYPE_SDHC) {
518  if (output) {
519  output->printMSG("Formating FAT16 ");
520  }
521  if(!makeFat16(dataStart, card, cache, numberOfHeads, sectorsPerTrack, cardSizeBlocks, sectorsPerCluster, relSector, partSize, partType, fatSize, fatStart, reservedSectors, output)) {
522  return false;
523  }
524  } else {
525  if (output) {
526  output->printMSG("Formating FAT32 ", false);
527  }
528  if(!makeFat32(dataStart, card, cache, numberOfHeads, sectorsPerTrack, cardSizeBlocks, sectorsPerCluster, relSector, partSize, partType, fatSize, fatStart, reservedSectors, output)) {
529  return false;
530  }
531  }
532  if (output) {
533  output->printLN("");
534  }
535  return true;
536 }
537 
538 bool ESP_SD::format(ESP3DOutput * output)
539 {
540  if (ESP_SD::getState(true) == ESP_SDCARD_IDLE) {
541  Sd2Card card;
542  uint32_t cardSizeBlocks;
543  uint32_t cardCapacityMB;
544  // cache for SD block
545  cache_t cache;
546 
547  // MBR information
548  uint8_t partType;
549  uint32_t relSector;
550  uint32_t partSize;
551 
552  // Fake disk geometry
553  uint8_t numberOfHeads;
554  uint8_t sectorsPerTrack;
555 
556  // FAT parameters
557  uint16_t reservedSectors;
558  uint8_t sectorsPerCluster;
559  uint32_t fatStart;
560  uint32_t fatSize;
561  uint32_t dataStart;
562  if (!card.begin((ESP_SD_CS_PIN == -1)?SS:ESP_SD_CS_PIN, SD_SCK_HZ(F_CPU/_spi_speed_divider))) {
563  return false;
564  }
565  cardSizeBlocks = card.cardSize();
566  if (cardSizeBlocks == 0) {
567  return false;
568  }
569  cardCapacityMB = (cardSizeBlocks + 2047)/2048;
570  if (output) {
571  String s = "Capacity detected :" + String((1.048576*cardCapacityMB)/1024) + "GB";
572  output->printMSG(s.c_str());
573  }
574  if (!eraseCard(card, cache, cardSizeBlocks, output)) {
575  return false;
576  }
577 
578  if (!formatCard(dataStart, card, cache, numberOfHeads,
579  sectorsPerTrack, cardSizeBlocks,
580  sectorsPerCluster, relSector, partSize, partType,
581  fatSize, fatStart, cardCapacityMB, reservedSectors,output)) {
582  return false;
583  }
584  return true;
585  }
586  return false;
587 }
588 
589 ESP_SDFile ESP_SD::open(const char* path, uint8_t mode)
590 {
591  //do some check
592  if(((strcmp(path,"/") == 0) && ((mode == ESP_FILE_WRITE) || (mode == ESP_FILE_APPEND))) || (strlen(path) == 0)) {
593  _sizechanged = true;
594  return ESP_SDFile();
595  }
596  // path must start by '/'
597  if (path[0] != '/') {
598  return ESP_SDFile();
599  }
600  if (mode != ESP_FILE_READ) {
601  //check container exists
602  String p = path;
603  p.remove(p.lastIndexOf('/') +1);
604  if (!exists(p.c_str())) {
605  log_esp3d("Error opening: %s", path);
606  return ESP_SDFile();
607  }
608  }
609  sdfat::File tmp = SD.open(path, (mode == ESP_FILE_READ)?FILE_READ:(mode == ESP_FILE_WRITE)?FILE_WRITE:FILE_WRITE);
610  ESP_SDFile esptmp(&tmp, tmp.isDir(),(mode == ESP_FILE_READ)?false:true, path);
611  return esptmp;
612 }
613 
614 bool ESP_SD::exists(const char* path)
615 {
616  bool res = false;
617  //root should always be there if started
618  if (strcmp(path, "/") == 0) {
619  return _started;
620  }
621  res = SD.exists(path);
622  if (!res) {
623  ESP_SDFile root = ESP_SD::open(path, ESP_FILE_READ);
624  if (root) {
625  res = root.isDirectory();
626  }
627  }
628  return res;
629 }
630 
631 bool ESP_SD::remove(const char *path)
632 {
633  _sizechanged = true;
634  return SD.remove(path);
635 }
636 
637 bool ESP_SD::mkdir(const char *path)
638 {
639  return SD.mkdir(path);
640 }
641 
642 bool ESP_SD::rmdir(const char *path)
643 {
644  if (!exists(path)) {
645  return false;
646  }
647  bool res = true;
648  GenLinkedList<String > pathlist;
649  String p = path;
650  pathlist.push(p);
651  while (pathlist.count() > 0) {
652  sdfat::File dir = SD.open(pathlist.getLast().c_str());
653  dir.rewindDirectory();
654  sdfat::File f = dir.openNextFile();
655  bool candelete = true;
656  while (f) {
657  if (f.isDir()) {
658  candelete = false;
659  String newdir;
660  char tmp[255];
661  f.getName(tmp,254);
662  newdir = tmp;
663  pathlist.push(newdir);
664  f.close();
665  f = sdfat::File();
666  } else {
667  char tmp[255];
668  f.getName(tmp,254);
669  _sizechanged = true;
670  SD.remove(tmp);
671  f.close();
672  f = dir.openNextFile();
673  }
674  }
675  if (candelete) {
676  if (pathlist.getLast() !="/") {
677  res = SD.rmdir(pathlist.getLast().c_str());
678  }
679  pathlist.pop();
680  }
681  dir.close();
682  }
683  p = String();
684  log_esp3d("count %d", pathlist.count());
685  return res;
686 }
687 
688 void ESP_SD::closeAll()
689 {
690  for (uint8_t i = 0; i < ESP_MAX_SD_OPENHANDLE; i++) {
691  tSDFile_handle[i].close();
692  tSDFile_handle[i] = sdfat::File();
693  }
694 }
695 
696 ESP_SDFile::ESP_SDFile(void* handle, bool isdir, bool iswritemode, const char * path)
697 {
698  _isdir = isdir;
699  _dirlist = "";
700  _index = -1;
701  _filename = "";
702  _name = "";
703  _lastwrite = 0;
704  _iswritemode = iswritemode;
705  _size = 0;
706  if (!handle) {
707  return ;
708  }
709  bool set =false;
710  for (uint8_t i=0; (i < ESP_MAX_SD_OPENHANDLE) && !set; i++) {
711  if (!tSDFile_handle[i]) {
712  tSDFile_handle[i] = *((sdfat::File*)handle);
713  //filename
714  char tmp[255];
715  tSDFile_handle[i].getName(tmp,254);
716  _filename = path;
717  //name
718  _name = tmp;
719  if (_name.endsWith("/")) {
720  _name.remove( _name.length() - 1,1);
721  _isdir = true;
722  }
723  if (_name[0] == '/') {
724  _name.remove( 0, 1);
725  }
726  int pos = _name.lastIndexOf('/');
727  if (pos != -1) {
728  _name.remove( 0, pos+1);
729  }
730  if (_name.length() == 0) {
731  _name = "/";
732  }
733  //size
734  _size = tSDFile_handle[i].size();
735  //time
736  if (!_isdir) {
737  _lastwrite = getDateTimeFile(tSDFile_handle[i]);
738 
739  } else {
740  //no need date time for directory
741  _lastwrite = 0;
742  }
743  _index = i;
744  //log_esp3d("Opening File at index %d",_index);
745  set = true;
746  }
747  }
748 }
749 //todo need also to add short filename
750 const char* ESP_SDFile::shortname() const
751 {
752  static char sname[13];
753  sdfat::File ftmp = SD.open(_filename.c_str());
754  if (ftmp) {
755  ftmp.getSFN(sname);
756  ftmp.close();
757  return sname;
758  } else {
759  return _name.c_str();
760  }
761 }
762 
763 void ESP_SDFile::close()
764 {
765  if (_index != -1) {
766  //log_esp3d("Closing File at index %d", _index);
767  tSDFile_handle[_index].close();
768  //reopen if mode = write
769  //udate size + date
770  if (_iswritemode && !_isdir) {
771  sdfat::File ftmp = SD.open(_filename.c_str());
772  if (ftmp) {
773  _size = ftmp.size();
774  _lastwrite = getDateTimeFile(ftmp);
775  ftmp.close();
776  }
777  }
778  tSDFile_handle[_index] = sdfat::File();
779  //log_esp3d("Closing File at index %d",_index);
780  _index = -1;
781  }
782 }
783 
785 {
786  if ((_index == -1) || !_isdir) {
787  log_esp3d("openNextFile failed");
788  return ESP_SDFile();
789  }
790  sdfat::File tmp = tSDFile_handle[_index].openNextFile();
791  if (tmp) {
792  char tmps[255];
793  tmp.getName(tmps,254);
794  log_esp3d("tmp name :%s %s", tmps, (tmp.isDir())?"isDir":"isFile");
795  String s = _filename ;
796  if (s!="/") {
797  s+="/";
798  }
799  s += tmps;
800  ESP_SDFile esptmp(&tmp, tmp.isDir(),false, s.c_str());
801  esptmp.close();
802  return esptmp;
803  }
804  return ESP_SDFile();
805 }
806 
807 const char * ESP_SD::FilesystemName()
808 {
809  return "SDFat";
810 }
811 
812 #endif //SD_DEVICE == ESP_SD_NATIVE
813 #endif //ARCH_ESP32 && SD_DEVICE
GenLinkedList
Definition: genLinkedList.h:30
ESP_SDCARD_NOT_PRESENT
#define ESP_SDCARD_NOT_PRESENT
Definition: defines.h:81
ESP3DOutput::printLN
size_t printLN(const char *s)
Definition: esp3doutput.cpp:165
ESP_SDFile::isDirectory
bool isDirectory()
Definition: esp_sd.cpp:125
ESP_SD::closeAll
static void closeAll()
ESP_SD::open
static ESP_SDFile open(const char *path, uint8_t mode=ESP_FILE_READ)
ESP_FILE_WRITE
#define ESP_FILE_WRITE
Definition: defines.h:121
ESP_GBFile::openNextFile
ESP_GBFile openNextFile()
Definition: esp_globalFS.cpp:711
ESP_FILE_READ
#define ESP_FILE_READ
Definition: defines.h:120
ESP_SD::totalBytes
static uint64_t totalBytes()
ESP_SDFile
Definition: esp_sd.h:31
GenLinkedList::getLast
T getLast()
Definition: genLinkedList.h:215
ESP_FILE_APPEND
#define ESP_FILE_APPEND
Definition: defines.h:122
ESP_SD::freeBytes
static uint64_t freeBytes()
ESP_GBFile::close
void close()
Definition: esp_globalFS.cpp:390
ESP_SD::remove
static bool remove(const char *path)
GenLinkedList::push
bool push(T data)
Definition: genLinkedList.h:99
ESP_SDCARD_IDLE
#define ESP_SDCARD_IDLE
Definition: defines.h:80
ESP_SD::begin
static bool begin()
ESP_SD::rmdir
static bool rmdir(const char *path)
ESP_SD::mkdir
static bool mkdir(const char *path)
GenLinkedList::pop
T pop()
Definition: genLinkedList.h:121
ESP_SD_SPEED_DIV
#define ESP_SD_SPEED_DIV
Definition: settings_esp3d.h:68
ESP_SDFile::openNextFile
ESP_SDFile openNextFile()
ESP_SD_DETECT_VALUE
#define ESP_SD_DETECT_VALUE
Definition: configuration.h:116
ESP_SD::getState
static uint8_t getState(bool refresh)
ESP3DOutput::printMSG
size_t printMSG(const char *s, bool withNL=true)
Definition: esp3doutput.cpp:190
ESP_SD_CS_PIN
#define ESP_SD_CS_PIN
Definition: pins.h:169
GenLinkedList::count
size_t count()
Definition: genLinkedList.h:93
ESP_SDFile::ESP_SDFile
ESP_SDFile(void *handle=nullptr, bool isdir=false, bool iswritemode=false, const char *path=nullptr)
ESP_SD::FilesystemName
static const char * FilesystemName()
ESP_SD::format
static bool format(ESP3DOutput *output=nullptr)
ESP_SDFile::shortname
const char * shortname() const
log_esp3d
#define log_esp3d(format,...)
Definition: debug_esp3d.h:29
ESP_SDFile::close
void close()
ESP_SD::rename
static bool rename(const char *oldpath, const char *newpath)
Settings_ESP3D::read_byte
static uint8_t read_byte(int pos, bool *haserror=NULL)
Definition: settings_esp3d.cpp:715
ESP_SD::exists
static bool exists(const char *path)
ESP_MAX_SD_OPENHANDLE
#define ESP_MAX_SD_OPENHANDLE
Definition: esp_sd.cpp:27
dir
FTPFile dir
Definition: FtpServer.cpp:103
tSDFile_handle
File tSDFile_handle[ESP_MAX_SD_OPENHANDLE]
Definition: esp_sd.cpp:38
ESP_SD_DETECT_PIN
#define ESP_SD_DETECT_PIN
Definition: configuration.h:114
ESP3DOutput
Definition: esp3doutput.h:48
ESP_SD::usedBytes
static uint64_t usedBytes()
ESP_SD::end
static void end()