chiark / gitweb /
eeprom: provide smaller code for SERIAL_ECHOPAIR
[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
561 #define XYZ_CONSTS_FROM_CONFIG(type, array, CONFIG)     \
562 static const PROGMEM type array##_P[3] =                \
563     { X_##CONFIG, Y_##CONFIG, Z_##CONFIG };             \
564 static inline type array(int axis)                      \
565     { return pgm_read_any(&array##_P[axis]); }
566
567 XYZ_CONSTS_FROM_CONFIG(float, base_min_pos,    MIN_POS);
568 XYZ_CONSTS_FROM_CONFIG(float, base_max_pos,    MAX_POS);
569 XYZ_CONSTS_FROM_CONFIG(float, base_home_pos,   HOME_POS);
570
571 static void axis_is_at_home(int axis) {
572   current_position[axis] = base_home_pos(axis) + add_homeing[axis];
573   min_pos[axis] =          base_min_pos(axis) + add_homeing[axis];
574   max_pos[axis] =          base_max_pos(axis) + add_homeing[axis];
575 }
576
577 #define HOMEAXIS(LETTER) \
578   if ((LETTER##_MIN_PIN > -1 && LETTER##_HOME_DIR==-1) || (LETTER##_MAX_PIN > -1 && LETTER##_HOME_DIR==1))\
579     { \
580     current_position[LETTER##_AXIS] = 0; \
581     plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); \
582     destination[LETTER##_AXIS] = 1.5 * LETTER##_MAX_LENGTH * LETTER##_HOME_DIR; \
583     feedrate = homing_feedrate[LETTER##_AXIS]; \
584     plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder); \
585     st_synchronize();\
586     \
587     current_position[LETTER##_AXIS] = 0;\
588     plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);\
589     destination[LETTER##_AXIS] = -LETTER##_HOME_RETRACT_MM * LETTER##_HOME_DIR;\
590     plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder); \
591     st_synchronize();\
592     \
593     destination[LETTER##_AXIS] = 2*LETTER##_HOME_RETRACT_MM * LETTER##_HOME_DIR;\
594     feedrate = homing_feedrate[LETTER##_AXIS]/2 ;  \
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     axis_is_at_home(LETTER##_AXIS);                                     \
599     destination[LETTER##_AXIS] = current_position[LETTER##_AXIS]; \
600     feedrate = 0.0;\
601     endstops_hit_on_purpose();\
602   }
603
604 void process_commands()
605 {
606   unsigned long codenum; //throw away variable
607   char *starpos = NULL;
608
609   if(code_seen('G'))
610   {
611     switch((int)code_value())
612     {
613     case 0: // G0 -> G1
614     case 1: // G1
615       if(Stopped == false) {
616         get_coordinates(); // For X Y Z E F
617         prepare_move();
618         //ClearToSend();
619         return;
620       }
621       //break;
622     case 2: // G2  - CW ARC
623       if(Stopped == false) {
624         get_arc_coordinates();
625         prepare_arc_move(true);
626         return;
627       }
628     case 3: // G3  - CCW ARC
629       if(Stopped == false) {
630         get_arc_coordinates();
631         prepare_arc_move(false);
632         return;
633       }
634     case 4: // G4 dwell
635       LCD_MESSAGEPGM(MSG_DWELL);
636       codenum = 0;
637       if(code_seen('P')) codenum = code_value(); // milliseconds to wait
638       if(code_seen('S')) codenum = code_value() * 1000; // seconds to wait
639       
640       st_synchronize();
641       codenum += millis();  // keep track of when we started waiting
642       previous_millis_cmd = millis();
643       while(millis()  < codenum ){
644         manage_heater();
645         manage_inactivity(1);
646                 LCD_STATUS;
647       }
648       break;
649       #ifdef FWRETRACT  
650       case 10: // G10 retract
651       if(!retracted) 
652       {
653         destination[X_AXIS]=current_position[X_AXIS];
654         destination[Y_AXIS]=current_position[Y_AXIS];
655         destination[Z_AXIS]=current_position[Z_AXIS]; 
656         current_position[Z_AXIS]+=-retract_zlift;
657         destination[E_AXIS]=current_position[E_AXIS]-retract_length; 
658         feedrate=retract_feedrate;
659         retracted=true;
660         prepare_move();
661       }
662       
663       break;
664       case 11: // G10 retract_recover
665       if(!retracted) 
666       {
667         destination[X_AXIS]=current_position[X_AXIS];
668         destination[Y_AXIS]=current_position[Y_AXIS];
669         destination[Z_AXIS]=current_position[Z_AXIS]; 
670         
671         current_position[Z_AXIS]+=retract_zlift;
672         current_position[E_AXIS]+=-retract_recover_length; 
673         feedrate=retract_recover_feedrate;
674         retracted=false;
675         prepare_move();
676       }
677       break;
678       #endif //FWRETRACT
679     case 28: //G28 Home all Axis one at a time
680       saved_feedrate = feedrate;
681       saved_feedmultiply = feedmultiply;
682       feedmultiply = 100;
683       previous_millis_cmd = millis();
684       
685       enable_endstops(true);
686       
687       for(int8_t i=0; i < NUM_AXIS; i++) {
688         destination[i] = current_position[i];
689       }
690       feedrate = 0.0;
691       home_all_axis = !((code_seen(axis_codes[0])) || (code_seen(axis_codes[1])) || (code_seen(axis_codes[2])));
692       
693       #if Z_HOME_DIR > 0                      // If homing away from BED do Z first
694       if((home_all_axis) || (code_seen(axis_codes[Z_AXIS]))) {
695         HOMEAXIS(Z);
696       }
697       #endif
698       
699       #ifdef QUICK_HOME
700       if((home_all_axis)||( code_seen(axis_codes[X_AXIS]) && code_seen(axis_codes[Y_AXIS])) )  //first diagonal move
701       {
702         current_position[X_AXIS] = 0;current_position[Y_AXIS] = 0;  
703
704         plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); 
705         destination[X_AXIS] = 1.5 * X_MAX_LENGTH * X_HOME_DIR;destination[Y_AXIS] = 1.5 * Y_MAX_LENGTH * Y_HOME_DIR;  
706         feedrate = homing_feedrate[X_AXIS]; 
707         if(homing_feedrate[Y_AXIS]<feedrate)
708           feedrate =homing_feedrate[Y_AXIS]; 
709         plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder);
710         st_synchronize();
711     
712         axis_is_at_home(X_AXIS);
713         axis_is_at_home(Y_AXIS);
714         plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
715         destination[X_AXIS] = current_position[X_AXIS];
716         destination[Y_AXIS] = current_position[Y_AXIS];
717         plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder);
718         feedrate = 0.0;
719         st_synchronize();
720         endstops_hit_on_purpose();
721       }
722       #endif
723       
724       if((home_all_axis) || (code_seen(axis_codes[X_AXIS]))) 
725       {
726         HOMEAXIS(X);
727       }
728
729       if((home_all_axis) || (code_seen(axis_codes[Y_AXIS]))) {
730         HOMEAXIS(Y);
731       }
732       
733       #if Z_HOME_DIR < 0                      // If homing towards BED do Z last
734       if((home_all_axis) || (code_seen(axis_codes[Z_AXIS]))) {
735         HOMEAXIS(Z);
736       }
737       #endif
738       
739       if(code_seen(axis_codes[X_AXIS])) 
740       {
741         if(code_value_long() != 0) {
742           current_position[X_AXIS]=code_value()+add_homeing[0];
743         }
744       }
745
746       if(code_seen(axis_codes[Y_AXIS])) {
747         if(code_value_long() != 0) {
748           current_position[Y_AXIS]=code_value()+add_homeing[1];
749         }
750       }
751
752       if(code_seen(axis_codes[Z_AXIS])) {
753         if(code_value_long() != 0) {
754           current_position[Z_AXIS]=code_value()+add_homeing[2];
755         }
756       }
757       plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
758       
759       #ifdef ENDSTOPS_ONLY_FOR_HOMING
760         enable_endstops(false);
761       #endif
762       
763       feedrate = saved_feedrate;
764       feedmultiply = saved_feedmultiply;
765       previous_millis_cmd = millis();
766       endstops_hit_on_purpose();
767       break;
768     case 90: // G90
769       relative_mode = false;
770       break;
771     case 91: // G91
772       relative_mode = true;
773       break;
774     case 92: // G92
775       if(!code_seen(axis_codes[E_AXIS]))
776         st_synchronize();
777       for(int8_t i=0; i < NUM_AXIS; i++) {
778         if(code_seen(axis_codes[i])) { 
779            if(i == E_AXIS) {
780              current_position[i] = code_value();  
781              plan_set_e_position(current_position[E_AXIS]);
782            }
783            else {
784              current_position[i] = code_value()+add_homeing[i];  
785              plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
786            }
787         }
788       }
789       break;
790     }
791   }
792
793   else if(code_seen('M'))
794   {
795     switch( (int)code_value() ) 
796     {
797 #ifdef ULTRA_LCD
798     case 0: // M0 - Unconditional stop - Wait for user button press on LCD
799     case 1: // M1 - Conditional stop - Wait for user button press on LCD
800     {
801       LCD_MESSAGEPGM(MSG_USERWAIT);
802       codenum = 0;
803       if(code_seen('P')) codenum = code_value(); // milliseconds to wait
804       if(code_seen('S')) codenum = code_value() * 1000; // seconds to wait
805       
806       st_synchronize();
807       previous_millis_cmd = millis();
808           if (codenum > 0)
809           {
810         codenum += millis();  // keep track of when we started waiting
811         while(millis()  < codenum && !CLICKED){
812           manage_heater();
813           manage_inactivity(1);
814                   LCD_STATUS;
815                 }
816       }else{
817         while(!CLICKED) {
818           manage_heater();
819           manage_inactivity(1);
820                   LCD_STATUS;
821                 }
822           }
823     }
824     break;
825 #endif
826     case 17:
827         LCD_MESSAGEPGM(MSG_NO_MOVE);
828         enable_x(); 
829         enable_y(); 
830         enable_z(); 
831         enable_e0(); 
832         enable_e1(); 
833         enable_e2(); 
834       break;
835
836 #ifdef SDSUPPORT
837     case 20: // M20 - list SD card
838       SERIAL_PROTOCOLLNPGM(MSG_BEGIN_FILE_LIST);
839       card.ls();
840       SERIAL_PROTOCOLLNPGM(MSG_END_FILE_LIST);
841       break;
842     case 21: // M21 - init SD card
843       
844       card.initsd();
845       
846       break;
847     case 22: //M22 - release SD card
848       card.release();
849
850       break;
851     case 23: //M23 - Select file
852       starpos = (strchr(strchr_pointer + 4,'*'));
853       if(starpos!=NULL)
854         *(starpos-1)='\0';
855       card.openFile(strchr_pointer + 4,true);
856       break;
857     case 24: //M24 - Start SD print
858       card.startFileprint();
859       starttime=millis();
860       break;
861     case 25: //M25 - Pause SD print
862       card.pauseSDPrint();
863       break;
864     case 26: //M26 - Set SD index
865       if(card.cardOK && code_seen('S')) {
866         card.setIndex(code_value_long());
867       }
868       break;
869     case 27: //M27 - Get SD status
870       card.getStatus();
871       break;
872     case 28: //M28 - Start SD write
873       starpos = (strchr(strchr_pointer + 4,'*'));
874       if(starpos != NULL){
875         char* npos = strchr(cmdbuffer[bufindr], 'N');
876         strchr_pointer = strchr(npos,' ') + 1;
877         *(starpos-1) = '\0';
878       }
879       card.openFile(strchr_pointer+4,false);
880       break;
881     case 29: //M29 - Stop SD write
882       //processed in write to file routine above
883       //card,saving = false;
884       break;
885     case 30: //M30 <filename> Delete File 
886         if (card.cardOK){
887                 card.closefile();
888                 starpos = (strchr(strchr_pointer + 4,'*'));
889                 if(starpos != NULL){
890                 char* npos = strchr(cmdbuffer[bufindr], 'N');
891                 strchr_pointer = strchr(npos,' ') + 1;
892                 *(starpos-1) = '\0';
893          }
894          card.removeFile(strchr_pointer + 4);
895         }
896         break;
897         
898 #endif //SDSUPPORT
899
900     case 31: //M31 take time since the start of the SD print or an M109 command
901       {
902       stoptime=millis();
903       char time[30];
904       unsigned long t=(stoptime-starttime)/1000;
905       int sec,min;
906       min=t/60;
907       sec=t%60;
908       sprintf(time,"%i min, %i sec",min,sec);
909       SERIAL_ECHO_START;
910       SERIAL_ECHOLN(time);
911       LCD_MESSAGE(time);
912       autotempShutdown();
913       }
914       break;
915     case 42: //M42 -Change pin status via gcode
916       if (code_seen('S'))
917       {
918         int pin_status = code_value();
919         if (code_seen('P') && pin_status >= 0 && pin_status <= 255)
920         {
921           int pin_number = code_value();
922           for(int8_t i = 0; i < (int8_t)sizeof(sensitive_pins); i++)
923           {
924             if (sensitive_pins[i] == pin_number)
925             {
926               pin_number = -1;
927               break;
928             }
929           }
930           
931           if (pin_number > -1)
932           {              
933             pinMode(pin_number, OUTPUT);
934             digitalWrite(pin_number, pin_status);
935             analogWrite(pin_number, pin_status);
936           }
937         }
938       }
939      break;
940     case 104: // M104
941       tmp_extruder = active_extruder;
942       if(code_seen('T')) {
943         tmp_extruder = code_value();
944         if(tmp_extruder >= EXTRUDERS) {
945           SERIAL_ECHO_START;
946           SERIAL_ECHO(MSG_M104_INVALID_EXTRUDER);
947           SERIAL_ECHOLN(tmp_extruder);
948           break;
949         }
950       }
951       if (code_seen('S')) setTargetHotend(code_value(), tmp_extruder);
952       setWatch();
953       break;
954     case 140: // M140 set bed temp
955       if (code_seen('S')) setTargetBed(code_value());
956       break;
957     case 105 : // M105
958       tmp_extruder = active_extruder;
959       if(code_seen('T')) {
960         tmp_extruder = code_value();
961         if(tmp_extruder >= EXTRUDERS) {
962           SERIAL_ECHO_START;
963           SERIAL_ECHO(MSG_M105_INVALID_EXTRUDER);
964           SERIAL_ECHOLN(tmp_extruder);
965           break;
966         }
967       }
968       #if (TEMP_0_PIN > -1)
969         SERIAL_PROTOCOLPGM("ok T:");
970         SERIAL_PROTOCOL_F(degHotend(tmp_extruder),1); 
971         SERIAL_PROTOCOLPGM(" /");
972         SERIAL_PROTOCOL_F(degTargetHotend(tmp_extruder),1); 
973         #if TEMP_BED_PIN > -1
974           SERIAL_PROTOCOLPGM(" B:");  
975           SERIAL_PROTOCOL_F(degBed(),1);
976           SERIAL_PROTOCOLPGM(" /");
977           SERIAL_PROTOCOL_F(degTargetBed(),1);
978         #endif //TEMP_BED_PIN
979       #else
980         SERIAL_ERROR_START;
981         SERIAL_ERRORLNPGM(MSG_ERR_NO_THERMISTORS);
982       #endif
983       #ifdef PIDTEMP
984         SERIAL_PROTOCOLPGM(" @:");
985         SERIAL_PROTOCOL(getHeaterPower(tmp_extruder));  
986       #endif
987         SERIAL_PROTOCOLLN("");
988       return;
989       break;
990     case 109: 
991     {// M109 - Wait for extruder heater to reach target.
992       tmp_extruder = active_extruder;
993       if(code_seen('T')) {
994         tmp_extruder = code_value();
995         if(tmp_extruder >= EXTRUDERS) {
996           SERIAL_ECHO_START;
997           SERIAL_ECHO(MSG_M109_INVALID_EXTRUDER);
998           SERIAL_ECHOLN(tmp_extruder);
999           break;
1000         }
1001       }
1002       LCD_MESSAGEPGM(MSG_HEATING);   
1003       #ifdef AUTOTEMP
1004         autotemp_enabled=false;
1005       #endif
1006       if (code_seen('S')) setTargetHotend(code_value(), tmp_extruder);
1007       #ifdef AUTOTEMP
1008         if (code_seen('S')) autotemp_min=code_value();
1009         if (code_seen('B')) autotemp_max=code_value();
1010         if (code_seen('F')) 
1011         {
1012           autotemp_factor=code_value();
1013           autotemp_enabled=true;
1014         }
1015       #endif
1016       
1017       setWatch();
1018       codenum = millis(); 
1019
1020       /* See if we are heating up or cooling down */
1021       bool target_direction = isHeatingHotend(tmp_extruder); // true if heating, false if cooling
1022
1023       #ifdef TEMP_RESIDENCY_TIME
1024         long residencyStart;
1025         residencyStart = -1;
1026         /* continue to loop until we have reached the target temp   
1027           _and_ until TEMP_RESIDENCY_TIME hasn't passed since we reached it */
1028         while((residencyStart == -1) ||
1029               (residencyStart >= 0 && (((unsigned int) (millis() - residencyStart)) < (TEMP_RESIDENCY_TIME * 1000UL))) ) {
1030       #else
1031         while ( target_direction ? (isHeatingHotend(tmp_extruder)) : (isCoolingHotend(tmp_extruder)&&(CooldownNoWait==false)) ) {
1032       #endif //TEMP_RESIDENCY_TIME
1033           if( (millis() - codenum) > 1000UL )
1034           { //Print Temp Reading and remaining time every 1 second while heating up/cooling down
1035             SERIAL_PROTOCOLPGM("T:");
1036             SERIAL_PROTOCOL_F(degHotend(tmp_extruder),1); 
1037             SERIAL_PROTOCOLPGM(" E:");
1038             SERIAL_PROTOCOL((int)tmp_extruder); 
1039             #ifdef TEMP_RESIDENCY_TIME
1040               SERIAL_PROTOCOLPGM(" W:");
1041               if(residencyStart > -1)
1042               {
1043                  codenum = ((TEMP_RESIDENCY_TIME * 1000UL) - (millis() - residencyStart)) / 1000UL;
1044                  SERIAL_PROTOCOLLN( codenum );
1045               }
1046               else 
1047               {
1048                  SERIAL_PROTOCOLLN( "?" );
1049               }
1050             #else
1051               SERIAL_PROTOCOLLN("");
1052             #endif
1053             codenum = millis();
1054           }
1055           manage_heater();
1056           manage_inactivity(1);
1057           LCD_STATUS;
1058         #ifdef TEMP_RESIDENCY_TIME
1059             /* start/restart the TEMP_RESIDENCY_TIME timer whenever we reach target temp for the first time
1060               or when current temp falls outside the hysteresis after target temp was reached */
1061           if ((residencyStart == -1 &&  target_direction && (degHotend(tmp_extruder) >= (degTargetHotend(tmp_extruder)-TEMP_WINDOW))) ||
1062               (residencyStart == -1 && !target_direction && (degHotend(tmp_extruder) <= (degTargetHotend(tmp_extruder)+TEMP_WINDOW))) ||
1063               (residencyStart > -1 && labs(degHotend(tmp_extruder) - degTargetHotend(tmp_extruder)) > TEMP_HYSTERESIS) ) 
1064           {
1065             residencyStart = millis();
1066           }
1067         #endif //TEMP_RESIDENCY_TIME
1068         }
1069         LCD_MESSAGEPGM(MSG_HEATING_COMPLETE);
1070         starttime=millis();
1071         previous_millis_cmd = millis();
1072       }
1073       break;
1074     case 190: // M190 - Wait for bed heater to reach target.
1075     #if TEMP_BED_PIN > -1
1076         LCD_MESSAGEPGM(MSG_BED_HEATING);
1077         if (code_seen('S')) setTargetBed(code_value());
1078         codenum = millis(); 
1079         while(isHeatingBed()) 
1080         {
1081           if(( millis() - codenum) > 1000 ) //Print Temp Reading every 1 second while heating up.
1082           {
1083             float tt=degHotend(active_extruder);
1084             SERIAL_PROTOCOLPGM("T:");
1085             SERIAL_PROTOCOL(tt);
1086             SERIAL_PROTOCOLPGM(" E:");
1087             SERIAL_PROTOCOL((int)active_extruder); 
1088             SERIAL_PROTOCOLPGM(" B:");
1089             SERIAL_PROTOCOL_F(degBed(),1); 
1090             SERIAL_PROTOCOLLN(""); 
1091             codenum = millis(); 
1092           }
1093           manage_heater();
1094           manage_inactivity(1);
1095           LCD_STATUS;
1096         }
1097         LCD_MESSAGEPGM(MSG_BED_DONE);
1098         previous_millis_cmd = millis();
1099     #endif
1100         break;
1101
1102     #if FAN_PIN > -1
1103       case 106: //M106 Fan On
1104         if (code_seen('S')){
1105            FanSpeed=constrain(code_value(),0,255);
1106         }
1107         else {
1108           FanSpeed=255;                 
1109         }
1110         break;
1111       case 107: //M107 Fan Off
1112         FanSpeed = 0;
1113         break;
1114     #endif //FAN_PIN
1115
1116     #if (PS_ON_PIN > -1)
1117       case 80: // M80 - ATX Power On
1118         SET_OUTPUT(PS_ON_PIN); //GND
1119         WRITE(PS_ON_PIN, LOW);
1120         break;
1121       #endif
1122       
1123       case 81: // M81 - ATX Power Off
1124       
1125       #if defined SUICIDE_PIN && SUICIDE_PIN > -1
1126         st_synchronize();
1127         suicide();
1128       #elif (PS_ON_PIN > -1)
1129         SET_INPUT(PS_ON_PIN); //Floating
1130       #endif
1131                 break;
1132         
1133     case 82:
1134       axis_relative_modes[3] = false;
1135       break;
1136     case 83:
1137       axis_relative_modes[3] = true;
1138       break;
1139     case 18: //compatibility
1140     case 84: // M84
1141       if(code_seen('S')){ 
1142         stepper_inactive_time = code_value() * 1000; 
1143       }
1144       else
1145       { 
1146         bool all_axis = !((code_seen(axis_codes[0])) || (code_seen(axis_codes[1])) || (code_seen(axis_codes[2]))|| (code_seen(axis_codes[3])));
1147         if(all_axis)
1148         {
1149           st_synchronize();
1150           disable_e0();
1151           disable_e1();
1152           disable_e2();
1153           finishAndDisableSteppers();
1154         }
1155         else
1156         {
1157           st_synchronize();
1158           if(code_seen('X')) disable_x();
1159           if(code_seen('Y')) disable_y();
1160           if(code_seen('Z')) disable_z();
1161           #if ((E0_ENABLE_PIN != X_ENABLE_PIN) && (E1_ENABLE_PIN != Y_ENABLE_PIN)) // Only enable on boards that have seperate ENABLE_PINS
1162             if(code_seen('E')) {
1163               disable_e0();
1164               disable_e1();
1165               disable_e2();
1166             }
1167           #endif 
1168           LCD_MESSAGEPGM(MSG_PART_RELEASE);
1169         }
1170       }
1171       break;
1172     case 85: // M85
1173       code_seen('S');
1174       max_inactive_time = code_value() * 1000; 
1175       break;
1176     case 92: // M92
1177       for(int8_t i=0; i < NUM_AXIS; i++) 
1178       {
1179         if(code_seen(axis_codes[i])) 
1180           
1181           if(i == 3) { // E
1182             float value = code_value();
1183             if(value < 20.0) {
1184               float factor = axis_steps_per_unit[i] / value; // increase e constants if M92 E14 is given for netfab.
1185               max_e_jerk *= factor;
1186               max_feedrate[i] *= factor;
1187               axis_steps_per_sqr_second[i] *= factor;
1188             }
1189             axis_steps_per_unit[i] = value;
1190           }
1191           else {
1192             axis_steps_per_unit[i] = code_value();
1193           }
1194       }
1195       break;
1196     case 115: // M115
1197       SerialprintPGM(MSG_M115_REPORT);
1198       break;
1199     case 117: // M117 display message
1200       LCD_MESSAGE(cmdbuffer[bufindr]+5);
1201       break;
1202     case 114: // M114
1203       SERIAL_PROTOCOLPGM("X:");
1204       SERIAL_PROTOCOL(current_position[X_AXIS]);
1205       SERIAL_PROTOCOLPGM("Y:");
1206       SERIAL_PROTOCOL(current_position[Y_AXIS]);
1207       SERIAL_PROTOCOLPGM("Z:");
1208       SERIAL_PROTOCOL(current_position[Z_AXIS]);
1209       SERIAL_PROTOCOLPGM("E:");      
1210       SERIAL_PROTOCOL(current_position[E_AXIS]);
1211       
1212       SERIAL_PROTOCOLPGM(MSG_COUNT_X);
1213       SERIAL_PROTOCOL(float(st_get_position(X_AXIS))/axis_steps_per_unit[X_AXIS]);
1214       SERIAL_PROTOCOLPGM("Y:");
1215       SERIAL_PROTOCOL(float(st_get_position(Y_AXIS))/axis_steps_per_unit[Y_AXIS]);
1216       SERIAL_PROTOCOLPGM("Z:");
1217       SERIAL_PROTOCOL(float(st_get_position(Z_AXIS))/axis_steps_per_unit[Z_AXIS]);
1218       
1219       SERIAL_PROTOCOLLN("");
1220       break;
1221     case 120: // M120
1222       enable_endstops(false) ;
1223       break;
1224     case 121: // M121
1225       enable_endstops(true) ;
1226       break;
1227     case 119: // M119
1228       #if (X_MIN_PIN > -1)
1229         SERIAL_PROTOCOLPGM(MSG_X_MIN);
1230         SERIAL_PROTOCOL(((READ(X_MIN_PIN)^X_ENDSTOPS_INVERTING)?"H ":"L "));
1231       #endif
1232       #if (X_MAX_PIN > -1)
1233         SERIAL_PROTOCOLPGM(MSG_X_MAX);
1234         SERIAL_PROTOCOL(((READ(X_MAX_PIN)^X_ENDSTOPS_INVERTING)?"H ":"L "));
1235       #endif
1236       #if (Y_MIN_PIN > -1)
1237         SERIAL_PROTOCOLPGM(MSG_Y_MIN);
1238         SERIAL_PROTOCOL(((READ(Y_MIN_PIN)^Y_ENDSTOPS_INVERTING)?"H ":"L "));
1239       #endif
1240       #if (Y_MAX_PIN > -1)
1241         SERIAL_PROTOCOLPGM(MSG_Y_MAX);
1242         SERIAL_PROTOCOL(((READ(Y_MAX_PIN)^Y_ENDSTOPS_INVERTING)?"H ":"L "));
1243       #endif
1244       #if (Z_MIN_PIN > -1)
1245         SERIAL_PROTOCOLPGM(MSG_Z_MIN);
1246         SERIAL_PROTOCOL(((READ(Z_MIN_PIN)^Z_ENDSTOPS_INVERTING)?"H ":"L "));
1247       #endif
1248       #if (Z_MAX_PIN > -1)
1249         SERIAL_PROTOCOLPGM(MSG_Z_MAX);
1250         SERIAL_PROTOCOL(((READ(Z_MAX_PIN)^Z_ENDSTOPS_INVERTING)?"H ":"L "));
1251       #endif
1252       SERIAL_PROTOCOLLN("");
1253       break;
1254       //TODO: update for all axis, use for loop
1255     case 201: // M201
1256       for(int8_t i=0; i < NUM_AXIS; i++) 
1257       {
1258         if(code_seen(axis_codes[i]))
1259         {
1260           max_acceleration_units_per_sq_second[i] = code_value();
1261           axis_steps_per_sqr_second[i] = code_value() * axis_steps_per_unit[i];
1262         }
1263       }
1264       break;
1265     #if 0 // Not used for Sprinter/grbl gen6
1266     case 202: // M202
1267       for(int8_t i=0; i < NUM_AXIS; i++) {
1268         if(code_seen(axis_codes[i])) axis_travel_steps_per_sqr_second[i] = code_value() * axis_steps_per_unit[i];
1269       }
1270       break;
1271     #endif
1272     case 203: // M203 max feedrate mm/sec
1273       for(int8_t i=0; i < NUM_AXIS; i++) {
1274         if(code_seen(axis_codes[i])) max_feedrate[i] = code_value();
1275       }
1276       break;
1277     case 204: // M204 acclereration S normal moves T filmanent only moves
1278       {
1279         if(code_seen('S')) acceleration = code_value() ;
1280         if(code_seen('T')) retract_acceleration = code_value() ;
1281       }
1282       break;
1283     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
1284     {
1285       if(code_seen('S')) minimumfeedrate = code_value();
1286       if(code_seen('T')) mintravelfeedrate = code_value();
1287       if(code_seen('B')) minsegmenttime = code_value() ;
1288       if(code_seen('X')) max_xy_jerk = code_value() ;
1289       if(code_seen('Z')) max_z_jerk = code_value() ;
1290       if(code_seen('E')) max_e_jerk = code_value() ;
1291     }
1292     break;
1293     case 206: // M206 additional homeing offset
1294       for(int8_t i=0; i < 3; i++) 
1295       {
1296         if(code_seen(axis_codes[i])) add_homeing[i] = code_value();
1297       }
1298       break;
1299     #ifdef FWRETRACT
1300     case 207: //M207 - set retract length S[positive mm] F[feedrate mm/sec] Z[additional zlift/hop]
1301     {
1302       if(code_seen('S')) 
1303       {
1304         retract_length = code_value() ;
1305       }
1306       if(code_seen('F')) 
1307       {
1308         retract_feedrate = code_value() ;
1309       }
1310       if(code_seen('Z')) 
1311       {
1312         retract_zlift = code_value() ;
1313       }
1314     }break;
1315     case 208: // M208 - set retract recover length S[positive mm surplus to the M207 S*] F[feedrate mm/sec]
1316     {
1317       if(code_seen('S')) 
1318       {
1319         retract_recover_length = code_value() ;
1320       }
1321       if(code_seen('F')) 
1322       {
1323         retract_recover_feedrate = code_value() ;
1324       }
1325     }break;
1326     
1327     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.
1328     {
1329       if(code_seen('S')) 
1330       {
1331         int t= code_value() ;
1332         switch(t)
1333         {
1334           case 0: autoretract_enabled=false;retracted=false;break;
1335           case 1: autoretract_enabled=true;retracted=false;break;
1336           default: 
1337             SERIAL_ECHO_START;
1338             SERIAL_ECHOPGM(MSG_UNKNOWN_COMMAND);
1339             SERIAL_ECHO(cmdbuffer[bufindr]);
1340             SERIAL_ECHOLNPGM("\"");
1341         }
1342       }
1343       
1344     }break;
1345     #endif
1346     case 220: // M220 S<factor in percent>- set speed factor override percentage
1347     {
1348       if(code_seen('S')) 
1349       {
1350         feedmultiply = code_value() ;
1351         feedmultiplychanged=true;
1352       }
1353     }
1354     break;
1355     case 221: // M221 S<factor in percent>- set extrude factor override percentage
1356     {
1357       if(code_seen('S')) 
1358       {
1359         extrudemultiply = code_value() ;
1360       }
1361     }
1362     break;
1363
1364     #ifdef PIDTEMP
1365     case 301: // M301
1366       {
1367         if(code_seen('P')) Kp = code_value();
1368         if(code_seen('I')) Ki = code_value()*PID_dT;
1369         if(code_seen('D')) Kd = code_value()/PID_dT;
1370         #ifdef PID_ADD_EXTRUSION_RATE
1371         if(code_seen('C')) Kc = code_value();
1372         #endif
1373         updatePID();
1374         SERIAL_PROTOCOL(MSG_OK);
1375                 SERIAL_PROTOCOL(" p:");
1376         SERIAL_PROTOCOL(Kp);
1377         SERIAL_PROTOCOL(" i:");
1378         SERIAL_PROTOCOL(Ki/PID_dT);
1379         SERIAL_PROTOCOL(" d:");
1380         SERIAL_PROTOCOL(Kd*PID_dT);
1381         #ifdef PID_ADD_EXTRUSION_RATE
1382         SERIAL_PROTOCOL(" c:");
1383         SERIAL_PROTOCOL(Kc*PID_dT);
1384         #endif
1385         SERIAL_PROTOCOLLN("");
1386       }
1387       break;
1388     #endif //PIDTEMP
1389     case 240: // M240  Triggers a camera by emulating a Canon RC-1 : http://www.doc-diy.net/photo/rc-1_hacked/
1390      {
1391       #ifdef PHOTOGRAPH_PIN
1392         #if (PHOTOGRAPH_PIN > -1)
1393         const uint8_t NUM_PULSES=16;
1394         const float PULSE_LENGTH=0.01524;
1395         for(int i=0; i < NUM_PULSES; i++) {
1396           WRITE(PHOTOGRAPH_PIN, HIGH);
1397           _delay_ms(PULSE_LENGTH);
1398           WRITE(PHOTOGRAPH_PIN, LOW);
1399           _delay_ms(PULSE_LENGTH);
1400         }
1401         delay(7.33);
1402         for(int i=0; i < NUM_PULSES; i++) {
1403           WRITE(PHOTOGRAPH_PIN, HIGH);
1404           _delay_ms(PULSE_LENGTH);
1405           WRITE(PHOTOGRAPH_PIN, LOW);
1406           _delay_ms(PULSE_LENGTH);
1407         }
1408         #endif
1409       #endif
1410      }
1411     break;
1412       
1413     case 302: // allow cold extrudes
1414     {
1415       allow_cold_extrudes(true);
1416     }
1417     break;
1418     case 303: // M303 PID autotune
1419     {
1420       float temp = 150.0;
1421       if (code_seen('S')) temp=code_value();
1422       PID_autotune(temp);
1423     }
1424     break;
1425     case 400: // M400 finish all moves
1426     {
1427       st_synchronize();
1428     }
1429     break;
1430     case 500: // Store settings in EEPROM
1431     {
1432         EEPROM_StoreSettings();
1433     }
1434     break;
1435     case 501: // Read settings from EEPROM
1436     {
1437       EEPROM_RetrieveSettings();
1438     }
1439     break;
1440     case 502: // Revert to default settings
1441     {
1442       EEPROM_RetrieveSettings(true);
1443     }
1444     break;
1445     case 503: // print settings currently in memory
1446     {
1447       EEPROM_printSettings();
1448     }
1449     break;
1450     case 999: // Restart after being stopped
1451       Stopped = false;
1452       gcode_LastN = Stopped_gcode_LastN;
1453       FlushSerialRequestResend();
1454     break;
1455     }
1456   }
1457
1458   else if(code_seen('T')) 
1459   {
1460     tmp_extruder = code_value();
1461     if(tmp_extruder >= EXTRUDERS) {
1462       SERIAL_ECHO_START;
1463       SERIAL_ECHO("T");
1464       SERIAL_ECHO(tmp_extruder);
1465       SERIAL_ECHOLN(MSG_INVALID_EXTRUDER);
1466     }
1467     else {
1468       active_extruder = tmp_extruder;
1469       SERIAL_ECHO_START;
1470       SERIAL_ECHO(MSG_ACTIVE_EXTRUDER);
1471       SERIAL_PROTOCOLLN((int)active_extruder);
1472     }
1473   }
1474
1475   else
1476   {
1477     SERIAL_ECHO_START;
1478     SERIAL_ECHOPGM(MSG_UNKNOWN_COMMAND);
1479     SERIAL_ECHO(cmdbuffer[bufindr]);
1480     SERIAL_ECHOLNPGM("\"");
1481   }
1482
1483   ClearToSend();
1484 }
1485
1486 void FlushSerialRequestResend()
1487 {
1488   //char cmdbuffer[bufindr][100]="Resend:";
1489   MYSERIAL.flush();
1490   SERIAL_PROTOCOLPGM(MSG_RESEND);
1491   SERIAL_PROTOCOLLN(gcode_LastN + 1);
1492   ClearToSend();
1493 }
1494
1495 void ClearToSend()
1496 {
1497   previous_millis_cmd = millis();
1498   #ifdef SDSUPPORT
1499   if(fromsd[bufindr])
1500     return;
1501   #endif //SDSUPPORT
1502   SERIAL_PROTOCOLLNPGM(MSG_OK); 
1503 }
1504
1505 void get_coordinates()
1506 {
1507   bool seen[4]={false,false,false,false};
1508   for(int8_t i=0; i < NUM_AXIS; i++) {
1509     if(code_seen(axis_codes[i])) 
1510     {
1511       destination[i] = (float)code_value() + (axis_relative_modes[i] || relative_mode)*current_position[i];
1512       seen[i]=true;
1513     }
1514     else destination[i] = current_position[i]; //Are these else lines really needed?
1515   }
1516   if(code_seen('F')) {
1517     next_feedrate = code_value();
1518     if(next_feedrate > 0.0) feedrate = next_feedrate;
1519   }
1520   #ifdef FWRETRACT
1521   if(autoretract_enabled)
1522   if( !(seen[X_AXIS] || seen[Y_AXIS] || seen[Z_AXIS]) && seen[E_AXIS])
1523   {
1524     float echange=destination[E_AXIS]-current_position[E_AXIS];
1525     if(echange<-MIN_RETRACT) //retract
1526     {
1527       if(!retracted) 
1528       {
1529       
1530       destination[Z_AXIS]+=retract_zlift; //not sure why chaninging current_position negatively does not work.
1531       //if slicer retracted by echange=-1mm and you want to retract 3mm, corrrectede=-2mm additionally
1532       float correctede=-echange-retract_length;
1533       //to generate the additional steps, not the destination is changed, but inversely the current position
1534       current_position[E_AXIS]+=-correctede; 
1535       feedrate=retract_feedrate;
1536       retracted=true;
1537       }
1538       
1539     }
1540     else 
1541       if(echange>MIN_RETRACT) //retract_recover
1542     {
1543       if(retracted) 
1544       {
1545       //current_position[Z_AXIS]+=-retract_zlift;
1546       //if slicer retracted_recovered by echange=+1mm and you want to retract_recover 3mm, corrrectede=2mm additionally
1547       float correctede=-echange+1*retract_length+retract_recover_length; //total unretract=retract_length+retract_recover_length[surplus]
1548       current_position[E_AXIS]+=correctede; //to generate the additional steps, not the destination is changed, but inversely the current position
1549       feedrate=retract_recover_feedrate;
1550       retracted=false;
1551       }
1552     }
1553     
1554   }
1555   #endif //FWRETRACT
1556 }
1557
1558 void get_arc_coordinates()
1559 {
1560    get_coordinates();
1561    if(code_seen('I')) {
1562      offset[0] = code_value();
1563    } 
1564    else {
1565      offset[0] = 0.0;
1566    }
1567    if(code_seen('J')) {
1568      offset[1] = code_value();
1569    }
1570    else {
1571      offset[1] = 0.0;
1572    }
1573 }
1574
1575 void clamp_to_software_endstops(float target[3])
1576 {
1577   if (min_software_endstops) {
1578     if (target[X_AXIS] < min_pos[X_AXIS]) target[X_AXIS] = min_pos[X_AXIS];
1579     if (target[Y_AXIS] < min_pos[Y_AXIS]) target[Y_AXIS] = min_pos[Y_AXIS];
1580     if (target[Z_AXIS] < min_pos[Z_AXIS]) target[Z_AXIS] = min_pos[Z_AXIS];
1581   }
1582
1583   if (max_software_endstops) {
1584     if (target[X_AXIS] > max_pos[X_AXIS]) target[X_AXIS] = max_pos[X_AXIS];
1585     if (target[Y_AXIS] > max_pos[Y_AXIS]) target[Y_AXIS] = max_pos[Y_AXIS];
1586     if (target[Z_AXIS] > max_pos[Z_AXIS]) target[Z_AXIS] = max_pos[Z_AXIS];
1587   }
1588 }
1589
1590 void prepare_move()
1591 {
1592   clamp_to_software_endstops(destination);
1593
1594   previous_millis_cmd = millis();  
1595   plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate*feedmultiply/60/100.0, active_extruder);
1596   for(int8_t i=0; i < NUM_AXIS; i++) {
1597     current_position[i] = destination[i];
1598   }
1599 }
1600
1601 void prepare_arc_move(char isclockwise) {
1602   float r = hypot(offset[X_AXIS], offset[Y_AXIS]); // Compute arc radius for mc_arc
1603
1604   // Trace the arc
1605   mc_arc(current_position, destination, offset, X_AXIS, Y_AXIS, Z_AXIS, feedrate*feedmultiply/60/100.0, r, isclockwise, active_extruder);
1606   
1607   // As far as the parser is concerned, the position is now == target. In reality the
1608   // motion control system might still be processing the action and the real tool position
1609   // in any intermediate location.
1610   for(int8_t i=0; i < NUM_AXIS; i++) {
1611     current_position[i] = destination[i];
1612   }
1613   previous_millis_cmd = millis();
1614 }
1615
1616 #ifdef CONTROLLERFAN_PIN
1617 unsigned long lastMotor = 0; //Save the time for when a motor was turned on last
1618 unsigned long lastMotorCheck = 0;
1619
1620 void controllerFan()
1621 {
1622   if ((millis() - lastMotorCheck) >= 2500) //Not a time critical function, so we only check every 2500ms
1623   {
1624     lastMotorCheck = millis();
1625     
1626     if(!READ(X_ENABLE_PIN) || !READ(Y_ENABLE_PIN) || !READ(Z_ENABLE_PIN)
1627     #if EXTRUDERS > 2
1628        || !READ(E2_ENABLE_PIN)
1629     #endif
1630     #if EXTRUDER > 1
1631        || !READ(E2_ENABLE_PIN)
1632     #endif
1633        || !READ(E0_ENABLE_PIN)) //If any of the drivers are enabled...    
1634     {
1635       lastMotor = millis(); //... set time to NOW so the fan will turn on
1636     }
1637     
1638     if ((millis() - lastMotor) >= (CONTROLLERFAN_SEC*1000UL) || lastMotor == 0) //If the last time any driver was enabled, is longer since than CONTROLLERSEC...   
1639     {
1640       WRITE(CONTROLLERFAN_PIN, LOW); //... turn the fan off
1641     }
1642     else
1643     {
1644       WRITE(CONTROLLERFAN_PIN, HIGH); //... turn the fan on
1645     }
1646   }
1647 }
1648 #endif
1649
1650 void manage_inactivity(byte debug) 
1651
1652   if( (millis() - previous_millis_cmd) >  max_inactive_time ) 
1653     if(max_inactive_time) 
1654       kill(); 
1655   if(stepper_inactive_time)  {
1656     if( (millis() - previous_millis_cmd) >  stepper_inactive_time ) 
1657     {
1658       if(blocks_queued() == false) {
1659         disable_x();
1660         disable_y();
1661         disable_z();
1662         disable_e0();
1663         disable_e1();
1664         disable_e2();
1665       }
1666     }
1667   }
1668   #ifdef CONTROLLERFAN_PIN
1669     controllerFan(); //Check if fan should be turned on to cool stepper drivers down
1670   #endif
1671   #ifdef EXTRUDER_RUNOUT_PREVENT
1672     if( (millis() - previous_millis_cmd) >  EXTRUDER_RUNOUT_SECONDS*1000 ) 
1673     if(degHotend(active_extruder)>EXTRUDER_RUNOUT_MINTEMP)
1674     {
1675      bool oldstatus=READ(E0_ENABLE_PIN);
1676      enable_e0();
1677      float oldepos=current_position[E_AXIS];
1678      float oldedes=destination[E_AXIS];
1679      plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], 
1680                       current_position[E_AXIS]+EXTRUDER_RUNOUT_EXTRUDE*EXTRUDER_RUNOUT_ESTEPS/axis_steps_per_unit[E_AXIS], 
1681                       EXTRUDER_RUNOUT_SPEED/60.*EXTRUDER_RUNOUT_ESTEPS/axis_steps_per_unit[E_AXIS], active_extruder);
1682      current_position[E_AXIS]=oldepos;
1683      destination[E_AXIS]=oldedes;
1684      plan_set_e_position(oldepos);
1685      previous_millis_cmd=millis();
1686      st_synchronize();
1687      WRITE(E0_ENABLE_PIN,oldstatus);
1688     }
1689   #endif
1690   check_axes_activity();
1691 }
1692
1693 void kill()
1694 {
1695   cli(); // Stop interrupts
1696   disable_heater();
1697
1698   disable_x();
1699   disable_y();
1700   disable_z();
1701   disable_e0();
1702   disable_e1();
1703   disable_e2();
1704   
1705   if(PS_ON_PIN > -1) pinMode(PS_ON_PIN,INPUT);
1706   SERIAL_ERROR_START;
1707   SERIAL_ERRORLNPGM(MSG_ERR_KILLED);
1708   LCD_MESSAGEPGM(MSG_KILLED);
1709   suicide();
1710   while(1); // Wait for reset
1711 }
1712
1713 void Stop()
1714 {
1715   disable_heater();
1716   if(Stopped == false) {
1717     Stopped = true;
1718     Stopped_gcode_LastN = gcode_LastN; // Save last g_code for restart
1719     SERIAL_ERROR_START;
1720     SERIAL_ERRORLNPGM(MSG_ERR_STOPPED);
1721     LCD_MESSAGEPGM(MSG_STOPPED);
1722   }
1723 }
1724
1725 bool IsStopped() { return Stopped; };
1726
1727 #ifdef FAST_PWM_FAN
1728 void setPwmFrequency(uint8_t pin, int val)
1729 {
1730   val &= 0x07;
1731   switch(digitalPinToTimer(pin))
1732   {
1733  
1734     #if defined(TCCR0A)
1735     case TIMER0A:
1736     case TIMER0B:
1737 //         TCCR0B &= ~(CS00 | CS01 | CS02);
1738 //         TCCR0B |= val;
1739          break;
1740     #endif
1741
1742     #if defined(TCCR1A)
1743     case TIMER1A:
1744     case TIMER1B:
1745 //         TCCR1B &= ~(CS10 | CS11 | CS12);
1746 //         TCCR1B |= val;
1747          break;
1748     #endif
1749
1750     #if defined(TCCR2)
1751     case TIMER2:
1752     case TIMER2:
1753          TCCR2 &= ~(CS10 | CS11 | CS12);
1754          TCCR2 |= val;
1755          break;
1756     #endif
1757
1758     #if defined(TCCR2A)
1759     case TIMER2A:
1760     case TIMER2B:
1761          TCCR2B &= ~(CS20 | CS21 | CS22);
1762          TCCR2B |= val;
1763          break;
1764     #endif
1765
1766     #if defined(TCCR3A)
1767     case TIMER3A:
1768     case TIMER3B:
1769     case TIMER3C:
1770          TCCR3B &= ~(CS30 | CS31 | CS32);
1771          TCCR3B |= val;
1772          break;
1773     #endif
1774
1775     #if defined(TCCR4A) 
1776     case TIMER4A:
1777     case TIMER4B:
1778     case TIMER4C:
1779          TCCR4B &= ~(CS40 | CS41 | CS42);
1780          TCCR4B |= val;
1781          break;
1782    #endif
1783
1784     #if defined(TCCR5A) 
1785     case TIMER5A:
1786     case TIMER5B:
1787     case TIMER5C:
1788          TCCR5B &= ~(CS50 | CS51 | CS52);
1789          TCCR5B |= val;
1790          break;
1791    #endif
1792
1793   }
1794 }
1795 #endif
1796
1797