My Marlin configs for Fabrikator Mini and CTC i3 Pro B
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

cardreader.cpp 28KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976
  1. /**
  2. * Marlin 3D Printer Firmware
  3. * Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
  4. *
  5. * Based on Sprinter and grbl.
  6. * Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
  7. *
  8. * This program is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation, either version 3 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  20. *
  21. */
  22. #include "../inc/MarlinConfig.h"
  23. #if ENABLED(SDSUPPORT)
  24. #include "cardreader.h"
  25. #include "../Marlin.h"
  26. #include "../lcd/ultralcd.h"
  27. #include "../module/stepper.h"
  28. #include "../module/printcounter.h"
  29. #include "../core/language.h"
  30. #include "../gcode/queue.h"
  31. #if ENABLED(ADVANCED_PAUSE_FEATURE)
  32. #include "../feature/pause.h"
  33. #endif
  34. #include <ctype.h>
  35. #define LONGEST_FILENAME (longFilename[0] ? longFilename : filename)
  36. CardReader::CardReader() {
  37. #if ENABLED(SDCARD_SORT_ALPHA)
  38. sort_count = 0;
  39. #if ENABLED(SDSORT_GCODE)
  40. sort_alpha = true;
  41. sort_folders = FOLDER_SORTING;
  42. //sort_reverse = false;
  43. #endif
  44. #endif
  45. sdprinting = cardOK = saving = logging = false;
  46. filesize = 0;
  47. sdpos = 0;
  48. file_subcall_ctr = 0;
  49. workDirDepth = 0;
  50. ZERO(workDirParents);
  51. autostart_stilltocheck = true; //the SD start is delayed, because otherwise the serial cannot answer fast enough to make contact with the host software.
  52. autostart_index = 0;
  53. //power to SD reader
  54. #if SDPOWER > -1
  55. OUT_WRITE(SDPOWER, HIGH);
  56. #endif // SDPOWER
  57. next_autostart_ms = millis() + 5000;
  58. }
  59. char *createFilename(char *buffer, const dir_t &p) { //buffer > 12characters
  60. char *pos = buffer;
  61. for (uint8_t i = 0; i < 11; i++) {
  62. if (p.name[i] == ' ') continue;
  63. if (i == 8) *pos++ = '.';
  64. *pos++ = p.name[i];
  65. }
  66. *pos++ = 0;
  67. return buffer;
  68. }
  69. /**
  70. * Dive into a folder and recurse depth-first to perform a pre-set operation lsAction:
  71. * LS_Count - Add +1 to nrFiles for every file within the parent
  72. * LS_GetFilename - Get the filename of the file indexed by nrFile_index
  73. * LS_SerialPrint - Print the full path and size of each file to serial output
  74. */
  75. uint16_t nrFile_index;
  76. void CardReader::lsDive(const char *prepend, SdFile parent, const char * const match/*=NULL*/
  77. #if NUM_SERIAL > 1
  78. , const int8_t port/*= -1*/
  79. #endif
  80. ) {
  81. dir_t p;
  82. uint8_t cnt = 0;
  83. // Read the next entry from a directory
  84. while (parent.readDir(p, longFilename) > 0) {
  85. // If the entry is a directory and the action is LS_SerialPrint
  86. if (DIR_IS_SUBDIR(&p) && lsAction != LS_Count && lsAction != LS_GetFilename) {
  87. // Get the short name for the item, which we know is a folder
  88. char lfilename[FILENAME_LENGTH];
  89. createFilename(lfilename, p);
  90. // Allocate enough stack space for the full path to a folder, trailing slash, and nul
  91. bool prepend_is_empty = (prepend[0] == '\0');
  92. int len = (prepend_is_empty ? 1 : strlen(prepend)) + strlen(lfilename) + 1 + 1;
  93. char path[len];
  94. // Append the FOLDERNAME12/ to the passed string.
  95. // It contains the full path to the "parent" argument.
  96. // We now have the full path to the item in this folder.
  97. strcpy(path, prepend_is_empty ? "/" : prepend); // root slash if prepend is empty
  98. strcat(path, lfilename); // FILENAME_LENGTH-1 characters maximum
  99. strcat(path, "/"); // 1 character
  100. // Serial.print(path);
  101. // Get a new directory object using the full path
  102. // and dive recursively into it.
  103. SdFile dir;
  104. if (!dir.open(parent, lfilename, O_READ)) {
  105. if (lsAction == LS_SerialPrint) {
  106. SERIAL_ECHO_START_P(port);
  107. SERIAL_ECHOPGM_P(port, MSG_SD_CANT_OPEN_SUBDIR);
  108. SERIAL_ECHOLN_P(port, lfilename);
  109. }
  110. }
  111. lsDive(path, dir
  112. #if NUM_SERIAL > 1
  113. , NULL, port
  114. #endif
  115. );
  116. // close() is done automatically by destructor of SdFile
  117. }
  118. else {
  119. uint8_t pn0 = p.name[0];
  120. if (pn0 == DIR_NAME_FREE) break;
  121. if (pn0 == DIR_NAME_DELETED || pn0 == '.') continue;
  122. if (longFilename[0] == '.') continue;
  123. if (!DIR_IS_FILE_OR_SUBDIR(&p) || (p.attributes & DIR_ATT_HIDDEN)) continue;
  124. filenameIsDir = DIR_IS_SUBDIR(&p);
  125. if (!filenameIsDir && (p.name[8] != 'G' || p.name[9] == '~')) continue;
  126. switch (lsAction) { // 1 based file count
  127. case LS_Count:
  128. nrFiles++;
  129. break;
  130. case LS_SerialPrint:
  131. createFilename(filename, p);
  132. if (prepend) SERIAL_PROTOCOL_P(port, prepend);
  133. SERIAL_PROTOCOL_P(port, filename);
  134. SERIAL_PROTOCOLCHAR_P(port, ' ');
  135. SERIAL_PROTOCOLLN_P(port, p.fileSize);
  136. break;
  137. case LS_GetFilename:
  138. createFilename(filename, p);
  139. if (match != NULL) {
  140. if (strcasecmp(match, filename) == 0) return;
  141. }
  142. else if (cnt == nrFile_index) return; // 0 based index
  143. cnt++;
  144. break;
  145. }
  146. }
  147. } // while readDir
  148. }
  149. void CardReader::ls(
  150. #if NUM_SERIAL > 1
  151. const int8_t port
  152. #endif
  153. ) {
  154. lsAction = LS_SerialPrint;
  155. root.rewind();
  156. lsDive(NULL, root
  157. #if NUM_SERIAL > 1
  158. , NULL, port
  159. #endif
  160. );
  161. }
  162. #if ENABLED(LONG_FILENAME_HOST_SUPPORT)
  163. /**
  164. * Get a long pretty path based on a DOS 8.3 path
  165. */
  166. void CardReader::printLongPath(char *path
  167. #if NUM_SERIAL > 1
  168. , const int8_t port/*= -1*/
  169. #endif
  170. ) {
  171. lsAction = LS_GetFilename;
  172. int i, pathLen = strlen(path);
  173. // SERIAL_ECHOPGM_P(port, "Full Path: "); SERIAL_ECHOLN_P(port, path);
  174. // Zero out slashes to make segments
  175. for (i = 0; i < pathLen; i++) if (path[i] == '/') path[i] = '\0';
  176. SdFile diveDir = root; // start from the root for segment 1
  177. for (i = 0; i < pathLen;) {
  178. if (path[i] == '\0') i++; // move past a single nul
  179. char *segment = &path[i]; // The segment after most slashes
  180. // If a segment is empty (extra-slash) then exit
  181. if (!*segment) break;
  182. // Go to the next segment
  183. while (path[++i]) { }
  184. // SERIAL_ECHOPGM_P(port, "Looking for segment: "); SERIAL_ECHOLN_P(port, segment);
  185. // Find the item, setting the long filename
  186. diveDir.rewind();
  187. lsDive(NULL, diveDir, segment
  188. #if NUM_SERIAL > 1
  189. , port
  190. #endif
  191. );
  192. // Print /LongNamePart to serial output
  193. SERIAL_PROTOCOLCHAR_P(port, '/');
  194. SERIAL_PROTOCOL_P(port, longFilename[0] ? longFilename : "???");
  195. // If the filename was printed then that's it
  196. if (!filenameIsDir) break;
  197. // SERIAL_ECHOPGM_P(port, "Opening dir: "); SERIAL_ECHOLN_P(port, segment);
  198. // Open the sub-item as the new dive parent
  199. SdFile dir;
  200. if (!dir.open(diveDir, segment, O_READ)) {
  201. SERIAL_EOL_P(port);
  202. SERIAL_ECHO_START_P(port);
  203. SERIAL_ECHOPGM_P(port, MSG_SD_CANT_OPEN_SUBDIR);
  204. SERIAL_ECHO_P(port, segment);
  205. break;
  206. }
  207. diveDir.close();
  208. diveDir = dir;
  209. } // while i<pathLen
  210. SERIAL_EOL_P(port);
  211. }
  212. #endif // LONG_FILENAME_HOST_SUPPORT
  213. void CardReader::initsd() {
  214. cardOK = false;
  215. if (root.isOpen()) root.close();
  216. #ifndef SPI_SPEED
  217. #define SPI_SPEED SPI_FULL_SPEED
  218. #endif
  219. if (!card.init(SPI_SPEED, SDSS)
  220. #if defined(LCD_SDSS) && (LCD_SDSS != SDSS)
  221. && !card.init(SPI_SPEED, LCD_SDSS)
  222. #endif
  223. ) {
  224. //if (!card.init(SPI_HALF_SPEED,SDSS))
  225. SERIAL_ECHO_START();
  226. SERIAL_ECHOLNPGM(MSG_SD_INIT_FAIL);
  227. }
  228. else if (!volume.init(&card)) {
  229. SERIAL_ERROR_START();
  230. SERIAL_ERRORLNPGM(MSG_SD_VOL_INIT_FAIL);
  231. }
  232. else if (!root.openRoot(&volume)) {
  233. SERIAL_ERROR_START();
  234. SERIAL_ERRORLNPGM(MSG_SD_OPENROOT_FAIL);
  235. }
  236. else {
  237. cardOK = true;
  238. SERIAL_ECHO_START();
  239. SERIAL_ECHOLNPGM(MSG_SD_CARD_OK);
  240. }
  241. setroot();
  242. }
  243. void CardReader::setroot() {
  244. /*if (!workDir.openRoot(&volume)) {
  245. SERIAL_ECHOLNPGM(MSG_SD_WORKDIR_FAIL);
  246. }*/
  247. workDir = root;
  248. curDir = &workDir;
  249. #if ENABLED(SDCARD_SORT_ALPHA)
  250. presort();
  251. #endif
  252. }
  253. void CardReader::release() {
  254. sdprinting = false;
  255. cardOK = false;
  256. }
  257. void CardReader::openAndPrintFile(const char *name) {
  258. char cmd[4 + strlen(name) + 1]; // Room for "M23 ", filename, and null
  259. sprintf_P(cmd, PSTR("M23 %s"), name);
  260. for (char *c = &cmd[4]; *c; c++) *c = tolower(*c);
  261. enqueue_and_echo_command_now(cmd);
  262. enqueue_and_echo_commands_P(PSTR("M24"));
  263. }
  264. void CardReader::startFileprint() {
  265. if (cardOK) {
  266. sdprinting = true;
  267. #if SD_RESORT
  268. flush_presort();
  269. #endif
  270. }
  271. }
  272. void CardReader::stopSDPrint(
  273. #if SD_RESORT
  274. const bool re_sort/*=false*/
  275. #endif
  276. ) {
  277. #if ENABLED(ADVANCED_PAUSE_FEATURE)
  278. did_pause_print = 0;
  279. #endif
  280. sdprinting = false;
  281. if (isFileOpen()) file.close();
  282. #if SD_RESORT
  283. if (re_sort) presort();
  284. #endif
  285. }
  286. void CardReader::openLogFile(char* name) {
  287. logging = true;
  288. openFile(name, false);
  289. }
  290. void appendAtom(SdFile &file, char *& dst, uint8_t &cnt) {
  291. file.getFilename(dst);
  292. while (*dst && cnt < MAXPATHNAMELENGTH) { dst++; cnt++; }
  293. if (cnt < MAXPATHNAMELENGTH) { *dst = '/'; dst++; cnt++; }
  294. }
  295. void CardReader::getAbsFilename(char *t) {
  296. *t++ = '/'; // Root folder
  297. uint8_t cnt = 1;
  298. for (uint8_t i = 0; i < workDirDepth; i++) // Loop to current work dir
  299. appendAtom(workDirParents[i], t, cnt);
  300. if (cnt < MAXPATHNAMELENGTH - (FILENAME_LENGTH)) {
  301. appendAtom(file, t, cnt);
  302. --t;
  303. }
  304. *t = '\0';
  305. }
  306. void CardReader::openFile(char* name, const bool read, const bool subcall/*=false*/) {
  307. if (!cardOK) return;
  308. uint8_t doing = 0;
  309. if (isFileOpen()) { // Replacing current file or doing a subroutine
  310. if (subcall) {
  311. if (file_subcall_ctr > SD_PROCEDURE_DEPTH - 1) {
  312. SERIAL_ERROR_START();
  313. SERIAL_ERRORPGM("trying to call sub-gcode files with too many levels. MAX level is:");
  314. SERIAL_ERRORLN((int)SD_PROCEDURE_DEPTH);
  315. kill(PSTR(MSG_KILLED));
  316. return;
  317. }
  318. // Store current filename (based on workDirParents) and position
  319. getAbsFilename(proc_filenames[file_subcall_ctr]);
  320. filespos[file_subcall_ctr] = sdpos;
  321. SERIAL_ECHO_START();
  322. SERIAL_ECHOPAIR("SUBROUTINE CALL target:\"", name);
  323. SERIAL_ECHOPAIR("\" parent:\"", proc_filenames[file_subcall_ctr]);
  324. SERIAL_ECHOLNPAIR("\" pos", sdpos);
  325. file_subcall_ctr++;
  326. }
  327. else
  328. doing = 1;
  329. }
  330. else if (subcall) { // Returning from a subcall?
  331. SERIAL_ECHO_START();
  332. SERIAL_ECHOLNPGM("END SUBROUTINE");
  333. }
  334. else { // Opening fresh file
  335. doing = 2;
  336. file_subcall_ctr = 0; // Reset procedure depth in case user cancels print while in procedure
  337. }
  338. if (doing) {
  339. SERIAL_ECHO_START();
  340. SERIAL_ECHOPGM("Now ");
  341. serialprintPGM(doing == 1 ? PSTR("doing") : PSTR("fresh"));
  342. SERIAL_ECHOLNPAIR(" file: ", name);
  343. }
  344. stopSDPrint();
  345. SdFile myDir;
  346. curDir = &root;
  347. char *fname = name;
  348. char *dirname_start, *dirname_end;
  349. if (name[0] == '/') {
  350. dirname_start = &name[1];
  351. while (dirname_start != NULL) {
  352. dirname_end = strchr(dirname_start, '/');
  353. //SERIAL_ECHOPGM("start:");SERIAL_ECHOLN((int)(dirname_start - name));
  354. //SERIAL_ECHOPGM("end :");SERIAL_ECHOLN((int)(dirname_end - name));
  355. if (dirname_end != NULL && dirname_end > dirname_start) {
  356. char subdirname[FILENAME_LENGTH];
  357. strncpy(subdirname, dirname_start, dirname_end - dirname_start);
  358. subdirname[dirname_end - dirname_start] = '\0';
  359. if (!myDir.open(curDir, subdirname, O_READ)) {
  360. SERIAL_PROTOCOLPGM(MSG_SD_OPEN_FILE_FAIL);
  361. SERIAL_PROTOCOL(subdirname);
  362. SERIAL_PROTOCOLCHAR('.');
  363. return;
  364. }
  365. else {
  366. //SERIAL_ECHOLNPGM("dive ok");
  367. }
  368. curDir = &myDir;
  369. dirname_start = dirname_end + 1;
  370. }
  371. else { // the remainder after all /fsa/fdsa/ is the filename
  372. fname = dirname_start;
  373. //SERIAL_ECHOLNPGM("remainder");
  374. //SERIAL_ECHOLN(fname);
  375. break;
  376. }
  377. }
  378. }
  379. else
  380. curDir = &workDir; // Relative paths start in current directory
  381. if (read) {
  382. if (file.open(curDir, fname, O_READ)) {
  383. filesize = file.fileSize();
  384. sdpos = 0;
  385. SERIAL_PROTOCOLPAIR(MSG_SD_FILE_OPENED, fname);
  386. SERIAL_PROTOCOLLNPAIR(MSG_SD_SIZE, filesize);
  387. SERIAL_PROTOCOLLNPGM(MSG_SD_FILE_SELECTED);
  388. getfilename(0, fname);
  389. lcd_setstatus(longFilename[0] ? longFilename : fname);
  390. }
  391. else {
  392. SERIAL_PROTOCOLPAIR(MSG_SD_OPEN_FILE_FAIL, fname);
  393. SERIAL_PROTOCOLCHAR('.');
  394. SERIAL_EOL();
  395. }
  396. }
  397. else { //write
  398. if (!file.open(curDir, fname, O_CREAT | O_APPEND | O_WRITE | O_TRUNC)) {
  399. SERIAL_PROTOCOLPAIR(MSG_SD_OPEN_FILE_FAIL, fname);
  400. SERIAL_PROTOCOLCHAR('.');
  401. SERIAL_EOL();
  402. }
  403. else {
  404. saving = true;
  405. SERIAL_PROTOCOLLNPAIR(MSG_SD_WRITE_TO_FILE, name);
  406. lcd_setstatus(fname);
  407. }
  408. }
  409. }
  410. void CardReader::removeFile(const char * const name) {
  411. if (!cardOK) return;
  412. stopSDPrint();
  413. SdFile myDir;
  414. curDir = &root;
  415. const char *fname = name;
  416. char *dirname_start, *dirname_end;
  417. if (name[0] == '/') {
  418. dirname_start = strchr(name, '/') + 1;
  419. while (dirname_start != NULL) {
  420. dirname_end = strchr(dirname_start, '/');
  421. //SERIAL_ECHOPGM("start:");SERIAL_ECHOLN((int)(dirname_start - name));
  422. //SERIAL_ECHOPGM("end :");SERIAL_ECHOLN((int)(dirname_end - name));
  423. if (dirname_end != NULL && dirname_end > dirname_start) {
  424. char subdirname[FILENAME_LENGTH];
  425. strncpy(subdirname, dirname_start, dirname_end - dirname_start);
  426. subdirname[dirname_end - dirname_start] = 0;
  427. SERIAL_ECHOLN(subdirname);
  428. if (!myDir.open(curDir, subdirname, O_READ)) {
  429. SERIAL_PROTOCOLPAIR(MSG_SD_OPEN_FILE_FAIL, subdirname);
  430. SERIAL_PROTOCOLCHAR('.');
  431. SERIAL_EOL();
  432. return;
  433. }
  434. curDir = &myDir;
  435. dirname_start = dirname_end + 1;
  436. }
  437. else {
  438. fname = dirname_start;
  439. break;
  440. }
  441. }
  442. }
  443. else // Relative paths are rooted in the current directory
  444. curDir = &workDir;
  445. if (file.remove(curDir, fname)) {
  446. SERIAL_PROTOCOLPGM("File deleted:");
  447. SERIAL_PROTOCOLLN(fname);
  448. sdpos = 0;
  449. #if ENABLED(SDCARD_SORT_ALPHA)
  450. presort();
  451. #endif
  452. }
  453. else {
  454. SERIAL_PROTOCOLPGM("Deletion failed, File: ");
  455. SERIAL_PROTOCOL(fname);
  456. SERIAL_PROTOCOLCHAR('.');
  457. }
  458. }
  459. void CardReader::getStatus(
  460. #if NUM_SERIAL > 1
  461. const int8_t port/*= -1*/
  462. #endif
  463. ) {
  464. if (cardOK && sdprinting) {
  465. SERIAL_PROTOCOLPGM_P(port, MSG_SD_PRINTING_BYTE);
  466. SERIAL_PROTOCOL_P(port, sdpos);
  467. SERIAL_PROTOCOLCHAR_P(port, '/');
  468. SERIAL_PROTOCOLLN_P(port, filesize);
  469. }
  470. else
  471. SERIAL_PROTOCOLLNPGM_P(port, MSG_SD_NOT_PRINTING);
  472. }
  473. void CardReader::write_command(char *buf) {
  474. char* begin = buf;
  475. char* npos = NULL;
  476. char* end = buf + strlen(buf) - 1;
  477. file.writeError = false;
  478. if ((npos = strchr(buf, 'N')) != NULL) {
  479. begin = strchr(npos, ' ') + 1;
  480. end = strchr(npos, '*') - 1;
  481. }
  482. end[1] = '\r';
  483. end[2] = '\n';
  484. end[3] = '\0';
  485. file.write(begin);
  486. if (file.writeError) {
  487. SERIAL_ERROR_START();
  488. SERIAL_ERRORLNPGM(MSG_SD_ERR_WRITE_TO_FILE);
  489. }
  490. }
  491. void CardReader::checkautostart(bool force) {
  492. if (!force && (!autostart_stilltocheck || PENDING(millis(), next_autostart_ms)))
  493. return;
  494. autostart_stilltocheck = false;
  495. if (!cardOK) {
  496. initsd();
  497. if (!cardOK) return; // fail
  498. }
  499. char autoname[10];
  500. sprintf_P(autoname, PSTR("auto%i.g"), autostart_index);
  501. for (int8_t i = 0; i < (int8_t)strlen(autoname); i++) autoname[i] = tolower(autoname[i]);
  502. dir_t p;
  503. root.rewind();
  504. bool found = false;
  505. while (root.readDir(p, NULL) > 0) {
  506. for (int8_t i = (int8_t)strlen((char*)p.name); i--;) p.name[i] = tolower(p.name[i]);
  507. if (p.name[9] != '~' && strncmp((char*)p.name, autoname, 5) == 0) {
  508. openAndPrintFile(autoname);
  509. found = true;
  510. }
  511. }
  512. if (!found)
  513. autostart_index = -1;
  514. else
  515. autostart_index++;
  516. }
  517. void CardReader::closefile(bool store_location) {
  518. file.sync();
  519. file.close();
  520. saving = logging = false;
  521. if (store_location) {
  522. //future: store printer state, filename and position for continuing a stopped print
  523. // so one can unplug the printer and continue printing the next day.
  524. }
  525. }
  526. /**
  527. * Get the name of a file in the current directory by index
  528. */
  529. void CardReader::getfilename(uint16_t nr, const char * const match/*=NULL*/) {
  530. #if ENABLED(SDSORT_CACHE_NAMES)
  531. if (match != NULL) {
  532. while (nr < sort_count) {
  533. if (strcasecmp(match, sortshort[nr]) == 0) break;
  534. nr++;
  535. }
  536. }
  537. if (nr < sort_count) {
  538. strcpy(filename, sortshort[nr]);
  539. strcpy(longFilename, sortnames[nr]);
  540. filenameIsDir = TEST(isDir[nr>>3], nr & 0x07);
  541. return;
  542. }
  543. #endif // SDSORT_CACHE_NAMES
  544. curDir = &workDir;
  545. lsAction = LS_GetFilename;
  546. nrFile_index = nr;
  547. curDir->rewind();
  548. lsDive(NULL, *curDir, match);
  549. }
  550. uint16_t CardReader::getnrfilenames() {
  551. curDir = &workDir;
  552. lsAction = LS_Count;
  553. nrFiles = 0;
  554. curDir->rewind();
  555. lsDive(NULL, *curDir);
  556. //SERIAL_ECHOLN(nrFiles);
  557. return nrFiles;
  558. }
  559. void CardReader::chdir(const char * relpath) {
  560. SdFile newDir;
  561. SdFile *parent = &root;
  562. if (workDir.isOpen()) parent = &workDir;
  563. if (!newDir.open(*parent, relpath, O_READ)) {
  564. SERIAL_ECHO_START();
  565. SERIAL_ECHOPGM(MSG_SD_CANT_ENTER_SUBDIR);
  566. SERIAL_ECHOLN(relpath);
  567. }
  568. else {
  569. workDir = newDir;
  570. if (workDirDepth < MAX_DIR_DEPTH)
  571. workDirParents[workDirDepth++] = workDir;
  572. #if ENABLED(SDCARD_SORT_ALPHA)
  573. presort();
  574. #endif
  575. }
  576. }
  577. int8_t CardReader::updir() {
  578. if (workDirDepth > 0) { // At least 1 dir has been saved
  579. workDir = --workDirDepth ? workDirParents[workDirDepth - 1] : root; // Use parent, or root if none
  580. #if ENABLED(SDCARD_SORT_ALPHA)
  581. presort();
  582. #endif
  583. }
  584. return workDirDepth;
  585. }
  586. #if ENABLED(SDCARD_SORT_ALPHA)
  587. /**
  588. * Get the name of a file in the current directory by sort-index
  589. */
  590. void CardReader::getfilename_sorted(const uint16_t nr) {
  591. getfilename(
  592. #if ENABLED(SDSORT_GCODE)
  593. sort_alpha &&
  594. #endif
  595. (nr < sort_count) ? sort_order[nr] : nr
  596. );
  597. }
  598. /**
  599. * Read all the files and produce a sort key
  600. *
  601. * We can do this in 3 ways...
  602. * - Minimal RAM: Read two filenames at a time sorting along...
  603. * - Some RAM: Buffer the directory just for this sort
  604. * - Most RAM: Buffer the directory and return filenames from RAM
  605. */
  606. void CardReader::presort() {
  607. // Throw away old sort index
  608. flush_presort();
  609. // Sorting may be turned off
  610. #if ENABLED(SDSORT_GCODE)
  611. if (!sort_alpha) return;
  612. #endif
  613. // If there are files, sort up to the limit
  614. uint16_t fileCnt = getnrfilenames();
  615. if (fileCnt > 0) {
  616. // Never sort more than the max allowed
  617. // If you use folders to organize, 20 may be enough
  618. if (fileCnt > SDSORT_LIMIT) fileCnt = SDSORT_LIMIT;
  619. // Sort order is always needed. May be static or dynamic.
  620. #if ENABLED(SDSORT_DYNAMIC_RAM)
  621. sort_order = new uint8_t[fileCnt];
  622. #endif
  623. // Use RAM to store the entire directory during pre-sort.
  624. // SDSORT_LIMIT should be set to prevent over-allocation.
  625. #if ENABLED(SDSORT_USES_RAM)
  626. // If using dynamic ram for names, allocate on the heap.
  627. #if ENABLED(SDSORT_CACHE_NAMES)
  628. #if ENABLED(SDSORT_DYNAMIC_RAM)
  629. sortshort = new char*[fileCnt];
  630. sortnames = new char*[fileCnt];
  631. #endif
  632. #elif ENABLED(SDSORT_USES_STACK)
  633. char sortnames[fileCnt][SORTED_LONGNAME_MAXLEN];
  634. #endif
  635. // Folder sorting needs 1 bit per entry for flags.
  636. #if HAS_FOLDER_SORTING
  637. #if ENABLED(SDSORT_DYNAMIC_RAM)
  638. isDir = new uint8_t[(fileCnt + 7) >> 3];
  639. #elif ENABLED(SDSORT_USES_STACK)
  640. uint8_t isDir[(fileCnt + 7) >> 3];
  641. #endif
  642. #endif
  643. #else // !SDSORT_USES_RAM
  644. // By default re-read the names from SD for every compare
  645. // retaining only two filenames at a time. This is very
  646. // slow but is safest and uses minimal RAM.
  647. char name1[LONG_FILENAME_LENGTH + 1];
  648. #endif
  649. if (fileCnt > 1) {
  650. // Init sort order.
  651. for (uint16_t i = 0; i < fileCnt; i++) {
  652. sort_order[i] = i;
  653. // If using RAM then read all filenames now.
  654. #if ENABLED(SDSORT_USES_RAM)
  655. getfilename(i);
  656. #if ENABLED(SDSORT_DYNAMIC_RAM)
  657. // Use dynamic method to copy long filename
  658. sortnames[i] = strdup(LONGEST_FILENAME);
  659. #if ENABLED(SDSORT_CACHE_NAMES)
  660. // When caching also store the short name, since
  661. // we're replacing the getfilename() behavior.
  662. sortshort[i] = strdup(filename);
  663. #endif
  664. #else
  665. // Copy filenames into the static array
  666. #if SORTED_LONGNAME_MAXLEN != LONG_FILENAME_LENGTH
  667. strncpy(sortnames[i], LONGEST_FILENAME, SORTED_LONGNAME_MAXLEN);
  668. sortnames[i][SORTED_LONGNAME_MAXLEN - 1] = '\0';
  669. #else
  670. strncpy(sortnames[i], LONGEST_FILENAME, SORTED_LONGNAME_MAXLEN);
  671. #endif
  672. #if ENABLED(SDSORT_CACHE_NAMES)
  673. strcpy(sortshort[i], filename);
  674. #endif
  675. #endif
  676. // char out[30];
  677. // sprintf_P(out, PSTR("---- %i %s %s"), i, filenameIsDir ? "D" : " ", sortnames[i]);
  678. // SERIAL_ECHOLN(out);
  679. #if HAS_FOLDER_SORTING
  680. const uint16_t bit = i & 0x07, ind = i >> 3;
  681. if (bit == 0) isDir[ind] = 0x00;
  682. if (filenameIsDir) isDir[ind] |= _BV(bit);
  683. #endif
  684. #endif
  685. }
  686. // Bubble Sort
  687. for (uint16_t i = fileCnt; --i;) {
  688. bool didSwap = false;
  689. for (uint16_t j = 0; j < i; ++j) {
  690. const uint16_t o1 = sort_order[j], o2 = sort_order[j + 1];
  691. // Compare names from the array or just the two buffered names
  692. #if ENABLED(SDSORT_USES_RAM)
  693. #define _SORT_CMP_NODIR() (strcasecmp(sortnames[o1], sortnames[o2]) > 0)
  694. #else
  695. #define _SORT_CMP_NODIR() (strcasecmp(name1, name2) > 0)
  696. #endif
  697. #if HAS_FOLDER_SORTING
  698. #if ENABLED(SDSORT_USES_RAM)
  699. // Folder sorting needs an index and bit to test for folder-ness.
  700. const uint8_t ind1 = o1 >> 3, bit1 = o1 & 0x07,
  701. ind2 = o2 >> 3, bit2 = o2 & 0x07;
  702. #define _SORT_CMP_DIR(fs) \
  703. (((isDir[ind1] & _BV(bit1)) != 0) == ((isDir[ind2] & _BV(bit2)) != 0) \
  704. ? _SORT_CMP_NODIR() \
  705. : (isDir[fs > 0 ? ind1 : ind2] & (fs > 0 ? _BV(bit1) : _BV(bit2))) != 0)
  706. #else
  707. #define _SORT_CMP_DIR(fs) ((dir1 == filenameIsDir) ? _SORT_CMP_NODIR() : (fs > 0 ? dir1 : !dir1))
  708. #endif
  709. #endif
  710. // The most economical method reads names as-needed
  711. // throughout the loop. Slow if there are many.
  712. #if DISABLED(SDSORT_USES_RAM)
  713. getfilename(o1);
  714. strcpy(name1, LONGEST_FILENAME); // save (or getfilename below will trounce it)
  715. #if HAS_FOLDER_SORTING
  716. bool dir1 = filenameIsDir;
  717. #endif
  718. getfilename(o2);
  719. char *name2 = LONGEST_FILENAME; // use the string in-place
  720. #endif // !SDSORT_USES_RAM
  721. // Sort the current pair according to settings.
  722. if (
  723. #if HAS_FOLDER_SORTING
  724. #if ENABLED(SDSORT_GCODE)
  725. sort_folders ? _SORT_CMP_DIR(sort_folders) : _SORT_CMP_NODIR()
  726. #else
  727. _SORT_CMP_DIR(FOLDER_SORTING)
  728. #endif
  729. #else
  730. _SORT_CMP_NODIR()
  731. #endif
  732. ) {
  733. sort_order[j] = o2;
  734. sort_order[j + 1] = o1;
  735. didSwap = true;
  736. }
  737. }
  738. if (!didSwap) break;
  739. }
  740. // Using RAM but not keeping names around
  741. #if ENABLED(SDSORT_USES_RAM) && DISABLED(SDSORT_CACHE_NAMES)
  742. #if ENABLED(SDSORT_DYNAMIC_RAM)
  743. for (uint16_t i = 0; i < fileCnt; ++i) free(sortnames[i]);
  744. #if HAS_FOLDER_SORTING
  745. free(isDir);
  746. #endif
  747. #endif
  748. #endif
  749. }
  750. else {
  751. sort_order[0] = 0;
  752. #if ENABLED(SDSORT_USES_RAM) && ENABLED(SDSORT_CACHE_NAMES)
  753. getfilename(0);
  754. #if ENABLED(SDSORT_DYNAMIC_RAM)
  755. sortnames = new char*[1];
  756. sortnames[0] = strdup(LONGEST_FILENAME); // malloc
  757. #if ENABLED(SDSORT_CACHE_NAMES)
  758. sortshort = new char*[1];
  759. sortshort[0] = strdup(filename); // malloc
  760. #endif
  761. isDir = new uint8_t[1];
  762. #else
  763. #if SORTED_LONGNAME_MAXLEN != LONG_FILENAME_LENGTH
  764. strncpy(sortnames[0], LONGEST_FILENAME, SORTED_LONGNAME_MAXLEN);
  765. sortnames[0][SORTED_LONGNAME_MAXLEN - 1] = '\0';
  766. #else
  767. strncpy(sortnames[0], LONGEST_FILENAME, SORTED_LONGNAME_MAXLEN);
  768. #endif
  769. #if ENABLED(SDSORT_CACHE_NAMES)
  770. strcpy(sortshort[0], filename);
  771. #endif
  772. #endif
  773. isDir[0] = filenameIsDir ? 0x01 : 0x00;
  774. #endif
  775. }
  776. sort_count = fileCnt;
  777. }
  778. }
  779. void CardReader::flush_presort() {
  780. if (sort_count > 0) {
  781. #if ENABLED(SDSORT_DYNAMIC_RAM)
  782. delete sort_order;
  783. #if ENABLED(SDSORT_CACHE_NAMES)
  784. for (uint8_t i = 0; i < sort_count; ++i) {
  785. free(sortshort[i]); // strdup
  786. free(sortnames[i]); // strdup
  787. }
  788. delete sortshort;
  789. delete sortnames;
  790. #endif
  791. #endif
  792. sort_count = 0;
  793. }
  794. }
  795. #endif // SDCARD_SORT_ALPHA
  796. uint16_t CardReader::get_num_Files() {
  797. return
  798. #if ENABLED(SDCARD_SORT_ALPHA) && SDSORT_USES_RAM && SDSORT_CACHE_NAMES
  799. nrFiles // no need to access the SD card for filenames
  800. #else
  801. getnrfilenames()
  802. #endif
  803. ;
  804. }
  805. void CardReader::printingHasFinished() {
  806. stepper.synchronize();
  807. file.close();
  808. if (file_subcall_ctr > 0) { // Heading up to a parent file that called current as a procedure.
  809. file_subcall_ctr--;
  810. openFile(proc_filenames[file_subcall_ctr], true, true);
  811. setIndex(filespos[file_subcall_ctr]);
  812. startFileprint();
  813. }
  814. else {
  815. sdprinting = false;
  816. #if ENABLED(SD_FINISHED_STEPPERRELEASE) && defined(SD_FINISHED_RELEASECOMMAND)
  817. stepper.cleaning_buffer_counter = 1; // The command will fire from the Stepper ISR
  818. #endif
  819. print_job_timer.stop();
  820. if (print_job_timer.duration() > 60)
  821. enqueue_and_echo_commands_P(PSTR("M31"));
  822. #if ENABLED(SDCARD_SORT_ALPHA)
  823. presort();
  824. #endif
  825. #if ENABLED(SD_REPRINT_LAST_SELECTED_FILE)
  826. lcd_reselect_last_file();
  827. #endif
  828. }
  829. }
  830. #if ENABLED(AUTO_REPORT_SD_STATUS)
  831. uint8_t CardReader::auto_report_sd_interval = 0;
  832. millis_t CardReader::next_sd_report_ms;
  833. #if NUM_SERIAL > 1
  834. int8_t CardReader::serialport;
  835. #endif
  836. void CardReader::auto_report_sd_status() {
  837. millis_t current_ms = millis();
  838. if (auto_report_sd_interval && ELAPSED(current_ms, next_sd_report_ms)) {
  839. next_sd_report_ms = current_ms + 1000UL * auto_report_sd_interval;
  840. getStatus(
  841. #if NUM_SERIAL > 1
  842. serialport
  843. #endif
  844. );
  845. }
  846. }
  847. #endif // AUTO_REPORT_SD_STATUS
  848. #endif // SDSUPPORT