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