From ab965376ff70b3f80b180a47db67ee6dea33d5a6 Mon Sep 17 00:00:00 2001 From: bkubicek Date: Tue, 22 Oct 2013 10:02:18 +0200 Subject: [PATCH] Sub-file calls. by overloading M32 it is now possible to execute gcode files from other gcode files, with a fixed recursion level. This can be used e.g. for having a real start.g and end.g somewhere on the sd card, which are then called from the normal print file. Another usecase would be to have macro-files for nozzle-change and layerchange. I have not tested the speedwise performance. The testing was done with pronterface. syntax: normal call from sd card will open the new file and continue executing there. M32 !/path/filename# this however will call the new file and return to the caller file. M32 P !/path/filename# with the optional "S" the file starting position can be set. this is for continuing prints from a previous location. --- Marlin/Marlin_main.cpp | 43 +++++++++++++++----- Marlin/cardreader.cpp | 89 +++++++++++++++++++++++++++++++++++++----- Marlin/cardreader.h | 9 ++++- 3 files changed, 121 insertions(+), 20 deletions(-) diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index c53a5b583..4bea72b15 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -90,7 +90,10 @@ // M29 - Stop SD write // M30 - Delete file from SD (M30 filename.g) // M31 - Output time since last M109 or SD card start to serial -// M32 - Select file and start SD print (Can be used when printing from SD card) +// M32 - Select file and start SD print (Can be used _while_ printing from SD card files): +// syntax "M32 /path/filename#", or "M32 S !filename#" +// Call gcode file : "M32 P !filename#" and return to caller file after finishing (simiarl to #include). +// The '#' is necessary when calling from within sd files, as it stops buffer prereading // M42 - Change pin status via gcode Use M42 Px Sy to set pin x to value y, when omitting Px the onboard led will be used. // M80 - Turn on Power Supply // M81 - Turn off Power Supply @@ -1467,19 +1470,41 @@ void process_commands() card.removeFile(strchr_pointer + 4); } break; - case 32: //M32 - Select file and start SD print + case 32: //M32 - Select file and start SD print + { if(card.sdprinting) { st_synchronize(); - card.closefile(); - card.sdprinting = false; + } - starpos = (strchr(strchr_pointer + 4,'*')); + starpos = (strchr(strchr_pointer + 4,'*')); + + char* namestartpos = (strchr(strchr_pointer + 4,'!')); //find ! to indicate filename string start. + if(namestartpos==NULL) + { + namestartpos=strchr_pointer + 4; //default name position, 4 letters after the M + } + else + namestartpos++; //to skip the '!' + if(starpos!=NULL) *(starpos-1)='\0'; - card.openFile(strchr_pointer + 4,true); - card.startFileprint(); - starttime=millis(); - break; + + bool call_procedure=(code_seen('P')); + + if(strchr_pointer>namestartpos) + call_procedure=false; //false alert, 'P' found within filename + + if( card.cardOK ) + { + card.openFile(namestartpos,true,!call_procedure); + if(code_seen('S')) + if(strchr_pointer(int)SD_PROCEDURE_DEPTH-1) + { + SERIAL_ERROR_START; + SERIAL_ERRORPGM("trying to call sub-gcode files with too many levels. MAX level is:"); + SERIAL_ERRORLN(SD_PROCEDURE_DEPTH); + kill(); + return; + } + + SERIAL_ECHO_START; + SERIAL_ECHOPGM("SUBROUTINE CALL target:\""); + SERIAL_ECHO(name); + SERIAL_ECHOPGM("\" parent:\""); + + //store current filename and position + getAbsFilename(filenames[file_subcall_ctr]); + + SERIAL_ECHO(filenames[file_subcall_ctr]); + SERIAL_ECHOPGM("\" pos"); + SERIAL_ECHOLN(sdpos); + filespos[file_subcall_ctr]=sdpos; + file_subcall_ctr++; + } + else + { + SERIAL_ECHO_START; + SERIAL_ECHOPGM("Now doing file: "); + SERIAL_ECHOLN(name); + } + file.close(); + } + else //opening fresh file + { + file_subcall_ctr=0; //resetting procedure depth in case user cancels print while in procedure + SERIAL_ECHO_START; + SERIAL_ECHOPGM("Now fresh file: "); + SERIAL_ECHOLN(name); + } sdprinting = false; - + SdFile myDir; curDir=&root; char *fname=name; @@ -547,14 +605,25 @@ void CardReader::updir() void CardReader::printingHasFinished() { st_synchronize(); - quickStop(); - file.close(); - sdprinting = false; - if(SD_FINISHED_STEPPERRELEASE) + if(file_subcall_ctr>0) //heading up to a parent file that called current as a procedure. { - //finishAndDisableSteppers(); - enquecommand_P(PSTR(SD_FINISHED_RELEASECOMMAND)); + file.close(); + file_subcall_ctr--; + openFile(filenames[file_subcall_ctr],true,true); + setIndex(filespos[file_subcall_ctr]); + startFileprint(); + } + else + { + quickStop(); + file.close(); + sdprinting = false; + if(SD_FINISHED_STEPPERRELEASE) + { + //finishAndDisableSteppers(); + enquecommand_P(PSTR(SD_FINISHED_RELEASECOMMAND)); + } + autotempShutdown(); } - autotempShutdown(); } #endif //SDSUPPORT diff --git a/Marlin/cardreader.h b/Marlin/cardreader.h index 6e5964529..07c7090ce 100644 --- a/Marlin/cardreader.h +++ b/Marlin/cardreader.h @@ -18,7 +18,7 @@ public: //this is to delay autostart and hence the initialisaiton of the sd card to some seconds after the normal init, so the device is available quick after a reset void checkautostart(bool x); - void openFile(char* name,bool read); + void openFile(char* name,bool read,bool replace_current=true); void openLogFile(char* name); void removeFile(char* name); void closefile(); @@ -31,6 +31,8 @@ public: void getfilename(const uint8_t nr); uint16_t getnrfilenames(); + void getAbsFilename(char *t); + void ls(); void chdir(const char * relpath); @@ -60,6 +62,11 @@ private: Sd2Card card; SdVolume volume; SdFile file; + #define SD_PROCEDURE_DEPTH 1 + #define MAXPATHNAMELENGTH (13*MAX_DIR_DEPTH+MAX_DIR_DEPTH+1) + uint8_t file_subcall_ctr; + uint32_t filespos[SD_PROCEDURE_DEPTH]; + char filenames[SD_PROCEDURE_DEPTH][MAXPATHNAMELENGTH]; uint32_t filesize; //int16_t n; unsigned long autostart_atmillis;