Marlin.ino

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

mercurial