cardreader.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089
  1. #include "Marlin.h"
  2. #include "cardreader.h"
  3. #include "ultralcd.h"
  4. #include "stepper.h"
  5. #include "temperature.h"
  6. #include "language.h"
  7. #ifdef SDSUPPORT
  8. #define LONGEST_FILENAME (longFilename[0] ? longFilename : filename)
  9. CardReader::CardReader()
  10. {
  11. #ifdef SDCARD_SORT_ALPHA
  12. sort_count = 0;
  13. #if SDSORT_GCODE
  14. sort_alpha = true;
  15. sort_folders = FOLDER_SORTING;
  16. //sort_reverse = false;
  17. #endif
  18. #endif
  19. filesize = 0;
  20. sdpos = 0;
  21. sdprinting = false;
  22. cardOK = false;
  23. paused = false;
  24. saving = false;
  25. logging = false;
  26. autostart_atmillis=0;
  27. workDirDepth = 0;
  28. file_subcall_ctr=0;
  29. memset(workDirParents, 0, sizeof(workDirParents));
  30. autostart_stilltocheck=true; //the SD start is delayed, because otherwise the serial cannot answer fast enough to make contact with the host software.
  31. lastnr=0;
  32. //power to SD reader
  33. #if SDPOWER > -1
  34. SET_OUTPUT(SDPOWER);
  35. WRITE(SDPOWER,HIGH);
  36. #endif //SDPOWER
  37. autostart_atmillis=_millis()+5000;
  38. }
  39. char *createFilename(char *buffer,const dir_t &p) //buffer>12characters
  40. {
  41. char *pos=buffer;
  42. for (uint8_t i = 0; i < 11; i++)
  43. {
  44. if (p.name[i] == ' ')continue;
  45. if (i == 8)
  46. {
  47. *pos++='.';
  48. }
  49. *pos++=p.name[i];
  50. }
  51. *pos++=0;
  52. return buffer;
  53. }
  54. /**
  55. +* Dive into a folder and recurse depth-first to perform a pre-set operation lsAction:
  56. +* LS_Count - Add +1 to nrFiles for every file within the parent
  57. +* LS_GetFilename - Get the filename of the file indexed by nrFiles
  58. +* LS_SerialPrint - Print the full path and size of each file to serial output
  59. +*/
  60. void CardReader::lsDive(const char *prepend, SdFile parent, const char * const match/*=NULL*/) {
  61. dir_t p;
  62. uint8_t cnt = 0;
  63. // Read the next entry from a directory
  64. while (parent.readDir(p, longFilename) > 0) {
  65. // If the entry is a directory and the action is LS_SerialPrint
  66. if (DIR_IS_SUBDIR(&p) && lsAction != LS_Count && lsAction != LS_GetFilename) {
  67. // Get the short name for the item, which we know is a folder
  68. char lfilename[FILENAME_LENGTH];
  69. createFilename(lfilename, p);
  70. // Allocate enough stack space for the full path to a folder, trailing slash, and nul
  71. bool prepend_is_empty = (prepend[0] == '\0');
  72. int len = (prepend_is_empty ? 1 : strlen(prepend)) + strlen(lfilename) + 1 + 1;
  73. char path[len];
  74. // Append the FOLDERNAME12/ to the passed string.
  75. // It contains the full path to the "parent" argument.
  76. // We now have the full path to the item in this folder.
  77. strcpy(path, prepend_is_empty ? "/" : prepend); // root slash if prepend is empty
  78. strcat(path, lfilename); // FILENAME_LENGTH-1 characters maximum
  79. strcat(path, "/"); // 1 character
  80. // Serial.print(path);
  81. // Get a new directory object using the full path
  82. // and dive recursively into it.
  83. SdFile dir;
  84. if (!dir.open(parent, lfilename, O_READ)) {
  85. if (lsAction == LS_SerialPrint) {
  86. //SERIAL_ECHO_START();
  87. //SERIAL_ECHOPGM(_i("Cannot open subdir"));////MSG_SD_CANT_OPEN_SUBDIR
  88. //SERIAL_ECHOLN(lfilename);
  89. }
  90. }
  91. lsDive(path, dir);
  92. // close() is done automatically by destructor of SdFile
  93. }
  94. else {
  95. uint8_t pn0 = p.name[0];
  96. if (pn0 == DIR_NAME_FREE) break;
  97. if (pn0 == DIR_NAME_DELETED || pn0 == '.') continue;
  98. if (longFilename[0] == '.') continue;
  99. if (!DIR_IS_FILE_OR_SUBDIR(&p) || (p.attributes & DIR_ATT_HIDDEN)) continue;
  100. filenameIsDir = DIR_IS_SUBDIR(&p);
  101. if (!filenameIsDir && (p.name[8] != 'G' || p.name[9] == '~')) continue;
  102. switch (lsAction) {
  103. case LS_Count:
  104. nrFiles++;
  105. break;
  106. case LS_SerialPrint:
  107. createFilename(filename, p);
  108. SERIAL_PROTOCOL(prepend);
  109. SERIAL_PROTOCOL(filename);
  110. MYSERIAL.write(' ');
  111. SERIAL_PROTOCOLLN(p.fileSize);
  112. break;
  113. case LS_GetFilename:
  114. //SERIAL_ECHOPGM("File: ");
  115. createFilename(filename, p);
  116. cluster = parent.curCluster();
  117. position = parent.curPosition();
  118. /*MYSERIAL.println(filename);
  119. SERIAL_ECHOPGM("Write date: ");
  120. writeDate = p.lastWriteDate;
  121. MYSERIAL.println(writeDate);
  122. writeTime = p.lastWriteTime;
  123. SERIAL_ECHOPGM("Creation date: ");
  124. MYSERIAL.println(p.creationDate);
  125. SERIAL_ECHOPGM("Access date: ");
  126. MYSERIAL.println(p.lastAccessDate);
  127. SERIAL_ECHOLNPGM("");*/
  128. modificationDate = p.lastWriteDate;
  129. modificationTime = p.lastWriteTime;
  130. //writeDate = p.lastAccessDate;
  131. if (match != NULL) {
  132. if (strcasecmp(match, filename) == 0) return;
  133. }
  134. else if (cnt == nrFiles) return;
  135. cnt++;
  136. break;
  137. }
  138. }
  139. } // while readDir
  140. }
  141. void CardReader::ls()
  142. {
  143. lsAction=LS_SerialPrint;
  144. //if(lsAction==LS_Count)
  145. //nrFiles=0;
  146. root.rewind();
  147. lsDive("",root);
  148. }
  149. void CardReader::initsd()
  150. {
  151. cardOK = false;
  152. if(root.isOpen())
  153. root.close();
  154. #ifdef SDSLOW
  155. if (!card.init(SPI_HALF_SPEED,SDSS)
  156. #if defined(LCD_SDSS) && (LCD_SDSS != SDSS)
  157. && !card.init(SPI_HALF_SPEED,LCD_SDSS)
  158. #endif
  159. )
  160. #else
  161. if (!card.init(SPI_FULL_SPEED,SDSS)
  162. #if defined(LCD_SDSS) && (LCD_SDSS != SDSS)
  163. && !card.init(SPI_FULL_SPEED,LCD_SDSS)
  164. #endif
  165. )
  166. #endif
  167. {
  168. //if (!card.init(SPI_HALF_SPEED,SDSS))
  169. SERIAL_ECHO_START;
  170. SERIAL_ECHOLNRPGM(_n("SD init fail"));////MSG_SD_INIT_FAIL
  171. }
  172. else if (!volume.init(&card))
  173. {
  174. SERIAL_ERROR_START;
  175. SERIAL_ERRORLNRPGM(_n("volume.init failed"));////MSG_SD_VOL_INIT_FAIL
  176. }
  177. else if (!root.openRoot(&volume))
  178. {
  179. SERIAL_ERROR_START;
  180. SERIAL_ERRORLNRPGM(_n("openRoot failed"));////MSG_SD_OPENROOT_FAIL
  181. }
  182. else
  183. {
  184. cardOK = true;
  185. SERIAL_ECHO_START;
  186. SERIAL_ECHOLNRPGM(_n("SD card ok"));////MSG_SD_CARD_OK
  187. }
  188. workDir=root;
  189. curDir=&root;
  190. workDirDepth = 0;
  191. #ifdef SDCARD_SORT_ALPHA
  192. presort();
  193. #endif
  194. /*
  195. if(!workDir.openRoot(&volume))
  196. {
  197. SERIAL_ECHOLNPGM(MSG_SD_WORKDIR_FAIL);
  198. }
  199. */
  200. }
  201. void CardReader::setroot()
  202. {
  203. /*if(!workDir.openRoot(&volume))
  204. {
  205. SERIAL_ECHOLNPGM(MSG_SD_WORKDIR_FAIL);
  206. }*/
  207. workDir=root;
  208. curDir=&workDir;
  209. #ifdef SDCARD_SORT_ALPHA
  210. presort();
  211. #endif
  212. }
  213. void CardReader::release()
  214. {
  215. sdprinting = false;
  216. cardOK = false;
  217. }
  218. void CardReader::startFileprint()
  219. {
  220. if(cardOK)
  221. {
  222. sdprinting = true;
  223. paused = false;
  224. Stopped = false;
  225. #ifdef SDCARD_SORT_ALPHA
  226. //flush_presort();
  227. #endif
  228. }
  229. }
  230. void CardReader::pauseSDPrint()
  231. {
  232. if(sdprinting)
  233. {
  234. sdprinting = false;
  235. paused = true;
  236. }
  237. }
  238. void CardReader::openLogFile(const char* name)
  239. {
  240. logging = true;
  241. openFile(name, false);
  242. }
  243. void CardReader::getDirName(char* name, uint8_t level)
  244. {
  245. workDirParents[level].getFilename(name);
  246. }
  247. uint16_t CardReader::getWorkDirDepth() {
  248. return workDirDepth;
  249. }
  250. void CardReader::getAbsFilename(char *t)
  251. {
  252. uint8_t cnt=0;
  253. *t='/';t++;cnt++;
  254. for(uint8_t i=0;i<workDirDepth;i++)
  255. {
  256. workDirParents[i].getFilename(t); //SDBaseFile.getfilename!
  257. while(*t!=0 && cnt< MAXPATHNAMELENGTH)
  258. {t++;cnt++;} //crawl counter forward.
  259. }
  260. if(cnt<MAXPATHNAMELENGTH-13)
  261. file.getFilename(t);
  262. else
  263. t[0]=0;
  264. }
  265. /**
  266. * @brief Dive into subfolder
  267. *
  268. * Method sets curDir to point to root, in case fileName is null.
  269. * Method sets curDir to point to workDir, in case fileName path is relative
  270. * (doesn't start with '/')
  271. * Method sets curDir to point to dir, which is specified by absolute path
  272. * specified by fileName. In such case fileName is updated so it points to
  273. * file name without the path.
  274. *
  275. * @param[in,out] fileName
  276. * expects file name including path
  277. * in case of absolute path, file name without path is returned
  278. * @param[in,out] dir SdFile object to operate with,
  279. * in case of absolute path, curDir is modified to point to dir,
  280. * so it is not possible to create on stack inside this function,
  281. * as curDir would point to destroyed object.
  282. */
  283. void CardReader::diveSubfolder (const char *fileName, SdFile& dir)
  284. {
  285. curDir=&root;
  286. if (!fileName) return;
  287. const char *dirname_start, *dirname_end;
  288. if (fileName[0] == '/') // absolute path
  289. {
  290. dirname_start = fileName + 1;
  291. while (*dirname_start)
  292. {
  293. dirname_end = strchr(dirname_start, '/');
  294. //SERIAL_ECHO("start:");SERIAL_ECHOLN((int)(dirname_start-name));
  295. //SERIAL_ECHO("end :");SERIAL_ECHOLN((int)(dirname_end-name));
  296. if (dirname_end && dirname_end > dirname_start)
  297. {
  298. const size_t maxLen = 12;
  299. char subdirname[maxLen+1];
  300. subdirname[maxLen] = 0;
  301. const size_t len = ((static_cast<size_t>(dirname_end-dirname_start))>maxLen) ? maxLen : (dirname_end-dirname_start);
  302. strncpy(subdirname, dirname_start, len);
  303. SERIAL_ECHOLN(subdirname);
  304. if (!dir.open(curDir, subdirname, O_READ))
  305. {
  306. SERIAL_PROTOCOLRPGM(MSG_SD_OPEN_FILE_FAIL);
  307. SERIAL_PROTOCOL(subdirname);
  308. SERIAL_PROTOCOLLNPGM(".");
  309. return;
  310. }
  311. else
  312. {
  313. //SERIAL_ECHOLN("dive ok");
  314. }
  315. curDir = &dir;
  316. dirname_start = dirname_end + 1;
  317. }
  318. else // the reminder after all /fsa/fdsa/ is the filename
  319. {
  320. fileName = dirname_start;
  321. //SERIAL_ECHOLN("remaider");
  322. //SERIAL_ECHOLN(fname);
  323. break;
  324. }
  325. }
  326. }
  327. else //relative path
  328. {
  329. curDir = &workDir;
  330. }
  331. }
  332. void CardReader::openFile(const char* name,bool read, bool replace_current/*=true*/)
  333. {
  334. if(!cardOK)
  335. return;
  336. if(file.isOpen()) //replacing current file by new file, or subfile call
  337. {
  338. if(!replace_current)
  339. {
  340. if((int)file_subcall_ctr>(int)SD_PROCEDURE_DEPTH-1)
  341. {
  342. SERIAL_ERROR_START;
  343. SERIAL_ERRORPGM("trying to call sub-gcode files with too many levels. MAX level is:");
  344. SERIAL_ERRORLN(SD_PROCEDURE_DEPTH);
  345. kill("", 1);
  346. return;
  347. }
  348. SERIAL_ECHO_START;
  349. SERIAL_ECHOPGM("SUBROUTINE CALL target:\"");
  350. SERIAL_ECHO(name);
  351. SERIAL_ECHOPGM("\" parent:\"");
  352. //store current filename and position
  353. getAbsFilename(filenames[file_subcall_ctr]);
  354. SERIAL_ECHO(filenames[file_subcall_ctr]);
  355. SERIAL_ECHOPGM("\" pos");
  356. SERIAL_ECHOLN(sdpos);
  357. filespos[file_subcall_ctr]=sdpos;
  358. file_subcall_ctr++;
  359. }
  360. else
  361. {
  362. SERIAL_ECHO_START;
  363. SERIAL_ECHOPGM("Now doing file: ");
  364. SERIAL_ECHOLN(name);
  365. }
  366. file.close();
  367. }
  368. else //opening fresh file
  369. {
  370. file_subcall_ctr=0; //resetting procedure depth in case user cancels print while in procedure
  371. SERIAL_ECHO_START;
  372. SERIAL_ECHOPGM("Now fresh file: ");
  373. SERIAL_ECHOLN(name);
  374. }
  375. sdprinting = false;
  376. paused = false;
  377. SdFile myDir;
  378. const char *fname=name;
  379. diveSubfolder(fname,myDir);
  380. if(read)
  381. {
  382. if (file.open(curDir, fname, O_READ))
  383. {
  384. filesize = file.fileSize();
  385. SERIAL_PROTOCOLRPGM(_N("File opened: "));////MSG_SD_FILE_OPENED
  386. SERIAL_PROTOCOL(fname);
  387. SERIAL_PROTOCOLRPGM(_n(" Size: "));////MSG_SD_SIZE
  388. SERIAL_PROTOCOLLN(filesize);
  389. sdpos = 0;
  390. SERIAL_PROTOCOLLNRPGM(_N("File selected"));////MSG_SD_FILE_SELECTED
  391. getfilename(0, fname);
  392. lcd_setstatus(longFilename[0] ? longFilename : fname);
  393. lcd_setstatus("SD-PRINTING ");
  394. }
  395. else
  396. {
  397. SERIAL_PROTOCOLRPGM(MSG_SD_OPEN_FILE_FAIL);
  398. SERIAL_PROTOCOL(fname);
  399. SERIAL_PROTOCOLLNPGM(".");
  400. }
  401. }
  402. else
  403. { //write
  404. if (!file.open(curDir, fname, O_CREAT | O_APPEND | O_WRITE | O_TRUNC))
  405. {
  406. SERIAL_PROTOCOLRPGM(MSG_SD_OPEN_FILE_FAIL);
  407. SERIAL_PROTOCOL(fname);
  408. SERIAL_PROTOCOLLNPGM(".");
  409. }
  410. else
  411. {
  412. saving = true;
  413. SERIAL_PROTOCOLRPGM(_N("Writing to file: "));////MSG_SD_WRITE_TO_FILE
  414. SERIAL_PROTOCOLLN(name);
  415. lcd_setstatus(fname);
  416. }
  417. }
  418. }
  419. void CardReader::removeFile(const char* name)
  420. {
  421. if(!cardOK) return;
  422. file.close();
  423. sdprinting = false;
  424. SdFile myDir;
  425. const char *fname=name;
  426. diveSubfolder(fname,myDir);
  427. if (file.remove(curDir, fname))
  428. {
  429. SERIAL_PROTOCOLPGM("File deleted:");
  430. SERIAL_PROTOCOLLN(fname);
  431. sdpos = 0;
  432. #ifdef SDCARD_SORT_ALPHA
  433. presort();
  434. #endif
  435. }
  436. else
  437. {
  438. SERIAL_PROTOCOLPGM("Deletion failed, File: ");
  439. SERIAL_PROTOCOL(fname);
  440. SERIAL_PROTOCOLLNPGM(".");
  441. }
  442. }
  443. uint32_t CardReader::getFileSize()
  444. {
  445. return filesize;
  446. }
  447. void CardReader::getStatus()
  448. {
  449. if(sdprinting){
  450. SERIAL_PROTOCOL(longFilename);
  451. SERIAL_PROTOCOLPGM("\n");
  452. SERIAL_PROTOCOLRPGM(_N("SD printing byte "));////MSG_SD_PRINTING_BYTE
  453. SERIAL_PROTOCOL(sdpos);
  454. SERIAL_PROTOCOLPGM("/");
  455. SERIAL_PROTOCOLLN(filesize);
  456. uint16_t time = _millis()/60000 - starttime/60000;
  457. SERIAL_PROTOCOL(itostr2(time/60));
  458. SERIAL_PROTOCOL(':');
  459. SERIAL_PROTOCOL(itostr2(time%60));
  460. SERIAL_PROTOCOLPGM("\n");
  461. }
  462. else if (paused) {
  463. SERIAL_PROTOCOLLNPGM("SD print paused");
  464. }
  465. else if (saved_printing) {
  466. SERIAL_PROTOCOLLNPGM("Print saved");
  467. }
  468. else {
  469. SERIAL_PROTOCOLLNPGM("Not SD printing");
  470. }
  471. }
  472. void CardReader::write_command(char *buf)
  473. {
  474. char* begin = buf;
  475. char* npos = 0;
  476. char* end = buf + strlen(buf) - 1;
  477. file.writeError = false;
  478. if((npos = strchr(buf, 'N')) != NULL)
  479. {
  480. begin = strchr(npos, ' ') + 1;
  481. end = strchr(npos, '*') - 1;
  482. }
  483. end[1] = '\r';
  484. end[2] = '\n';
  485. end[3] = '\0';
  486. file.write(begin);
  487. if (file.writeError)
  488. {
  489. SERIAL_ERROR_START;
  490. SERIAL_ERRORLNRPGM(MSG_SD_ERR_WRITE_TO_FILE);
  491. }
  492. }
  493. #define CHUNK_SIZE 64
  494. void CardReader::write_command_no_newline(char *buf)
  495. {
  496. file.write(buf, CHUNK_SIZE);
  497. if (file.writeError)
  498. {
  499. SERIAL_ERROR_START;
  500. SERIAL_ERRORLNRPGM(MSG_SD_ERR_WRITE_TO_FILE);
  501. MYSERIAL.println("An error while writing to the SD Card.");
  502. }
  503. }
  504. void CardReader::checkautostart(bool force)
  505. {
  506. if(!force)
  507. {
  508. if(!autostart_stilltocheck)
  509. return;
  510. if(autostart_atmillis<_millis())
  511. return;
  512. }
  513. autostart_stilltocheck=false;
  514. if(!cardOK)
  515. {
  516. initsd();
  517. if(!cardOK) //fail
  518. return;
  519. }
  520. char autoname[30];
  521. sprintf_P(autoname, PSTR("auto%i.g"), lastnr);
  522. for(int8_t i=0;i<(int8_t)strlen(autoname);i++)
  523. autoname[i]=tolower(autoname[i]);
  524. dir_t p;
  525. root.rewind();
  526. bool found=false;
  527. while (root.readDir(p, NULL) > 0)
  528. {
  529. for(int8_t i=0;i<(int8_t)strlen((char*)p.name);i++)
  530. p.name[i]=tolower(p.name[i]);
  531. //Serial.print((char*)p.name);
  532. //Serial.print(" ");
  533. //Serial.println(autoname);
  534. if(p.name[9]!='~') //skip safety copies
  535. if(strncmp((char*)p.name,autoname,5)==0)
  536. {
  537. char cmd[30];
  538. // M23: Select SD file
  539. sprintf_P(cmd, PSTR("M23 %s"), autoname);
  540. enquecommand(cmd);
  541. // M24: Start/resume SD print
  542. enquecommand_P(PSTR("M24"));
  543. found=true;
  544. }
  545. }
  546. if(!found)
  547. lastnr=-1;
  548. else
  549. lastnr++;
  550. }
  551. void CardReader::closefile(bool store_location)
  552. {
  553. file.sync();
  554. file.close();
  555. saving = false;
  556. logging = false;
  557. if(store_location)
  558. {
  559. //future: store printer state, filename and position for continuing a stopped print
  560. // so one can unplug the printer and continue printing the next day.
  561. }
  562. }
  563. void CardReader::getfilename(uint16_t nr, const char * const match/*=NULL*/)
  564. {
  565. curDir=&workDir;
  566. lsAction=LS_GetFilename;
  567. nrFiles=nr;
  568. curDir->rewind();
  569. lsDive("",*curDir,match);
  570. }
  571. void CardReader::getfilename_simple(uint32_t position, const char * const match/*=NULL*/)
  572. {
  573. curDir = &workDir;
  574. lsAction = LS_GetFilename;
  575. nrFiles = 0;
  576. curDir->seekSet(position);
  577. lsDive("", *curDir, match);
  578. }
  579. uint16_t CardReader::getnrfilenames()
  580. {
  581. curDir=&workDir;
  582. lsAction=LS_Count;
  583. nrFiles=0;
  584. curDir->rewind();
  585. lsDive("",*curDir);
  586. //SERIAL_ECHOLN(nrFiles);
  587. return nrFiles;
  588. }
  589. void CardReader::chdir(const char * relpath)
  590. {
  591. SdFile newfile;
  592. SdFile *parent=&root;
  593. if(workDir.isOpen())
  594. parent=&workDir;
  595. if(!newfile.open(*parent,relpath, O_READ))
  596. {
  597. SERIAL_ECHO_START;
  598. SERIAL_ECHORPGM(_n("Cannot enter subdir: "));////MSG_SD_CANT_ENTER_SUBDIR
  599. SERIAL_ECHOLN(relpath);
  600. }
  601. else
  602. {
  603. if (workDirDepth < MAX_DIR_DEPTH) {
  604. for (int d = ++workDirDepth; d--;)
  605. workDirParents[d+1] = workDirParents[d];
  606. workDirParents[0]=*parent;
  607. }
  608. workDir=newfile;
  609. #ifdef SDCARD_SORT_ALPHA
  610. presort();
  611. #endif
  612. }
  613. }
  614. void CardReader::updir()
  615. {
  616. if(workDirDepth > 0)
  617. {
  618. --workDirDepth;
  619. workDir = workDirParents[0];
  620. for (unsigned int d = 0; d < workDirDepth; d++)
  621. {
  622. workDirParents[d] = workDirParents[d+1];
  623. }
  624. #ifdef SDCARD_SORT_ALPHA
  625. presort();
  626. #endif
  627. }
  628. }
  629. #ifdef SDCARD_SORT_ALPHA
  630. /**
  631. * Get the name of a file in the current directory by sort-index
  632. */
  633. void CardReader::getfilename_sorted(const uint16_t nr) {
  634. getfilename(
  635. #if SDSORT_GCODE
  636. sort_alpha &&
  637. #endif
  638. (nr < sort_count) ? sort_order[nr] : nr
  639. );
  640. }
  641. /**
  642. * Read all the files and produce a sort key
  643. *
  644. * We can do this in 3 ways...
  645. * - Minimal RAM: Read two filenames at a time sorting along...
  646. * - Some RAM: Buffer the directory just for this sort
  647. * - Most RAM: Buffer the directory and return filenames from RAM
  648. */
  649. void CardReader::presort() {
  650. if (farm_mode || IS_SD_INSERTED == false) return; //sorting is not used in farm mode
  651. uint8_t sdSort = eeprom_read_byte((uint8_t*)EEPROM_SD_SORT);
  652. if (sdSort == SD_SORT_NONE) return; //sd sort is turned off
  653. #if SDSORT_GCODE
  654. if (!sort_alpha) return;
  655. #endif
  656. KEEPALIVE_STATE(IN_HANDLER);
  657. // Throw away old sort index
  658. flush_presort();
  659. // If there are files, sort up to the limit
  660. uint16_t fileCnt = getnrfilenames();
  661. if (fileCnt > 0) {
  662. // Never sort more than the max allowed
  663. // If you use folders to organize, 20 may be enough
  664. if (fileCnt > SDSORT_LIMIT) {
  665. lcd_show_fullscreen_message_and_wait_P(_i("Some files will not be sorted. Max. No. of files in 1 folder for sorting is 100."));////MSG_FILE_CNT c=20 r=4
  666. fileCnt = SDSORT_LIMIT;
  667. }
  668. lcd_clear();
  669. lcd_puts_at_P(0, 1, _i("Sorting files"));////MSG_SORTING c=20 r=1
  670. // Sort order is always needed. May be static or dynamic.
  671. #if SDSORT_DYNAMIC_RAM
  672. sort_order = new uint8_t[fileCnt];
  673. #endif
  674. // Use RAM to store the entire directory during pre-sort.
  675. // SDSORT_LIMIT should be set to prevent over-allocation.
  676. #if SDSORT_USES_RAM
  677. // If using dynamic ram for names, allocate on the heap.
  678. #if SDSORT_CACHE_NAMES
  679. #if SDSORT_DYNAMIC_RAM
  680. sortshort = new char*[fileCnt];
  681. sortnames = new char*[fileCnt];
  682. #endif
  683. #elif SDSORT_USES_STACK
  684. char sortnames[fileCnt][LONG_FILENAME_LENGTH];
  685. uint16_t modification_time[fileCnt];
  686. uint16_t modification_date[fileCnt];
  687. #endif
  688. // Folder sorting needs 1 bit per entry for flags.
  689. #if HAS_FOLDER_SORTING
  690. #if SDSORT_DYNAMIC_RAM
  691. isDir = new uint8_t[(fileCnt + 7) >> 3];
  692. #elif SDSORT_USES_STACK
  693. uint8_t isDir[(fileCnt + 7) >> 3];
  694. #endif
  695. #endif
  696. #else // !SDSORT_USES_RAM
  697. uint32_t positions[fileCnt];
  698. // By default re-read the names from SD for every compare
  699. // retaining only two filenames at a time. This is very
  700. // slow but is safest and uses minimal RAM.
  701. char name1[LONG_FILENAME_LENGTH + 1];
  702. uint16_t modification_time_bckp;
  703. uint16_t modification_date_bckp;
  704. #endif
  705. position = 0;
  706. if (fileCnt > 1) {
  707. // Init sort order.
  708. for (uint16_t i = 0; i < fileCnt; i++) {
  709. if (!IS_SD_INSERTED) return;
  710. manage_heater();
  711. sort_order[i] = i;
  712. positions[i] = position;
  713. getfilename(i);
  714. // If using RAM then read all filenames now.
  715. #if SDSORT_USES_RAM
  716. getfilename(i);
  717. #if SDSORT_DYNAMIC_RAM
  718. // Use dynamic method to copy long filename
  719. sortnames[i] = strdup(LONGEST_FILENAME);
  720. #if SDSORT_CACHE_NAMES
  721. // When caching also store the short name, since
  722. // we're replacing the getfilename() behavior.
  723. sortshort[i] = strdup(filename);
  724. #endif
  725. #else
  726. // Copy filenames into the static array
  727. strcpy(sortnames[i], LONGEST_FILENAME);
  728. modification_time[i] = modificationTime;
  729. modification_date[i] = modificationDate;
  730. #if SDSORT_CACHE_NAMES
  731. strcpy(sortshort[i], filename);
  732. #endif
  733. #endif
  734. // char out[30];
  735. // sprintf_P(out, PSTR("---- %i %s %s"), i, filenameIsDir ? "D" : " ", sortnames[i]);
  736. // SERIAL_ECHOLN(out);
  737. #if HAS_FOLDER_SORTING
  738. const uint16_t bit = i & 0x07, ind = i >> 3;
  739. if (bit == 0) isDir[ind] = 0x00;
  740. if (filenameIsDir) isDir[ind] |= _BV(bit);
  741. #endif
  742. #endif
  743. }
  744. #ifdef QUICKSORT
  745. quicksort(0, fileCnt - 1);
  746. #elif defined(SHELLSORT)
  747. #define _SORT_CMP_NODIR() (strcasecmp(name2, name1) > 0)
  748. #define _SORT_CMP_TIME_NODIR() (((modification_date_bckp == modificationDate) && (modification_time_bckp < modificationTime)) || (modification_date_bckp < modificationDate))
  749. #define _SORT_CMP_DIR(fs) ((dir1 == filenameIsDir) ? _SORT_CMP_NODIR() : (fs > 0 ? dir1 : !dir1))
  750. #define _SORT_CMP_TIME_DIR(fs) ((dir1 == filenameIsDir) ? _SORT_CMP_TIME_NODIR() : (fs < 0 ? dir1 : !dir1))
  751. uint16_t counter = 0;
  752. uint16_t total = 0;
  753. for (uint16_t i = fileCnt/2; i > 0; i /= 2) total += fileCnt - i; //total runs for progress bar
  754. for (uint16_t gap = fileCnt/2; gap > 0; gap /= 2)
  755. {
  756. for (uint16_t i = gap; i < fileCnt; i++)
  757. {
  758. if (!IS_SD_INSERTED) return;
  759. int8_t percent = (counter * 100) / total;
  760. for (int column = 0; column < 20; column++) {
  761. if (column < (percent / 5))
  762. {
  763. lcd_set_cursor(column, 2);
  764. lcd_print('\xFF'); //simple progress bar
  765. }
  766. }
  767. counter++;
  768. manage_heater();
  769. uint8_t orderBckp = sort_order[i];
  770. getfilename_simple(positions[orderBckp]);
  771. strcpy(name1, LONGEST_FILENAME); // save (or getfilename below will trounce it)
  772. modification_date_bckp = modificationDate;
  773. modification_time_bckp = modificationTime;
  774. #if HAS_FOLDER_SORTING
  775. bool dir1 = filenameIsDir;
  776. #endif
  777. uint16_t j = i;
  778. getfilename_simple(positions[sort_order[j - gap]]);
  779. char *name2 = LONGEST_FILENAME; // use the string in-place
  780. #if HAS_FOLDER_SORTING
  781. for (; j >= gap && ((sdSort == SD_SORT_TIME && _SORT_CMP_TIME_DIR(FOLDER_SORTING)) || (sdSort == SD_SORT_ALPHA && _SORT_CMP_DIR(FOLDER_SORTING)));)
  782. #else
  783. for (; j >= gap && ((sdSort == SD_SORT_TIME && _SORT_CMP_TIME_NODIR()) || (sdSort == SD_SORT_ALPHA && _SORT_CMP_NODIR()));)
  784. #endif
  785. {
  786. sort_order[j] = sort_order[j - gap];
  787. j -= gap;
  788. #ifdef SORTING_DUMP
  789. for (uint16_t z = 0; z < fileCnt; z++)
  790. {
  791. printf_P(PSTR("%2u "), sort_order[z]);
  792. }
  793. printf_P(PSTR("i%2d j%2d gap%2d orderBckp%2d\n"), i, j, gap, orderBckp);
  794. #endif
  795. if (j < gap) break;
  796. getfilename_simple(positions[sort_order[j - gap]]);
  797. name2 = LONGEST_FILENAME; // use the string in-place
  798. }
  799. sort_order[j] = orderBckp;
  800. }
  801. }
  802. #else //Bubble Sort
  803. uint32_t counter = 0;
  804. uint16_t total = 0.5*(fileCnt - 1)*(fileCnt);
  805. // Compare names from the array or just the two buffered names
  806. #if SDSORT_USES_RAM
  807. #define _SORT_CMP_NODIR() (strcasecmp(sortnames[o1], sortnames[o2]) > 0)
  808. #define _SORT_CMP_TIME_NODIR() (((modification_date[o1] == modification_date[o2]) && (modification_time[o1] < modification_time[o2])) || \
  809. (modification_date[o1] < modification_date [o2]))
  810. #else
  811. #define _SORT_CMP_NODIR() (strcasecmp(name1, name2) > 0) //true if lowercase(name1) > lowercase(name2)
  812. #define _SORT_CMP_TIME_NODIR() (((modification_date_bckp == modificationDate) && (modification_time_bckp > modificationTime)) || \
  813. (modification_date_bckp > modificationDate))
  814. #endif
  815. #if HAS_FOLDER_SORTING
  816. #if SDSORT_USES_RAM
  817. // Folder sorting needs an index and bit to test for folder-ness.
  818. const uint8_t ind1 = o1 >> 3, bit1 = o1 & 0x07,
  819. ind2 = o2 >> 3, bit2 = o2 & 0x07;
  820. #define _SORT_CMP_DIR(fs) \
  821. (((isDir[ind1] & _BV(bit1)) != 0) == ((isDir[ind2] & _BV(bit2)) != 0) \
  822. ? _SORT_CMP_NODIR() \
  823. : (isDir[fs > 0 ? ind1 : ind2] & (fs > 0 ? _BV(bit1) : _BV(bit2))) != 0)
  824. #define _SORT_CMP_TIME_DIR(fs) \
  825. (((isDir[ind1] & _BV(bit1)) != 0) == ((isDir[ind2] & _BV(bit2)) != 0) \
  826. ? _SORT_CMP_TIME_NODIR() \
  827. : (isDir[fs > 0 ? ind1 : ind2] & (fs > 0 ? _BV(bit1) : _BV(bit2))) != 0)
  828. #else
  829. #define _SORT_CMP_DIR(fs) ((dir1 == filenameIsDir) ? _SORT_CMP_NODIR() : (fs > 0 ? dir1 : !dir1))
  830. #define _SORT_CMP_TIME_DIR(fs) ((dir1 == filenameIsDir) ? _SORT_CMP_TIME_NODIR() : (fs < 0 ? dir1 : !dir1))
  831. #endif
  832. #endif
  833. for (uint16_t i = fileCnt; --i;) {
  834. if (!IS_SD_INSERTED) return;
  835. bool didSwap = false;
  836. #if !SDSORT_USES_RAM //show progresss bar only if slow sorting method is used
  837. int8_t percent = (counter * 100) / total;//((counter * 100) / pow((fileCnt-1),2));
  838. for (int column = 0; column < 20; column++) {
  839. if (column < (percent / 5))
  840. {
  841. lcd_set_cursor(column, 2);
  842. lcd_print('\xFF'); //simple progress bar
  843. }
  844. }
  845. counter++;
  846. #endif
  847. //MYSERIAL.println(int(i));
  848. for (uint16_t j = 0; j < i; ++j) {
  849. if (!IS_SD_INSERTED) return;
  850. #ifdef SORTING_DUMP
  851. for (uint16_t z = 0; z < fileCnt; z++)
  852. {
  853. printf_P(PSTR("%2u "), sort_order[z]);
  854. }
  855. MYSERIAL.println();
  856. #endif
  857. manage_heater();
  858. const uint16_t o1 = sort_order[j], o2 = sort_order[j + 1];
  859. // The most economical method reads names as-needed
  860. // throughout the loop. Slow if there are many.
  861. #if !SDSORT_USES_RAM
  862. counter++;
  863. getfilename_simple(positions[o1]);
  864. strcpy(name1, LONGEST_FILENAME); // save (or getfilename below will trounce it)
  865. modification_date_bckp = modificationDate;
  866. modification_time_bckp = modificationTime;
  867. #if HAS_FOLDER_SORTING
  868. bool dir1 = filenameIsDir;
  869. #endif
  870. getfilename_simple(positions[o2]);
  871. char *name2 = LONGEST_FILENAME; // use the string in-place
  872. #endif // !SDSORT_USES_RAM
  873. // Sort the current pair according to settings.
  874. if (
  875. #if HAS_FOLDER_SORTING
  876. (sdSort == SD_SORT_TIME && _SORT_CMP_TIME_DIR(FOLDER_SORTING)) || (sdSort == SD_SORT_ALPHA && _SORT_CMP_DIR(FOLDER_SORTING))
  877. #else
  878. (sdSort == SD_SORT_TIME && _SORT_CMP_TIME_NODIR()) || (sdSort == SD_SORT_ALPHA && _SORT_CMP_NODIR())
  879. #endif
  880. )
  881. {
  882. sort_order[j] = o2;
  883. sort_order[j + 1] = o1;
  884. didSwap = true;
  885. }
  886. }
  887. if (!didSwap) break;
  888. } //end of bubble sort loop
  889. #endif
  890. // Using RAM but not keeping names around
  891. #if (SDSORT_USES_RAM && !SDSORT_CACHE_NAMES)
  892. #if SDSORT_DYNAMIC_RAM
  893. for (uint16_t i = 0; i < fileCnt; ++i) free(sortnames[i]);
  894. #if HAS_FOLDER_SORTING
  895. free(isDir);
  896. #endif
  897. #endif
  898. #endif
  899. }
  900. else {
  901. sort_order[0] = 0;
  902. #if (SDSORT_USES_RAM && SDSORT_CACHE_NAMES)
  903. getfilename(0);
  904. #if SDSORT_DYNAMIC_RAM
  905. sortnames = new char*[1];
  906. sortnames[0] = strdup(LONGEST_FILENAME); // malloc
  907. sortshort = new char*[1];
  908. sortshort[0] = strdup(filename); // malloc
  909. isDir = new uint8_t[1];
  910. #else
  911. strcpy(sortnames[0], LONGEST_FILENAME);
  912. strcpy(sortshort[0], filename);
  913. #endif
  914. isDir[0] = filenameIsDir ? 0x01 : 0x00;
  915. #endif
  916. }
  917. sort_count = fileCnt;
  918. }
  919. #if !SDSORT_USES_RAM //show progresss bar only if slow sorting method is used
  920. for (int column = 0; column <= 19; column++)
  921. {
  922. lcd_set_cursor(column, 2);
  923. lcd_print('\xFF'); //simple progress bar
  924. }
  925. _delay(300);
  926. lcd_clear();
  927. #endif
  928. lcd_update(2);
  929. KEEPALIVE_STATE(NOT_BUSY);
  930. lcd_timeoutToStatus.start();
  931. }
  932. void CardReader::flush_presort() {
  933. if (sort_count > 0) {
  934. #if SDSORT_DYNAMIC_RAM
  935. delete sort_order;
  936. #if SDSORT_CACHE_NAMES
  937. for (uint8_t i = 0; i < sort_count; ++i) {
  938. free(sortshort[i]); // strdup
  939. free(sortnames[i]); // strdup
  940. }
  941. delete sortshort;
  942. delete sortnames;
  943. #endif
  944. #endif
  945. sort_count = 0;
  946. }
  947. }
  948. #endif // SDCARD_SORT_ALPHA
  949. void CardReader::printingHasFinished()
  950. {
  951. st_synchronize();
  952. if(file_subcall_ctr>0) //heading up to a parent file that called current as a procedure.
  953. {
  954. file.close();
  955. file_subcall_ctr--;
  956. openFile(filenames[file_subcall_ctr],true,true);
  957. setIndex(filespos[file_subcall_ctr]);
  958. startFileprint();
  959. }
  960. else
  961. {
  962. quickStop();
  963. file.close();
  964. sdprinting = false;
  965. if(SD_FINISHED_STEPPERRELEASE)
  966. {
  967. finishAndDisableSteppers();
  968. //enquecommand_P(PSTR(SD_FINISHED_RELEASECOMMAND));
  969. }
  970. autotempShutdown();
  971. #ifdef SDCARD_SORT_ALPHA
  972. //presort();
  973. #endif
  974. }
  975. }
  976. bool CardReader::ToshibaFlashAir_GetIP(uint8_t *ip)
  977. {
  978. memset(ip, 0, 4);
  979. return card.readExtMemory(1, 1, 0x400+0x150, 4, ip);
  980. }
  981. #endif //SDSUPPORT