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<position>" the  file starting position can be set.
this is for continuing prints from a previous location.
This commit is contained in:
bkubicek 2013-10-22 10:02:18 +02:00
parent b2cc27e5ea
commit ab965376ff
3 changed files with 121 additions and 20 deletions

View File

@ -90,7 +90,10 @@
// M29 - Stop SD write // M29 - Stop SD write
// M30 - Delete file from SD (M30 filename.g) // M30 - Delete file from SD (M30 filename.g)
// M31 - Output time since last M109 or SD card start to serial // 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<startpos bytes> !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. // 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 // M80 - Turn on Power Supply
// M81 - Turn off Power Supply // M81 - Turn off Power Supply
@ -1468,18 +1471,40 @@ void process_commands()
} }
break; break;
case 32: //M32 - Select file and start SD print case 32: //M32 - Select file and start SD print
{
if(card.sdprinting) { if(card.sdprinting) {
st_synchronize(); 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) if(starpos!=NULL)
*(starpos-1)='\0'; *(starpos-1)='\0';
card.openFile(strchr_pointer + 4,true);
card.startFileprint(); bool call_procedure=(code_seen('P'));
starttime=millis();
break; 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<namestartpos) //only if "S" is occuring _before_ the filename
card.setIndex(code_value_long());
card.startFileprint();
if(!call_procedure)
starttime=millis(); //procedure calls count as normal print time.
}
} break;
case 928: //M928 - Start SD write case 928: //M928 - Start SD write
starpos = (strchr(strchr_pointer + 5,'*')); starpos = (strchr(strchr_pointer + 5,'*'));
if(starpos != NULL){ if(starpos != NULL){

View File

@ -19,6 +19,7 @@ CardReader::CardReader()
logging = false; logging = false;
autostart_atmillis=0; autostart_atmillis=0;
workDirDepth = 0; workDirDepth = 0;
file_subcall_ctr=0;
memset(workDirParents, 0, sizeof(workDirParents)); memset(workDirParents, 0, sizeof(workDirParents));
autostart_stilltocheck=true; //the sd start is delayed, because otherwise the serial cannot answer fast enought to make contact with the hostsoftware. autostart_stilltocheck=true; //the sd start is delayed, because otherwise the serial cannot answer fast enought to make contact with the hostsoftware.
@ -224,11 +225,68 @@ void CardReader::openLogFile(char* name)
openFile(name, false); openFile(name, false);
} }
void CardReader::openFile(char* name,bool read) void CardReader::getAbsFilename(char *t)
{
uint8_t cnt=0;
*t='/';t++;cnt++;
for(uint8_t i=0;i<workDirDepth;i++)
{
workDirParents[i].getFilename(t); //SDBaseFile.getfilename!
while(*t!=0 && cnt< MAXPATHNAMELENGTH)
{t++;cnt++;} //crawl counter forward.
}
if(cnt<MAXPATHNAMELENGTH-13)
file.getFilename(t);
else
t[0]=0;
}
void CardReader::openFile(char* name,bool read, bool replace_current/*=true*/)
{ {
if(!cardOK) if(!cardOK)
return; return;
file.close(); if(file.isOpen()) //replaceing current file by new file, or subfile call
{
if(!replace_current)
{
if((int)file_subcall_ctr>(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; sdprinting = false;
@ -547,14 +605,25 @@ void CardReader::updir()
void CardReader::printingHasFinished() void CardReader::printingHasFinished()
{ {
st_synchronize(); st_synchronize();
quickStop(); if(file_subcall_ctr>0) //heading up to a parent file that called current as a procedure.
file.close();
sdprinting = false;
if(SD_FINISHED_STEPPERRELEASE)
{ {
//finishAndDisableSteppers(); file.close();
enquecommand_P(PSTR(SD_FINISHED_RELEASECOMMAND)); 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 #endif //SDSUPPORT

View File

@ -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 //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 checkautostart(bool x);
void openFile(char* name,bool read); void openFile(char* name,bool read,bool replace_current=true);
void openLogFile(char* name); void openLogFile(char* name);
void removeFile(char* name); void removeFile(char* name);
void closefile(); void closefile();
@ -31,6 +31,8 @@ public:
void getfilename(const uint8_t nr); void getfilename(const uint8_t nr);
uint16_t getnrfilenames(); uint16_t getnrfilenames();
void getAbsFilename(char *t);
void ls(); void ls();
void chdir(const char * relpath); void chdir(const char * relpath);
@ -60,6 +62,11 @@ private:
Sd2Card card; Sd2Card card;
SdVolume volume; SdVolume volume;
SdFile file; 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; uint32_t filesize;
//int16_t n; //int16_t n;
unsigned long autostart_atmillis; unsigned long autostart_atmillis;