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