chiark / gitweb /
minimums too
[marlin.git] / Marlin / Marlin.pde
1 /*
2     Reprap firmware based on Sprinter and grbl.
3  Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
4  
5  This program is free software: you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation, either version 3 of the License, or
8  (at your option) any later version.
9  
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  GNU General Public License for more details.
14  
15  You should have received a copy of the GNU General Public License
16  along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 /*
20  This firmware is a mashup between Sprinter and grbl.
21   (https://github.com/kliment/Sprinter)
22   (https://github.com/simen/grbl/tree)
23  
24  It has preliminary support for Matthew Roberts advance algorithm 
25     http://reprap.org/pipermail/reprap-dev/2011-May/003323.html
26  */
27
28 #include "Marlin.h"
29
30 #include "ultralcd.h"
31 #include "planner.h"
32 #include "stepper.h"
33 #include "temperature.h"
34 #include "motion_control.h"
35 #include "cardreader.h"
36 #include "watchdog.h"
37 #include "EEPROMwrite.h"
38 #include "language.h"
39 #include "pins_arduino.h"
40
41 #define VERSION_STRING  "1.0.0 RC2"
42
43 // look here for descriptions of gcodes: http://linuxcnc.org/handbook/gcode/g-code.html
44 // http://objects.reprap.org/wiki/Mendel_User_Manual:_RepRapGCodes
45
46 //Implemented Codes
47 //-------------------
48 // G0  -> G1
49 // G1  - Coordinated Movement X Y Z E
50 // G2  - CW ARC
51 // G3  - CCW ARC
52 // G4  - Dwell S<seconds> or P<milliseconds>
53 // G10 - retract filament according to settings of M207
54 // G11 - retract recover filament according to settings of M208
55 // G28 - Home all Axis
56 // G90 - Use Absolute Coordinates
57 // G91 - Use Relative Coordinates
58 // G92 - Set current position to cordinates given
59
60 //RepRap M Codes
61 // M0   - Unconditional stop - Wait for user to press a button on the LCD (Only if ULTRA_LCD is enabled)
62 // M1   - Same as M0
63 // M104 - Set extruder target temp
64 // M105 - Read current temp
65 // M106 - Fan on
66 // M107 - Fan off
67 // M109 - Wait for extruder current temp to reach target temp.
68 // M114 - Display current position
69
70 //Custom M Codes
71 // M17  - Enable/Power all stepper motors
72 // M18  - Disable all stepper motors; same as M84
73 // M20  - List SD card
74 // M21  - Init SD card
75 // M22  - Release SD card
76 // M23  - Select SD file (M23 filename.g)
77 // M24  - Start/resume SD print
78 // M25  - Pause SD print
79 // M26  - Set SD position in bytes (M26 S12345)
80 // M27  - Report SD print status
81 // M28  - Start SD write (M28 filename.g)
82 // M29  - Stop SD write
83 // M30  - Delete file from SD (M30 filename.g)
84 // M31  - Output time since last M109 or SD card start to serial
85 // M42  - Change pin status via gcode
86 // M80  - Turn on Power Supply
87 // M81  - Turn off Power Supply
88 // M82  - Set E codes absolute (default)
89 // M83  - Set E codes relative while in Absolute Coordinates (G90) mode
90 // M84  - Disable steppers until next move, 
91 //        or use S<seconds> to specify an inactivity timeout, after which the steppers will be disabled.  S0 to disable the timeout.
92 // M85  - Set inactivity shutdown timer with parameter S<seconds>. To disable set zero (default)
93 // M92  - Set axis_steps_per_unit - same syntax as G92
94 // M114 - Output current position to serial port 
95 // M115 - Capabilities string
96 // M117 - display message
97 // M119 - Output Endstop status to serial port
98 // M140 - Set bed target temp
99 // M190 - Wait for bed current temp to reach target temp.
100 // M200 - Set filament diameter
101 // M201 - Set max acceleration in units/s^2 for print moves (M201 X1000 Y1000)
102 // M202 - Set max acceleration in units/s^2 for travel moves (M202 X1000 Y1000) Unused in Marlin!!
103 // M203 - Set maximum feedrate that your machine can sustain (M203 X200 Y200 Z300 E10000) in mm/sec
104 // M204 - Set default acceleration: S normal moves T filament only moves (M204 S3000 T7000) im mm/sec^2  also sets minimum segment time in ms (B20000) to prevent buffer underruns and M20 minimum feedrate
105 // M205 -  advanced settings:  minimum travel speed S=while printing T=travel only,  B=minimum segment time X= maximum xy jerk, Z=maximum Z jerk, E=maximum E jerk
106 // M206 - set additional homeing offset
107 // M207 - set retract length S[positive mm] F[feedrate mm/sec] Z[additional zlift/hop]
108 // M208 - set recover=unretract length S[positive mm surplus to the M207 S*] F[feedrate mm/sec]
109 // M209 - S<1=true/0=false> enable automatic retract detect if the slicer did not support G10/11: every normal extrude-only move will be classified as retract depending on the direction.
110 // M220 S<factor in percent>- set speed factor override percentage
111 // M221 S<factor in percent>- set extrude factor override percentage
112 // M240 - Trigger a camera to take a photograph
113 // M301 - Set PID parameters P I and D
114 // M302 - Allow cold extrudes
115 // M303 - PID relay autotune S<temperature> sets the target temperature. (default target temperature = 150C)
116 // M400 - Finish all moves
117 // M500 - stores paramters in EEPROM
118 // M501 - reads parameters from EEPROM (if you need reset them after you changed them temporarily).  
119 // M502 - reverts to the default "factory settings".  You still need to store them in EEPROM afterwards if you want to.
120 // M503 - print the current settings (from memory not from eeprom)
121 // M999 - Restart after being stopped by error
122
123 //Stepper Movement Variables
124
125 //===========================================================================
126 //=============================imported variables============================
127 //===========================================================================
128
129
130 //===========================================================================
131 //=============================public variables=============================
132 //===========================================================================
133 #ifdef SDSUPPORT
134 CardReader card;
135 #endif
136 float homing_feedrate[] = HOMING_FEEDRATE;
137 bool axis_relative_modes[] = AXIS_RELATIVE_MODES;
138 volatile int feedmultiply=100; //100->1 200->2
139 int saved_feedmultiply;
140 volatile bool feedmultiplychanged=false;
141 volatile int extrudemultiply=100; //100->1 200->2
142 float current_position[NUM_AXIS] = { 0.0, 0.0, 0.0, 0.0 };
143 float add_homeing[3]={0,0,0};
144 float min_pos[3] = { X_MIN_POS, Y_MIN_POS, Z_MIN_POS };
145 uint8_t active_extruder = 0;
146 unsigned char FanSpeed=0;
147
148 #ifdef FWRETRACT
149   bool autoretract_enabled=true;
150   bool retracted=false;
151   float retract_length=3, retract_feedrate=17*60, retract_zlift=0.8;
152   float retract_recover_length=0, retract_recover_feedrate=8*60;
153 #endif
154
155 //===========================================================================
156 //=============================private variables=============================
157 //===========================================================================
158 const char axis_codes[NUM_AXIS] = {'X', 'Y', 'Z', 'E'};
159 static float destination[NUM_AXIS] = {  0.0, 0.0, 0.0, 0.0};
160 static float offset[3] = {0.0, 0.0, 0.0};
161 static bool home_all_axis = true;
162 static float feedrate = 1500.0, next_feedrate, saved_feedrate;
163 static long gcode_N, gcode_LastN, Stopped_gcode_LastN = 0;
164
165 static bool relative_mode = false;  //Determines Absolute or Relative Coordinates
166 static bool relative_mode_e = false;  //Determines Absolute or Relative E Codes while in Absolute Coordinates mode. E is always relative in Relative Coordinates mode.
167
168 static char cmdbuffer[BUFSIZE][MAX_CMD_SIZE];
169 static bool fromsd[BUFSIZE];
170 static int bufindr = 0;
171 static int bufindw = 0;
172 static int buflen = 0;
173 //static int i = 0;
174 static char serial_char;
175 static int serial_count = 0;
176 static boolean comment_mode = false;
177 static char *strchr_pointer; // just a pointer to find chars in the cmd string like X, Y, Z, E, etc
178
179 const int sensitive_pins[] = SENSITIVE_PINS; // Sensitive pin list for M42
180
181 //static float tt = 0;
182 //static float bt = 0;
183
184 //Inactivity shutdown variables
185 static unsigned long previous_millis_cmd = 0;
186 static unsigned long max_inactive_time = 0;
187 static unsigned long stepper_inactive_time = DEFAULT_STEPPER_DEACTIVE_TIME*1000l;
188
189 static unsigned long starttime=0;
190 static unsigned long stoptime=0;
191
192 static uint8_t tmp_extruder;
193
194
195 bool Stopped=false;
196
197 //===========================================================================
198 //=============================ROUTINES=============================
199 //===========================================================================
200
201 void get_arc_coordinates();
202
203 extern "C"{
204   extern unsigned int __bss_end;
205   extern unsigned int __heap_start;
206   extern void *__brkval;
207
208   int freeMemory() {
209     int free_memory;
210
211     if((int)__brkval == 0)
212       free_memory = ((int)&free_memory) - ((int)&__bss_end);
213     else
214       free_memory = ((int)&free_memory) - ((int)__brkval);
215
216     return free_memory;
217   }
218 }
219
220 //adds an command to the main command buffer
221 //thats really done in a non-safe way.
222 //needs overworking someday
223 void enquecommand(const char *cmd)
224 {
225   if(buflen < BUFSIZE)
226   {
227     //this is dangerous if a mixing of serial and this happsens
228     strcpy(&(cmdbuffer[bufindw][0]),cmd);
229     SERIAL_ECHO_START;
230     SERIAL_ECHOPGM("enqueing \"");
231     SERIAL_ECHO(cmdbuffer[bufindw]);
232     SERIAL_ECHOLNPGM("\"");
233     bufindw= (bufindw + 1)%BUFSIZE;
234     buflen += 1;
235   }
236 }
237
238 void setup_photpin()
239 {
240   #ifdef PHOTOGRAPH_PIN
241     #if (PHOTOGRAPH_PIN > -1)
242     SET_OUTPUT(PHOTOGRAPH_PIN);
243     WRITE(PHOTOGRAPH_PIN, LOW);
244     #endif
245   #endif 
246 }
247
248 void setup_powerhold()
249 {
250  #ifdef SUICIDE_PIN
251    #if (SUICIDE_PIN> -1)
252       SET_OUTPUT(SUICIDE_PIN);
253       WRITE(SUICIDE_PIN, HIGH);
254    #endif
255  #endif
256 }
257
258 void suicide()
259 {
260  #ifdef SUICIDE_PIN
261     #if (SUICIDE_PIN> -1) 
262       SET_OUTPUT(SUICIDE_PIN);
263       WRITE(SUICIDE_PIN, LOW);
264     #endif
265   #endif
266 }
267
268 void setup()
269
270   setup_powerhold();
271   MYSERIAL.begin(BAUDRATE);
272   SERIAL_PROTOCOLLNPGM("start");
273   SERIAL_ECHO_START;
274
275   // Check startup - does nothing if bootloader sets MCUSR to 0
276   byte mcu = MCUSR;
277   if(mcu & 1) SERIAL_ECHOLNPGM(MSG_POWERUP);
278   if(mcu & 2) SERIAL_ECHOLNPGM(MSG_EXTERNAL_RESET);
279   if(mcu & 4) SERIAL_ECHOLNPGM(MSG_BROWNOUT_RESET);
280   if(mcu & 8) SERIAL_ECHOLNPGM(MSG_WATCHDOG_RESET);
281   if(mcu & 32) SERIAL_ECHOLNPGM(MSG_SOFTWARE_RESET);
282   MCUSR=0;
283
284   SERIAL_ECHOPGM(MSG_MARLIN);
285   SERIAL_ECHOLNPGM(VERSION_STRING);
286   #ifdef STRING_VERSION_CONFIG_H
287     #ifdef STRING_CONFIG_H_AUTHOR
288       SERIAL_ECHO_START;
289       SERIAL_ECHOPGM(MSG_CONFIGURATION_VER);
290       SERIAL_ECHOPGM(STRING_VERSION_CONFIG_H);
291       SERIAL_ECHOPGM(MSG_AUTHOR);
292       SERIAL_ECHOLNPGM(STRING_CONFIG_H_AUTHOR);
293     #endif
294   #endif
295   SERIAL_ECHO_START;
296   SERIAL_ECHOPGM(MSG_FREE_MEMORY);
297   SERIAL_ECHO(freeMemory());
298   SERIAL_ECHOPGM(MSG_PLANNER_BUFFER_BYTES);
299   SERIAL_ECHOLN((int)sizeof(block_t)*BLOCK_BUFFER_SIZE);
300   for(int8_t i = 0; i < BUFSIZE; i++)
301   {
302     fromsd[i] = false;
303   }
304   
305   EEPROM_RetrieveSettings(); // loads data from EEPROM if available
306
307   for(int8_t i=0; i < NUM_AXIS; i++)
308   {
309     axis_steps_per_sqr_second[i] = max_acceleration_units_per_sq_second[i] * axis_steps_per_unit[i];
310   }
311
312
313   tp_init();    // Initialize temperature loop 
314   plan_init();  // Initialize planner;
315   st_init();    // Initialize stepper;
316   wd_init();
317   setup_photpin();
318   
319   LCD_INIT;
320 }
321
322
323 void loop()
324 {
325   if(buflen < (BUFSIZE-1))
326     get_command();
327   #ifdef SDSUPPORT
328   card.checkautostart(false);
329   #endif
330   if(buflen)
331   {
332     #ifdef SDSUPPORT
333       if(card.saving)
334       {
335         if(strstr(cmdbuffer[bufindr],"M29") == NULL)
336         {
337           card.write_command(cmdbuffer[bufindr]);
338           SERIAL_PROTOCOLLNPGM(MSG_OK);
339         }
340         else
341         {
342           card.closefile();
343           SERIAL_PROTOCOLLNPGM(MSG_FILE_SAVED);
344         }
345       }
346       else
347       {
348         process_commands();
349       }
350     #else
351       process_commands();
352     #endif //SDSUPPORT
353     buflen = (buflen-1);
354     bufindr = (bufindr + 1)%BUFSIZE;
355   }
356   //check heater every n milliseconds
357   manage_heater();
358   manage_inactivity(1);
359   checkHitEndstops();
360   LCD_STATUS;
361 }
362
363 void get_command() 
364
365   while( MYSERIAL.available() > 0  && buflen < BUFSIZE) {
366     serial_char = MYSERIAL.read();
367     if(serial_char == '\n' || 
368        serial_char == '\r' || 
369        (serial_char == ':' && comment_mode == false) || 
370        serial_count >= (MAX_CMD_SIZE - 1) ) 
371     {
372       if(!serial_count) { //if empty line
373         comment_mode = false; //for new command
374         return;
375       }
376       cmdbuffer[bufindw][serial_count] = 0; //terminate string
377       if(!comment_mode){
378         comment_mode = false; //for new command
379         fromsd[bufindw] = false;
380         if(strstr(cmdbuffer[bufindw], "N") != NULL)
381         {
382           strchr_pointer = strchr(cmdbuffer[bufindw], 'N');
383           gcode_N = (strtol(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL, 10));
384           if(gcode_N != gcode_LastN+1 && (strstr(cmdbuffer[bufindw], "M110") == NULL) ) {
385             SERIAL_ERROR_START;
386             SERIAL_ERRORPGM(MSG_ERR_LINE_NO);
387             SERIAL_ERRORLN(gcode_LastN);
388             //Serial.println(gcode_N);
389             FlushSerialRequestResend();
390             serial_count = 0;
391             return;
392           }
393
394           if(strstr(cmdbuffer[bufindw], "*") != NULL)
395           {
396             byte checksum = 0;
397             byte count = 0;
398             while(cmdbuffer[bufindw][count] != '*') checksum = checksum^cmdbuffer[bufindw][count++];
399             strchr_pointer = strchr(cmdbuffer[bufindw], '*');
400
401             if( (int)(strtod(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL)) != checksum) {
402               SERIAL_ERROR_START;
403               SERIAL_ERRORPGM(MSG_ERR_CHECKSUM_MISMATCH);
404               SERIAL_ERRORLN(gcode_LastN);
405               FlushSerialRequestResend();
406               serial_count = 0;
407               return;
408             }
409             //if no errors, continue parsing
410           }
411           else 
412           {
413             SERIAL_ERROR_START;
414             SERIAL_ERRORPGM(MSG_ERR_NO_CHECKSUM);
415             SERIAL_ERRORLN(gcode_LastN);
416             FlushSerialRequestResend();
417             serial_count = 0;
418             return;
419           }
420
421           gcode_LastN = gcode_N;
422           //if no errors, continue parsing
423         }
424         else  // if we don't receive 'N' but still see '*'
425         {
426           if((strstr(cmdbuffer[bufindw], "*") != NULL))
427           {
428             SERIAL_ERROR_START;
429             SERIAL_ERRORPGM(MSG_ERR_NO_LINENUMBER_WITH_CHECKSUM);
430             SERIAL_ERRORLN(gcode_LastN);
431             serial_count = 0;
432             return;
433           }
434         }
435         if((strstr(cmdbuffer[bufindw], "G") != NULL)){
436           strchr_pointer = strchr(cmdbuffer[bufindw], 'G');
437           switch((int)((strtod(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL)))){
438           case 0:
439           case 1:
440           case 2:
441           case 3:
442             if(Stopped == false) { // If printer is stopped by an error the G[0-3] codes are ignored.
443               #ifdef SDSUPPORT
444               if(card.saving)
445                 break;
446               #endif //SDSUPPORT
447               SERIAL_PROTOCOLLNPGM(MSG_OK); 
448             }
449             else {
450               SERIAL_ERRORLNPGM(MSG_ERR_STOPPED);
451               LCD_MESSAGEPGM(MSG_STOPPED);
452             }
453             break;
454           default:
455             break;
456           }
457
458         }
459         bufindw = (bufindw + 1)%BUFSIZE;
460         buflen += 1;
461       }
462       serial_count = 0; //clear buffer
463     }
464     else
465     {
466       if(serial_char == ';') comment_mode = true;
467       if(!comment_mode) cmdbuffer[bufindw][serial_count++] = serial_char;
468     }
469   }
470   #ifdef SDSUPPORT
471   if(!card.sdprinting || serial_count!=0){
472     return;
473   }
474   while( !card.eof()  && buflen < BUFSIZE) {
475     int16_t n=card.get();
476     serial_char = (char)n;
477     if(serial_char == '\n' || 
478        serial_char == '\r' || 
479        (serial_char == ':' && comment_mode == false) || 
480        serial_count >= (MAX_CMD_SIZE - 1)||n==-1) 
481     {
482       if(card.eof()){
483         SERIAL_PROTOCOLLNPGM(MSG_FILE_PRINTED);
484         stoptime=millis();
485         char time[30];
486         unsigned long t=(stoptime-starttime)/1000;
487         int sec,min;
488         min=t/60;
489         sec=t%60;
490         sprintf(time,"%i min, %i sec",min,sec);
491         SERIAL_ECHO_START;
492         SERIAL_ECHOLN(time);
493         LCD_MESSAGE(time);
494         card.printingHasFinished();
495         card.checkautostart(true);
496         
497       }
498       if(!serial_count)
499       {
500         comment_mode = false; //for new command
501         return; //if empty line
502       }
503       cmdbuffer[bufindw][serial_count] = 0; //terminate string
504 //      if(!comment_mode){
505         fromsd[bufindw] = true;
506         buflen += 1;
507         bufindw = (bufindw + 1)%BUFSIZE;
508 //      }     
509       comment_mode = false; //for new command
510       serial_count = 0; //clear buffer
511     }
512     else
513     {
514       if(serial_char == ';') comment_mode = true;
515       if(!comment_mode) cmdbuffer[bufindw][serial_count++] = serial_char;
516     }
517   }
518   
519   #endif //SDSUPPORT
520
521 }
522
523
524 float code_value() 
525
526   return (strtod(&cmdbuffer[bufindr][strchr_pointer - cmdbuffer[bufindr] + 1], NULL)); 
527 }
528
529 long code_value_long() 
530
531   return (strtol(&cmdbuffer[bufindr][strchr_pointer - cmdbuffer[bufindr] + 1], NULL, 10)); 
532 }
533
534 bool code_seen(char code_string[]) //Return True if the string was found
535
536   return (strstr(cmdbuffer[bufindr], code_string) != NULL); 
537 }  
538
539 bool code_seen(char code)
540 {
541   strchr_pointer = strchr(cmdbuffer[bufindr], code);
542   return (strchr_pointer != NULL);  //Return True if a character was found
543 }
544
545 static const float base_min_pos[3] = { X_MIN_POS, Y_MIN_POS, Z_MIN_POS };
546 static const float base_home_pos[3] = { X_HOME_POS, Y_HOME_POS, Z_HOME_POS };
547
548 static void axis_is_at_home(int axis) {
549   current_position[axis] = base_home_pos[axis] + add_homeing[axis];
550   min_pos[axis] = base_min_pos[axis] + add_homeing[axis];
551 }
552
553 #define HOMEAXIS(LETTER) \
554   if ((LETTER##_MIN_PIN > -1 && LETTER##_HOME_DIR==-1) || (LETTER##_MAX_PIN > -1 && LETTER##_HOME_DIR==1))\
555     { \
556     current_position[LETTER##_AXIS] = 0; \
557     plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); \
558     destination[LETTER##_AXIS] = 1.5 * LETTER##_MAX_LENGTH * LETTER##_HOME_DIR; \
559     feedrate = homing_feedrate[LETTER##_AXIS]; \
560     plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder); \
561     st_synchronize();\
562     \
563     current_position[LETTER##_AXIS] = 0;\
564     plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);\
565     destination[LETTER##_AXIS] = -LETTER##_HOME_RETRACT_MM * LETTER##_HOME_DIR;\
566     plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder); \
567     st_synchronize();\
568     \
569     destination[LETTER##_AXIS] = 2*LETTER##_HOME_RETRACT_MM * LETTER##_HOME_DIR;\
570     feedrate = homing_feedrate[LETTER##_AXIS]/2 ;  \
571     plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder); \
572     st_synchronize();\
573     \
574     axis_is_at_home(LETTER##_AXIS);                                     \
575     destination[LETTER##_AXIS] = current_position[LETTER##_AXIS]; \
576     feedrate = 0.0;\
577     endstops_hit_on_purpose();\
578   }
579
580 void process_commands()
581 {
582   unsigned long codenum; //throw away variable
583   char *starpos = NULL;
584
585   if(code_seen('G'))
586   {
587     switch((int)code_value())
588     {
589     case 0: // G0 -> G1
590     case 1: // G1
591       if(Stopped == false) {
592         get_coordinates(); // For X Y Z E F
593         prepare_move();
594         //ClearToSend();
595         return;
596       }
597       //break;
598     case 2: // G2  - CW ARC
599       if(Stopped == false) {
600         get_arc_coordinates();
601         prepare_arc_move(true);
602         return;
603       }
604     case 3: // G3  - CCW ARC
605       if(Stopped == false) {
606         get_arc_coordinates();
607         prepare_arc_move(false);
608         return;
609       }
610     case 4: // G4 dwell
611       LCD_MESSAGEPGM(MSG_DWELL);
612       codenum = 0;
613       if(code_seen('P')) codenum = code_value(); // milliseconds to wait
614       if(code_seen('S')) codenum = code_value() * 1000; // seconds to wait
615       
616       st_synchronize();
617       codenum += millis();  // keep track of when we started waiting
618       previous_millis_cmd = millis();
619       while(millis()  < codenum ){
620         manage_heater();
621         manage_inactivity(1);
622                 LCD_STATUS;
623       }
624       break;
625       #ifdef FWRETRACT  
626       case 10: // G10 retract
627       if(!retracted) 
628       {
629         destination[X_AXIS]=current_position[X_AXIS];
630         destination[Y_AXIS]=current_position[Y_AXIS];
631         destination[Z_AXIS]=current_position[Z_AXIS]; 
632         current_position[Z_AXIS]+=-retract_zlift;
633         destination[E_AXIS]=current_position[E_AXIS]-retract_length; 
634         feedrate=retract_feedrate;
635         retracted=true;
636         prepare_move();
637       }
638       
639       break;
640       case 11: // G10 retract_recover
641       if(!retracted) 
642       {
643         destination[X_AXIS]=current_position[X_AXIS];
644         destination[Y_AXIS]=current_position[Y_AXIS];
645         destination[Z_AXIS]=current_position[Z_AXIS]; 
646         
647         current_position[Z_AXIS]+=retract_zlift;
648         current_position[E_AXIS]+=-retract_recover_length; 
649         feedrate=retract_recover_feedrate;
650         retracted=false;
651         prepare_move();
652       }
653       break;
654       #endif //FWRETRACT
655     case 28: //G28 Home all Axis one at a time
656       saved_feedrate = feedrate;
657       saved_feedmultiply = feedmultiply;
658       feedmultiply = 100;
659       previous_millis_cmd = millis();
660       
661       enable_endstops(true);
662       
663       for(int8_t i=0; i < NUM_AXIS; i++) {
664         destination[i] = current_position[i];
665       }
666       feedrate = 0.0;
667       home_all_axis = !((code_seen(axis_codes[0])) || (code_seen(axis_codes[1])) || (code_seen(axis_codes[2])));
668       
669       #if Z_HOME_DIR > 0                      // If homing away from BED do Z first
670       if((home_all_axis) || (code_seen(axis_codes[Z_AXIS]))) {
671         HOMEAXIS(Z);
672       }
673       #endif
674       
675       #ifdef QUICK_HOME
676       if((home_all_axis)||( code_seen(axis_codes[X_AXIS]) && code_seen(axis_codes[Y_AXIS])) )  //first diagonal move
677       {
678         current_position[X_AXIS] = 0;current_position[Y_AXIS] = 0;  
679
680         plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); 
681         destination[X_AXIS] = 1.5 * X_MAX_LENGTH * X_HOME_DIR;destination[Y_AXIS] = 1.5 * Y_MAX_LENGTH * Y_HOME_DIR;  
682         feedrate = homing_feedrate[X_AXIS]; 
683         if(homing_feedrate[Y_AXIS]<feedrate)
684           feedrate =homing_feedrate[Y_AXIS]; 
685         plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder);
686         st_synchronize();
687     
688         axis_is_at_home(X_AXIS);
689         axis_is_at_home(Y_AXIS);
690         plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
691         destination[X_AXIS] = current_position[X_AXIS];
692         destination[Y_AXIS] = current_position[Y_AXIS];
693         plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder);
694         feedrate = 0.0;
695         st_synchronize();
696         endstops_hit_on_purpose();
697       }
698       #endif
699       
700       if((home_all_axis) || (code_seen(axis_codes[X_AXIS]))) 
701       {
702         HOMEAXIS(X);
703       }
704
705       if((home_all_axis) || (code_seen(axis_codes[Y_AXIS]))) {
706         HOMEAXIS(Y);
707       }
708       
709       #if Z_HOME_DIR < 0                      // If homing towards BED do Z last
710       if((home_all_axis) || (code_seen(axis_codes[Z_AXIS]))) {
711         HOMEAXIS(Z);
712       }
713       #endif
714       
715       if(code_seen(axis_codes[X_AXIS])) 
716       {
717         if(code_value_long() != 0) {
718           current_position[X_AXIS]=code_value()+add_homeing[0];
719         }
720       }
721
722       if(code_seen(axis_codes[Y_AXIS])) {
723         if(code_value_long() != 0) {
724           current_position[Y_AXIS]=code_value()+add_homeing[1];
725         }
726       }
727
728       if(code_seen(axis_codes[Z_AXIS])) {
729         if(code_value_long() != 0) {
730           current_position[Z_AXIS]=code_value()+add_homeing[2];
731         }
732       }
733       plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
734       
735       #ifdef ENDSTOPS_ONLY_FOR_HOMING
736         enable_endstops(false);
737       #endif
738       
739       feedrate = saved_feedrate;
740       feedmultiply = saved_feedmultiply;
741       previous_millis_cmd = millis();
742       endstops_hit_on_purpose();
743       break;
744     case 90: // G90
745       relative_mode = false;
746       break;
747     case 91: // G91
748       relative_mode = true;
749       break;
750     case 92: // G92
751       if(!code_seen(axis_codes[E_AXIS]))
752         st_synchronize();
753       for(int8_t i=0; i < NUM_AXIS; i++) {
754         if(code_seen(axis_codes[i])) { 
755            if(i == E_AXIS) {
756              current_position[i] = code_value();  
757              plan_set_e_position(current_position[E_AXIS]);
758            }
759            else {
760              current_position[i] = code_value()+add_homeing[i];  
761              plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
762            }
763         }
764       }
765       break;
766     }
767   }
768
769   else if(code_seen('M'))
770   {
771     switch( (int)code_value() ) 
772     {
773 #ifdef ULTRA_LCD
774     case 0: // M0 - Unconditional stop - Wait for user button press on LCD
775     case 1: // M1 - Conditional stop - Wait for user button press on LCD
776     {
777       LCD_MESSAGEPGM(MSG_USERWAIT);
778       codenum = 0;
779       if(code_seen('P')) codenum = code_value(); // milliseconds to wait
780       if(code_seen('S')) codenum = code_value() * 1000; // seconds to wait
781       
782       st_synchronize();
783       previous_millis_cmd = millis();
784           if (codenum > 0)
785           {
786         codenum += millis();  // keep track of when we started waiting
787         while(millis()  < codenum && !CLICKED){
788           manage_heater();
789           manage_inactivity(1);
790                   LCD_STATUS;
791                 }
792       }else{
793         while(!CLICKED) {
794           manage_heater();
795           manage_inactivity(1);
796                   LCD_STATUS;
797                 }
798           }
799     }
800     break;
801 #endif
802     case 17:
803         LCD_MESSAGEPGM(MSG_NO_MOVE);
804         enable_x(); 
805         enable_y(); 
806         enable_z(); 
807         enable_e0(); 
808         enable_e1(); 
809         enable_e2(); 
810       break;
811
812 #ifdef SDSUPPORT
813     case 20: // M20 - list SD card
814       SERIAL_PROTOCOLLNPGM(MSG_BEGIN_FILE_LIST);
815       card.ls();
816       SERIAL_PROTOCOLLNPGM(MSG_END_FILE_LIST);
817       break;
818     case 21: // M21 - init SD card
819       
820       card.initsd();
821       
822       break;
823     case 22: //M22 - release SD card
824       card.release();
825
826       break;
827     case 23: //M23 - Select file
828       starpos = (strchr(strchr_pointer + 4,'*'));
829       if(starpos!=NULL)
830         *(starpos-1)='\0';
831       card.openFile(strchr_pointer + 4,true);
832       break;
833     case 24: //M24 - Start SD print
834       card.startFileprint();
835       starttime=millis();
836       break;
837     case 25: //M25 - Pause SD print
838       card.pauseSDPrint();
839       break;
840     case 26: //M26 - Set SD index
841       if(card.cardOK && code_seen('S')) {
842         card.setIndex(code_value_long());
843       }
844       break;
845     case 27: //M27 - Get SD status
846       card.getStatus();
847       break;
848     case 28: //M28 - Start SD write
849       starpos = (strchr(strchr_pointer + 4,'*'));
850       if(starpos != NULL){
851         char* npos = strchr(cmdbuffer[bufindr], 'N');
852         strchr_pointer = strchr(npos,' ') + 1;
853         *(starpos-1) = '\0';
854       }
855       card.openFile(strchr_pointer+4,false);
856       break;
857     case 29: //M29 - Stop SD write
858       //processed in write to file routine above
859       //card,saving = false;
860       break;
861     case 30: //M30 <filename> Delete File 
862         if (card.cardOK){
863                 card.closefile();
864                 starpos = (strchr(strchr_pointer + 4,'*'));
865                 if(starpos != NULL){
866                 char* npos = strchr(cmdbuffer[bufindr], 'N');
867                 strchr_pointer = strchr(npos,' ') + 1;
868                 *(starpos-1) = '\0';
869          }
870          card.removeFile(strchr_pointer + 4);
871         }
872         break;
873         
874 #endif //SDSUPPORT
875
876     case 31: //M31 take time since the start of the SD print or an M109 command
877       {
878       stoptime=millis();
879       char time[30];
880       unsigned long t=(stoptime-starttime)/1000;
881       int sec,min;
882       min=t/60;
883       sec=t%60;
884       sprintf(time,"%i min, %i sec",min,sec);
885       SERIAL_ECHO_START;
886       SERIAL_ECHOLN(time);
887       LCD_MESSAGE(time);
888       autotempShutdown();
889       }
890       break;
891     case 42: //M42 -Change pin status via gcode
892       if (code_seen('S'))
893       {
894         int pin_status = code_value();
895         if (code_seen('P') && pin_status >= 0 && pin_status <= 255)
896         {
897           int pin_number = code_value();
898           for(int8_t i = 0; i < (int8_t)sizeof(sensitive_pins); i++)
899           {
900             if (sensitive_pins[i] == pin_number)
901             {
902               pin_number = -1;
903               break;
904             }
905           }
906           
907           if (pin_number > -1)
908           {              
909             pinMode(pin_number, OUTPUT);
910             digitalWrite(pin_number, pin_status);
911             analogWrite(pin_number, pin_status);
912           }
913         }
914       }
915      break;
916     case 104: // M104
917       tmp_extruder = active_extruder;
918       if(code_seen('T')) {
919         tmp_extruder = code_value();
920         if(tmp_extruder >= EXTRUDERS) {
921           SERIAL_ECHO_START;
922           SERIAL_ECHO(MSG_M104_INVALID_EXTRUDER);
923           SERIAL_ECHOLN(tmp_extruder);
924           break;
925         }
926       }
927       if (code_seen('S')) setTargetHotend(code_value(), tmp_extruder);
928       setWatch();
929       break;
930     case 140: // M140 set bed temp
931       if (code_seen('S')) setTargetBed(code_value());
932       break;
933     case 105 : // M105
934       tmp_extruder = active_extruder;
935       if(code_seen('T')) {
936         tmp_extruder = code_value();
937         if(tmp_extruder >= EXTRUDERS) {
938           SERIAL_ECHO_START;
939           SERIAL_ECHO(MSG_M105_INVALID_EXTRUDER);
940           SERIAL_ECHOLN(tmp_extruder);
941           break;
942         }
943       }
944       #if (TEMP_0_PIN > -1)
945         SERIAL_PROTOCOLPGM("ok T:");
946         SERIAL_PROTOCOL_F(degHotend(tmp_extruder),1); 
947         SERIAL_PROTOCOLPGM(" /");
948         SERIAL_PROTOCOL_F(degTargetHotend(tmp_extruder),1); 
949         #if TEMP_BED_PIN > -1
950           SERIAL_PROTOCOLPGM(" B:");  
951           SERIAL_PROTOCOL_F(degBed(),1);
952           SERIAL_PROTOCOLPGM(" /");
953           SERIAL_PROTOCOL_F(degTargetBed(),1);
954         #endif //TEMP_BED_PIN
955       #else
956         SERIAL_ERROR_START;
957         SERIAL_ERRORLNPGM(MSG_ERR_NO_THERMISTORS);
958       #endif
959       #ifdef PIDTEMP
960         SERIAL_PROTOCOLPGM(" @:");
961         SERIAL_PROTOCOL(getHeaterPower(tmp_extruder));  
962       #endif
963         SERIAL_PROTOCOLLN("");
964       return;
965       break;
966     case 109: 
967     {// M109 - Wait for extruder heater to reach target.
968       tmp_extruder = active_extruder;
969       if(code_seen('T')) {
970         tmp_extruder = code_value();
971         if(tmp_extruder >= EXTRUDERS) {
972           SERIAL_ECHO_START;
973           SERIAL_ECHO(MSG_M109_INVALID_EXTRUDER);
974           SERIAL_ECHOLN(tmp_extruder);
975           break;
976         }
977       }
978       LCD_MESSAGEPGM(MSG_HEATING);   
979       #ifdef AUTOTEMP
980         autotemp_enabled=false;
981       #endif
982       if (code_seen('S')) setTargetHotend(code_value(), tmp_extruder);
983       #ifdef AUTOTEMP
984         if (code_seen('S')) autotemp_min=code_value();
985         if (code_seen('B')) autotemp_max=code_value();
986         if (code_seen('F')) 
987         {
988           autotemp_factor=code_value();
989           autotemp_enabled=true;
990         }
991       #endif
992       
993       setWatch();
994       codenum = millis(); 
995
996       /* See if we are heating up or cooling down */
997       bool target_direction = isHeatingHotend(tmp_extruder); // true if heating, false if cooling
998
999       #ifdef TEMP_RESIDENCY_TIME
1000         long residencyStart;
1001         residencyStart = -1;
1002         /* continue to loop until we have reached the target temp   
1003           _and_ until TEMP_RESIDENCY_TIME hasn't passed since we reached it */
1004         while((residencyStart == -1) ||
1005               (residencyStart >= 0 && (((unsigned int) (millis() - residencyStart)) < (TEMP_RESIDENCY_TIME * 1000UL))) ) {
1006       #else
1007         while ( target_direction ? (isHeatingHotend(tmp_extruder)) : (isCoolingHotend(tmp_extruder)&&(CooldownNoWait==false)) ) {
1008       #endif //TEMP_RESIDENCY_TIME
1009           if( (millis() - codenum) > 1000UL )
1010           { //Print Temp Reading and remaining time every 1 second while heating up/cooling down
1011             SERIAL_PROTOCOLPGM("T:");
1012             SERIAL_PROTOCOL_F(degHotend(tmp_extruder),1); 
1013             SERIAL_PROTOCOLPGM(" E:");
1014             SERIAL_PROTOCOL((int)tmp_extruder); 
1015             #ifdef TEMP_RESIDENCY_TIME
1016               SERIAL_PROTOCOLPGM(" W:");
1017               if(residencyStart > -1)
1018               {
1019                  codenum = ((TEMP_RESIDENCY_TIME * 1000UL) - (millis() - residencyStart)) / 1000UL;
1020                  SERIAL_PROTOCOLLN( codenum );
1021               }
1022               else 
1023               {
1024                  SERIAL_PROTOCOLLN( "?" );
1025               }
1026             #else
1027               SERIAL_PROTOCOLLN("");
1028             #endif
1029             codenum = millis();
1030           }
1031           manage_heater();
1032           manage_inactivity(1);
1033           LCD_STATUS;
1034         #ifdef TEMP_RESIDENCY_TIME
1035             /* start/restart the TEMP_RESIDENCY_TIME timer whenever we reach target temp for the first time
1036               or when current temp falls outside the hysteresis after target temp was reached */
1037           if ((residencyStart == -1 &&  target_direction && (degHotend(tmp_extruder) >= (degTargetHotend(tmp_extruder)-TEMP_WINDOW))) ||
1038               (residencyStart == -1 && !target_direction && (degHotend(tmp_extruder) <= (degTargetHotend(tmp_extruder)+TEMP_WINDOW))) ||
1039               (residencyStart > -1 && labs(degHotend(tmp_extruder) - degTargetHotend(tmp_extruder)) > TEMP_HYSTERESIS) ) 
1040           {
1041             residencyStart = millis();
1042           }
1043         #endif //TEMP_RESIDENCY_TIME
1044         }
1045         LCD_MESSAGEPGM(MSG_HEATING_COMPLETE);
1046         starttime=millis();
1047         previous_millis_cmd = millis();
1048       }
1049       break;
1050     case 190: // M190 - Wait for bed heater to reach target.
1051     #if TEMP_BED_PIN > -1
1052         LCD_MESSAGEPGM(MSG_BED_HEATING);
1053         if (code_seen('S')) setTargetBed(code_value());
1054         codenum = millis(); 
1055         while(isHeatingBed()) 
1056         {
1057           if(( millis() - codenum) > 1000 ) //Print Temp Reading every 1 second while heating up.
1058           {
1059             float tt=degHotend(active_extruder);
1060             SERIAL_PROTOCOLPGM("T:");
1061             SERIAL_PROTOCOL(tt);
1062             SERIAL_PROTOCOLPGM(" E:");
1063             SERIAL_PROTOCOL((int)active_extruder); 
1064             SERIAL_PROTOCOLPGM(" B:");
1065             SERIAL_PROTOCOL_F(degBed(),1); 
1066             SERIAL_PROTOCOLLN(""); 
1067             codenum = millis(); 
1068           }
1069           manage_heater();
1070           manage_inactivity(1);
1071           LCD_STATUS;
1072         }
1073         LCD_MESSAGEPGM(MSG_BED_DONE);
1074         previous_millis_cmd = millis();
1075     #endif
1076         break;
1077
1078     #if FAN_PIN > -1
1079       case 106: //M106 Fan On
1080         if (code_seen('S')){
1081            FanSpeed=constrain(code_value(),0,255);
1082         }
1083         else {
1084           FanSpeed=255;                 
1085         }
1086         break;
1087       case 107: //M107 Fan Off
1088         FanSpeed = 0;
1089         break;
1090     #endif //FAN_PIN
1091
1092     #if (PS_ON_PIN > -1)
1093       case 80: // M80 - ATX Power On
1094         SET_OUTPUT(PS_ON_PIN); //GND
1095         WRITE(PS_ON_PIN, LOW);
1096         break;
1097       #endif
1098       
1099       case 81: // M81 - ATX Power Off
1100       
1101       #if defined SUICIDE_PIN && SUICIDE_PIN > -1
1102         st_synchronize();
1103         suicide();
1104       #elif (PS_ON_PIN > -1)
1105         SET_INPUT(PS_ON_PIN); //Floating
1106       #endif
1107                 break;
1108         
1109     case 82:
1110       axis_relative_modes[3] = false;
1111       break;
1112     case 83:
1113       axis_relative_modes[3] = true;
1114       break;
1115     case 18: //compatibility
1116     case 84: // M84
1117       if(code_seen('S')){ 
1118         stepper_inactive_time = code_value() * 1000; 
1119       }
1120       else
1121       { 
1122         bool all_axis = !((code_seen(axis_codes[0])) || (code_seen(axis_codes[1])) || (code_seen(axis_codes[2]))|| (code_seen(axis_codes[3])));
1123         if(all_axis)
1124         {
1125           st_synchronize();
1126           disable_e0();
1127           disable_e1();
1128           disable_e2();
1129           finishAndDisableSteppers();
1130         }
1131         else
1132         {
1133           st_synchronize();
1134           if(code_seen('X')) disable_x();
1135           if(code_seen('Y')) disable_y();
1136           if(code_seen('Z')) disable_z();
1137           #if ((E0_ENABLE_PIN != X_ENABLE_PIN) && (E1_ENABLE_PIN != Y_ENABLE_PIN)) // Only enable on boards that have seperate ENABLE_PINS
1138             if(code_seen('E')) {
1139               disable_e0();
1140               disable_e1();
1141               disable_e2();
1142             }
1143           #endif 
1144           LCD_MESSAGEPGM(MSG_PART_RELEASE);
1145         }
1146       }
1147       break;
1148     case 85: // M85
1149       code_seen('S');
1150       max_inactive_time = code_value() * 1000; 
1151       break;
1152     case 92: // M92
1153       for(int8_t i=0; i < NUM_AXIS; i++) 
1154       {
1155         if(code_seen(axis_codes[i])) 
1156           
1157           if(i == 3) { // E
1158             float value = code_value();
1159             if(value < 20.0) {
1160               float factor = axis_steps_per_unit[i] / value; // increase e constants if M92 E14 is given for netfab.
1161               max_e_jerk *= factor;
1162               max_feedrate[i] *= factor;
1163               axis_steps_per_sqr_second[i] *= factor;
1164             }
1165             axis_steps_per_unit[i] = value;
1166           }
1167           else {
1168             axis_steps_per_unit[i] = code_value();
1169           }
1170       }
1171       break;
1172     case 115: // M115
1173       SerialprintPGM(MSG_M115_REPORT);
1174       break;
1175     case 117: // M117 display message
1176       LCD_MESSAGE(cmdbuffer[bufindr]+5);
1177       break;
1178     case 114: // M114
1179       SERIAL_PROTOCOLPGM("X:");
1180       SERIAL_PROTOCOL(current_position[X_AXIS]);
1181       SERIAL_PROTOCOLPGM("Y:");
1182       SERIAL_PROTOCOL(current_position[Y_AXIS]);
1183       SERIAL_PROTOCOLPGM("Z:");
1184       SERIAL_PROTOCOL(current_position[Z_AXIS]);
1185       SERIAL_PROTOCOLPGM("E:");      
1186       SERIAL_PROTOCOL(current_position[E_AXIS]);
1187       
1188       SERIAL_PROTOCOLPGM(MSG_COUNT_X);
1189       SERIAL_PROTOCOL(float(st_get_position(X_AXIS))/axis_steps_per_unit[X_AXIS]);
1190       SERIAL_PROTOCOLPGM("Y:");
1191       SERIAL_PROTOCOL(float(st_get_position(Y_AXIS))/axis_steps_per_unit[Y_AXIS]);
1192       SERIAL_PROTOCOLPGM("Z:");
1193       SERIAL_PROTOCOL(float(st_get_position(Z_AXIS))/axis_steps_per_unit[Z_AXIS]);
1194       
1195       SERIAL_PROTOCOLLN("");
1196       break;
1197     case 120: // M120
1198       enable_endstops(false) ;
1199       break;
1200     case 121: // M121
1201       enable_endstops(true) ;
1202       break;
1203     case 119: // M119
1204       #if (X_MIN_PIN > -1)
1205         SERIAL_PROTOCOLPGM(MSG_X_MIN);
1206         SERIAL_PROTOCOL(((READ(X_MIN_PIN)^X_ENDSTOPS_INVERTING)?"H ":"L "));
1207       #endif
1208       #if (X_MAX_PIN > -1)
1209         SERIAL_PROTOCOLPGM(MSG_X_MAX);
1210         SERIAL_PROTOCOL(((READ(X_MAX_PIN)^X_ENDSTOPS_INVERTING)?"H ":"L "));
1211       #endif
1212       #if (Y_MIN_PIN > -1)
1213         SERIAL_PROTOCOLPGM(MSG_Y_MIN);
1214         SERIAL_PROTOCOL(((READ(Y_MIN_PIN)^Y_ENDSTOPS_INVERTING)?"H ":"L "));
1215       #endif
1216       #if (Y_MAX_PIN > -1)
1217         SERIAL_PROTOCOLPGM(MSG_Y_MAX);
1218         SERIAL_PROTOCOL(((READ(Y_MAX_PIN)^Y_ENDSTOPS_INVERTING)?"H ":"L "));
1219       #endif
1220       #if (Z_MIN_PIN > -1)
1221         SERIAL_PROTOCOLPGM(MSG_Z_MIN);
1222         SERIAL_PROTOCOL(((READ(Z_MIN_PIN)^Z_ENDSTOPS_INVERTING)?"H ":"L "));
1223       #endif
1224       #if (Z_MAX_PIN > -1)
1225         SERIAL_PROTOCOLPGM(MSG_Z_MAX);
1226         SERIAL_PROTOCOL(((READ(Z_MAX_PIN)^Z_ENDSTOPS_INVERTING)?"H ":"L "));
1227       #endif
1228       SERIAL_PROTOCOLLN("");
1229       break;
1230       //TODO: update for all axis, use for loop
1231     case 201: // M201
1232       for(int8_t i=0; i < NUM_AXIS; i++) 
1233       {
1234         if(code_seen(axis_codes[i]))
1235         {
1236           max_acceleration_units_per_sq_second[i] = code_value();
1237           axis_steps_per_sqr_second[i] = code_value() * axis_steps_per_unit[i];
1238         }
1239       }
1240       break;
1241     #if 0 // Not used for Sprinter/grbl gen6
1242     case 202: // M202
1243       for(int8_t i=0; i < NUM_AXIS; i++) {
1244         if(code_seen(axis_codes[i])) axis_travel_steps_per_sqr_second[i] = code_value() * axis_steps_per_unit[i];
1245       }
1246       break;
1247     #endif
1248     case 203: // M203 max feedrate mm/sec
1249       for(int8_t i=0; i < NUM_AXIS; i++) {
1250         if(code_seen(axis_codes[i])) max_feedrate[i] = code_value();
1251       }
1252       break;
1253     case 204: // M204 acclereration S normal moves T filmanent only moves
1254       {
1255         if(code_seen('S')) acceleration = code_value() ;
1256         if(code_seen('T')) retract_acceleration = code_value() ;
1257       }
1258       break;
1259     case 205: //M205 advanced settings:  minimum travel speed S=while printing T=travel only,  B=minimum segment time X= maximum xy jerk, Z=maximum Z jerk
1260     {
1261       if(code_seen('S')) minimumfeedrate = code_value();
1262       if(code_seen('T')) mintravelfeedrate = code_value();
1263       if(code_seen('B')) minsegmenttime = code_value() ;
1264       if(code_seen('X')) max_xy_jerk = code_value() ;
1265       if(code_seen('Z')) max_z_jerk = code_value() ;
1266       if(code_seen('E')) max_e_jerk = code_value() ;
1267     }
1268     break;
1269     case 206: // M206 additional homeing offset
1270       for(int8_t i=0; i < 3; i++) 
1271       {
1272         if(code_seen(axis_codes[i])) add_homeing[i] = code_value();
1273       }
1274       break;
1275     #ifdef FWRETRACT
1276     case 207: //M207 - set retract length S[positive mm] F[feedrate mm/sec] Z[additional zlift/hop]
1277     {
1278       if(code_seen('S')) 
1279       {
1280         retract_length = code_value() ;
1281       }
1282       if(code_seen('F')) 
1283       {
1284         retract_feedrate = code_value() ;
1285       }
1286       if(code_seen('Z')) 
1287       {
1288         retract_zlift = code_value() ;
1289       }
1290     }break;
1291     case 208: // M208 - set retract recover length S[positive mm surplus to the M207 S*] F[feedrate mm/sec]
1292     {
1293       if(code_seen('S')) 
1294       {
1295         retract_recover_length = code_value() ;
1296       }
1297       if(code_seen('F')) 
1298       {
1299         retract_recover_feedrate = code_value() ;
1300       }
1301     }break;
1302     
1303     case 209: // M209 - S<1=true/0=false> enable automatic retract detect if the slicer did not support G10/11: every normal extrude-only move will be classified as retract depending on the direction.
1304     {
1305       if(code_seen('S')) 
1306       {
1307         int t= code_value() ;
1308         switch(t)
1309         {
1310           case 0: autoretract_enabled=false;retracted=false;break;
1311           case 1: autoretract_enabled=true;retracted=false;break;
1312           default: 
1313             SERIAL_ECHO_START;
1314             SERIAL_ECHOPGM(MSG_UNKNOWN_COMMAND);
1315             SERIAL_ECHO(cmdbuffer[bufindr]);
1316             SERIAL_ECHOLNPGM("\"");
1317         }
1318       }
1319       
1320     }break;
1321     #endif
1322     case 220: // M220 S<factor in percent>- set speed factor override percentage
1323     {
1324       if(code_seen('S')) 
1325       {
1326         feedmultiply = code_value() ;
1327         feedmultiplychanged=true;
1328       }
1329     }
1330     break;
1331     case 221: // M221 S<factor in percent>- set extrude factor override percentage
1332     {
1333       if(code_seen('S')) 
1334       {
1335         extrudemultiply = code_value() ;
1336       }
1337     }
1338     break;
1339
1340     #ifdef PIDTEMP
1341     case 301: // M301
1342       {
1343         if(code_seen('P')) Kp = code_value();
1344         if(code_seen('I')) Ki = code_value()*PID_dT;
1345         if(code_seen('D')) Kd = code_value()/PID_dT;
1346         #ifdef PID_ADD_EXTRUSION_RATE
1347         if(code_seen('C')) Kc = code_value();
1348         #endif
1349         updatePID();
1350         SERIAL_PROTOCOL(MSG_OK);
1351                 SERIAL_PROTOCOL(" p:");
1352         SERIAL_PROTOCOL(Kp);
1353         SERIAL_PROTOCOL(" i:");
1354         SERIAL_PROTOCOL(Ki/PID_dT);
1355         SERIAL_PROTOCOL(" d:");
1356         SERIAL_PROTOCOL(Kd*PID_dT);
1357         #ifdef PID_ADD_EXTRUSION_RATE
1358         SERIAL_PROTOCOL(" c:");
1359         SERIAL_PROTOCOL(Kc*PID_dT);
1360         #endif
1361         SERIAL_PROTOCOLLN("");
1362       }
1363       break;
1364     #endif //PIDTEMP
1365     case 240: // M240  Triggers a camera by emulating a Canon RC-1 : http://www.doc-diy.net/photo/rc-1_hacked/
1366      {
1367       #ifdef PHOTOGRAPH_PIN
1368         #if (PHOTOGRAPH_PIN > -1)
1369         const uint8_t NUM_PULSES=16;
1370         const float PULSE_LENGTH=0.01524;
1371         for(int i=0; i < NUM_PULSES; i++) {
1372           WRITE(PHOTOGRAPH_PIN, HIGH);
1373           _delay_ms(PULSE_LENGTH);
1374           WRITE(PHOTOGRAPH_PIN, LOW);
1375           _delay_ms(PULSE_LENGTH);
1376         }
1377         delay(7.33);
1378         for(int i=0; i < NUM_PULSES; i++) {
1379           WRITE(PHOTOGRAPH_PIN, HIGH);
1380           _delay_ms(PULSE_LENGTH);
1381           WRITE(PHOTOGRAPH_PIN, LOW);
1382           _delay_ms(PULSE_LENGTH);
1383         }
1384         #endif
1385       #endif
1386      }
1387     break;
1388       
1389     case 302: // allow cold extrudes
1390     {
1391       allow_cold_extrudes(true);
1392     }
1393     break;
1394     case 303: // M303 PID autotune
1395     {
1396       float temp = 150.0;
1397       if (code_seen('S')) temp=code_value();
1398       PID_autotune(temp);
1399     }
1400     break;
1401     case 400: // M400 finish all moves
1402     {
1403       st_synchronize();
1404     }
1405     break;
1406     case 500: // Store settings in EEPROM
1407     {
1408         EEPROM_StoreSettings();
1409     }
1410     break;
1411     case 501: // Read settings from EEPROM
1412     {
1413       EEPROM_RetrieveSettings();
1414     }
1415     break;
1416     case 502: // Revert to default settings
1417     {
1418       EEPROM_RetrieveSettings(true);
1419     }
1420     break;
1421     case 503: // print settings currently in memory
1422     {
1423       EEPROM_printSettings();
1424     }
1425     break;
1426     case 999: // Restart after being stopped
1427       Stopped = false;
1428       gcode_LastN = Stopped_gcode_LastN;
1429       FlushSerialRequestResend();
1430     break;
1431     }
1432   }
1433
1434   else if(code_seen('T')) 
1435   {
1436     tmp_extruder = code_value();
1437     if(tmp_extruder >= EXTRUDERS) {
1438       SERIAL_ECHO_START;
1439       SERIAL_ECHO("T");
1440       SERIAL_ECHO(tmp_extruder);
1441       SERIAL_ECHOLN(MSG_INVALID_EXTRUDER);
1442     }
1443     else {
1444       active_extruder = tmp_extruder;
1445       SERIAL_ECHO_START;
1446       SERIAL_ECHO(MSG_ACTIVE_EXTRUDER);
1447       SERIAL_PROTOCOLLN((int)active_extruder);
1448     }
1449   }
1450
1451   else
1452   {
1453     SERIAL_ECHO_START;
1454     SERIAL_ECHOPGM(MSG_UNKNOWN_COMMAND);
1455     SERIAL_ECHO(cmdbuffer[bufindr]);
1456     SERIAL_ECHOLNPGM("\"");
1457   }
1458
1459   ClearToSend();
1460 }
1461
1462 void FlushSerialRequestResend()
1463 {
1464   //char cmdbuffer[bufindr][100]="Resend:";
1465   MYSERIAL.flush();
1466   SERIAL_PROTOCOLPGM(MSG_RESEND);
1467   SERIAL_PROTOCOLLN(gcode_LastN + 1);
1468   ClearToSend();
1469 }
1470
1471 void ClearToSend()
1472 {
1473   previous_millis_cmd = millis();
1474   #ifdef SDSUPPORT
1475   if(fromsd[bufindr])
1476     return;
1477   #endif //SDSUPPORT
1478   SERIAL_PROTOCOLLNPGM(MSG_OK); 
1479 }
1480
1481 void get_coordinates()
1482 {
1483   bool seen[4]={false,false,false,false};
1484   for(int8_t i=0; i < NUM_AXIS; i++) {
1485     if(code_seen(axis_codes[i])) 
1486     {
1487       destination[i] = (float)code_value() + (axis_relative_modes[i] || relative_mode)*current_position[i];
1488       seen[i]=true;
1489     }
1490     else destination[i] = current_position[i]; //Are these else lines really needed?
1491   }
1492   if(code_seen('F')) {
1493     next_feedrate = code_value();
1494     if(next_feedrate > 0.0) feedrate = next_feedrate;
1495   }
1496   #ifdef FWRETRACT
1497   if(autoretract_enabled)
1498   if( !(seen[X_AXIS] || seen[Y_AXIS] || seen[Z_AXIS]) && seen[E_AXIS])
1499   {
1500     float echange=destination[E_AXIS]-current_position[E_AXIS];
1501     if(echange<-MIN_RETRACT) //retract
1502     {
1503       if(!retracted) 
1504       {
1505       
1506       destination[Z_AXIS]+=retract_zlift; //not sure why chaninging current_position negatively does not work.
1507       //if slicer retracted by echange=-1mm and you want to retract 3mm, corrrectede=-2mm additionally
1508       float correctede=-echange-retract_length;
1509       //to generate the additional steps, not the destination is changed, but inversely the current position
1510       current_position[E_AXIS]+=-correctede; 
1511       feedrate=retract_feedrate;
1512       retracted=true;
1513       }
1514       
1515     }
1516     else 
1517       if(echange>MIN_RETRACT) //retract_recover
1518     {
1519       if(retracted) 
1520       {
1521       //current_position[Z_AXIS]+=-retract_zlift;
1522       //if slicer retracted_recovered by echange=+1mm and you want to retract_recover 3mm, corrrectede=2mm additionally
1523       float correctede=-echange+1*retract_length+retract_recover_length; //total unretract=retract_length+retract_recover_length[surplus]
1524       current_position[E_AXIS]+=correctede; //to generate the additional steps, not the destination is changed, but inversely the current position
1525       feedrate=retract_recover_feedrate;
1526       retracted=false;
1527       }
1528     }
1529     
1530   }
1531   #endif //FWRETRACT
1532 }
1533
1534 void get_arc_coordinates()
1535 {
1536    get_coordinates();
1537    if(code_seen('I')) {
1538      offset[0] = code_value();
1539    } 
1540    else {
1541      offset[0] = 0.0;
1542    }
1543    if(code_seen('J')) {
1544      offset[1] = code_value();
1545    }
1546    else {
1547      offset[1] = 0.0;
1548    }
1549 }
1550
1551 void prepare_move()
1552 {
1553   if (min_software_endstops) {
1554     if (destination[X_AXIS] < min_pos[0]) destination[X_AXIS] = min_pos[0];
1555     if (destination[Y_AXIS] < min_pos[1]) destination[Y_AXIS] = min_pos[1];
1556     if (destination[Z_AXIS] < min_pos[2]) destination[Z_AXIS] = min_pos[2];
1557   }
1558
1559   if (max_software_endstops) {
1560     if (destination[X_AXIS] > X_MAX_POS) destination[X_AXIS] = X_MAX_POS;
1561     if (destination[Y_AXIS] > Y_MAX_POS) destination[Y_AXIS] = Y_MAX_POS;
1562     if (destination[Z_AXIS] > Z_MAX_POS) destination[Z_AXIS] = Z_MAX_POS;
1563   }
1564   previous_millis_cmd = millis();  
1565   plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate*feedmultiply/60/100.0, active_extruder);
1566   for(int8_t i=0; i < NUM_AXIS; i++) {
1567     current_position[i] = destination[i];
1568   }
1569 }
1570
1571 void prepare_arc_move(char isclockwise) {
1572   float r = hypot(offset[X_AXIS], offset[Y_AXIS]); // Compute arc radius for mc_arc
1573
1574   // Trace the arc
1575   mc_arc(current_position, destination, offset, X_AXIS, Y_AXIS, Z_AXIS, feedrate*feedmultiply/60/100.0, r, isclockwise, active_extruder);
1576   
1577   // As far as the parser is concerned, the position is now == target. In reality the
1578   // motion control system might still be processing the action and the real tool position
1579   // in any intermediate location.
1580   for(int8_t i=0; i < NUM_AXIS; i++) {
1581     current_position[i] = destination[i];
1582   }
1583   previous_millis_cmd = millis();
1584 }
1585
1586 #ifdef CONTROLLERFAN_PIN
1587 unsigned long lastMotor = 0; //Save the time for when a motor was turned on last
1588 unsigned long lastMotorCheck = 0;
1589
1590 void controllerFan()
1591 {
1592   if ((millis() - lastMotorCheck) >= 2500) //Not a time critical function, so we only check every 2500ms
1593   {
1594     lastMotorCheck = millis();
1595     
1596     if(!READ(X_ENABLE_PIN) || !READ(Y_ENABLE_PIN) || !READ(Z_ENABLE_PIN)
1597     #if EXTRUDERS > 2
1598        || !READ(E2_ENABLE_PIN)
1599     #endif
1600     #if EXTRUDER > 1
1601        || !READ(E2_ENABLE_PIN)
1602     #endif
1603        || !READ(E0_ENABLE_PIN)) //If any of the drivers are enabled...    
1604     {
1605       lastMotor = millis(); //... set time to NOW so the fan will turn on
1606     }
1607     
1608     if ((millis() - lastMotor) >= (CONTROLLERFAN_SEC*1000UL) || lastMotor == 0) //If the last time any driver was enabled, is longer since than CONTROLLERSEC...   
1609     {
1610       WRITE(CONTROLLERFAN_PIN, LOW); //... turn the fan off
1611     }
1612     else
1613     {
1614       WRITE(CONTROLLERFAN_PIN, HIGH); //... turn the fan on
1615     }
1616   }
1617 }
1618 #endif
1619
1620 void manage_inactivity(byte debug) 
1621
1622   if( (millis() - previous_millis_cmd) >  max_inactive_time ) 
1623     if(max_inactive_time) 
1624       kill(); 
1625   if(stepper_inactive_time)  {
1626     if( (millis() - previous_millis_cmd) >  stepper_inactive_time ) 
1627     {
1628       if(blocks_queued() == false) {
1629         disable_x();
1630         disable_y();
1631         disable_z();
1632         disable_e0();
1633         disable_e1();
1634         disable_e2();
1635       }
1636     }
1637   }
1638   #ifdef CONTROLLERFAN_PIN
1639     controllerFan(); //Check if fan should be turned on to cool stepper drivers down
1640   #endif
1641   #ifdef EXTRUDER_RUNOUT_PREVENT
1642     if( (millis() - previous_millis_cmd) >  EXTRUDER_RUNOUT_SECONDS*1000 ) 
1643     if(degHotend(active_extruder)>EXTRUDER_RUNOUT_MINTEMP)
1644     {
1645      bool oldstatus=READ(E0_ENABLE_PIN);
1646      enable_e0();
1647      float oldepos=current_position[E_AXIS];
1648      float oldedes=destination[E_AXIS];
1649      plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], 
1650                       current_position[E_AXIS]+EXTRUDER_RUNOUT_EXTRUDE*EXTRUDER_RUNOUT_ESTEPS/axis_steps_per_unit[E_AXIS], 
1651                       EXTRUDER_RUNOUT_SPEED/60.*EXTRUDER_RUNOUT_ESTEPS/axis_steps_per_unit[E_AXIS], active_extruder);
1652      current_position[E_AXIS]=oldepos;
1653      destination[E_AXIS]=oldedes;
1654      plan_set_e_position(oldepos);
1655      previous_millis_cmd=millis();
1656      st_synchronize();
1657      WRITE(E0_ENABLE_PIN,oldstatus);
1658     }
1659   #endif
1660   check_axes_activity();
1661 }
1662
1663 void kill()
1664 {
1665   cli(); // Stop interrupts
1666   disable_heater();
1667
1668   disable_x();
1669   disable_y();
1670   disable_z();
1671   disable_e0();
1672   disable_e1();
1673   disable_e2();
1674   
1675   if(PS_ON_PIN > -1) pinMode(PS_ON_PIN,INPUT);
1676   SERIAL_ERROR_START;
1677   SERIAL_ERRORLNPGM(MSG_ERR_KILLED);
1678   LCD_MESSAGEPGM(MSG_KILLED);
1679   suicide();
1680   while(1); // Wait for reset
1681 }
1682
1683 void Stop()
1684 {
1685   disable_heater();
1686   if(Stopped == false) {
1687     Stopped = true;
1688     Stopped_gcode_LastN = gcode_LastN; // Save last g_code for restart
1689     SERIAL_ERROR_START;
1690     SERIAL_ERRORLNPGM(MSG_ERR_STOPPED);
1691     LCD_MESSAGEPGM(MSG_STOPPED);
1692   }
1693 }
1694
1695 bool IsStopped() { return Stopped; };
1696
1697 #ifdef FAST_PWM_FAN
1698 void setPwmFrequency(uint8_t pin, int val)
1699 {
1700   val &= 0x07;
1701   switch(digitalPinToTimer(pin))
1702   {
1703  
1704     #if defined(TCCR0A)
1705     case TIMER0A:
1706     case TIMER0B:
1707 //         TCCR0B &= ~(CS00 | CS01 | CS02);
1708 //         TCCR0B |= val;
1709          break;
1710     #endif
1711
1712     #if defined(TCCR1A)
1713     case TIMER1A:
1714     case TIMER1B:
1715 //         TCCR1B &= ~(CS10 | CS11 | CS12);
1716 //         TCCR1B |= val;
1717          break;
1718     #endif
1719
1720     #if defined(TCCR2)
1721     case TIMER2:
1722     case TIMER2:
1723          TCCR2 &= ~(CS10 | CS11 | CS12);
1724          TCCR2 |= val;
1725          break;
1726     #endif
1727
1728     #if defined(TCCR2A)
1729     case TIMER2A:
1730     case TIMER2B:
1731          TCCR2B &= ~(CS20 | CS21 | CS22);
1732          TCCR2B |= val;
1733          break;
1734     #endif
1735
1736     #if defined(TCCR3A)
1737     case TIMER3A:
1738     case TIMER3B:
1739     case TIMER3C:
1740          TCCR3B &= ~(CS30 | CS31 | CS32);
1741          TCCR3B |= val;
1742          break;
1743     #endif
1744
1745     #if defined(TCCR4A) 
1746     case TIMER4A:
1747     case TIMER4B:
1748     case TIMER4C:
1749          TCCR4B &= ~(CS40 | CS41 | CS42);
1750          TCCR4B |= val;
1751          break;
1752    #endif
1753
1754     #if defined(TCCR5A) 
1755     case TIMER5A:
1756     case TIMER5B:
1757     case TIMER5C:
1758          TCCR5B &= ~(CS50 | CS51 | CS52);
1759          TCCR5B |= val;
1760          break;
1761    #endif
1762
1763   }
1764 }
1765 #endif
1766
1767