cardreader.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686
  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. {
  10. filesize = 0;
  11. sdpos = 0;
  12. sdprinting = false;
  13. cardOK = false;
  14. saving = false;
  15. logging = false;
  16. autostart_atmillis=0;
  17. workDirDepth = 0;
  18. file_subcall_ctr=0;
  19. memset(workDirParents, 0, sizeof(workDirParents));
  20. autostart_stilltocheck=true; //the sd start is delayed, because otherwise the serial cannot answer fast enought to make contact with the hostsoftware.
  21. lastnr=0;
  22. //power to SD reader
  23. #if SDPOWER > -1
  24. SET_OUTPUT(SDPOWER);
  25. WRITE(SDPOWER,HIGH);
  26. #endif //SDPOWER
  27. autostart_atmillis=millis()+5000;
  28. }
  29. char *createFilename(char *buffer,const dir_t &p) //buffer>12characters
  30. {
  31. char *pos=buffer;
  32. for (uint8_t i = 0; i < 11; i++)
  33. {
  34. if (p.name[i] == ' ')continue;
  35. if (i == 8)
  36. {
  37. *pos++='.';
  38. }
  39. *pos++=p.name[i];
  40. }
  41. *pos++=0;
  42. return buffer;
  43. }
  44. void CardReader::lsDive(const char *prepend,SdFile parent)
  45. {
  46. dir_t p;
  47. uint8_t cnt=0;
  48. while (parent.readDir(p, longFilename) > 0)
  49. {
  50. if( DIR_IS_SUBDIR(&p) && lsAction!=LS_Count && lsAction!=LS_GetFilename) // hence LS_SerialPrint
  51. {
  52. char path[13*2];
  53. char lfilename[13];
  54. createFilename(lfilename,p);
  55. path[0]=0;
  56. if(strlen(prepend)==0) //avoid leading / if already in prepend
  57. {
  58. strcat(path,"/");
  59. }
  60. strcat(path,prepend);
  61. strcat(path,lfilename);
  62. strcat(path,"/");
  63. //Serial.print(path);
  64. SdFile dir;
  65. if(!dir.open(parent,lfilename, O_READ))
  66. {
  67. if(lsAction==LS_SerialPrint)
  68. {
  69. SERIAL_ECHO_START;
  70. SERIAL_ECHOLN(MSG_SD_CANT_OPEN_SUBDIR);
  71. SERIAL_ECHOLN(lfilename);
  72. }
  73. }
  74. lsDive(path,dir);
  75. //close done automatically by destructor of SdFile
  76. }
  77. else
  78. {
  79. if (p.name[0] == DIR_NAME_FREE) break;
  80. if (p.name[0] == DIR_NAME_DELETED || p.name[0] == '.'|| p.name[0] == '_') continue;
  81. if (longFilename[0] != '\0' &&
  82. (longFilename[0] == '.' || longFilename[0] == '_')) continue;
  83. if ( p.name[0] == '.')
  84. {
  85. if ( p.name[1] != '.')
  86. continue;
  87. }
  88. if (!DIR_IS_FILE_OR_SUBDIR(&p)) continue;
  89. filenameIsDir=DIR_IS_SUBDIR(&p);
  90. if(!filenameIsDir)
  91. {
  92. if(p.name[8]!='G') continue;
  93. if(p.name[9]=='~') continue;
  94. }
  95. //if(cnt++!=nr) continue;
  96. createFilename(filename,p);
  97. if(lsAction==LS_SerialPrint)
  98. {
  99. SERIAL_PROTOCOL(prepend);
  100. SERIAL_PROTOCOLLN(filename);
  101. }
  102. else if(lsAction==LS_Count)
  103. {
  104. nrFiles++;
  105. }
  106. else if(lsAction==LS_GetFilename)
  107. {
  108. if(cnt==nrFiles)
  109. return;
  110. cnt++;
  111. }
  112. }
  113. }
  114. }
  115. void CardReader::ls()
  116. {
  117. lsAction=LS_SerialPrint;
  118. if(lsAction==LS_Count)
  119. nrFiles=0;
  120. root.rewind();
  121. lsDive("",root);
  122. }
  123. void CardReader::initsd()
  124. {
  125. cardOK = false;
  126. if(root.isOpen())
  127. root.close();
  128. #ifdef SDSLOW
  129. if (!card.init(SPI_HALF_SPEED,SDSS))
  130. #else
  131. if (!card.init(SPI_FULL_SPEED,SDSS))
  132. #endif
  133. {
  134. //if (!card.init(SPI_HALF_SPEED,SDSS))
  135. SERIAL_ECHO_START;
  136. SERIAL_ECHOLNPGM(MSG_SD_INIT_FAIL);
  137. }
  138. else if (!volume.init(&card))
  139. {
  140. SERIAL_ERROR_START;
  141. SERIAL_ERRORLNPGM(MSG_SD_VOL_INIT_FAIL);
  142. }
  143. else if (!root.openRoot(&volume))
  144. {
  145. SERIAL_ERROR_START;
  146. SERIAL_ERRORLNPGM(MSG_SD_OPENROOT_FAIL);
  147. }
  148. else
  149. {
  150. cardOK = true;
  151. SERIAL_ECHO_START;
  152. SERIAL_ECHOLNPGM(MSG_SD_CARD_OK);
  153. }
  154. workDir=root;
  155. curDir=&root;
  156. /*
  157. if(!workDir.openRoot(&volume))
  158. {
  159. SERIAL_ECHOLNPGM(MSG_SD_WORKDIR_FAIL);
  160. }
  161. */
  162. }
  163. void CardReader::setroot()
  164. {
  165. /*if(!workDir.openRoot(&volume))
  166. {
  167. SERIAL_ECHOLNPGM(MSG_SD_WORKDIR_FAIL);
  168. }*/
  169. workDir=root;
  170. curDir=&workDir;
  171. }
  172. void CardReader::release()
  173. {
  174. sdprinting = false;
  175. cardOK = false;
  176. }
  177. void CardReader::startFileprint()
  178. {
  179. if(cardOK)
  180. {
  181. sdprinting = true;
  182. }
  183. }
  184. void CardReader::pauseSDPrint()
  185. {
  186. if(sdprinting)
  187. {
  188. sdprinting = false;
  189. }
  190. }
  191. void CardReader::openLogFile(char* name)
  192. {
  193. logging = true;
  194. openFile(name, false);
  195. }
  196. #if defined(SDSUPPORT) && defined(POWEROFF_SAVE_SD_FILE)
  197. void CardReader::openPowerOffFile(char* name, uint8_t oflag) {
  198. if (!cardOK) return;
  199. if (powerOffFile.isOpen()) return;
  200. if (!powerOffFile.open(&root, name, oflag)) {
  201. SERIAL_PROTOCOLPGM(MSG_SD_OPEN_FILE_FAIL);
  202. SERIAL_PROTOCOL(name);
  203. SERIAL_PROTOCOLPGM(".\n");
  204. }
  205. else {
  206. SERIAL_PROTOCOLPGM(MSG_SD_WRITE_TO_FILE);
  207. SERIAL_PROTOCOLLN(name);
  208. }
  209. }
  210. void CardReader::closePowerOffFile() {
  211. powerOffFile.close();
  212. }
  213. bool CardReader::existPowerOffFile(char* name) {
  214. bool ret = powerOffFile.open(&root, name, O_READ);
  215. return ret;
  216. }
  217. int16_t CardReader::savePowerOffInfo(const void* data, uint16_t size) {
  218. powerOffFile.seekSet(0);
  219. return powerOffFile.write(data, size);
  220. }
  221. int16_t CardReader::getPowerOffInfo(void* data, uint16_t size) {
  222. return powerOffFile.read(data, size);
  223. }
  224. void CardReader::removePowerOffFile() {
  225. if (powerOffFile.remove(&root, power_off_info.power_off_filename)) {
  226. SERIAL_PROTOCOLPGM("File(bin) deleted");
  227. }
  228. else {
  229. SERIAL_PROTOCOLPGM("Deletion(bin) failed");
  230. }
  231. SERIAL_PROTOCOLPGM(".\n");
  232. }
  233. #endif
  234. void CardReader::getAbsFilename(char *t)
  235. {
  236. uint8_t cnt=0;
  237. *t='/';t++;cnt++;
  238. for(uint8_t i=0;i<workDirDepth;i++)
  239. {
  240. workDirParents[i].getFilename(t); //SDBaseFile.getfilename!
  241. while(*t!=0 && cnt< MAXPATHNAMELENGTH)
  242. {t++;cnt++;} //crawl counter forward.
  243. }
  244. if(cnt<MAXPATHNAMELENGTH-13)
  245. file.getFilename(t);
  246. else
  247. t[0]=0;
  248. }
  249. void CardReader::openFile(char* name,bool read, bool replace_current/*=true*/)
  250. {
  251. if(!cardOK)
  252. return;
  253. if(file.isOpen()) //replaceing current file by new file, or subfile call
  254. {
  255. if(!replace_current)
  256. {
  257. if((int)file_subcall_ctr>(int)SD_PROCEDURE_DEPTH-1)
  258. {
  259. SERIAL_ERROR_START;
  260. SERIAL_ERRORPGM("trying to call sub-gcode files with too many levels. MAX level is:");
  261. SERIAL_ERRORLN(SD_PROCEDURE_DEPTH);
  262. kill();
  263. return;
  264. }
  265. SERIAL_ECHO_START;
  266. SERIAL_ECHOPGM("SUBROUTINE CALL target:\"");
  267. SERIAL_ECHO(name);
  268. SERIAL_ECHOPGM("\" parent:\"");
  269. //store current filename and position
  270. getAbsFilename(filenames[file_subcall_ctr]);
  271. SERIAL_ECHO(filenames[file_subcall_ctr]);
  272. SERIAL_ECHOPGM("\" pos");
  273. SERIAL_ECHOLN(sdpos);
  274. filespos[file_subcall_ctr]=sdpos;
  275. file_subcall_ctr++;
  276. }
  277. else
  278. {
  279. SERIAL_ECHO_START;
  280. SERIAL_ECHOPGM("Now doing file: ");
  281. SERIAL_ECHOLN(name);
  282. }
  283. file.close();
  284. }
  285. else //opening fresh file
  286. {
  287. file_subcall_ctr=0; //resetting procedure depth in case user cancels print while in procedure
  288. SERIAL_ECHO_START;
  289. SERIAL_ECHOPGM("Now fresh file: ");
  290. SERIAL_ECHOLN(name);
  291. }
  292. sdprinting = false;
  293. SdFile myDir;
  294. curDir=&root;
  295. char *fname=name;
  296. char *dirname_start,*dirname_end;
  297. if(name[0]=='/')
  298. {
  299. dirname_start=strchr(name,'/')+1;
  300. while(dirname_start>0)
  301. {
  302. dirname_end=strchr(dirname_start,'/');
  303. //SERIAL_ECHO("start:");SERIAL_ECHOLN((int)(dirname_start-name));
  304. //SERIAL_ECHO("end :");SERIAL_ECHOLN((int)(dirname_end-name));
  305. if(dirname_end>0 && dirname_end>dirname_start)
  306. {
  307. char subdirname[13];
  308. strncpy(subdirname, dirname_start, dirname_end-dirname_start);
  309. subdirname[dirname_end-dirname_start]=0;
  310. SERIAL_ECHOLN(subdirname);
  311. if(!myDir.open(curDir,subdirname,O_READ))
  312. {
  313. SERIAL_PROTOCOLPGM(MSG_SD_OPEN_FILE_FAIL);
  314. SERIAL_PROTOCOL(subdirname);
  315. SERIAL_PROTOCOLLNPGM(".");
  316. return;
  317. }
  318. else
  319. {
  320. //SERIAL_ECHOLN("dive ok");
  321. }
  322. curDir=&myDir;
  323. dirname_start=dirname_end+1;
  324. }
  325. else // the reminder after all /fsa/fdsa/ is the filename
  326. {
  327. fname=dirname_start;
  328. //SERIAL_ECHOLN("remaider");
  329. //SERIAL_ECHOLN(fname);
  330. break;
  331. }
  332. }
  333. }
  334. else //relative path
  335. {
  336. curDir=&workDir;
  337. }
  338. if(read)
  339. {
  340. if (file.open(curDir, fname, O_READ))
  341. {
  342. filesize = file.fileSize();
  343. SERIAL_PROTOCOLPGM(MSG_SD_FILE_OPENED);
  344. SERIAL_PROTOCOL(fname);
  345. SERIAL_PROTOCOLPGM(MSG_SD_SIZE);
  346. SERIAL_PROTOCOLLN(filesize);
  347. sdpos = 0;
  348. SERIAL_PROTOCOLLNPGM(MSG_SD_FILE_SELECTED);
  349. lcd_setstatus(fname);
  350. }
  351. else
  352. {
  353. SERIAL_PROTOCOLPGM(MSG_SD_OPEN_FILE_FAIL);
  354. SERIAL_PROTOCOL(fname);
  355. SERIAL_PROTOCOLLNPGM(".");
  356. }
  357. }
  358. else
  359. { //write
  360. if (!file.open(curDir, fname, O_CREAT | O_APPEND | O_WRITE | O_TRUNC))
  361. {
  362. SERIAL_PROTOCOLPGM(MSG_SD_OPEN_FILE_FAIL);
  363. SERIAL_PROTOCOL(fname);
  364. SERIAL_PROTOCOLLNPGM(".");
  365. }
  366. else
  367. {
  368. saving = true;
  369. SERIAL_PROTOCOLPGM(MSG_SD_WRITE_TO_FILE);
  370. SERIAL_PROTOCOLLN(name);
  371. lcd_setstatus(fname);
  372. }
  373. }
  374. }
  375. void CardReader::removeFile(char* name)
  376. {
  377. if(!cardOK)
  378. return;
  379. file.close();
  380. sdprinting = false;
  381. SdFile myDir;
  382. curDir=&root;
  383. char *fname=name;
  384. char *dirname_start,*dirname_end;
  385. if(name[0]=='/')
  386. {
  387. dirname_start=strchr(name,'/')+1;
  388. while(dirname_start>0)
  389. {
  390. dirname_end=strchr(dirname_start,'/');
  391. //SERIAL_ECHO("start:");SERIAL_ECHOLN((int)(dirname_start-name));
  392. //SERIAL_ECHO("end :");SERIAL_ECHOLN((int)(dirname_end-name));
  393. if(dirname_end>0 && dirname_end>dirname_start)
  394. {
  395. char subdirname[13];
  396. strncpy(subdirname, dirname_start, dirname_end-dirname_start);
  397. subdirname[dirname_end-dirname_start]=0;
  398. SERIAL_ECHOLN(subdirname);
  399. if(!myDir.open(curDir,subdirname,O_READ))
  400. {
  401. SERIAL_PROTOCOLPGM("open failed, File: ");
  402. SERIAL_PROTOCOL(subdirname);
  403. SERIAL_PROTOCOLLNPGM(".");
  404. return;
  405. }
  406. else
  407. {
  408. //SERIAL_ECHOLN("dive ok");
  409. }
  410. curDir=&myDir;
  411. dirname_start=dirname_end+1;
  412. }
  413. else // the reminder after all /fsa/fdsa/ is the filename
  414. {
  415. fname=dirname_start;
  416. //SERIAL_ECHOLN("remaider");
  417. //SERIAL_ECHOLN(fname);
  418. break;
  419. }
  420. }
  421. }
  422. else //relative path
  423. {
  424. curDir=&workDir;
  425. }
  426. if (file.remove(curDir, fname))
  427. {
  428. SERIAL_PROTOCOLPGM("File deleted:");
  429. SERIAL_PROTOCOL(fname);
  430. sdpos = 0;
  431. }
  432. else
  433. {
  434. SERIAL_PROTOCOLPGM("Deletion failed, File: ");
  435. SERIAL_PROTOCOL(fname);
  436. SERIAL_PROTOCOLLNPGM(".");
  437. }
  438. }
  439. void CardReader::getStatus()
  440. {
  441. if(cardOK){
  442. SERIAL_PROTOCOLPGM(MSG_SD_PRINTING_BYTE);
  443. SERIAL_PROTOCOL(sdpos);
  444. SERIAL_PROTOCOLPGM("/");
  445. SERIAL_PROTOCOLLN(filesize);
  446. }
  447. else{
  448. SERIAL_PROTOCOLLNPGM(MSG_SD_NOT_PRINTING);
  449. }
  450. }
  451. void CardReader::write_command(char *buf)
  452. {
  453. char* begin = buf;
  454. char* npos = 0;
  455. char* end = buf + strlen(buf) - 1;
  456. file.writeError = false;
  457. if((npos = strchr(buf, 'N')) != NULL)
  458. {
  459. begin = strchr(npos, ' ') + 1;
  460. end = strchr(npos, '*') - 1;
  461. }
  462. end[1] = '\r';
  463. end[2] = '\n';
  464. end[3] = '\0';
  465. file.write(begin);
  466. if (file.writeError)
  467. {
  468. SERIAL_ERROR_START;
  469. SERIAL_ERRORLNPGM(MSG_SD_ERR_WRITE_TO_FILE);
  470. }
  471. }
  472. void CardReader::checkautostart(bool force)
  473. {
  474. if(!force)
  475. {
  476. if(!autostart_stilltocheck)
  477. return;
  478. if(autostart_atmillis<millis())
  479. return;
  480. }
  481. autostart_stilltocheck=false;
  482. if(!cardOK)
  483. {
  484. initsd();
  485. if(!cardOK) //fail
  486. return;
  487. }
  488. char autoname[30];
  489. sprintf_P(autoname, PSTR("auto%i.g"), lastnr);
  490. for(int8_t i=0;i<(int8_t)strlen(autoname);i++)
  491. autoname[i]=tolower(autoname[i]);
  492. dir_t p;
  493. root.rewind();
  494. bool found=false;
  495. while (root.readDir(p, NULL) > 0)
  496. {
  497. for(int8_t i=0;i<(int8_t)strlen((char*)p.name);i++)
  498. p.name[i]=tolower(p.name[i]);
  499. //Serial.print((char*)p.name);
  500. //Serial.print(" ");
  501. //Serial.println(autoname);
  502. if(p.name[9]!='~') //skip safety copies
  503. if(strncmp((char*)p.name,autoname,5)==0)
  504. {
  505. char cmd[30];
  506. sprintf_P(cmd, PSTR("M23 %s"), autoname);
  507. enqueuecommand(cmd);
  508. enqueuecommands_P(PSTR("M24"));
  509. found=true;
  510. }
  511. }
  512. if(!found)
  513. lastnr=-1;
  514. else
  515. lastnr++;
  516. }
  517. void CardReader::closefile(bool store_location)
  518. {
  519. file.sync();
  520. file.close();
  521. saving = false;
  522. logging = false;
  523. if(store_location)
  524. {
  525. //future: store printer state, filename and position for continueing a stoped print
  526. // so one can unplug the printer and continue printing the next day.
  527. }
  528. }
  529. void CardReader::getfilename(const uint8_t nr)
  530. {
  531. curDir=&workDir;
  532. lsAction=LS_GetFilename;
  533. nrFiles=nr;
  534. curDir->rewind();
  535. lsDive("",*curDir);
  536. }
  537. uint16_t CardReader::getnrfilenames()
  538. {
  539. curDir=&workDir;
  540. lsAction=LS_Count;
  541. nrFiles=0;
  542. curDir->rewind();
  543. lsDive("",*curDir);
  544. //SERIAL_ECHOLN(nrFiles);
  545. return nrFiles;
  546. }
  547. void CardReader::chdir(const char * relpath)
  548. {
  549. SdFile newfile;
  550. SdFile *parent=&root;
  551. if(workDir.isOpen())
  552. parent=&workDir;
  553. if(!newfile.open(*parent,relpath, O_READ))
  554. {
  555. SERIAL_ECHO_START;
  556. SERIAL_ECHOPGM(MSG_SD_CANT_ENTER_SUBDIR);
  557. SERIAL_ECHOLN(relpath);
  558. }
  559. else
  560. {
  561. if (workDirDepth < MAX_DIR_DEPTH) {
  562. for (int d = ++workDirDepth; d--;)
  563. workDirParents[d+1] = workDirParents[d];
  564. workDirParents[0]=*parent;
  565. }
  566. workDir=newfile;
  567. }
  568. }
  569. void CardReader::updir()
  570. {
  571. if(workDirDepth > 0)
  572. {
  573. --workDirDepth;
  574. workDir = workDirParents[0];
  575. int d;
  576. for (int d = 0; d < workDirDepth; d++)
  577. workDirParents[d] = workDirParents[d+1];
  578. }
  579. }
  580. void CardReader::printingHasFinished()
  581. {
  582. st_synchronize();
  583. if(file_subcall_ctr>0) //heading up to a parent file that called current as a procedure.
  584. {
  585. file.close();
  586. file_subcall_ctr--;
  587. openFile(filenames[file_subcall_ctr],true,true);
  588. setIndex(filespos[file_subcall_ctr]);
  589. startFileprint();
  590. }
  591. else
  592. {
  593. quickStop();
  594. file.close();
  595. sdprinting = false;
  596. #if defined(SDSUPPORT) && defined(POWEROFF_SAVE_SD_FILE)
  597. openPowerOffFile(power_off_info.power_off_filename, O_CREAT | O_WRITE | O_TRUNC | O_SYNC);
  598. power_off_info.valid_head = 0;
  599. power_off_info.valid_foot = 0;
  600. if (savePowerOffInfo(&power_off_info, sizeof(power_off_info)) == -1){
  601. SERIAL_PROTOCOLLN("Stop to Write power off file failed.");
  602. }
  603. power_off_commands_count = 0;
  604. closePowerOffFile();
  605. #endif
  606. if(SD_FINISHED_STEPPERRELEASE)
  607. {
  608. //finishAndDisableSteppers();
  609. enqueuecommands_P(PSTR(SD_FINISHED_RELEASECOMMAND));
  610. }
  611. autotempShutdown();
  612. }
  613. }
  614. #endif //SDSUPPORT