Sat, 07 Nov 2015 13:23:07 +0100
Initial code from reprappro Marlin repository
0 | 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 |