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