cardreader.cpp 28 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079
  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. #if !SDSORT_USES_RAM
  670. lcd_set_progress();
  671. #endif
  672. lcd_puts_at_P(0, 1, _i("Sorting files"));////MSG_SORTING c=20 r=1
  673. // Sort order is always needed. May be static or dynamic.
  674. #if SDSORT_DYNAMIC_RAM
  675. sort_order = new uint8_t[fileCnt];
  676. #endif
  677. // Use RAM to store the entire directory during pre-sort.
  678. // SDSORT_LIMIT should be set to prevent over-allocation.
  679. #if SDSORT_USES_RAM
  680. // If using dynamic ram for names, allocate on the heap.
  681. #if SDSORT_CACHE_NAMES
  682. #if SDSORT_DYNAMIC_RAM
  683. sortshort = new char*[fileCnt];
  684. sortnames = new char*[fileCnt];
  685. #endif
  686. #elif SDSORT_USES_STACK
  687. char sortnames[fileCnt][LONG_FILENAME_LENGTH];
  688. uint16_t modification_time[fileCnt];
  689. uint16_t modification_date[fileCnt];
  690. #endif
  691. // Folder sorting needs 1 bit per entry for flags.
  692. #if HAS_FOLDER_SORTING
  693. #if SDSORT_DYNAMIC_RAM
  694. isDir = new uint8_t[(fileCnt + 7) >> 3];
  695. #elif SDSORT_USES_STACK
  696. uint8_t isDir[(fileCnt + 7) >> 3];
  697. #endif
  698. #endif
  699. #else // !SDSORT_USES_RAM
  700. uint32_t positions[fileCnt];
  701. // By default re-read the names from SD for every compare
  702. // retaining only two filenames at a time. This is very
  703. // slow but is safest and uses minimal RAM.
  704. char name1[LONG_FILENAME_LENGTH + 1];
  705. uint16_t modification_time_bckp;
  706. uint16_t modification_date_bckp;
  707. #endif
  708. position = 0;
  709. if (fileCnt > 1) {
  710. // Init sort order.
  711. for (uint16_t i = 0; i < fileCnt; i++) {
  712. if (!IS_SD_INSERTED) return;
  713. manage_heater();
  714. sort_order[i] = i;
  715. positions[i] = position;
  716. getfilename(i);
  717. // If using RAM then read all filenames now.
  718. #if SDSORT_USES_RAM
  719. getfilename(i);
  720. #if SDSORT_DYNAMIC_RAM
  721. // Use dynamic method to copy long filename
  722. sortnames[i] = strdup(LONGEST_FILENAME);
  723. #if SDSORT_CACHE_NAMES
  724. // When caching also store the short name, since
  725. // we're replacing the getfilename() behavior.
  726. sortshort[i] = strdup(filename);
  727. #endif
  728. #else
  729. // Copy filenames into the static array
  730. strcpy(sortnames[i], LONGEST_FILENAME);
  731. modification_time[i] = modificationTime;
  732. modification_date[i] = modificationDate;
  733. #if SDSORT_CACHE_NAMES
  734. strcpy(sortshort[i], filename);
  735. #endif
  736. #endif
  737. // char out[30];
  738. // sprintf_P(out, PSTR("---- %i %s %s"), i, filenameIsDir ? "D" : " ", sortnames[i]);
  739. // SERIAL_ECHOLN(out);
  740. #if HAS_FOLDER_SORTING
  741. const uint16_t bit = i & 0x07, ind = i >> 3;
  742. if (bit == 0) isDir[ind] = 0x00;
  743. if (filenameIsDir) isDir[ind] |= _BV(bit);
  744. #endif
  745. #endif
  746. }
  747. #ifdef QUICKSORT
  748. quicksort(0, fileCnt - 1);
  749. #elif defined(SHELLSORT)
  750. #define _SORT_CMP_NODIR() (strcasecmp(name2, name1) > 0)
  751. #define _SORT_CMP_TIME_NODIR() (((modification_date_bckp == modificationDate) && (modification_time_bckp < modificationTime)) || (modification_date_bckp < modificationDate))
  752. #define _SORT_CMP_DIR(fs) ((dir1 == filenameIsDir) ? _SORT_CMP_NODIR() : (fs > 0 ? dir1 : !dir1))
  753. #define _SORT_CMP_TIME_DIR(fs) ((dir1 == filenameIsDir) ? _SORT_CMP_TIME_NODIR() : (fs < 0 ? dir1 : !dir1))
  754. for (int16_t gap = fileCnt/2; gap > 0; gap /= 2)
  755. {
  756. for (int16_t i = gap; i < fileCnt; i++)
  757. {
  758. if (!IS_SD_INSERTED) return;
  759. manage_heater();
  760. uint8_t orderBckp = sort_order[i];
  761. getfilename_simple(positions[orderBckp]);
  762. strcpy(name1, LONGEST_FILENAME); // save (or getfilename below will trounce it)
  763. modification_date_bckp = modificationDate;
  764. modification_time_bckp = modificationTime;
  765. #if HAS_FOLDER_SORTING
  766. bool dir1 = filenameIsDir;
  767. #endif
  768. int16_t j = i;
  769. getfilename_simple(positions[sort_order[j - gap]]);
  770. char *name2 = LONGEST_FILENAME; // use the string in-place
  771. #if HAS_FOLDER_SORTING
  772. for (; j >= gap && ((sdSort == SD_SORT_TIME && _SORT_CMP_TIME_DIR(FOLDER_SORTING)) || (sdSort == SD_SORT_ALPHA && _SORT_CMP_DIR(FOLDER_SORTING)));)
  773. #else
  774. for (; j >= gap && ((sdSort == SD_SORT_TIME && _SORT_CMP_TIME_NODIR()) || (sdSort == SD_SORT_ALPHA && _SORT_CMP_NODIR()));)
  775. #endif
  776. {
  777. sort_order[j] = sort_order[j - gap];
  778. j -= gap;
  779. #ifdef SORTING_DUMP
  780. for (uint16_t z = 0; z < fileCnt; z++)
  781. {
  782. printf_P(PSTR("%2u "), sort_order[z]);
  783. }
  784. printf_P(PSTR("i%2d j%2d gap%2d orderBckp%2d\n"), i, j, gap, orderBckp);
  785. #endif
  786. if (j < gap) break;
  787. getfilename_simple(positions[sort_order[j - gap]]);
  788. name2 = LONGEST_FILENAME; // use the string in-place
  789. }
  790. sort_order[j] = orderBckp;
  791. }
  792. }
  793. #else //Bubble Sort
  794. uint32_t counter = 0;
  795. uint16_t total = 0.5*(fileCnt - 1)*(fileCnt);
  796. // Compare names from the array or just the two buffered names
  797. #if SDSORT_USES_RAM
  798. #define _SORT_CMP_NODIR() (strcasecmp(sortnames[o1], sortnames[o2]) > 0)
  799. #define _SORT_CMP_TIME_NODIR() (((modification_date[o1] == modification_date[o2]) && (modification_time[o1] < modification_time[o2])) || \
  800. (modification_date[o1] < modification_date [o2]))
  801. #else
  802. #define _SORT_CMP_NODIR() (strcasecmp(name1, name2) > 0) //true if lowercase(name1) > lowercase(name2)
  803. #define _SORT_CMP_TIME_NODIR() (((modification_date_bckp == modificationDate) && (modification_time_bckp > modificationTime)) || \
  804. (modification_date_bckp > modificationDate))
  805. #endif
  806. #if HAS_FOLDER_SORTING
  807. #if SDSORT_USES_RAM
  808. // Folder sorting needs an index and bit to test for folder-ness.
  809. const uint8_t ind1 = o1 >> 3, bit1 = o1 & 0x07,
  810. ind2 = o2 >> 3, bit2 = o2 & 0x07;
  811. #define _SORT_CMP_DIR(fs) \
  812. (((isDir[ind1] & _BV(bit1)) != 0) == ((isDir[ind2] & _BV(bit2)) != 0) \
  813. ? _SORT_CMP_NODIR() \
  814. : (isDir[fs > 0 ? ind1 : ind2] & (fs > 0 ? _BV(bit1) : _BV(bit2))) != 0)
  815. #define _SORT_CMP_TIME_DIR(fs) \
  816. (((isDir[ind1] & _BV(bit1)) != 0) == ((isDir[ind2] & _BV(bit2)) != 0) \
  817. ? _SORT_CMP_TIME_NODIR() \
  818. : (isDir[fs > 0 ? ind1 : ind2] & (fs > 0 ? _BV(bit1) : _BV(bit2))) != 0)
  819. #else
  820. #define _SORT_CMP_DIR(fs) ((dir1 == filenameIsDir) ? _SORT_CMP_NODIR() : (fs > 0 ? dir1 : !dir1))
  821. #define _SORT_CMP_TIME_DIR(fs) ((dir1 == filenameIsDir) ? _SORT_CMP_TIME_NODIR() : (fs < 0 ? dir1 : !dir1))
  822. #endif
  823. #endif
  824. for (uint16_t i = fileCnt; --i;) {
  825. if (!IS_SD_INSERTED) return;
  826. bool didSwap = false;
  827. #if !SDSORT_USES_RAM //show progresss bar only if slow sorting method is used
  828. int8_t percent = (counter * 100) / total;//((counter * 100) / pow((fileCnt-1),2));
  829. for (int column = 0; column < 20; column++) {
  830. if (column < (percent / 5))
  831. {
  832. lcd_set_cursor(column, 2);
  833. lcd_print('\x01'); //simple progress bar
  834. }
  835. }
  836. counter++;
  837. #endif
  838. //MYSERIAL.println(int(i));
  839. for (uint16_t j = 0; j < i; ++j) {
  840. if (!IS_SD_INSERTED) return;
  841. #ifdef SORTING_DUMP
  842. for (uint16_t z = 0; z < fileCnt; z++)
  843. {
  844. printf_P(PSTR("%2u "), sort_order[z]);
  845. }
  846. MYSERIAL.println();
  847. #endif
  848. manage_heater();
  849. const uint16_t o1 = sort_order[j], o2 = sort_order[j + 1];
  850. // The most economical method reads names as-needed
  851. // throughout the loop. Slow if there are many.
  852. #if !SDSORT_USES_RAM
  853. counter++;
  854. getfilename_simple(positions[o1]);
  855. strcpy(name1, LONGEST_FILENAME); // save (or getfilename below will trounce it)
  856. modification_date_bckp = modificationDate;
  857. modification_time_bckp = modificationTime;
  858. #if HAS_FOLDER_SORTING
  859. bool dir1 = filenameIsDir;
  860. #endif
  861. getfilename_simple(positions[o2]);
  862. char *name2 = LONGEST_FILENAME; // use the string in-place
  863. #endif // !SDSORT_USES_RAM
  864. // Sort the current pair according to settings.
  865. if (
  866. #if HAS_FOLDER_SORTING
  867. (sdSort == SD_SORT_TIME && _SORT_CMP_TIME_DIR(FOLDER_SORTING)) || (sdSort == SD_SORT_ALPHA && _SORT_CMP_DIR(FOLDER_SORTING))
  868. #else
  869. (sdSort == SD_SORT_TIME && _SORT_CMP_TIME_NODIR()) || (sdSort == SD_SORT_ALPHA && _SORT_CMP_NODIR())
  870. #endif
  871. )
  872. {
  873. sort_order[j] = o2;
  874. sort_order[j + 1] = o1;
  875. didSwap = true;
  876. }
  877. }
  878. if (!didSwap) break;
  879. } //end of bubble sort loop
  880. #endif
  881. // Using RAM but not keeping names around
  882. #if (SDSORT_USES_RAM && !SDSORT_CACHE_NAMES)
  883. #if SDSORT_DYNAMIC_RAM
  884. for (uint16_t i = 0; i < fileCnt; ++i) free(sortnames[i]);
  885. #if HAS_FOLDER_SORTING
  886. free(isDir);
  887. #endif
  888. #endif
  889. #endif
  890. }
  891. else {
  892. sort_order[0] = 0;
  893. #if (SDSORT_USES_RAM && SDSORT_CACHE_NAMES)
  894. getfilename(0);
  895. #if SDSORT_DYNAMIC_RAM
  896. sortnames = new char*[1];
  897. sortnames[0] = strdup(LONGEST_FILENAME); // malloc
  898. sortshort = new char*[1];
  899. sortshort[0] = strdup(filename); // malloc
  900. isDir = new uint8_t[1];
  901. #else
  902. strcpy(sortnames[0], LONGEST_FILENAME);
  903. strcpy(sortshort[0], filename);
  904. #endif
  905. isDir[0] = filenameIsDir ? 0x01 : 0x00;
  906. #endif
  907. }
  908. sort_count = fileCnt;
  909. }
  910. #if !SDSORT_USES_RAM //show progresss bar only if slow sorting method is used
  911. for (int column = 0; column <= 19; column++)
  912. {
  913. lcd_set_cursor(column, 2);
  914. lcd_print('\x01'); //simple progress bar
  915. }
  916. _delay(300);
  917. lcd_set_degree();
  918. lcd_clear();
  919. #endif
  920. lcd_update(2);
  921. KEEPALIVE_STATE(NOT_BUSY);
  922. lcd_timeoutToStatus.start();
  923. }
  924. void CardReader::flush_presort() {
  925. if (sort_count > 0) {
  926. #if SDSORT_DYNAMIC_RAM
  927. delete sort_order;
  928. #if SDSORT_CACHE_NAMES
  929. for (uint8_t i = 0; i < sort_count; ++i) {
  930. free(sortshort[i]); // strdup
  931. free(sortnames[i]); // strdup
  932. }
  933. delete sortshort;
  934. delete sortnames;
  935. #endif
  936. #endif
  937. sort_count = 0;
  938. }
  939. }
  940. #endif // SDCARD_SORT_ALPHA
  941. void CardReader::printingHasFinished()
  942. {
  943. st_synchronize();
  944. if(file_subcall_ctr>0) //heading up to a parent file that called current as a procedure.
  945. {
  946. file.close();
  947. file_subcall_ctr--;
  948. openFile(filenames[file_subcall_ctr],true,true);
  949. setIndex(filespos[file_subcall_ctr]);
  950. startFileprint();
  951. }
  952. else
  953. {
  954. quickStop();
  955. file.close();
  956. sdprinting = false;
  957. if(SD_FINISHED_STEPPERRELEASE)
  958. {
  959. finishAndDisableSteppers();
  960. //enquecommand_P(PSTR(SD_FINISHED_RELEASECOMMAND));
  961. }
  962. autotempShutdown();
  963. #ifdef SDCARD_SORT_ALPHA
  964. //presort();
  965. #endif
  966. }
  967. }
  968. bool CardReader::ToshibaFlashAir_GetIP(uint8_t *ip)
  969. {
  970. memset(ip, 0, 4);
  971. return card.readExtMemory(1, 1, 0x400+0x150, 4, ip);
  972. }
  973. #endif //SDSUPPORT