cardreader.cpp

changeset 0
2c8ba1964db7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cardreader.cpp	Sat Nov 07 13:23:07 2015 +0100
@@ -0,0 +1,633 @@
+#include "Marlin.h"
+#include "cardreader.h"
+#include "ultralcd.h"
+#include "stepper.h"
+#include "temperature.h"
+#include "language.h"
+
+#ifdef SDSUPPORT
+
+
+
+CardReader::CardReader()
+{
+   filesize = 0;
+   sdpos = 0;
+   sdprinting = false;
+   cardOK = false;
+   saving = false;
+   autostart_atmillis=0;
+
+   autostart_stilltocheck=true; //the sd start is delayed, because otherwise the serial cannot answer fast enought to make contact with the hostsoftware.
+   lastnr=0;
+  //power to SD reader
+  #if SDPOWER > -1
+    SET_OUTPUT(SDPOWER); 
+    WRITE(SDPOWER,HIGH);
+  #endif //SDPOWER
+  
+  autostart_atmillis=millis()+5000;
+}
+
+char *createFilename(char *buffer,const dir_t &p) //buffer>12characters
+{
+  char *pos=buffer;
+  for (uint8_t i = 0; i < 11; i++) 
+  {
+    if (p.name[i] == ' ')continue;
+    if (i == 8) 
+    {
+      *pos++='.';
+    }
+    *pos++=p.name[i];
+  }
+  *pos++=0;
+  return buffer;
+}
+
+
+void  CardReader::lsDive(const char *prepend,SdFile parent)
+{
+  dir_t p;
+ uint8_t cnt=0;
+ 
+  while (parent.readDir(p) > 0)
+  {
+    if( DIR_IS_SUBDIR(&p) && lsAction!=LS_Count && lsAction!=LS_GetFilename) // hence LS_SerialPrint
+    {
+
+      char path[13*2];
+      char lfilename[13];
+      createFilename(lfilename,p);
+      
+      path[0]=0;
+      if(strlen(prepend)==0) //avoid leading / if already in prepend
+      {
+       strcat(path,"/");
+      }
+      strcat(path,prepend);
+      strcat(path,lfilename);
+      strcat(path,"/");
+      
+      //Serial.print(path);
+      
+      SdFile dir;
+      if(!dir.open(parent,lfilename, O_READ))
+      {
+        if(lsAction==LS_SerialPrint)
+        {
+          SERIAL_ECHO_START;
+          SERIAL_ECHOLN(MSG_SD_CANT_OPEN_SUBDIR);
+          SERIAL_ECHOLN(lfilename);
+        }
+      }
+      lsDive(path,dir);
+      //close done automatically by destructor of SdFile
+
+      
+    }
+    else
+    {
+      if (p.name[0] == DIR_NAME_FREE) break;
+      if (p.name[0] == DIR_NAME_DELETED || p.name[0] == '.'|| p.name[0] == '_') continue;
+      if ( p.name[0] == '.')
+      {
+        if ( p.name[1] != '.')
+        continue;
+      }
+      
+      if (!DIR_IS_FILE_OR_SUBDIR(&p)) continue;
+      filenameIsDir=DIR_IS_SUBDIR(&p);
+      
+      
+      if(!filenameIsDir)
+      {
+        if(p.name[8]!='G') continue;
+        if(p.name[9]=='~') continue;
+      }
+      //if(cnt++!=nr) continue;
+      createFilename(filename,p);
+      if(lsAction==LS_SerialPrint)
+      {
+        SERIAL_PROTOCOL(prepend);
+        SERIAL_PROTOCOLLN(filename);
+      }
+      else if(lsAction==LS_Count)
+      {
+        nrFiles++;
+      } 
+      else if(lsAction==LS_GetFilename)
+      {
+        if(cnt==nrFiles)
+          return;
+        cnt++;
+        
+      }
+    }
+  }
+}
+
+void CardReader::ls() 
+{
+  lsAction=LS_SerialPrint;
+  if(lsAction==LS_Count)
+  nrFiles=0;
+
+  root.rewind();
+  lsDive("",root);
+}
+
+
+void CardReader::initsd()
+{
+  cardOK = false;
+  if(root.isOpen())
+    root.close();
+  if (!card.init(SPI_FULL_SPEED,SDSS))
+  {
+    //if (!card.init(SPI_HALF_SPEED,SDSS))
+    SERIAL_ECHO_START;
+    SERIAL_ECHOLNPGM(MSG_SD_INIT_FAIL);
+  }
+  else if (!volume.init(&card))
+  {
+    SERIAL_ERROR_START;
+    SERIAL_ERRORLNPGM(MSG_SD_VOL_INIT_FAIL);
+  }
+  else if (!root.openRoot(&volume)) 
+  {
+    SERIAL_ERROR_START;
+    SERIAL_ERRORLNPGM(MSG_SD_OPENROOT_FAIL);
+  }
+  else 
+  {
+    cardOK = true;
+    SERIAL_ECHO_START;
+    SERIAL_ECHOLNPGM(MSG_SD_CARD_OK);
+  }
+  workDir=root;
+  curDir=&root;
+  /*
+  if(!workDir.openRoot(&volume))
+  {
+    SERIAL_ECHOLNPGM(MSG_SD_WORKDIR_FAIL);
+  }
+  */
+  
+}
+
+void CardReader::setroot()
+{
+  /*if(!workDir.openRoot(&volume))
+  {
+    SERIAL_ECHOLNPGM(MSG_SD_WORKDIR_FAIL);
+  }*/
+  workDir=root;
+  
+  curDir=&workDir;
+}
+void CardReader::release()
+{
+  sdprinting = false;
+  cardOK = false;
+}
+
+void CardReader::startFileprint()
+{
+  if(cardOK)
+  {
+    sdprinting = true;
+    
+  }
+}
+
+void CardReader::pauseSDPrint()
+{
+  if(sdprinting)
+  {
+    sdprinting = false;
+  }
+}
+
+
+
+void CardReader::openFile(char* name,bool read)
+{
+  if(!cardOK)
+    return;
+  file.close();
+  sdprinting = false;
+  
+  
+  SdFile myDir;
+  curDir=&root;
+  char *fname=name;
+  
+  char *dirname_start,*dirname_end;
+  if(name[0]=='/')
+  {
+    dirname_start=strchr(name,'/')+1;
+    while(dirname_start>0)
+    {
+      dirname_end=strchr(dirname_start,'/');
+      //SERIAL_ECHO("start:");SERIAL_ECHOLN((int)(dirname_start-name));
+      //SERIAL_ECHO("end  :");SERIAL_ECHOLN((int)(dirname_end-name));
+      if(dirname_end>0 && dirname_end>dirname_start)
+      {
+        char subdirname[13];
+        strncpy(subdirname, dirname_start, dirname_end-dirname_start);
+        subdirname[dirname_end-dirname_start]=0;
+        SERIAL_ECHOLN(subdirname);
+        if(!myDir.open(curDir,subdirname,O_READ))
+        {
+          SERIAL_PROTOCOLPGM(MSG_SD_OPEN_FILE_FAIL);
+          SERIAL_PROTOCOL(subdirname);
+          SERIAL_PROTOCOLLNPGM(".");
+          return;
+        }
+        else
+          ;//SERIAL_ECHOLN("dive ok");
+          
+        curDir=&myDir; 
+        dirname_start=dirname_end+1;
+      }
+      else // the reminder after all /fsa/fdsa/ is the filename
+      {
+        fname=dirname_start;
+        //SERIAL_ECHOLN("remaider");
+        //SERIAL_ECHOLN(fname);
+        break;
+      }
+      
+    }
+  }
+  else //relative path
+  {
+    curDir=&workDir;
+  }
+  if(read)
+  {
+    if (file.open(curDir, fname, O_READ)) 
+    {
+      filesize = file.fileSize();
+      SERIAL_PROTOCOLPGM(MSG_SD_FILE_OPENED);
+      SERIAL_PROTOCOL(fname);
+      SERIAL_PROTOCOLPGM(MSG_SD_SIZE);
+      SERIAL_PROTOCOLLN(filesize);
+      sdpos = 0;
+      
+      SERIAL_PROTOCOLLNPGM(MSG_SD_FILE_SELECTED);
+      LCD_MESSAGE(fname);
+    }
+    else
+    {
+      SERIAL_PROTOCOLPGM(MSG_SD_OPEN_FILE_FAIL);
+      SERIAL_PROTOCOL(fname);
+      SERIAL_PROTOCOLLNPGM(".");
+    }
+  }
+  else 
+  { //write
+    if (!file.open(curDir, fname, O_CREAT | O_APPEND | O_WRITE | O_TRUNC))
+    {
+      SERIAL_PROTOCOLPGM(MSG_SD_OPEN_FILE_FAIL);
+      SERIAL_PROTOCOL(fname);
+      SERIAL_PROTOCOLLNPGM(".");
+    }
+    else
+    {
+      saving = true;
+      SERIAL_PROTOCOLPGM(MSG_SD_WRITE_TO_FILE);
+      SERIAL_PROTOCOLLN(name);
+      LCD_MESSAGE(fname);
+    }
+  }
+  
+}
+
+void CardReader::removeFile(char* name)
+{
+  if(!cardOK)
+    return;
+  file.close();
+  sdprinting = false;
+  
+  
+  SdFile myDir;
+  curDir=&root;
+  char *fname=name;
+  
+  char *dirname_start,*dirname_end;
+  if(name[0]=='/')
+  {
+    dirname_start=strchr(name,'/')+1;
+    while(dirname_start>0)
+    {
+      dirname_end=strchr(dirname_start,'/');
+      //SERIAL_ECHO("start:");SERIAL_ECHOLN((int)(dirname_start-name));
+      //SERIAL_ECHO("end  :");SERIAL_ECHOLN((int)(dirname_end-name));
+      if(dirname_end>0 && dirname_end>dirname_start)
+      {
+        char subdirname[13];
+        strncpy(subdirname, dirname_start, dirname_end-dirname_start);
+        subdirname[dirname_end-dirname_start]=0;
+        SERIAL_ECHOLN(subdirname);
+        if(!myDir.open(curDir,subdirname,O_READ))
+        {
+          SERIAL_PROTOCOLPGM("open failed, File: ");
+          SERIAL_PROTOCOL(subdirname);
+          SERIAL_PROTOCOLLNPGM(".");
+          return;
+        }
+        else
+          ;//SERIAL_ECHOLN("dive ok");
+          
+        curDir=&myDir; 
+        dirname_start=dirname_end+1;
+      }
+      else // the reminder after all /fsa/fdsa/ is the filename
+      {
+        fname=dirname_start;
+        //SERIAL_ECHOLN("remaider");
+        //SERIAL_ECHOLN(fname);
+        break;
+      }
+      
+    }
+  }
+  else //relative path
+  {
+    curDir=&workDir;
+  }
+    if (file.remove(curDir, fname)) 
+    {
+      SERIAL_PROTOCOLPGM("File deleted:");
+      SERIAL_PROTOCOL(fname);
+      sdpos = 0;
+    }
+    else
+    {
+      SERIAL_PROTOCOLPGM("Deletion failed, File: ");
+      SERIAL_PROTOCOL(fname);
+      SERIAL_PROTOCOLLNPGM(".");
+    }
+  
+}
+
+void CardReader::getStatus()
+{
+  if(cardOK){
+    SERIAL_PROTOCOLPGM(MSG_SD_PRINTING_BYTE);
+    SERIAL_PROTOCOL(sdpos);
+    SERIAL_PROTOCOLPGM("/");
+    SERIAL_PROTOCOLLN(filesize);
+  }
+  else{
+    SERIAL_PROTOCOLLNPGM(MSG_SD_NOT_PRINTING);
+  }
+}
+void CardReader::write_command(char *buf)
+{
+  char* begin = buf;
+  char* npos = 0;
+  char* end = buf + strlen(buf) - 1;
+
+  file.writeError = false;
+  if((npos = strchr(buf, 'N')) != NULL)
+  {
+    begin = strchr(npos, ' ') + 1;
+    end = strchr(npos, '*') - 1;
+  }
+  end[1] = '\r';
+  end[2] = '\n';
+  end[3] = '\0';
+  file.write(begin);
+  if (file.writeError)
+  {
+    SERIAL_ERROR_START;
+    SERIAL_ERRORLNPGM(MSG_SD_ERR_WRITE_TO_FILE);
+  }
+}
+
+
+void CardReader::checkautostart(bool force)
+{
+  if(!force)
+  {
+    if(!autostart_stilltocheck)
+      return;
+    if(autostart_atmillis<millis())
+      return;
+  }
+  autostart_stilltocheck=false;
+  if(!cardOK)
+  {
+    initsd();
+    if(!cardOK) //fail
+      return;
+  }
+  
+  char autoname[30];
+  sprintf(autoname,"auto%i.g",lastnr);
+  for(int8_t i=0;i<(int)strlen(autoname);i++)
+    autoname[i]=tolower(autoname[i]);
+  dir_t p;
+
+  root.rewind();
+  
+  bool found=false;
+  while (root.readDir(p) > 0) 
+  {
+    for(int8_t i=0;i<(int)strlen((char*)p.name);i++)
+    p.name[i]=tolower(p.name[i]);
+    //Serial.print((char*)p.name);
+    //Serial.print(" ");
+    //Serial.println(autoname);
+    if(p.name[9]!='~') //skip safety copies
+    if(strncmp((char*)p.name,autoname,5)==0)
+    {
+      char cmd[30];
+
+      sprintf(cmd,"M23 %s",autoname);
+      enquecommand(cmd);
+      enquecommand("M24");
+      found=true;
+    }
+  }
+  if(!found)
+    lastnr=-1;
+  else
+    lastnr++;
+}
+
+void CardReader::closefile()
+{
+  file.sync();
+  file.close();
+  saving = false; 
+}
+
+void CardReader::getfilename(const uint8_t nr)
+{
+  curDir=&workDir;
+  lsAction=LS_GetFilename;
+  nrFiles=nr;
+  curDir->rewind();
+  lsDive("",*curDir);
+  
+}
+
+uint16_t CardReader::getnrfilenames()
+{
+  curDir=&workDir;
+  lsAction=LS_Count;
+  nrFiles=0;
+  curDir->rewind();
+  lsDive("",*curDir);
+  //SERIAL_ECHOLN(nrFiles);
+  return nrFiles;
+}
+
+void CardReader::chdir(const char * relpath)
+{
+  SdFile newfile;
+  SdFile *parent=&root;
+  
+  if(workDir.isOpen())
+    parent=&workDir;
+  
+  if(!newfile.open(*parent,relpath, O_READ))
+  {
+   SERIAL_ECHO_START;
+   SERIAL_ECHOPGM(MSG_SD_CANT_ENTER_SUBDIR);
+   SERIAL_ECHOLN(relpath);
+  }
+  else
+  {
+    workDirParentParent=workDirParent;
+    workDirParent=*parent;
+    
+    workDir=newfile;
+  }
+}
+
+void CardReader::updir()
+{
+  if(!workDir.isRoot())
+  {
+    workDir=workDirParent;
+    workDirParent=workDirParentParent;
+  }
+}
+
+
+void CardReader::printingHasFinished()
+{
+ st_synchronize();
+ quickStop();
+ sdprinting = false;
+ if(SD_FINISHED_STEPPERRELEASE)
+ {
+   //finishAndDisableSteppers();
+   enquecommand(SD_FINISHED_RELEASECOMMAND);
+ }
+}
+void CardReader::fast_xfer(char* strchr_pointer)
+  {
+    char *pstr;
+    boolean done = false;
+    
+    //force heater pins low
+    if(HEATER_0_PIN > -1) WRITE(HEATER_0_PIN,LOW);
+    if(HEATER_BED_PIN > -1) WRITE(HEATER_BED_PIN,LOW);
+    
+    lastxferchar = 1;
+    xferbytes = 0;
+    
+    pstr = strstr(strchr_pointer, " ");
+    //pstr = strchr_pointer;
+
+    if(pstr == NULL)
+    {
+      SERIAL_ECHOLN("invalid command");
+      return;
+    }
+    
+    *pstr = '\0';
+    
+    //check mode (currently only RAW is supported
+    if(strcmp(strchr_pointer, "RAW") != 0)
+    {
+      SERIAL_ECHOLN("Invalid transfer codec");
+      return;
+    }else{
+      SERIAL_ECHOPGM("Selected codec: ");
+      SERIAL_ECHOLN(strchr_pointer+4);
+    }
+    
+    if (!file.open(&root, pstr+1, O_CREAT | O_APPEND | O_WRITE | O_TRUNC))
+    {
+      SERIAL_ECHOPGM("open failed, File: ");
+      SERIAL_ECHOLN(pstr+1);
+      SERIAL_ECHOPGM(".");
+    }else{
+      SERIAL_ECHOPGM("Writing to file: ");
+      SERIAL_ECHOLN(pstr+1);
+    }
+        
+    SERIAL_ECHOLN("ok");
+    
+    //RAW transfer codec
+    //Host sends \0 then up to SD_FAST_XFER_CHUNK_SIZE then \0
+    //when host is done, it sends \0\0.
+    //if a non \0 character is recieved at the beginning, host has failed somehow, kill the transfer.
+    
+    //read SD_FAST_XFER_CHUNK_SIZE bytes (or until \0 is recieved)
+    while(!done)
+    {
+      while(!MYSERIAL.available())
+      {
+      }
+      if(MYSERIAL.peek() != 0)
+      {
+        //host has failed, this isn't a RAW chunk, it's an actual command
+        file.sync();
+        file.close();
+        SERIAL_ECHOLN("Not RAW data");
+        return;
+      }
+      //clear the initial 0
+      MYSERIAL.read();
+      for(int i=0;i<SD_FAST_XFER_CHUNK_SIZE+1;i++)
+      {
+        while(!MYSERIAL.available())
+        {
+        }
+        lastxferchar = MYSERIAL.read();
+        //buffer the data...
+        fastxferbuffer[i] = lastxferchar;
+        
+        xferbytes++;
+        
+        if(lastxferchar == 0)
+          break;
+      }
+      
+      if(fastxferbuffer[0] != 0)
+      {
+        fastxferbuffer[SD_FAST_XFER_CHUNK_SIZE] = 0;
+        file.write(fastxferbuffer);
+        SERIAL_ECHOLN("ok");
+      }else{
+        SERIAL_ECHOPGM("Wrote ");
+        SERIAL_ECHO(xferbytes);
+        SERIAL_ECHOLN(" bytes.");
+        done = true;
+      }
+    }
+
+    file.sync();
+    file.close();
+  }
+
+#endif //SDSUPPORT

mercurial