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.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517
  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. CardReader::CardReader() {
  9. filesize = 0;
  10. sdpos = 0;
  11. sdprinting = false;
  12. cardOK = false;
  13. saving = false;
  14. logging = false;
  15. workDirDepth = 0;
  16. file_subcall_ctr = 0;
  17. memset(workDirParents, 0, sizeof(workDirParents));
  18. autostart_stilltocheck = true; //the SD start is delayed, because otherwise the serial cannot answer fast enough to make contact with the host software.
  19. autostart_index = 0;
  20. //power to SD reader
  21. #if SDPOWER > -1
  22. OUT_WRITE(SDPOWER, HIGH);
  23. #endif //SDPOWER
  24. autostart_atmillis = millis() + 5000;
  25. }
  26. char *createFilename(char *buffer, const dir_t &p) { //buffer > 12characters
  27. char *pos = buffer;
  28. for (uint8_t i = 0; i < 11; i++) {
  29. if (p.name[i] == ' ') continue;
  30. if (i == 8) *pos++ = '.';
  31. *pos++ = p.name[i];
  32. }
  33. *pos++ = 0;
  34. return buffer;
  35. }
  36. void CardReader::lsDive(const char *prepend, SdFile parent, const char * const match/*=NULL*/) {
  37. dir_t p;
  38. uint8_t cnt = 0;
  39. while (parent.readDir(p, longFilename) > 0) {
  40. if (DIR_IS_SUBDIR(&p) && lsAction != LS_Count && lsAction != LS_GetFilename) { // hence LS_SerialPrint
  41. char path[FILENAME_LENGTH*2];
  42. char lfilename[FILENAME_LENGTH];
  43. createFilename(lfilename, p);
  44. path[0] = 0;
  45. if (prepend[0] == 0) strcat(path, "/"); //avoid leading / if already in prepend
  46. strcat(path, prepend);
  47. strcat(path, lfilename);
  48. strcat(path, "/");
  49. //Serial.print(path);
  50. SdFile dir;
  51. if (!dir.open(parent, lfilename, O_READ)) {
  52. if (lsAction == LS_SerialPrint) {
  53. SERIAL_ECHO_START;
  54. SERIAL_ECHOLN(MSG_SD_CANT_OPEN_SUBDIR);
  55. SERIAL_ECHOLN(lfilename);
  56. }
  57. }
  58. lsDive(path, dir);
  59. //close done automatically by destructor of SdFile
  60. }
  61. else {
  62. char pn0 = p.name[0];
  63. if (pn0 == DIR_NAME_FREE) break;
  64. if (pn0 == DIR_NAME_DELETED || pn0 == '.') continue;
  65. char lf0 = longFilename[0];
  66. if (lf0 == '.') continue;
  67. if (!DIR_IS_FILE_OR_SUBDIR(&p)) continue;
  68. filenameIsDir = DIR_IS_SUBDIR(&p);
  69. if (!filenameIsDir && (p.name[8] != 'G' || p.name[9] == '~')) continue;
  70. //if (cnt++ != nr) continue;
  71. createFilename(filename, p);
  72. if (lsAction == LS_SerialPrint) {
  73. SERIAL_PROTOCOL(prepend);
  74. SERIAL_PROTOCOLLN(filename);
  75. }
  76. else if (lsAction == LS_Count) {
  77. nrFiles++;
  78. }
  79. else if (lsAction == LS_GetFilename) {
  80. if (match != NULL) {
  81. if (strcasecmp(match, filename) == 0) return;
  82. }
  83. else if (cnt == nrFiles) return;
  84. cnt++;
  85. }
  86. }
  87. }
  88. }
  89. void CardReader::ls() {
  90. lsAction = LS_SerialPrint;
  91. root.rewind();
  92. lsDive("", root);
  93. }
  94. void CardReader::initsd() {
  95. cardOK = false;
  96. if (root.isOpen()) root.close();
  97. #ifdef SDSLOW
  98. #define SPI_SPEED SPI_HALF_SPEED
  99. #else
  100. #define SPI_SPEED SPI_FULL_SPEED
  101. #endif
  102. if (!card.init(SPI_SPEED,SDSS)
  103. #if defined(LCD_SDSS) && (LCD_SDSS != SDSS)
  104. && !card.init(SPI_SPEED, LCD_SDSS)
  105. #endif
  106. ) {
  107. //if (!card.init(SPI_HALF_SPEED,SDSS))
  108. SERIAL_ECHO_START;
  109. SERIAL_ECHOLNPGM(MSG_SD_INIT_FAIL);
  110. }
  111. else if (!volume.init(&card)) {
  112. SERIAL_ERROR_START;
  113. SERIAL_ERRORLNPGM(MSG_SD_VOL_INIT_FAIL);
  114. }
  115. else if (!root.openRoot(&volume)) {
  116. SERIAL_ERROR_START;
  117. SERIAL_ERRORLNPGM(MSG_SD_OPENROOT_FAIL);
  118. }
  119. else {
  120. cardOK = true;
  121. SERIAL_ECHO_START;
  122. SERIAL_ECHOLNPGM(MSG_SD_CARD_OK);
  123. }
  124. workDir = root;
  125. curDir = &root;
  126. /*
  127. if (!workDir.openRoot(&volume)) {
  128. SERIAL_ECHOLNPGM(MSG_SD_WORKDIR_FAIL);
  129. }
  130. */
  131. }
  132. void CardReader::setroot() {
  133. /*if (!workDir.openRoot(&volume)) {
  134. SERIAL_ECHOLNPGM(MSG_SD_WORKDIR_FAIL);
  135. }*/
  136. workDir = root;
  137. curDir = &workDir;
  138. }
  139. void CardReader::release() {
  140. sdprinting = false;
  141. cardOK = false;
  142. }
  143. void CardReader::startFileprint() {
  144. if (cardOK) {
  145. sdprinting = true;
  146. }
  147. }
  148. void CardReader::pauseSDPrint() {
  149. if (sdprinting) sdprinting = false;
  150. }
  151. void CardReader::openLogFile(char* name) {
  152. logging = true;
  153. openFile(name, false);
  154. }
  155. void CardReader::getAbsFilename(char *t) {
  156. uint8_t cnt = 0;
  157. *t = '/'; t++; cnt++;
  158. for (uint8_t i = 0; i < workDirDepth; i++) {
  159. workDirParents[i].getFilename(t); //SDBaseFile.getfilename!
  160. while(*t && cnt < MAXPATHNAMELENGTH) { t++; cnt++; } //crawl counter forward.
  161. }
  162. if (cnt < MAXPATHNAMELENGTH - FILENAME_LENGTH)
  163. file.getFilename(t);
  164. else
  165. t[0] = 0;
  166. }
  167. void CardReader::openFile(char* name, bool read, bool replace_current/*=true*/) {
  168. if (!cardOK) return;
  169. if (file.isOpen()) { //replacing current file by new file, or subfile call
  170. if (!replace_current) {
  171. if (file_subcall_ctr > SD_PROCEDURE_DEPTH - 1) {
  172. SERIAL_ERROR_START;
  173. SERIAL_ERRORPGM("trying to call sub-gcode files with too many levels. MAX level is:");
  174. SERIAL_ERRORLN(SD_PROCEDURE_DEPTH);
  175. kill();
  176. return;
  177. }
  178. SERIAL_ECHO_START;
  179. SERIAL_ECHOPGM("SUBROUTINE CALL target:\"");
  180. SERIAL_ECHO(name);
  181. SERIAL_ECHOPGM("\" parent:\"");
  182. //store current filename and position
  183. getAbsFilename(filenames[file_subcall_ctr]);
  184. SERIAL_ECHO(filenames[file_subcall_ctr]);
  185. SERIAL_ECHOPGM("\" pos");
  186. SERIAL_ECHOLN(sdpos);
  187. filespos[file_subcall_ctr] = sdpos;
  188. file_subcall_ctr++;
  189. }
  190. else {
  191. SERIAL_ECHO_START;
  192. SERIAL_ECHOPGM("Now doing file: ");
  193. SERIAL_ECHOLN(name);
  194. }
  195. file.close();
  196. }
  197. else { //opening fresh file
  198. file_subcall_ctr = 0; //resetting procedure depth in case user cancels print while in procedure
  199. SERIAL_ECHO_START;
  200. SERIAL_ECHOPGM("Now fresh file: ");
  201. SERIAL_ECHOLN(name);
  202. }
  203. sdprinting = false;
  204. SdFile myDir;
  205. curDir = &root;
  206. char *fname = name;
  207. char *dirname_start, *dirname_end;
  208. if (name[0] == '/') {
  209. dirname_start = &name[1];
  210. while(dirname_start > 0) {
  211. dirname_end = strchr(dirname_start, '/');
  212. //SERIAL_ECHO("start:");SERIAL_ECHOLN((int)(dirname_start - name));
  213. //SERIAL_ECHO("end :");SERIAL_ECHOLN((int)(dirname_end - name));
  214. if (dirname_end > 0 && dirname_end > dirname_start) {
  215. char subdirname[FILENAME_LENGTH];
  216. strncpy(subdirname, dirname_start, dirname_end - dirname_start);
  217. subdirname[dirname_end - dirname_start] = 0;
  218. SERIAL_ECHOLN(subdirname);
  219. if (!myDir.open(curDir, subdirname, O_READ)) {
  220. SERIAL_PROTOCOLPGM(MSG_SD_OPEN_FILE_FAIL);
  221. SERIAL_PROTOCOL(subdirname);
  222. SERIAL_PROTOCOLLNPGM(".");
  223. return;
  224. }
  225. else {
  226. //SERIAL_ECHOLN("dive ok");
  227. }
  228. curDir = &myDir;
  229. dirname_start = dirname_end + 1;
  230. }
  231. else { // the remainder after all /fsa/fdsa/ is the filename
  232. fname = dirname_start;
  233. //SERIAL_ECHOLN("remainder");
  234. //SERIAL_ECHOLN(fname);
  235. break;
  236. }
  237. }
  238. }
  239. else { //relative path
  240. curDir = &workDir;
  241. }
  242. if (read) {
  243. if (file.open(curDir, fname, O_READ)) {
  244. filesize = file.fileSize();
  245. SERIAL_PROTOCOLPGM(MSG_SD_FILE_OPENED);
  246. SERIAL_PROTOCOL(fname);
  247. SERIAL_PROTOCOLPGM(MSG_SD_SIZE);
  248. SERIAL_PROTOCOLLN(filesize);
  249. sdpos = 0;
  250. SERIAL_PROTOCOLLNPGM(MSG_SD_FILE_SELECTED);
  251. getfilename(0, fname);
  252. lcd_setstatus(longFilename[0] ? longFilename : fname);
  253. }
  254. else {
  255. SERIAL_PROTOCOLPGM(MSG_SD_OPEN_FILE_FAIL);
  256. SERIAL_PROTOCOL(fname);
  257. SERIAL_PROTOCOLLNPGM(".");
  258. }
  259. }
  260. else { //write
  261. if (!file.open(curDir, fname, O_CREAT | O_APPEND | O_WRITE | O_TRUNC)) {
  262. SERIAL_PROTOCOLPGM(MSG_SD_OPEN_FILE_FAIL);
  263. SERIAL_PROTOCOL(fname);
  264. SERIAL_PROTOCOLLNPGM(".");
  265. }
  266. else {
  267. saving = true;
  268. SERIAL_PROTOCOLPGM(MSG_SD_WRITE_TO_FILE);
  269. SERIAL_PROTOCOLLN(name);
  270. lcd_setstatus(fname);
  271. }
  272. }
  273. }
  274. void CardReader::removeFile(char* name) {
  275. if (!cardOK) return;
  276. file.close();
  277. sdprinting = false;
  278. SdFile myDir;
  279. curDir = &root;
  280. char *fname = name;
  281. char *dirname_start, *dirname_end;
  282. if (name[0] == '/') {
  283. dirname_start = strchr(name, '/') + 1;
  284. while (dirname_start > 0) {
  285. dirname_end = strchr(dirname_start, '/');
  286. //SERIAL_ECHO("start:");SERIAL_ECHOLN((int)(dirname_start - name));
  287. //SERIAL_ECHO("end :");SERIAL_ECHOLN((int)(dirname_end - name));
  288. if (dirname_end > 0 && dirname_end > dirname_start) {
  289. char subdirname[FILENAME_LENGTH];
  290. strncpy(subdirname, dirname_start, dirname_end - dirname_start);
  291. subdirname[dirname_end - dirname_start] = 0;
  292. SERIAL_ECHOLN(subdirname);
  293. if (!myDir.open(curDir, subdirname, O_READ)) {
  294. SERIAL_PROTOCOLPGM("open failed, File: ");
  295. SERIAL_PROTOCOL(subdirname);
  296. SERIAL_PROTOCOLLNPGM(".");
  297. return;
  298. }
  299. else {
  300. //SERIAL_ECHOLN("dive ok");
  301. }
  302. curDir = &myDir;
  303. dirname_start = dirname_end + 1;
  304. }
  305. else { // the remainder after all /fsa/fdsa/ is the filename
  306. fname = dirname_start;
  307. //SERIAL_ECHOLN("remainder");
  308. //SERIAL_ECHOLN(fname);
  309. break;
  310. }
  311. }
  312. }
  313. else { // relative path
  314. curDir = &workDir;
  315. }
  316. if (file.remove(curDir, fname)) {
  317. SERIAL_PROTOCOLPGM("File deleted:");
  318. SERIAL_PROTOCOLLN(fname);
  319. sdpos = 0;
  320. }
  321. else {
  322. SERIAL_PROTOCOLPGM("Deletion failed, File: ");
  323. SERIAL_PROTOCOL(fname);
  324. SERIAL_PROTOCOLLNPGM(".");
  325. }
  326. }
  327. void CardReader::getStatus() {
  328. if (cardOK) {
  329. SERIAL_PROTOCOLPGM(MSG_SD_PRINTING_BYTE);
  330. SERIAL_PROTOCOL(sdpos);
  331. SERIAL_PROTOCOLPGM("/");
  332. SERIAL_PROTOCOLLN(filesize);
  333. }
  334. else {
  335. SERIAL_PROTOCOLLNPGM(MSG_SD_NOT_PRINTING);
  336. }
  337. }
  338. void CardReader::write_command(char *buf) {
  339. char* begin = buf;
  340. char* npos = 0;
  341. char* end = buf + strlen(buf) - 1;
  342. file.writeError = false;
  343. if ((npos = strchr(buf, 'N')) != NULL) {
  344. begin = strchr(npos, ' ') + 1;
  345. end = strchr(npos, '*') - 1;
  346. }
  347. end[1] = '\r';
  348. end[2] = '\n';
  349. end[3] = '\0';
  350. file.write(begin);
  351. if (file.writeError) {
  352. SERIAL_ERROR_START;
  353. SERIAL_ERRORLNPGM(MSG_SD_ERR_WRITE_TO_FILE);
  354. }
  355. }
  356. void CardReader::checkautostart(bool force) {
  357. if (!force && (!autostart_stilltocheck || autostart_atmillis < millis()))
  358. return;
  359. autostart_stilltocheck = false;
  360. if (!cardOK) {
  361. initsd();
  362. if (!cardOK) return; // fail
  363. }
  364. char autoname[30];
  365. sprintf_P(autoname, PSTR("auto%i.g"), autostart_index);
  366. for (int8_t i = 0; i < (int8_t)strlen(autoname); i++) autoname[i] = tolower(autoname[i]);
  367. dir_t p;
  368. root.rewind();
  369. bool found = false;
  370. while (root.readDir(p, NULL) > 0) {
  371. for (int8_t i = 0; i < (int8_t)strlen((char*)p.name); i++) p.name[i] = tolower(p.name[i]);
  372. if (p.name[9] != '~' && strncmp((char*)p.name, autoname, 5) == 0) {
  373. char cmd[30];
  374. sprintf_P(cmd, PSTR("M23 %s"), autoname);
  375. enquecommand(cmd);
  376. enquecommands_P(PSTR("M24"));
  377. found = true;
  378. }
  379. }
  380. if (!found)
  381. autostart_index = -1;
  382. else
  383. autostart_index++;
  384. }
  385. void CardReader::closefile(bool store_location) {
  386. file.sync();
  387. file.close();
  388. saving = logging = false;
  389. if (store_location) {
  390. //future: store printer state, filename and position for continuing a stopped print
  391. // so one can unplug the printer and continue printing the next day.
  392. }
  393. }
  394. /**
  395. * Get the name of a file in the current directory by index
  396. */
  397. void CardReader::getfilename(uint16_t nr, const char * const match/*=NULL*/) {
  398. curDir = &workDir;
  399. lsAction = LS_GetFilename;
  400. nrFiles = nr;
  401. curDir->rewind();
  402. lsDive("", *curDir, match);
  403. }
  404. uint16_t CardReader::getnrfilenames() {
  405. curDir = &workDir;
  406. lsAction = LS_Count;
  407. nrFiles = 0;
  408. curDir->rewind();
  409. lsDive("", *curDir);
  410. //SERIAL_ECHOLN(nrFiles);
  411. return nrFiles;
  412. }
  413. void CardReader::chdir(const char * relpath) {
  414. SdFile newfile;
  415. SdFile *parent = &root;
  416. if (workDir.isOpen()) parent = &workDir;
  417. if (!newfile.open(*parent, relpath, O_READ)) {
  418. SERIAL_ECHO_START;
  419. SERIAL_ECHOPGM(MSG_SD_CANT_ENTER_SUBDIR);
  420. SERIAL_ECHOLN(relpath);
  421. }
  422. else {
  423. if (workDirDepth < MAX_DIR_DEPTH) {
  424. ++workDirDepth;
  425. for (int d = workDirDepth; d--;) workDirParents[d + 1] = workDirParents[d];
  426. workDirParents[0] = *parent;
  427. }
  428. workDir = newfile;
  429. }
  430. }
  431. void CardReader::updir() {
  432. if (workDirDepth > 0) {
  433. --workDirDepth;
  434. workDir = workDirParents[0];
  435. for (uint16_t d = 0; d < workDirDepth; d++)
  436. workDirParents[d] = workDirParents[d+1];
  437. }
  438. }
  439. void CardReader::printingHasFinished() {
  440. st_synchronize();
  441. if (file_subcall_ctr > 0) { // Heading up to a parent file that called current as a procedure.
  442. file.close();
  443. file_subcall_ctr--;
  444. openFile(filenames[file_subcall_ctr], true, true);
  445. setIndex(filespos[file_subcall_ctr]);
  446. startFileprint();
  447. }
  448. else {
  449. file.close();
  450. sdprinting = false;
  451. if (SD_FINISHED_STEPPERRELEASE) {
  452. //finishAndDisableSteppers();
  453. enquecommands_P(PSTR(SD_FINISHED_RELEASECOMMAND));
  454. }
  455. autotempShutdown();
  456. }
  457. }
  458. #endif //SDSUPPORT