2012-08-08 18:56:39 +02:00
/* -*- c++ -*- */
2011-11-06 12:39:00 +01:00
/*
Reprap firmware based on Sprinter and grbl.
Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
This firmware is a mashup between Sprinter and grbl.
(https://github.com/kliment/Sprinter)
(https://github.com/simen/grbl/tree)
It has preliminary support for Matthew Roberts advance algorithm
http://reprap.org/pipermail/reprap-dev/2011-May/003323.html
*/
2011-12-22 12:38:50 +01:00
#include "Marlin.h"
2011-12-07 20:56:47 +01:00
2011-11-06 12:39:00 +01:00
#include "ultralcd.h"
#include "planner.h"
#include "stepper.h"
#include "temperature.h"
#include "motion_control.h"
2011-11-06 21:39:53 +01:00
#include "cardreader.h"
2011-11-15 20:54:40 +01:00
#include "watchdog.h"
2011-12-22 14:55:45 +01:00
#include "EEPROMwrite.h"
2012-02-20 23:22:46 +01:00
#include "language.h"
2012-05-02 19:26:14 +02:00
#include "pins_arduino.h"
2011-12-07 20:56:47 +01:00
2012-02-26 16:26:40 +01:00
#define VERSION_STRING "1.0.0 RC2"
2011-11-07 22:33:13 +01:00
2011-11-06 12:39:00 +01:00
// look here for descriptions of gcodes: http://linuxcnc.org/handbook/gcode/g-code.html
// http://objects.reprap.org/wiki/Mendel_User_Manual:_RepRapGCodes
//Implemented Codes
//-------------------
// G0 -> G1
// G1 - Coordinated Movement X Y Z E
// G2 - CW ARC
// G3 - CCW ARC
// G4 - Dwell S<seconds> or P<milliseconds>
2012-06-02 20:32:28 +02:00
// G10 - retract filament according to settings of M207
// G11 - retract recover filament according to settings of M208
2011-11-06 12:39:00 +01:00
// G28 - Home all Axis
// G90 - Use Absolute Coordinates
// G91 - Use Relative Coordinates
// G92 - Set current position to cordinates given
//RepRap M Codes
2012-05-20 14:37:30 +02:00
// M0 - Unconditional stop - Wait for user to press a button on the LCD (Only if ULTRA_LCD is enabled)
// M1 - Same as M0
2011-11-06 12:39:00 +01:00
// M104 - Set extruder target temp
// M105 - Read current temp
// M106 - Fan on
// M107 - Fan off
// M109 - Wait for extruder current temp to reach target temp.
// M114 - Display current position
//Custom M Codes
2011-11-19 18:22:22 +01:00
// M17 - Enable/Power all stepper motors
2011-11-19 21:01:07 +01:00
// M18 - Disable all stepper motors; same as M84
2011-11-06 12:39:00 +01:00
// M20 - List SD card
// M21 - Init SD card
// M22 - Release SD card
// M23 - Select SD file (M23 filename.g)
// M24 - Start/resume SD print
// M25 - Pause SD print
// M26 - Set SD position in bytes (M26 S12345)
// M27 - Report SD print status
// M28 - Start SD write (M28 filename.g)
// M29 - Stop SD write
2012-03-03 21:58:12 +01:00
// M30 - Delete file from SD (M30 filename.g)
// M31 - Output time since last M109 or SD card start to serial
2011-11-06 12:39:00 +01:00
// M42 - Change pin status via gcode
// M80 - Turn on Power Supply
// M81 - Turn off Power Supply
// M82 - Set E codes absolute (default)
// M83 - Set E codes relative while in Absolute Coordinates (G90) mode
// M84 - Disable steppers until next move,
// or use S<seconds> to specify an inactivity timeout, after which the steppers will be disabled. S0 to disable the timeout.
// M85 - Set inactivity shutdown timer with parameter S<seconds>. To disable set zero (default)
// M92 - Set axis_steps_per_unit - same syntax as G92
2011-11-19 21:01:07 +01:00
// M114 - Output current position to serial port
2011-11-06 12:39:00 +01:00
// M115 - Capabilities string
2011-11-27 16:53:11 +01:00
// M117 - display message
2011-11-19 21:01:07 +01:00
// M119 - Output Endstop status to serial port
2011-11-06 12:39:00 +01:00
// M140 - Set bed target temp
// M190 - Wait for bed current temp to reach target temp.
// M200 - Set filament diameter
// M201 - Set max acceleration in units/s^2 for print moves (M201 X1000 Y1000)
// M202 - Set max acceleration in units/s^2 for travel moves (M202 X1000 Y1000) Unused in Marlin!!
// M203 - Set maximum feedrate that your machine can sustain (M203 X200 Y200 Z300 E10000) in mm/sec
// 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
2012-03-04 16:34:58 +01:00
// 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
2011-11-27 17:27:17 +01:00
// M206 - set additional homeing offset
2012-06-02 20:32:28 +02:00
// M207 - set retract length S[positive mm] F[feedrate mm/sec] Z[additional zlift/hop]
// M208 - set recover=unretract length S[positive mm surplus to the M207 S*] F[feedrate mm/sec]
// 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.
2012-02-24 20:42:07 +01:00
// M220 S<factor in percent>- set speed factor override percentage
// M221 S<factor in percent>- set extrude factor override percentage
2011-12-22 12:11:39 +01:00
// M240 - Trigger a camera to take a photograph
2011-11-06 12:39:00 +01:00
// M301 - Set PID parameters P I and D
2011-12-09 15:09:52 +01:00
// M302 - Allow cold extrudes
2012-04-30 13:36:19 +02:00
// M303 - PID relay autotune S<temperature> sets the target temperature. (default target temperature = 150C)
2011-11-13 19:58:09 +01:00
// M400 - Finish all moves
2011-11-06 12:39:00 +01:00
// M500 - stores paramters in EEPROM
2011-11-09 20:27:15 +01:00
// M501 - reads parameters from EEPROM (if you need reset them after you changed them temporarily).
2011-11-06 12:39:00 +01:00
// M502 - reverts to the default "factory settings". You still need to store them in EEPROM afterwards if you want to.
2011-12-04 22:26:42 +01:00
// M503 - print the current settings (from memory not from eeprom)
2012-03-25 14:36:51 +02:00
// M999 - Restart after being stopped by error
2011-11-06 12:39:00 +01:00
//Stepper Movement Variables
2011-11-06 19:48:37 +01:00
//===========================================================================
//=============================imported variables============================
//===========================================================================
2011-11-06 12:39:00 +01:00
2011-11-06 21:39:53 +01:00
//===========================================================================
//=============================public variables=============================
//===========================================================================
2011-11-15 22:50:43 +01:00
#ifdef SDSUPPORT
2011-11-06 21:39:53 +01:00
CardReader card;
2011-11-15 22:50:43 +01:00
#endif
2011-11-06 12:39:00 +01:00
float homing_feedrate[] = HOMING_FEEDRATE;
bool axis_relative_modes[] = AXIS_RELATIVE_MODES;
volatile int feedmultiply=100; //100->1 200->2
int saved_feedmultiply;
volatile bool feedmultiplychanged=false;
2012-02-24 20:42:07 +01:00
volatile int extrudemultiply=100; //100->1 200->2
2011-12-06 05:33:33 +01:00
float current_position[NUM_AXIS] = { 0.0, 0.0, 0.0, 0.0 };
2011-11-27 17:27:17 +01:00
float add_homeing[3]={0,0,0};
M206: always use homing ("homeing") offsets
Previously the parameters set in M206 would only be used if a G82
command was sent with specific axis home values. This limits its
usefulness.
Really, we should have a way to adjust the XYZ homing of a machine in
the eeprom. So as the first stage of this, make M206 affect every
home command. The values set using M206 are now added to the
configuration variables [XYZ]_HOME_POS.
This is achieved by replacing all uses of [XYZ]_HOME_POS in the code
by a new home_pos[] which includes the adjustment. We also have to
adjust the uses of [XYZ]_{MIN,MAX}_POS similarly - see below.
To allow axis_is_at_home to be written as a function taking an axis
index rather than a macro taking an axis letter, we provide
constant arrays in program memory containing the values of
[XYZ]_{MIN,MAX,HOME}_POS from the compiled-in configuration.
This is done with some helper macros to deal with the declaration
(XYZ_CONSTS_FROM_CONFIG) and definition of the inline function which
does the program memory access.
We also introduce the overloaded function read_pgm_any, whose
instances are produced with DEFINE_PGM_READ_ANY, which allows the
access functions to automatically produce the correct type.
The type- and pointer-massaging code in the access function boils
down, when compiled, to a simple program memory access.
A question arises: if the M206 offset is set, should this adjustment
to the home position shift or change the possible range of movement
permitted by the software endstops ?
The documentation in Configuration.h describes these limits as:
// Travel limits after homing
Since this is a file containing physical limits, and actual suggested
values for these configuration parameters appear to include a certain
amount of slop, I've taken the view that these should be regarded as
nominal physical distances from the limit switches, and that the
permissible travel should be unaffected by M206.
So for example with the (rather unrealistic)
#define X_HOME_DIR -1
#define X_MIN_POS -20
#define X_HOME_POS 0
#define X_MAX_POS 100
no matter the setting of M206 X, the machine would be permitted
to move from 20mm "beyond" the limit switch trigger point in
the negative X direction and 100mm away from the limit switch in
the positive X direction, for a total travel of 120mm.
With M206 X-10 that would be considered to correspond to X coordinates
-30 to +90. With M206 X+10 that would be considered to correspond to
X coordinates -10 to +110.
fixes #200 (in ErikZalm/Marlin).
Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
2012-08-01 22:12:14 +02:00
float min_pos[3] = { X_MIN_POS, Y_MIN_POS, Z_MIN_POS };
float max_pos[3] = { X_MAX_POS, Y_MAX_POS, Z_MAX_POS };
2011-12-06 05:33:33 +01:00
uint8_t active_extruder = 0;
2012-03-04 13:05:26 +01:00
unsigned char FanSpeed=0;
2011-11-06 19:23:08 +01:00
2012-06-02 20:32:28 +02:00
#ifdef FWRETRACT
bool autoretract_enabled=true;
bool retracted=false;
float retract_length=3, retract_feedrate=17*60, retract_zlift=0.8;
float retract_recover_length=0, retract_recover_feedrate=8*60;
#endif
2012-03-25 14:36:51 +02:00
2011-11-06 19:48:37 +01:00
//===========================================================================
//=============================private variables=============================
//===========================================================================
const char axis_codes[NUM_AXIS] = {'X', 'Y', 'Z', 'E'};
static float destination[NUM_AXIS] = { 0.0, 0.0, 0.0, 0.0};
static float offset[3] = {0.0, 0.0, 0.0};
static bool home_all_axis = true;
static float feedrate = 1500.0, next_feedrate, saved_feedrate;
2012-03-25 14:36:51 +02:00
static long gcode_N, gcode_LastN, Stopped_gcode_LastN = 0;
2011-11-06 19:48:37 +01:00
static bool relative_mode = false; //Determines Absolute or Relative Coordinates
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.
static char cmdbuffer[BUFSIZE][MAX_CMD_SIZE];
static bool fromsd[BUFSIZE];
static int bufindr = 0;
static int bufindw = 0;
static int buflen = 0;
2012-01-15 17:06:10 +01:00
//static int i = 0;
2011-11-06 19:48:37 +01:00
static char serial_char;
static int serial_count = 0;
static boolean comment_mode = false;
static char *strchr_pointer; // just a pointer to find chars in the cmd string like X, Y, Z, E, etc
2011-11-06 12:39:00 +01:00
const int sensitive_pins[] = SENSITIVE_PINS; // Sensitive pin list for M42
2011-12-04 12:40:18 +01:00
//static float tt = 0;
//static float bt = 0;
2011-11-06 14:03:41 +01:00
2011-11-06 12:39:00 +01:00
//Inactivity shutdown variables
2011-11-06 19:48:37 +01:00
static unsigned long previous_millis_cmd = 0;
static unsigned long max_inactive_time = 0;
2012-02-09 19:38:53 +01:00
static unsigned long stepper_inactive_time = DEFAULT_STEPPER_DEACTIVE_TIME*1000l;
2011-11-06 19:48:37 +01:00
static unsigned long starttime=0;
static unsigned long stoptime=0;
2011-11-06 12:39:00 +01:00
2011-11-26 17:33:25 +01:00
static uint8_t tmp_extruder;
2011-11-06 19:23:08 +01:00
2012-06-02 20:32:28 +02:00
2012-03-25 14:36:51 +02:00
bool Stopped=false;
2011-11-27 21:12:55 +01:00
2011-11-06 19:48:37 +01:00
//===========================================================================
//=============================ROUTINES=============================
//===========================================================================
2011-11-06 19:23:08 +01:00
2011-11-19 13:13:34 +01:00
void get_arc_coordinates();
2011-11-06 12:39:00 +01:00
2012-08-04 17:13:25 +02:00
void serial_echopair_P(const char *s_P, float v)
{ serialprintPGM(s_P); SERIAL_ECHO(v); }
void serial_echopair_P(const char *s_P, double v)
{ serialprintPGM(s_P); SERIAL_ECHO(v); }
void serial_echopair_P(const char *s_P, unsigned long v)
{ serialprintPGM(s_P); SERIAL_ECHO(v); }
2011-11-07 22:33:13 +01:00
extern "C"{
extern unsigned int __bss_end;
extern unsigned int __heap_start;
extern void *__brkval;
int freeMemory() {
int free_memory;
if((int)__brkval == 0)
free_memory = ((int)&free_memory) - ((int)&__bss_end);
else
free_memory = ((int)&free_memory) - ((int)__brkval);
return free_memory;
}
}
2011-11-06 19:23:08 +01:00
//adds an command to the main command buffer
//thats really done in a non-safe way.
//needs overworking someday
2011-11-06 12:39:00 +01:00
void enquecommand(const char *cmd)
{
if(buflen < BUFSIZE)
{
//this is dangerous if a mixing of serial and this happsens
strcpy(&(cmdbuffer[bufindw][0]),cmd);
2011-11-09 20:27:15 +01:00
SERIAL_ECHO_START;
SERIAL_ECHOPGM("enqueing \"");
SERIAL_ECHO(cmdbuffer[bufindw]);
SERIAL_ECHOLNPGM("\"");
2011-11-06 12:39:00 +01:00
bufindw= (bufindw + 1)%BUFSIZE;
buflen += 1;
}
}
2012-02-08 18:28:54 +01:00
2011-12-22 12:11:39 +01:00
void setup_photpin()
{
#ifdef PHOTOGRAPH_PIN
#if (PHOTOGRAPH_PIN > -1)
SET_OUTPUT(PHOTOGRAPH_PIN);
WRITE(PHOTOGRAPH_PIN, LOW);
#endif
#endif
}
2012-01-15 17:06:10 +01:00
void setup_powerhold()
{
#ifdef SUICIDE_PIN
2012-02-13 12:31:53 +01:00
#if (SUICIDE_PIN> -1)
2012-01-15 17:06:10 +01:00
SET_OUTPUT(SUICIDE_PIN);
WRITE(SUICIDE_PIN, HIGH);
2012-02-13 12:31:53 +01:00
#endif
#endif
2012-01-15 17:06:10 +01:00
}
void suicide()
{
#ifdef SUICIDE_PIN
#if (SUICIDE_PIN> -1)
SET_OUTPUT(SUICIDE_PIN);
WRITE(SUICIDE_PIN, LOW);
#endif
#endif
}
2011-11-06 12:39:00 +01:00
void setup()
{
2012-01-15 17:06:10 +01:00
setup_powerhold();
2012-02-11 16:02:47 +01:00
MYSERIAL.begin(BAUDRATE);
2012-02-09 20:26:17 +01:00
SERIAL_PROTOCOLLNPGM("start");
2011-11-09 20:27:15 +01:00
SERIAL_ECHO_START;
2012-02-20 08:30:31 +01:00
// Check startup - does nothing if bootloader sets MCUSR to 0
byte mcu = MCUSR;
2012-03-03 16:51:47 +01:00
if(mcu & 1) SERIAL_ECHOLNPGM(MSG_POWERUP);
if(mcu & 2) SERIAL_ECHOLNPGM(MSG_EXTERNAL_RESET);
if(mcu & 4) SERIAL_ECHOLNPGM(MSG_BROWNOUT_RESET);
if(mcu & 8) SERIAL_ECHOLNPGM(MSG_WATCHDOG_RESET);
if(mcu & 32) SERIAL_ECHOLNPGM(MSG_SOFTWARE_RESET);
2012-02-20 08:30:31 +01:00
MCUSR=0;
2012-03-03 16:51:47 +01:00
SERIAL_ECHOPGM(MSG_MARLIN);
2011-11-13 19:58:09 +01:00
SERIAL_ECHOLNPGM(VERSION_STRING);
2012-02-09 20:26:17 +01:00
#ifdef STRING_VERSION_CONFIG_H
#ifdef STRING_CONFIG_H_AUTHOR
SERIAL_ECHO_START;
2012-03-03 16:51:47 +01:00
SERIAL_ECHOPGM(MSG_CONFIGURATION_VER);
2012-02-09 20:26:17 +01:00
SERIAL_ECHOPGM(STRING_VERSION_CONFIG_H);
2012-03-03 16:51:47 +01:00
SERIAL_ECHOPGM(MSG_AUTHOR);
2012-02-09 20:26:17 +01:00
SERIAL_ECHOLNPGM(STRING_CONFIG_H_AUTHOR);
#endif
#endif
2011-11-09 20:27:15 +01:00
SERIAL_ECHO_START;
2012-03-03 16:51:47 +01:00
SERIAL_ECHOPGM(MSG_FREE_MEMORY);
2011-12-11 15:42:56 +01:00
SERIAL_ECHO(freeMemory());
2012-03-03 16:51:47 +01:00
SERIAL_ECHOPGM(MSG_PLANNER_BUFFER_BYTES);
2011-12-11 15:42:56 +01:00
SERIAL_ECHOLN((int)sizeof(block_t)*BLOCK_BUFFER_SIZE);
2011-11-06 23:21:12 +01:00
for(int8_t i = 0; i < BUFSIZE; i++)
2011-11-06 19:23:08 +01:00
{
2011-11-06 12:39:00 +01:00
fromsd[i] = false;
}
2011-12-04 22:26:42 +01:00
EEPROM_RetrieveSettings(); // loads data from EEPROM if available
2011-11-06 12:39:00 +01:00
2011-11-06 23:21:12 +01:00
for(int8_t i=0; i < NUM_AXIS; i++)
2011-11-06 19:23:08 +01:00
{
2011-11-06 12:39:00 +01:00
axis_steps_per_sqr_second[i] = max_acceleration_units_per_sq_second[i] * axis_steps_per_unit[i];
}
2012-03-11 10:44:10 +01:00
2011-11-18 18:59:17 +01:00
tp_init(); // Initialize temperature loop
2011-11-06 12:39:00 +01:00
plan_init(); // Initialize planner;
st_init(); // Initialize stepper;
2011-11-15 20:54:40 +01:00
wd_init();
2011-12-22 12:11:39 +01:00
setup_photpin();
2012-05-03 14:28:17 +02:00
LCD_INIT;
2011-11-06 12:39:00 +01:00
}
void loop()
{
2012-03-03 20:15:41 +01:00
if(buflen < (BUFSIZE-1))
2011-11-06 12:39:00 +01:00
get_command();
2011-11-15 22:50:43 +01:00
#ifdef SDSUPPORT
2011-11-06 21:39:53 +01:00
card.checkautostart(false);
2011-11-15 22:50:43 +01:00
#endif
2011-11-06 12:39:00 +01:00
if(buflen)
{
2011-11-06 19:23:08 +01:00
#ifdef SDSUPPORT
2011-11-06 22:48:15 +01:00
if(card.saving)
2011-11-06 19:23:08 +01:00
{
if(strstr(cmdbuffer[bufindr],"M29") == NULL)
{
2011-11-06 21:39:53 +01:00
card.write_command(cmdbuffer[bufindr]);
2012-03-03 16:51:47 +01:00
SERIAL_PROTOCOLLNPGM(MSG_OK);
2011-11-06 19:23:08 +01:00
}
else
{
2011-11-06 21:39:53 +01:00
card.closefile();
2012-03-03 16:51:47 +01:00
SERIAL_PROTOCOLLNPGM(MSG_FILE_SAVED);
2011-11-06 19:23:08 +01:00
}
2011-11-06 12:39:00 +01:00
}
2011-11-06 19:23:08 +01:00
else
{
process_commands();
2011-11-06 12:39:00 +01:00
}
2011-11-06 19:23:08 +01:00
#else
2011-11-06 12:39:00 +01:00
process_commands();
2011-11-06 19:23:08 +01:00
#endif //SDSUPPORT
2011-11-06 12:39:00 +01:00
buflen = (buflen-1);
bufindr = (bufindr + 1)%BUFSIZE;
}
//check heater every n milliseconds
manage_heater();
manage_inactivity(1);
2011-11-13 19:58:09 +01:00
checkHitEndstops();
2011-11-06 12:39:00 +01:00
LCD_STATUS;
}
2012-02-05 12:42:15 +01:00
void get_command()
2011-11-06 12:39:00 +01:00
{
2012-02-11 16:02:47 +01:00
while( MYSERIAL.available() > 0 && buflen < BUFSIZE) {
serial_char = MYSERIAL.read();
2012-03-25 14:41:26 +02:00
if(serial_char == '\n' ||
serial_char == '\r' ||
(serial_char == ':' && comment_mode == false) ||
serial_count >= (MAX_CMD_SIZE - 1) )
2011-11-06 12:39:00 +01:00
{
2012-02-24 20:42:07 +01:00
if(!serial_count) { //if empty line
comment_mode = false; //for new command
return;
}
2011-11-06 12:39:00 +01:00
cmdbuffer[bufindw][serial_count] = 0; //terminate string
if(!comment_mode){
2012-02-24 20:42:07 +01:00
comment_mode = false; //for new command
2011-11-06 12:39:00 +01:00
fromsd[bufindw] = false;
if(strstr(cmdbuffer[bufindw], "N") != NULL)
{
strchr_pointer = strchr(cmdbuffer[bufindw], 'N');
gcode_N = (strtol(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL, 10));
if(gcode_N != gcode_LastN+1 && (strstr(cmdbuffer[bufindw], "M110") == NULL) ) {
2011-11-09 20:27:15 +01:00
SERIAL_ERROR_START;
2012-03-03 16:51:47 +01:00
SERIAL_ERRORPGM(MSG_ERR_LINE_NO);
2011-11-09 20:27:15 +01:00
SERIAL_ERRORLN(gcode_LastN);
2011-11-06 12:39:00 +01:00
//Serial.println(gcode_N);
FlushSerialRequestResend();
serial_count = 0;
return;
}
if(strstr(cmdbuffer[bufindw], "*") != NULL)
{
byte checksum = 0;
byte count = 0;
while(cmdbuffer[bufindw][count] != '*') checksum = checksum^cmdbuffer[bufindw][count++];
strchr_pointer = strchr(cmdbuffer[bufindw], '*');
if( (int)(strtod(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL)) != checksum) {
2011-11-09 20:27:15 +01:00
SERIAL_ERROR_START;
2012-03-03 16:51:47 +01:00
SERIAL_ERRORPGM(MSG_ERR_CHECKSUM_MISMATCH);
2011-11-09 20:27:15 +01:00
SERIAL_ERRORLN(gcode_LastN);
2011-11-06 12:39:00 +01:00
FlushSerialRequestResend();
serial_count = 0;
return;
}
//if no errors, continue parsing
}
else
{
2011-11-09 20:27:15 +01:00
SERIAL_ERROR_START;
2012-03-03 16:51:47 +01:00
SERIAL_ERRORPGM(MSG_ERR_NO_CHECKSUM);
2011-11-09 20:27:15 +01:00
SERIAL_ERRORLN(gcode_LastN);
2011-11-06 12:39:00 +01:00
FlushSerialRequestResend();
serial_count = 0;
return;
}
gcode_LastN = gcode_N;
//if no errors, continue parsing
}
else // if we don't receive 'N' but still see '*'
{
if((strstr(cmdbuffer[bufindw], "*") != NULL))
{
2011-11-09 20:27:15 +01:00
SERIAL_ERROR_START;
2012-03-03 16:51:47 +01:00
SERIAL_ERRORPGM(MSG_ERR_NO_LINENUMBER_WITH_CHECKSUM);
2011-11-09 20:27:15 +01:00
SERIAL_ERRORLN(gcode_LastN);
2011-11-06 12:39:00 +01:00
serial_count = 0;
return;
}
}
if((strstr(cmdbuffer[bufindw], "G") != NULL)){
strchr_pointer = strchr(cmdbuffer[bufindw], 'G');
switch((int)((strtod(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL)))){
case 0:
case 1:
case 2:
case 3:
2012-03-25 14:36:51 +02:00
if(Stopped == false) { // If printer is stopped by an error the G[0-3] codes are ignored.
#ifdef SDSUPPORT
if(card.saving)
break;
#endif //SDSUPPORT
SERIAL_PROTOCOLLNPGM(MSG_OK);
}
else {
SERIAL_ERRORLNPGM(MSG_ERR_STOPPED);
LCD_MESSAGEPGM(MSG_STOPPED);
}
2011-11-06 12:39:00 +01:00
break;
default:
break;
}
}
bufindw = (bufindw + 1)%BUFSIZE;
buflen += 1;
}
serial_count = 0; //clear buffer
}
else
{
if(serial_char == ';') comment_mode = true;
if(!comment_mode) cmdbuffer[bufindw][serial_count++] = serial_char;
}
}
2011-11-06 19:23:08 +01:00
#ifdef SDSUPPORT
2011-11-06 22:48:15 +01:00
if(!card.sdprinting || serial_count!=0){
2011-11-06 12:39:00 +01:00
return;
}
2011-11-06 22:48:15 +01:00
while( !card.eof() && buflen < BUFSIZE) {
2011-11-09 20:27:15 +01:00
int16_t n=card.get();
serial_char = (char)n;
2012-03-25 14:41:26 +02:00
if(serial_char == '\n' ||
serial_char == '\r' ||
(serial_char == ':' && comment_mode == false) ||
serial_count >= (MAX_CMD_SIZE - 1)||n==-1)
2011-11-06 12:39:00 +01:00
{
2011-11-06 22:48:15 +01:00
if(card.eof()){
2012-03-03 16:51:47 +01:00
SERIAL_PROTOCOLLNPGM(MSG_FILE_PRINTED);
2011-11-06 19:23:08 +01:00
stoptime=millis();
char time[30];
unsigned long t=(stoptime-starttime)/1000;
int sec,min;
min=t/60;
sec=t%60;
2011-11-07 22:33:13 +01:00
sprintf(time,"%i min, %i sec",min,sec);
2011-11-09 20:27:15 +01:00
SERIAL_ECHO_START;
2011-11-07 22:33:13 +01:00
SERIAL_ECHOLN(time);
2011-11-06 19:23:08 +01:00
LCD_MESSAGE(time);
2011-11-28 22:09:17 +01:00
card.printingHasFinished();
2011-11-06 21:39:53 +01:00
card.checkautostart(true);
2011-11-28 22:09:17 +01:00
2011-11-06 12:39:00 +01:00
}
2011-11-18 22:17:37 +01:00
if(!serial_count)
{
2012-02-24 20:42:07 +01:00
comment_mode = false; //for new command
2011-11-18 22:17:37 +01:00
return; //if empty line
}
2011-11-06 12:39:00 +01:00
cmdbuffer[bufindw][serial_count] = 0; //terminate string
2012-03-03 21:28:33 +01:00
// if(!comment_mode){
2011-11-06 12:39:00 +01:00
fromsd[bufindw] = true;
buflen += 1;
bufindw = (bufindw + 1)%BUFSIZE;
2012-03-03 21:28:33 +01:00
// }
2012-02-24 20:42:07 +01:00
comment_mode = false; //for new command
2011-11-06 12:39:00 +01:00
serial_count = 0; //clear buffer
}
else
{
if(serial_char == ';') comment_mode = true;
if(!comment_mode) cmdbuffer[bufindw][serial_count++] = serial_char;
}
}
2011-11-09 20:27:15 +01:00
2011-11-06 19:23:08 +01:00
#endif //SDSUPPORT
2011-11-06 12:39:00 +01:00
}
2012-02-05 12:42:15 +01:00
float code_value()
2011-11-06 19:23:08 +01:00
{
2011-11-06 12:39:00 +01:00
return (strtod(&cmdbuffer[bufindr][strchr_pointer - cmdbuffer[bufindr] + 1], NULL));
}
2012-02-28 18:20:03 +01:00
2012-02-05 12:42:15 +01:00
long code_value_long()
2011-11-06 19:23:08 +01:00
{
2011-11-06 12:39:00 +01:00
return (strtol(&cmdbuffer[bufindr][strchr_pointer - cmdbuffer[bufindr] + 1], NULL, 10));
}
2012-02-28 18:20:03 +01:00
2012-02-05 12:42:15 +01:00
bool code_seen(char code_string[]) //Return True if the string was found
2011-11-06 19:23:08 +01:00
{
2011-11-06 12:39:00 +01:00
return (strstr(cmdbuffer[bufindr], code_string) != NULL);
2011-11-06 19:23:08 +01:00
}
2011-11-06 12:39:00 +01:00
2012-02-05 12:42:15 +01:00
bool code_seen(char code)
2011-11-06 12:39:00 +01:00
{
strchr_pointer = strchr(cmdbuffer[bufindr], code);
return (strchr_pointer != NULL); //Return True if a character was found
}
2012-02-28 18:20:03 +01:00
M206: always use homing ("homeing") offsets
Previously the parameters set in M206 would only be used if a G82
command was sent with specific axis home values. This limits its
usefulness.
Really, we should have a way to adjust the XYZ homing of a machine in
the eeprom. So as the first stage of this, make M206 affect every
home command. The values set using M206 are now added to the
configuration variables [XYZ]_HOME_POS.
This is achieved by replacing all uses of [XYZ]_HOME_POS in the code
by a new home_pos[] which includes the adjustment. We also have to
adjust the uses of [XYZ]_{MIN,MAX}_POS similarly - see below.
To allow axis_is_at_home to be written as a function taking an axis
index rather than a macro taking an axis letter, we provide
constant arrays in program memory containing the values of
[XYZ]_{MIN,MAX,HOME}_POS from the compiled-in configuration.
This is done with some helper macros to deal with the declaration
(XYZ_CONSTS_FROM_CONFIG) and definition of the inline function which
does the program memory access.
We also introduce the overloaded function read_pgm_any, whose
instances are produced with DEFINE_PGM_READ_ANY, which allows the
access functions to automatically produce the correct type.
The type- and pointer-massaging code in the access function boils
down, when compiled, to a simple program memory access.
A question arises: if the M206 offset is set, should this adjustment
to the home position shift or change the possible range of movement
permitted by the software endstops ?
The documentation in Configuration.h describes these limits as:
// Travel limits after homing
Since this is a file containing physical limits, and actual suggested
values for these configuration parameters appear to include a certain
amount of slop, I've taken the view that these should be regarded as
nominal physical distances from the limit switches, and that the
permissible travel should be unaffected by M206.
So for example with the (rather unrealistic)
#define X_HOME_DIR -1
#define X_MIN_POS -20
#define X_HOME_POS 0
#define X_MAX_POS 100
no matter the setting of M206 X, the machine would be permitted
to move from 20mm "beyond" the limit switch trigger point in
the negative X direction and 100mm away from the limit switch in
the positive X direction, for a total travel of 120mm.
With M206 X-10 that would be considered to correspond to X coordinates
-30 to +90. With M206 X+10 that would be considered to correspond to
X coordinates -10 to +110.
fixes #200 (in ErikZalm/Marlin).
Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
2012-08-01 22:12:14 +02:00
#define DEFINE_PGM_READ_ANY(type, reader) \
static inline type pgm_read_any(const type *p) \
{ return pgm_read_##reader##_near(p); }
DEFINE_PGM_READ_ANY(float, float);
#define XYZ_CONSTS_FROM_CONFIG(type, array, CONFIG) \
static const PROGMEM type array##_P[3] = \
{ X_##CONFIG, Y_##CONFIG, Z_##CONFIG }; \
static inline type array(int axis) \
{ return pgm_read_any(&array##_P[axis]); }
XYZ_CONSTS_FROM_CONFIG(float, base_min_pos, MIN_POS);
XYZ_CONSTS_FROM_CONFIG(float, base_max_pos, MAX_POS);
XYZ_CONSTS_FROM_CONFIG(float, base_home_pos, HOME_POS);
static void axis_is_at_home(int axis) {
current_position[axis] = base_home_pos(axis) + add_homeing[axis];
min_pos[axis] = base_min_pos(axis) + add_homeing[axis];
max_pos[axis] = base_max_pos(axis) + add_homeing[axis];
}
2011-11-06 23:13:19 +01:00
#define HOMEAXIS(LETTER) \
if ((LETTER##_MIN_PIN > -1 && LETTER##_HOME_DIR==-1) || (LETTER##_MAX_PIN > -1 && LETTER##_HOME_DIR==1))\
{ \
current_position[LETTER##_AXIS] = 0; \
plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); \
destination[LETTER##_AXIS] = 1.5 * LETTER##_MAX_LENGTH * LETTER##_HOME_DIR; \
feedrate = homing_feedrate[LETTER##_AXIS]; \
2011-12-12 19:34:37 +01:00
plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder); \
2012-02-27 18:31:40 +01:00
st_synchronize();\
2011-11-06 23:13:19 +01:00
\
current_position[LETTER##_AXIS] = 0;\
plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);\
2011-11-26 12:04:06 +01:00
destination[LETTER##_AXIS] = -LETTER##_HOME_RETRACT_MM * LETTER##_HOME_DIR;\
2011-12-12 19:34:37 +01:00
plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder); \
2012-02-27 18:31:40 +01:00
st_synchronize();\
2011-11-06 23:13:19 +01:00
\
2011-11-26 12:04:06 +01:00
destination[LETTER##_AXIS] = 2*LETTER##_HOME_RETRACT_MM * LETTER##_HOME_DIR;\
2011-11-06 23:13:19 +01:00
feedrate = homing_feedrate[LETTER##_AXIS]/2 ; \
2011-12-12 19:34:37 +01:00
plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder); \
2012-02-27 18:31:40 +01:00
st_synchronize();\
2011-11-06 23:13:19 +01:00
\
M206: always use homing ("homeing") offsets
Previously the parameters set in M206 would only be used if a G82
command was sent with specific axis home values. This limits its
usefulness.
Really, we should have a way to adjust the XYZ homing of a machine in
the eeprom. So as the first stage of this, make M206 affect every
home command. The values set using M206 are now added to the
configuration variables [XYZ]_HOME_POS.
This is achieved by replacing all uses of [XYZ]_HOME_POS in the code
by a new home_pos[] which includes the adjustment. We also have to
adjust the uses of [XYZ]_{MIN,MAX}_POS similarly - see below.
To allow axis_is_at_home to be written as a function taking an axis
index rather than a macro taking an axis letter, we provide
constant arrays in program memory containing the values of
[XYZ]_{MIN,MAX,HOME}_POS from the compiled-in configuration.
This is done with some helper macros to deal with the declaration
(XYZ_CONSTS_FROM_CONFIG) and definition of the inline function which
does the program memory access.
We also introduce the overloaded function read_pgm_any, whose
instances are produced with DEFINE_PGM_READ_ANY, which allows the
access functions to automatically produce the correct type.
The type- and pointer-massaging code in the access function boils
down, when compiled, to a simple program memory access.
A question arises: if the M206 offset is set, should this adjustment
to the home position shift or change the possible range of movement
permitted by the software endstops ?
The documentation in Configuration.h describes these limits as:
// Travel limits after homing
Since this is a file containing physical limits, and actual suggested
values for these configuration parameters appear to include a certain
amount of slop, I've taken the view that these should be regarded as
nominal physical distances from the limit switches, and that the
permissible travel should be unaffected by M206.
So for example with the (rather unrealistic)
#define X_HOME_DIR -1
#define X_MIN_POS -20
#define X_HOME_POS 0
#define X_MAX_POS 100
no matter the setting of M206 X, the machine would be permitted
to move from 20mm "beyond" the limit switch trigger point in
the negative X direction and 100mm away from the limit switch in
the positive X direction, for a total travel of 120mm.
With M206 X-10 that would be considered to correspond to X coordinates
-30 to +90. With M206 X+10 that would be considered to correspond to
X coordinates -10 to +110.
fixes #200 (in ErikZalm/Marlin).
Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
2012-08-01 22:12:14 +02:00
axis_is_at_home(LETTER##_AXIS); \
destination[LETTER##_AXIS] = current_position[LETTER##_AXIS]; \
2011-11-06 23:13:19 +01:00
feedrate = 0.0;\
2011-11-13 19:58:09 +01:00
endstops_hit_on_purpose();\
2011-11-06 23:13:19 +01:00
}
2011-11-06 12:39:00 +01:00
2012-02-05 12:42:15 +01:00
void process_commands()
2011-11-06 12:39:00 +01:00
{
unsigned long codenum; //throw away variable
char *starpos = NULL;
if(code_seen('G'))
{
switch((int)code_value())
{
case 0: // G0 -> G1
case 1: // G1
2012-03-25 14:36:51 +02:00
if(Stopped == false) {
get_coordinates(); // For X Y Z E F
prepare_move();
//ClearToSend();
return;
}
2011-11-06 12:39:00 +01:00
//break;
case 2: // G2 - CW ARC
2012-03-25 14:36:51 +02:00
if(Stopped == false) {
get_arc_coordinates();
prepare_arc_move(true);
return;
}
2011-11-06 12:39:00 +01:00
case 3: // G3 - CCW ARC
2012-03-25 14:36:51 +02:00
if(Stopped == false) {
get_arc_coordinates();
prepare_arc_move(false);
return;
}
2011-11-06 12:39:00 +01:00
case 4: // G4 dwell
2012-03-03 16:51:47 +01:00
LCD_MESSAGEPGM(MSG_DWELL);
2011-11-06 12:39:00 +01:00
codenum = 0;
if(code_seen('P')) codenum = code_value(); // milliseconds to wait
if(code_seen('S')) codenum = code_value() * 1000; // seconds to wait
2011-11-26 09:03:12 +01:00
st_synchronize();
2012-02-08 18:28:54 +01:00
codenum += millis(); // keep track of when we started waiting
2011-12-09 13:39:00 +01:00
previous_millis_cmd = millis();
2012-02-08 18:28:54 +01:00
while(millis() < codenum ){
2011-11-06 12:39:00 +01:00
manage_heater();
2012-03-11 17:59:44 +01:00
manage_inactivity(1);
2012-05-19 17:54:07 +02:00
LCD_STATUS;
2011-11-06 12:39:00 +01:00
}
break;
2012-06-02 20:32:28 +02:00
#ifdef FWRETRACT
case 10: // G10 retract
if(!retracted)
{
destination[X_AXIS]=current_position[X_AXIS];
destination[Y_AXIS]=current_position[Y_AXIS];
destination[Z_AXIS]=current_position[Z_AXIS];
current_position[Z_AXIS]+=-retract_zlift;
destination[E_AXIS]=current_position[E_AXIS]-retract_length;
feedrate=retract_feedrate;
retracted=true;
prepare_move();
}
break;
case 11: // G10 retract_recover
if(!retracted)
{
destination[X_AXIS]=current_position[X_AXIS];
destination[Y_AXIS]=current_position[Y_AXIS];
destination[Z_AXIS]=current_position[Z_AXIS];
current_position[Z_AXIS]+=retract_zlift;
current_position[E_AXIS]+=-retract_recover_length;
feedrate=retract_recover_feedrate;
retracted=false;
prepare_move();
}
break;
#endif //FWRETRACT
2011-11-06 12:39:00 +01:00
case 28: //G28 Home all Axis one at a time
saved_feedrate = feedrate;
saved_feedmultiply = feedmultiply;
feedmultiply = 100;
2012-03-09 20:20:01 +01:00
previous_millis_cmd = millis();
2011-11-06 12:39:00 +01:00
2011-12-04 20:17:21 +01:00
enable_endstops(true);
2011-11-06 23:21:12 +01:00
for(int8_t i=0; i < NUM_AXIS; i++) {
2011-11-06 12:39:00 +01:00
destination[i] = current_position[i];
}
feedrate = 0.0;
home_all_axis = !((code_seen(axis_codes[0])) || (code_seen(axis_codes[1])) || (code_seen(axis_codes[2])));
2012-06-02 14:17:47 +02:00
#if Z_HOME_DIR > 0 // If homing away from BED do Z first
if((home_all_axis) || (code_seen(axis_codes[Z_AXIS]))) {
HOMEAXIS(Z);
}
#endif
2011-12-04 09:02:09 +01:00
#ifdef QUICK_HOME
2012-04-22 20:44:27 +02:00
if((home_all_axis)||( code_seen(axis_codes[X_AXIS]) && code_seen(axis_codes[Y_AXIS])) ) //first diagonal move
2011-11-29 22:06:31 +01:00
{
2011-12-07 20:54:34 +01:00
current_position[X_AXIS] = 0;current_position[Y_AXIS] = 0;
2011-12-12 19:34:37 +01:00
2011-11-29 22:06:31 +01:00
plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
2011-12-07 20:54:34 +01:00
destination[X_AXIS] = 1.5 * X_MAX_LENGTH * X_HOME_DIR;destination[Y_AXIS] = 1.5 * Y_MAX_LENGTH * Y_HOME_DIR;
feedrate = homing_feedrate[X_AXIS];
2011-11-29 22:06:31 +01:00
if(homing_feedrate[Y_AXIS]<feedrate)
feedrate =homing_feedrate[Y_AXIS];
2012-02-28 18:20:03 +01:00
plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder);
2012-02-27 18:31:40 +01:00
st_synchronize();
2011-12-07 20:54:34 +01:00
M206: always use homing ("homeing") offsets
Previously the parameters set in M206 would only be used if a G82
command was sent with specific axis home values. This limits its
usefulness.
Really, we should have a way to adjust the XYZ homing of a machine in
the eeprom. So as the first stage of this, make M206 affect every
home command. The values set using M206 are now added to the
configuration variables [XYZ]_HOME_POS.
This is achieved by replacing all uses of [XYZ]_HOME_POS in the code
by a new home_pos[] which includes the adjustment. We also have to
adjust the uses of [XYZ]_{MIN,MAX}_POS similarly - see below.
To allow axis_is_at_home to be written as a function taking an axis
index rather than a macro taking an axis letter, we provide
constant arrays in program memory containing the values of
[XYZ]_{MIN,MAX,HOME}_POS from the compiled-in configuration.
This is done with some helper macros to deal with the declaration
(XYZ_CONSTS_FROM_CONFIG) and definition of the inline function which
does the program memory access.
We also introduce the overloaded function read_pgm_any, whose
instances are produced with DEFINE_PGM_READ_ANY, which allows the
access functions to automatically produce the correct type.
The type- and pointer-massaging code in the access function boils
down, when compiled, to a simple program memory access.
A question arises: if the M206 offset is set, should this adjustment
to the home position shift or change the possible range of movement
permitted by the software endstops ?
The documentation in Configuration.h describes these limits as:
// Travel limits after homing
Since this is a file containing physical limits, and actual suggested
values for these configuration parameters appear to include a certain
amount of slop, I've taken the view that these should be regarded as
nominal physical distances from the limit switches, and that the
permissible travel should be unaffected by M206.
So for example with the (rather unrealistic)
#define X_HOME_DIR -1
#define X_MIN_POS -20
#define X_HOME_POS 0
#define X_MAX_POS 100
no matter the setting of M206 X, the machine would be permitted
to move from 20mm "beyond" the limit switch trigger point in
the negative X direction and 100mm away from the limit switch in
the positive X direction, for a total travel of 120mm.
With M206 X-10 that would be considered to correspond to X coordinates
-30 to +90. With M206 X+10 that would be considered to correspond to
X coordinates -10 to +110.
fixes #200 (in ErikZalm/Marlin).
Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
2012-08-01 22:12:14 +02:00
axis_is_at_home(X_AXIS);
axis_is_at_home(Y_AXIS);
2011-12-07 20:54:34 +01:00
plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
destination[X_AXIS] = current_position[X_AXIS];
destination[Y_AXIS] = current_position[Y_AXIS];
2012-02-28 18:20:03 +01:00
plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder);
2011-12-07 20:54:34 +01:00
feedrate = 0.0;
st_synchronize();
endstops_hit_on_purpose();
2011-11-29 22:06:31 +01:00
}
2011-12-04 09:02:09 +01:00
#endif
2011-11-29 22:06:31 +01:00
2011-11-06 19:23:08 +01:00
if((home_all_axis) || (code_seen(axis_codes[X_AXIS])))
{
2011-11-06 23:13:19 +01:00
HOMEAXIS(X);
2011-11-06 12:39:00 +01:00
}
if((home_all_axis) || (code_seen(axis_codes[Y_AXIS]))) {
2012-06-02 14:17:47 +02:00
HOMEAXIS(Y);
2011-11-06 12:39:00 +01:00
}
2012-02-21 20:17:28 +01:00
2012-06-02 14:17:47 +02:00
#if Z_HOME_DIR < 0 // If homing towards BED do Z last
2011-11-06 12:39:00 +01:00
if((home_all_axis) || (code_seen(axis_codes[Z_AXIS]))) {
2011-11-06 23:13:19 +01:00
HOMEAXIS(Z);
2011-12-07 20:54:34 +01:00
}
2012-06-02 14:17:47 +02:00
#endif
2011-12-07 20:54:34 +01:00
if(code_seen(axis_codes[X_AXIS]))
{
2012-02-28 18:20:03 +01:00
if(code_value_long() != 0) {
current_position[X_AXIS]=code_value()+add_homeing[0];
}
2011-12-07 20:54:34 +01:00
}
if(code_seen(axis_codes[Y_AXIS])) {
2012-02-28 18:20:03 +01:00
if(code_value_long() != 0) {
current_position[Y_AXIS]=code_value()+add_homeing[1];
}
2011-12-07 20:54:34 +01:00
}
if(code_seen(axis_codes[Z_AXIS])) {
2012-02-28 18:20:03 +01:00
if(code_value_long() != 0) {
current_position[Z_AXIS]=code_value()+add_homeing[2];
}
2011-12-07 20:54:34 +01:00
}
2012-02-21 20:17:28 +01:00
plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
2011-12-04 20:17:21 +01:00
#ifdef ENDSTOPS_ONLY_FOR_HOMING
enable_endstops(false);
#endif
2011-11-27 17:27:17 +01:00
2011-11-06 12:39:00 +01:00
feedrate = saved_feedrate;
feedmultiply = saved_feedmultiply;
previous_millis_cmd = millis();
2011-11-13 19:58:09 +01:00
endstops_hit_on_purpose();
2011-11-06 12:39:00 +01:00
break;
case 90: // G90
relative_mode = false;
break;
case 91: // G91
relative_mode = true;
break;
case 92: // G92
2011-11-25 13:43:06 +01:00
if(!code_seen(axis_codes[E_AXIS]))
2011-11-06 12:39:00 +01:00
st_synchronize();
2011-11-06 23:21:12 +01:00
for(int8_t i=0; i < NUM_AXIS; i++) {
2011-11-25 13:43:06 +01:00
if(code_seen(axis_codes[i])) {
if(i == E_AXIS) {
2011-12-12 20:43:47 +01:00
current_position[i] = code_value();
2011-11-25 13:43:06 +01:00
plan_set_e_position(current_position[E_AXIS]);
}
else {
2011-12-12 20:43:47 +01:00
current_position[i] = code_value()+add_homeing[i];
2011-11-25 13:43:06 +01:00
plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
}
}
2011-11-06 12:39:00 +01:00
}
break;
}
}
else if(code_seen('M'))
{
switch( (int)code_value() )
{
2012-05-20 14:37:30 +02:00
#ifdef ULTRA_LCD
case 0: // M0 - Unconditional stop - Wait for user button press on LCD
case 1: // M1 - Conditional stop - Wait for user button press on LCD
{
LCD_MESSAGEPGM(MSG_USERWAIT);
codenum = 0;
if(code_seen('P')) codenum = code_value(); // milliseconds to wait
if(code_seen('S')) codenum = code_value() * 1000; // seconds to wait
st_synchronize();
previous_millis_cmd = millis();
if (codenum > 0)
{
codenum += millis(); // keep track of when we started waiting
while(millis() < codenum && !CLICKED){
manage_heater();
manage_inactivity(1);
LCD_STATUS;
}
}else{
while(!CLICKED) {
manage_heater();
manage_inactivity(1);
LCD_STATUS;
}
}
}
break;
#endif
2011-11-26 09:03:12 +01:00
case 17:
2012-03-03 16:51:47 +01:00
LCD_MESSAGEPGM(MSG_NO_MOVE);
2011-11-19 18:22:22 +01:00
enable_x();
enable_y();
enable_z();
2011-12-06 05:33:33 +01:00
enable_e0();
enable_e1();
enable_e2();
2011-11-19 18:22:22 +01:00
break;
2011-11-06 12:39:00 +01:00
2011-12-06 05:33:33 +01:00
#ifdef SDSUPPORT
2011-11-06 12:39:00 +01:00
case 20: // M20 - list SD card
2012-03-03 16:51:47 +01:00
SERIAL_PROTOCOLLNPGM(MSG_BEGIN_FILE_LIST);
2011-11-06 22:48:15 +01:00
card.ls();
2012-03-03 16:51:47 +01:00
SERIAL_PROTOCOLLNPGM(MSG_END_FILE_LIST);
2011-11-06 12:39:00 +01:00
break;
case 21: // M21 - init SD card
2011-11-06 22:48:15 +01:00
2011-11-06 21:39:53 +01:00
card.initsd();
2011-11-09 20:27:15 +01:00
2011-11-06 12:39:00 +01:00
break;
case 22: //M22 - release SD card
2011-11-06 22:48:15 +01:00
card.release();
2011-11-06 12:39:00 +01:00
break;
case 23: //M23 - Select file
2011-11-06 22:48:15 +01:00
starpos = (strchr(strchr_pointer + 4,'*'));
if(starpos!=NULL)
*(starpos-1)='\0';
2011-11-19 13:13:34 +01:00
card.openFile(strchr_pointer + 4,true);
2011-11-06 12:39:00 +01:00
break;
case 24: //M24 - Start SD print
2011-11-06 22:48:15 +01:00
card.startFileprint();
starttime=millis();
2011-11-06 12:39:00 +01:00
break;
case 25: //M25 - Pause SD print
2011-11-06 22:48:15 +01:00
card.pauseSDPrint();
2011-11-06 12:39:00 +01:00
break;
case 26: //M26 - Set SD index
2011-12-06 05:33:33 +01:00
if(card.cardOK && code_seen('S')) {
2011-11-06 22:48:15 +01:00
card.setIndex(code_value_long());
2011-11-06 12:39:00 +01:00
}
break;
case 27: //M27 - Get SD status
2011-11-06 22:48:15 +01:00
card.getStatus();
2011-11-06 12:39:00 +01:00
break;
case 28: //M28 - Start SD write
2011-11-06 22:48:15 +01:00
starpos = (strchr(strchr_pointer + 4,'*'));
if(starpos != NULL){
char* npos = strchr(cmdbuffer[bufindr], 'N');
strchr_pointer = strchr(npos,' ') + 1;
*(starpos-1) = '\0';
2011-11-06 12:39:00 +01:00
}
2011-11-19 13:13:34 +01:00
card.openFile(strchr_pointer+4,false);
2011-11-06 12:39:00 +01:00
break;
case 29: //M29 - Stop SD write
//processed in write to file routine above
2011-11-06 22:48:15 +01:00
//card,saving = false;
2011-11-06 12:39:00 +01:00
break;
2012-03-03 21:58:12 +01:00
case 30: //M30 <filename> Delete File
2012-03-02 21:49:05 +01:00
if (card.cardOK){
2012-02-29 14:51:15 +01:00
card.closefile();
2012-03-02 21:49:05 +01:00
starpos = (strchr(strchr_pointer + 4,'*'));
if(starpos != NULL){
char* npos = strchr(cmdbuffer[bufindr], 'N');
strchr_pointer = strchr(npos,' ') + 1;
*(starpos-1) = '\0';
}
card.removeFile(strchr_pointer + 4);
2012-02-29 14:51:15 +01:00
}
2012-03-02 21:49:05 +01:00
break;
2012-02-29 14:51:15 +01:00
2011-12-06 05:33:33 +01:00
#endif //SDSUPPORT
2011-11-06 19:23:08 +01:00
2012-03-03 21:58:12 +01:00
case 31: //M31 take time since the start of the SD print or an M109 command
2011-12-06 05:33:33 +01:00
{
2011-11-06 17:33:09 +01:00
stoptime=millis();
char time[30];
unsigned long t=(stoptime-starttime)/1000;
int sec,min;
min=t/60;
sec=t%60;
2011-11-07 22:33:13 +01:00
sprintf(time,"%i min, %i sec",min,sec);
2011-11-09 20:27:15 +01:00
SERIAL_ECHO_START;
SERIAL_ECHOLN(time);
2011-11-06 17:33:09 +01:00
LCD_MESSAGE(time);
2011-12-04 09:48:53 +01:00
autotempShutdown();
2011-12-06 05:33:33 +01:00
}
break;
2011-11-06 19:23:08 +01:00
case 42: //M42 -Change pin status via gcode
if (code_seen('S'))
{
int pin_status = code_value();
if (code_seen('P') && pin_status >= 0 && pin_status <= 255)
2011-11-06 12:39:00 +01:00
{
2011-11-06 19:23:08 +01:00
int pin_number = code_value();
2011-11-06 23:21:12 +01:00
for(int8_t i = 0; i < (int8_t)sizeof(sensitive_pins); i++)
2011-11-06 12:39:00 +01:00
{
2011-11-06 19:23:08 +01:00
if (sensitive_pins[i] == pin_number)
2011-11-06 12:39:00 +01:00
{
2011-11-06 19:23:08 +01:00
pin_number = -1;
break;
2011-11-06 12:39:00 +01:00
}
}
2011-11-06 19:23:08 +01:00
if (pin_number > -1)
{
pinMode(pin_number, OUTPUT);
digitalWrite(pin_number, pin_status);
analogWrite(pin_number, pin_status);
}
2011-11-06 12:39:00 +01:00
}
2011-11-06 19:23:08 +01:00
}
break;
case 104: // M104
2011-11-26 17:33:25 +01:00
tmp_extruder = active_extruder;
if(code_seen('T')) {
tmp_extruder = code_value();
if(tmp_extruder >= EXTRUDERS) {
SERIAL_ECHO_START;
2012-03-03 16:51:47 +01:00
SERIAL_ECHO(MSG_M104_INVALID_EXTRUDER);
2011-11-26 17:33:25 +01:00
SERIAL_ECHOLN(tmp_extruder);
break;
}
}
if (code_seen('S')) setTargetHotend(code_value(), tmp_extruder);
2011-11-06 19:23:08 +01:00
setWatch();
break;
case 140: // M140 set bed temp
if (code_seen('S')) setTargetBed(code_value());
break;
2011-11-20 14:50:08 +01:00
case 105 : // M105
2011-12-12 19:34:37 +01:00
tmp_extruder = active_extruder;
2011-11-26 17:33:25 +01:00
if(code_seen('T')) {
tmp_extruder = code_value();
if(tmp_extruder >= EXTRUDERS) {
SERIAL_ECHO_START;
2012-03-03 16:51:47 +01:00
SERIAL_ECHO(MSG_M105_INVALID_EXTRUDER);
2011-11-26 17:33:25 +01:00
SERIAL_ECHOLN(tmp_extruder);
break;
}
}
2011-12-06 05:33:33 +01:00
#if (TEMP_0_PIN > -1)
2011-11-09 20:27:15 +01:00
SERIAL_PROTOCOLPGM("ok T:");
2012-04-15 19:17:33 +02:00
SERIAL_PROTOCOL_F(degHotend(tmp_extruder),1);
SERIAL_PROTOCOLPGM(" /");
SERIAL_PROTOCOL_F(degTargetHotend(tmp_extruder),1);
2012-02-08 18:28:54 +01:00
#if TEMP_BED_PIN > -1
2011-11-12 20:37:28 +01:00
SERIAL_PROTOCOLPGM(" B:");
2012-04-15 19:17:33 +02:00
SERIAL_PROTOCOL_F(degBed(),1);
SERIAL_PROTOCOLPGM(" /");
SERIAL_PROTOCOL_F(degTargetBed(),1);
2011-12-06 05:33:33 +01:00
#endif //TEMP_BED_PIN
2011-11-12 20:37:28 +01:00
#else
SERIAL_ERROR_START;
2012-03-03 16:51:47 +01:00
SERIAL_ERRORLNPGM(MSG_ERR_NO_THERMISTORS);
2011-12-12 19:34:37 +01:00
#endif
#ifdef PIDTEMP
SERIAL_PROTOCOLPGM(" @:");
SERIAL_PROTOCOL(getHeaterPower(tmp_extruder));
2011-11-12 20:37:28 +01:00
#endif
SERIAL_PROTOCOLLN("");
2011-11-06 19:23:08 +01:00
return;
2011-11-06 12:39:00 +01:00
break;
2011-11-06 19:23:08 +01:00
case 109:
{// M109 - Wait for extruder heater to reach target.
2011-11-26 17:33:25 +01:00
tmp_extruder = active_extruder;
if(code_seen('T')) {
tmp_extruder = code_value();
if(tmp_extruder >= EXTRUDERS) {
SERIAL_ECHO_START;
2012-03-03 16:51:47 +01:00
SERIAL_ECHO(MSG_M109_INVALID_EXTRUDER);
2011-11-26 17:33:25 +01:00
SERIAL_ECHOLN(tmp_extruder);
break;
}
}
2012-03-03 16:51:47 +01:00
LCD_MESSAGEPGM(MSG_HEATING);
2011-11-26 17:33:25 +01:00
#ifdef AUTOTEMP
autotemp_enabled=false;
#endif
if (code_seen('S')) setTargetHotend(code_value(), tmp_extruder);
#ifdef AUTOTEMP
if (code_seen('S')) autotemp_min=code_value();
2012-04-15 19:17:33 +02:00
if (code_seen('B')) autotemp_max=code_value();
2011-11-26 17:33:25 +01:00
if (code_seen('F'))
{
autotemp_factor=code_value();
autotemp_enabled=true;
}
#endif
setWatch();
codenum = millis();
/* See if we are heating up or cooling down */
bool target_direction = isHeatingHotend(tmp_extruder); // true if heating, false if cooling
#ifdef TEMP_RESIDENCY_TIME
long residencyStart;
residencyStart = -1;
/* continue to loop until we have reached the target temp
_and_ until TEMP_RESIDENCY_TIME hasn't passed since we reached it */
2011-12-06 05:33:33 +01:00
while((residencyStart == -1) ||
2012-01-24 04:24:24 +01:00
(residencyStart >= 0 && (((unsigned int) (millis() - residencyStart)) < (TEMP_RESIDENCY_TIME * 1000UL))) ) {
2011-11-26 17:33:25 +01:00
#else
2011-12-12 19:34:37 +01:00
while ( target_direction ? (isHeatingHotend(tmp_extruder)) : (isCoolingHotend(tmp_extruder)&&(CooldownNoWait==false)) ) {
2011-11-26 17:33:25 +01:00
#endif //TEMP_RESIDENCY_TIME
2012-01-24 04:24:24 +01:00
if( (millis() - codenum) > 1000UL )
2011-12-06 05:33:33 +01:00
{ //Print Temp Reading and remaining time every 1 second while heating up/cooling down
SERIAL_PROTOCOLPGM("T:");
2012-04-15 19:17:33 +02:00
SERIAL_PROTOCOL_F(degHotend(tmp_extruder),1);
2011-12-06 05:33:33 +01:00
SERIAL_PROTOCOLPGM(" E:");
2012-04-15 19:17:33 +02:00
SERIAL_PROTOCOL((int)tmp_extruder);
2011-12-12 19:34:37 +01:00
#ifdef TEMP_RESIDENCY_TIME
SERIAL_PROTOCOLPGM(" W:");
if(residencyStart > -1)
{
2012-01-24 04:24:24 +01:00
codenum = ((TEMP_RESIDENCY_TIME * 1000UL) - (millis() - residencyStart)) / 1000UL;
2011-12-12 19:34:37 +01:00
SERIAL_PROTOCOLLN( codenum );
}
else
{
SERIAL_PROTOCOLLN( "?" );
}
2012-01-22 12:25:56 +01:00
#else
SERIAL_PROTOCOLLN("");
2011-12-12 19:34:37 +01:00
#endif
2011-12-06 05:33:33 +01:00
codenum = millis();
}
manage_heater();
2012-03-11 17:59:44 +01:00
manage_inactivity(1);
2011-12-06 05:33:33 +01:00
LCD_STATUS;
2011-11-06 19:23:08 +01:00
#ifdef TEMP_RESIDENCY_TIME
/* start/restart the TEMP_RESIDENCY_TIME timer whenever we reach target temp for the first time
or when current temp falls outside the hysteresis after target temp was reached */
2012-04-30 13:36:19 +02:00
if ((residencyStart == -1 && target_direction && (degHotend(tmp_extruder) >= (degTargetHotend(tmp_extruder)-TEMP_WINDOW))) ||
(residencyStart == -1 && !target_direction && (degHotend(tmp_extruder) <= (degTargetHotend(tmp_extruder)+TEMP_WINDOW))) ||
2011-11-26 17:33:25 +01:00
(residencyStart > -1 && labs(degHotend(tmp_extruder) - degTargetHotend(tmp_extruder)) > TEMP_HYSTERESIS) )
2011-11-06 19:23:08 +01:00
{
residencyStart = millis();
}
#endif //TEMP_RESIDENCY_TIME
}
2012-03-03 16:51:47 +01:00
LCD_MESSAGEPGM(MSG_HEATING_COMPLETE);
2011-11-06 19:23:08 +01:00
starttime=millis();
2011-12-09 13:39:00 +01:00
previous_millis_cmd = millis();
2011-11-06 19:23:08 +01:00
}
break;
2011-12-06 05:33:33 +01:00
case 190: // M190 - Wait for bed heater to reach target.
#if TEMP_BED_PIN > -1
2012-03-03 16:51:47 +01:00
LCD_MESSAGEPGM(MSG_BED_HEATING);
2011-11-06 19:23:08 +01:00
if (code_seen('S')) setTargetBed(code_value());
codenum = millis();
while(isHeatingBed())
{
2012-02-08 18:28:54 +01:00
if(( millis() - codenum) > 1000 ) //Print Temp Reading every 1 second while heating up.
2011-11-06 19:23:08 +01:00
{
2011-12-12 19:34:37 +01:00
float tt=degHotend(active_extruder);
2011-11-09 20:27:15 +01:00
SERIAL_PROTOCOLPGM("T:");
2011-12-06 05:33:33 +01:00
SERIAL_PROTOCOL(tt);
SERIAL_PROTOCOLPGM(" E:");
2012-04-15 19:17:33 +02:00
SERIAL_PROTOCOL((int)active_extruder);
2011-11-09 20:27:15 +01:00
SERIAL_PROTOCOLPGM(" B:");
2012-04-15 19:17:33 +02:00
SERIAL_PROTOCOL_F(degBed(),1);
SERIAL_PROTOCOLLN("");
2011-11-06 19:23:08 +01:00
codenum = millis();
}
manage_heater();
2012-03-11 17:59:44 +01:00
manage_inactivity(1);
2012-03-05 16:12:26 +01:00
LCD_STATUS;
2011-11-06 19:23:08 +01:00
}
2012-03-03 16:51:47 +01:00
LCD_MESSAGEPGM(MSG_BED_DONE);
2011-12-09 13:39:00 +01:00
previous_millis_cmd = millis();
2011-11-06 19:23:08 +01:00
#endif
2012-01-24 04:24:41 +01:00
break;
2011-11-06 19:23:08 +01:00
#if FAN_PIN > -1
2011-11-06 12:39:00 +01:00
case 106: //M106 Fan On
if (code_seen('S')){
2012-03-04 13:05:26 +01:00
FanSpeed=constrain(code_value(),0,255);
2011-11-06 12:39:00 +01:00
}
else {
2012-03-04 13:05:26 +01:00
FanSpeed=255;
2011-11-06 12:39:00 +01:00
}
break;
case 107: //M107 Fan Off
2012-03-04 13:05:26 +01:00
FanSpeed = 0;
2011-11-06 12:39:00 +01:00
break;
2011-11-06 19:23:08 +01:00
#endif //FAN_PIN
#if (PS_ON_PIN > -1)
2011-11-06 12:39:00 +01:00
case 80: // M80 - ATX Power On
SET_OUTPUT(PS_ON_PIN); //GND
2012-03-25 14:36:51 +02:00
WRITE(PS_ON_PIN, LOW);
2011-11-06 12:39:00 +01:00
break;
2012-01-15 17:06:10 +01:00
#endif
2011-11-06 12:39:00 +01:00
case 81: // M81 - ATX Power Off
2012-01-15 18:31:21 +01:00
2012-01-24 04:24:41 +01:00
#if defined SUICIDE_PIN && SUICIDE_PIN > -1
2012-01-15 18:31:21 +01:00
st_synchronize();
2012-01-15 17:06:10 +01:00
suicide();
2012-01-24 04:24:41 +01:00
#elif (PS_ON_PIN > -1)
SET_INPUT(PS_ON_PIN); //Floating
2012-01-15 17:06:10 +01:00
#endif
2012-01-24 04:24:41 +01:00
break;
2012-01-15 17:06:10 +01:00
2011-11-06 12:39:00 +01:00
case 82:
axis_relative_modes[3] = false;
break;
case 83:
axis_relative_modes[3] = true;
break;
2011-11-06 19:23:08 +01:00
case 18: //compatibility
2011-11-20 14:50:08 +01:00
case 84: // M84
2011-11-06 12:39:00 +01:00
if(code_seen('S')){
stepper_inactive_time = code_value() * 1000;
}
2011-11-06 19:23:08 +01:00
else
{
2011-12-09 12:51:08 +01:00
bool all_axis = !((code_seen(axis_codes[0])) || (code_seen(axis_codes[1])) || (code_seen(axis_codes[2]))|| (code_seen(axis_codes[3])));
if(all_axis)
{
2012-02-08 18:28:54 +01:00
st_synchronize();
2011-12-06 05:33:33 +01:00
disable_e0();
disable_e1();
disable_e2();
2011-11-28 21:49:54 +01:00
finishAndDisableSteppers();
}
2011-12-09 12:51:08 +01:00
else
{
st_synchronize();
if(code_seen('X')) disable_x();
if(code_seen('Y')) disable_y();
if(code_seen('Z')) disable_z();
2011-12-15 11:59:07 +01:00
#if ((E0_ENABLE_PIN != X_ENABLE_PIN) && (E1_ENABLE_PIN != Y_ENABLE_PIN)) // Only enable on boards that have seperate ENABLE_PINS
2011-12-12 20:43:47 +01:00
if(code_seen('E')) {
disable_e0();
disable_e1();
disable_e2();
}
2011-12-09 12:51:08 +01:00
#endif
2012-03-03 16:51:47 +01:00
LCD_MESSAGEPGM(MSG_PART_RELEASE);
2011-12-09 12:51:08 +01:00
}
2011-11-06 12:39:00 +01:00
}
break;
case 85: // M85
code_seen('S');
max_inactive_time = code_value() * 1000;
break;
case 92: // M92
2011-11-06 23:21:12 +01:00
for(int8_t i=0; i < NUM_AXIS; i++)
2011-11-06 19:23:08 +01:00
{
if(code_seen(axis_codes[i]))
2012-04-15 19:17:33 +02:00
if(i == 3) { // E
float value = code_value();
if(value < 20.0) {
float factor = axis_steps_per_unit[i] / value; // increase e constants if M92 E14 is given for netfab.
max_e_jerk *= factor;
max_feedrate[i] *= factor;
axis_steps_per_sqr_second[i] *= factor;
}
axis_steps_per_unit[i] = value;
}
else {
axis_steps_per_unit[i] = code_value();
}
2011-11-06 12:39:00 +01:00
}
break;
case 115: // M115
2012-03-03 16:51:47 +01:00
SerialprintPGM(MSG_M115_REPORT);
2011-11-06 12:39:00 +01:00
break;
2011-11-27 16:53:11 +01:00
case 117: // M117 display message
LCD_MESSAGE(cmdbuffer[bufindr]+5);
break;
2011-11-06 12:39:00 +01:00
case 114: // M114
2011-11-09 20:27:15 +01:00
SERIAL_PROTOCOLPGM("X:");
2011-11-07 22:33:13 +01:00
SERIAL_PROTOCOL(current_position[X_AXIS]);
2011-11-09 20:27:15 +01:00
SERIAL_PROTOCOLPGM("Y:");
2011-11-07 22:33:13 +01:00
SERIAL_PROTOCOL(current_position[Y_AXIS]);
2011-11-09 20:27:15 +01:00
SERIAL_PROTOCOLPGM("Z:");
2011-11-07 22:33:13 +01:00
SERIAL_PROTOCOL(current_position[Z_AXIS]);
2011-11-09 20:27:15 +01:00
SERIAL_PROTOCOLPGM("E:");
2011-11-07 22:33:13 +01:00
SERIAL_PROTOCOL(current_position[E_AXIS]);
2011-11-20 14:50:08 +01:00
2012-03-03 16:51:47 +01:00
SERIAL_PROTOCOLPGM(MSG_COUNT_X);
2011-11-20 14:50:08 +01:00
SERIAL_PROTOCOL(float(st_get_position(X_AXIS))/axis_steps_per_unit[X_AXIS]);
SERIAL_PROTOCOLPGM("Y:");
SERIAL_PROTOCOL(float(st_get_position(Y_AXIS))/axis_steps_per_unit[Y_AXIS]);
SERIAL_PROTOCOLPGM("Z:");
SERIAL_PROTOCOL(float(st_get_position(Z_AXIS))/axis_steps_per_unit[Z_AXIS]);
2011-11-07 22:33:13 +01:00
SERIAL_PROTOCOLLN("");
2011-11-06 12:39:00 +01:00
break;
2012-04-28 16:31:22 +02:00
case 120: // M120
enable_endstops(false) ;
break;
case 121: // M121
enable_endstops(true) ;
break;
2011-11-06 12:39:00 +01:00
case 119: // M119
2011-11-06 19:23:08 +01:00
#if (X_MIN_PIN > -1)
2012-03-03 16:51:47 +01:00
SERIAL_PROTOCOLPGM(MSG_X_MIN);
2011-11-25 13:43:06 +01:00
SERIAL_PROTOCOL(((READ(X_MIN_PIN)^X_ENDSTOPS_INVERTING)?"H ":"L "));
2011-11-06 19:23:08 +01:00
#endif
#if (X_MAX_PIN > -1)
2012-03-03 16:51:47 +01:00
SERIAL_PROTOCOLPGM(MSG_X_MAX);
2011-11-25 13:43:06 +01:00
SERIAL_PROTOCOL(((READ(X_MAX_PIN)^X_ENDSTOPS_INVERTING)?"H ":"L "));
2011-11-06 19:23:08 +01:00
#endif
#if (Y_MIN_PIN > -1)
2012-03-03 16:51:47 +01:00
SERIAL_PROTOCOLPGM(MSG_Y_MIN);
2011-11-25 13:43:06 +01:00
SERIAL_PROTOCOL(((READ(Y_MIN_PIN)^Y_ENDSTOPS_INVERTING)?"H ":"L "));
2011-11-06 19:23:08 +01:00
#endif
#if (Y_MAX_PIN > -1)
2012-03-03 16:51:47 +01:00
SERIAL_PROTOCOLPGM(MSG_Y_MAX);
2011-11-25 13:43:06 +01:00
SERIAL_PROTOCOL(((READ(Y_MAX_PIN)^Y_ENDSTOPS_INVERTING)?"H ":"L "));
2011-11-06 19:23:08 +01:00
#endif
#if (Z_MIN_PIN > -1)
2012-03-03 16:51:47 +01:00
SERIAL_PROTOCOLPGM(MSG_Z_MIN);
2011-11-25 13:43:06 +01:00
SERIAL_PROTOCOL(((READ(Z_MIN_PIN)^Z_ENDSTOPS_INVERTING)?"H ":"L "));
2011-11-06 19:23:08 +01:00
#endif
#if (Z_MAX_PIN > -1)
2012-03-03 16:51:47 +01:00
SERIAL_PROTOCOLPGM(MSG_Z_MAX);
2011-11-25 13:43:06 +01:00
SERIAL_PROTOCOL(((READ(Z_MAX_PIN)^Z_ENDSTOPS_INVERTING)?"H ":"L "));
2011-11-06 19:23:08 +01:00
#endif
2011-11-07 22:33:13 +01:00
SERIAL_PROTOCOLLN("");
2011-11-06 12:39:00 +01:00
break;
//TODO: update for all axis, use for loop
case 201: // M201
2011-11-06 23:21:12 +01:00
for(int8_t i=0; i < NUM_AXIS; i++)
2011-11-06 19:23:08 +01:00
{
2011-12-08 11:25:32 +01:00
if(code_seen(axis_codes[i]))
{
max_acceleration_units_per_sq_second[i] = code_value();
axis_steps_per_sqr_second[i] = code_value() * axis_steps_per_unit[i];
}
2011-11-06 12:39:00 +01:00
}
break;
2011-11-06 19:23:08 +01:00
#if 0 // Not used for Sprinter/grbl gen6
2011-11-06 12:39:00 +01:00
case 202: // M202
2011-11-06 23:21:12 +01:00
for(int8_t i=0; i < NUM_AXIS; i++) {
2011-11-06 12:39:00 +01:00
if(code_seen(axis_codes[i])) axis_travel_steps_per_sqr_second[i] = code_value() * axis_steps_per_unit[i];
}
break;
2011-11-06 19:23:08 +01:00
#endif
2011-11-06 12:39:00 +01:00
case 203: // M203 max feedrate mm/sec
2011-11-06 23:21:12 +01:00
for(int8_t i=0; i < NUM_AXIS; i++) {
2011-11-25 22:32:26 +01:00
if(code_seen(axis_codes[i])) max_feedrate[i] = code_value();
2011-11-06 12:39:00 +01:00
}
break;
case 204: // M204 acclereration S normal moves T filmanent only moves
{
if(code_seen('S')) acceleration = code_value() ;
if(code_seen('T')) retract_acceleration = code_value() ;
}
break;
2011-11-06 19:23:08 +01:00
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
{
2011-11-25 22:32:26 +01:00
if(code_seen('S')) minimumfeedrate = code_value();
if(code_seen('T')) mintravelfeedrate = code_value();
2011-11-06 19:23:08 +01:00
if(code_seen('B')) minsegmenttime = code_value() ;
2011-11-25 22:32:26 +01:00
if(code_seen('X')) max_xy_jerk = code_value() ;
2011-11-25 22:34:12 +01:00
if(code_seen('Z')) max_z_jerk = code_value() ;
2012-03-04 16:34:58 +01:00
if(code_seen('E')) max_e_jerk = code_value() ;
2011-11-06 19:23:08 +01:00
}
break;
2011-11-27 17:27:17 +01:00
case 206: // M206 additional homeing offset
for(int8_t i=0; i < 3; i++)
{
if(code_seen(axis_codes[i])) add_homeing[i] = code_value();
}
break;
2012-06-02 20:32:28 +02:00
#ifdef FWRETRACT
case 207: //M207 - set retract length S[positive mm] F[feedrate mm/sec] Z[additional zlift/hop]
{
if(code_seen('S'))
{
retract_length = code_value() ;
}
if(code_seen('F'))
{
retract_feedrate = code_value() ;
}
if(code_seen('Z'))
{
retract_zlift = code_value() ;
}
}break;
case 208: // M208 - set retract recover length S[positive mm surplus to the M207 S*] F[feedrate mm/sec]
{
if(code_seen('S'))
{
retract_recover_length = code_value() ;
}
if(code_seen('F'))
{
retract_recover_feedrate = code_value() ;
}
}break;
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.
{
if(code_seen('S'))
{
int t= code_value() ;
switch(t)
{
case 0: autoretract_enabled=false;retracted=false;break;
case 1: autoretract_enabled=true;retracted=false;break;
default:
SERIAL_ECHO_START;
SERIAL_ECHOPGM(MSG_UNKNOWN_COMMAND);
SERIAL_ECHO(cmdbuffer[bufindr]);
SERIAL_ECHOLNPGM("\"");
}
}
}break;
#endif
2011-11-06 19:23:08 +01:00
case 220: // M220 S<factor in percent>- set speed factor override percentage
{
if(code_seen('S'))
2011-11-06 12:39:00 +01:00
{
2011-11-06 19:23:08 +01:00
feedmultiply = code_value() ;
feedmultiplychanged=true;
2011-11-06 12:39:00 +01:00
}
2011-11-06 19:23:08 +01:00
}
break;
2012-02-24 20:42:07 +01:00
case 221: // M221 S<factor in percent>- set extrude factor override percentage
{
if(code_seen('S'))
{
extrudemultiply = code_value() ;
2012-02-24 23:34:41 +01:00
}
2012-02-24 20:42:07 +01:00
}
break;
2011-11-06 19:23:08 +01:00
#ifdef PIDTEMP
2011-11-06 12:39:00 +01:00
case 301: // M301
2011-11-13 21:43:26 +01:00
{
if(code_seen('P')) Kp = code_value();
if(code_seen('I')) Ki = code_value()*PID_dT;
if(code_seen('D')) Kd = code_value()/PID_dT;
#ifdef PID_ADD_EXTRUSION_RATE
if(code_seen('C')) Kc = code_value();
#endif
updatePID();
2012-03-03 16:51:47 +01:00
SERIAL_PROTOCOL(MSG_OK);
SERIAL_PROTOCOL(" p:");
2011-11-13 21:43:26 +01:00
SERIAL_PROTOCOL(Kp);
SERIAL_PROTOCOL(" i:");
SERIAL_PROTOCOL(Ki/PID_dT);
SERIAL_PROTOCOL(" d:");
SERIAL_PROTOCOL(Kd*PID_dT);
#ifdef PID_ADD_EXTRUSION_RATE
SERIAL_PROTOCOL(" c:");
SERIAL_PROTOCOL(Kc*PID_dT);
#endif
SERIAL_PROTOCOLLN("");
}
2011-11-06 12:39:00 +01:00
break;
2011-11-06 19:23:08 +01:00
#endif //PIDTEMP
2011-12-22 12:11:39 +01:00
case 240: // M240 Triggers a camera by emulating a Canon RC-1 : http://www.doc-diy.net/photo/rc-1_hacked/
{
#ifdef PHOTOGRAPH_PIN
#if (PHOTOGRAPH_PIN > -1)
const uint8_t NUM_PULSES=16;
const float PULSE_LENGTH=0.01524;
for(int i=0; i < NUM_PULSES; i++) {
WRITE(PHOTOGRAPH_PIN, HIGH);
_delay_ms(PULSE_LENGTH);
WRITE(PHOTOGRAPH_PIN, LOW);
_delay_ms(PULSE_LENGTH);
}
delay(7.33);
for(int i=0; i < NUM_PULSES; i++) {
WRITE(PHOTOGRAPH_PIN, HIGH);
_delay_ms(PULSE_LENGTH);
WRITE(PHOTOGRAPH_PIN, LOW);
_delay_ms(PULSE_LENGTH);
}
#endif
#endif
}
break;
2011-12-09 15:09:52 +01:00
2012-05-03 14:13:53 +02:00
case 302: // allow cold extrudes
2011-12-09 15:09:52 +01:00
{
allow_cold_extrudes(true);
}
break;
2012-03-08 21:43:21 +01:00
case 303: // M303 PID autotune
{
float temp = 150.0;
if (code_seen('S')) temp=code_value();
PID_autotune(temp);
}
break;
2012-05-19 17:54:07 +02:00
case 400: // M400 finish all moves
2011-11-13 19:58:09 +01:00
{
st_synchronize();
}
break;
2011-11-06 19:23:08 +01:00
case 500: // Store settings in EEPROM
{
2011-12-04 22:26:42 +01:00
EEPROM_StoreSettings();
2011-11-06 19:23:08 +01:00
}
break;
case 501: // Read settings from EEPROM
{
2011-12-04 22:26:42 +01:00
EEPROM_RetrieveSettings();
2011-11-06 19:23:08 +01:00
}
break;
case 502: // Revert to default settings
{
2011-12-04 22:26:42 +01:00
EEPROM_RetrieveSettings(true);
}
break;
case 503: // print settings currently in memory
{
EEPROM_printSettings();
2011-11-06 19:23:08 +01:00
}
break;
2012-03-25 14:36:51 +02:00
case 999: // Restart after being stopped
Stopped = false;
gcode_LastN = Stopped_gcode_LastN;
FlushSerialRequestResend();
break;
2011-11-06 12:39:00 +01:00
}
}
2011-12-06 05:33:33 +01:00
else if(code_seen('T'))
{
2011-11-26 17:33:25 +01:00
tmp_extruder = code_value();
if(tmp_extruder >= EXTRUDERS) {
SERIAL_ECHO_START;
SERIAL_ECHO("T");
SERIAL_ECHO(tmp_extruder);
2012-03-03 16:51:47 +01:00
SERIAL_ECHOLN(MSG_INVALID_EXTRUDER);
2011-11-26 17:33:25 +01:00
}
else {
active_extruder = tmp_extruder;
2011-12-06 05:33:33 +01:00
SERIAL_ECHO_START;
2012-03-03 16:51:47 +01:00
SERIAL_ECHO(MSG_ACTIVE_EXTRUDER);
2011-12-06 05:33:33 +01:00
SERIAL_PROTOCOLLN((int)active_extruder);
2011-11-26 17:33:25 +01:00
}
}
2011-12-06 05:33:33 +01:00
2011-11-06 19:23:08 +01:00
else
{
2011-11-09 20:27:15 +01:00
SERIAL_ECHO_START;
2012-03-03 16:51:47 +01:00
SERIAL_ECHOPGM(MSG_UNKNOWN_COMMAND);
2011-11-09 20:27:15 +01:00
SERIAL_ECHO(cmdbuffer[bufindr]);
SERIAL_ECHOLNPGM("\"");
2011-11-06 12:39:00 +01:00
}
ClearToSend();
}
void FlushSerialRequestResend()
{
//char cmdbuffer[bufindr][100]="Resend:";
2012-02-11 16:02:47 +01:00
MYSERIAL.flush();
2012-03-03 16:51:47 +01:00
SERIAL_PROTOCOLPGM(MSG_RESEND);
2011-11-09 20:27:15 +01:00
SERIAL_PROTOCOLLN(gcode_LastN + 1);
2011-11-06 12:39:00 +01:00
ClearToSend();
}
void ClearToSend()
{
previous_millis_cmd = millis();
2011-11-06 19:23:08 +01:00
#ifdef SDSUPPORT
2011-11-06 12:39:00 +01:00
if(fromsd[bufindr])
return;
2011-11-06 19:23:08 +01:00
#endif //SDSUPPORT
2012-03-03 16:51:47 +01:00
SERIAL_PROTOCOLLNPGM(MSG_OK);
2011-11-06 12:39:00 +01:00
}
2012-02-05 12:42:15 +01:00
void get_coordinates()
2011-11-15 22:50:43 +01:00
{
2012-06-02 20:32:28 +02:00
bool seen[4]={false,false,false,false};
2011-11-15 22:50:43 +01:00
for(int8_t i=0; i < NUM_AXIS; i++) {
2012-06-02 20:32:28 +02:00
if(code_seen(axis_codes[i]))
{
destination[i] = (float)code_value() + (axis_relative_modes[i] || relative_mode)*current_position[i];
seen[i]=true;
}
2011-11-15 22:50:43 +01:00
else destination[i] = current_position[i]; //Are these else lines really needed?
}
if(code_seen('F')) {
next_feedrate = code_value();
if(next_feedrate > 0.0) feedrate = next_feedrate;
}
2012-06-02 20:32:28 +02:00
#ifdef FWRETRACT
if(autoretract_enabled)
if( !(seen[X_AXIS] || seen[Y_AXIS] || seen[Z_AXIS]) && seen[E_AXIS])
{
float echange=destination[E_AXIS]-current_position[E_AXIS];
if(echange<-MIN_RETRACT) //retract
{
if(!retracted)
{
destination[Z_AXIS]+=retract_zlift; //not sure why chaninging current_position negatively does not work.
//if slicer retracted by echange=-1mm and you want to retract 3mm, corrrectede=-2mm additionally
float correctede=-echange-retract_length;
//to generate the additional steps, not the destination is changed, but inversely the current position
2012-06-03 16:56:40 +02:00
current_position[E_AXIS]+=-correctede;
2012-06-02 20:32:28 +02:00
feedrate=retract_feedrate;
retracted=true;
}
}
else
if(echange>MIN_RETRACT) //retract_recover
{
if(retracted)
{
//current_position[Z_AXIS]+=-retract_zlift;
//if slicer retracted_recovered by echange=+1mm and you want to retract_recover 3mm, corrrectede=2mm additionally
2012-06-03 16:56:40 +02:00
float correctede=-echange+1*retract_length+retract_recover_length; //total unretract=retract_length+retract_recover_length[surplus]
current_position[E_AXIS]+=correctede; //to generate the additional steps, not the destination is changed, but inversely the current position
2012-06-02 20:32:28 +02:00
feedrate=retract_recover_feedrate;
retracted=false;
}
}
}
#endif //FWRETRACT
2011-11-15 22:50:43 +01:00
}
2012-02-05 12:42:15 +01:00
void get_arc_coordinates()
2011-11-15 22:50:43 +01:00
{
get_coordinates();
2012-03-27 19:03:33 +02:00
if(code_seen('I')) {
offset[0] = code_value();
}
else {
offset[0] = 0.0;
}
if(code_seen('J')) {
offset[1] = code_value();
}
else {
offset[1] = 0.0;
}
2011-11-15 22:50:43 +01:00
}
2011-11-06 12:39:00 +01:00
2012-08-09 19:15:32 +02:00
void clamp_to_software_endstops(float target[3])
2011-11-15 22:50:43 +01:00
{
2012-02-27 18:31:40 +01:00
if (min_software_endstops) {
M206: always use homing ("homeing") offsets
Previously the parameters set in M206 would only be used if a G82
command was sent with specific axis home values. This limits its
usefulness.
Really, we should have a way to adjust the XYZ homing of a machine in
the eeprom. So as the first stage of this, make M206 affect every
home command. The values set using M206 are now added to the
configuration variables [XYZ]_HOME_POS.
This is achieved by replacing all uses of [XYZ]_HOME_POS in the code
by a new home_pos[] which includes the adjustment. We also have to
adjust the uses of [XYZ]_{MIN,MAX}_POS similarly - see below.
To allow axis_is_at_home to be written as a function taking an axis
index rather than a macro taking an axis letter, we provide
constant arrays in program memory containing the values of
[XYZ]_{MIN,MAX,HOME}_POS from the compiled-in configuration.
This is done with some helper macros to deal with the declaration
(XYZ_CONSTS_FROM_CONFIG) and definition of the inline function which
does the program memory access.
We also introduce the overloaded function read_pgm_any, whose
instances are produced with DEFINE_PGM_READ_ANY, which allows the
access functions to automatically produce the correct type.
The type- and pointer-massaging code in the access function boils
down, when compiled, to a simple program memory access.
A question arises: if the M206 offset is set, should this adjustment
to the home position shift or change the possible range of movement
permitted by the software endstops ?
The documentation in Configuration.h describes these limits as:
// Travel limits after homing
Since this is a file containing physical limits, and actual suggested
values for these configuration parameters appear to include a certain
amount of slop, I've taken the view that these should be regarded as
nominal physical distances from the limit switches, and that the
permissible travel should be unaffected by M206.
So for example with the (rather unrealistic)
#define X_HOME_DIR -1
#define X_MIN_POS -20
#define X_HOME_POS 0
#define X_MAX_POS 100
no matter the setting of M206 X, the machine would be permitted
to move from 20mm "beyond" the limit switch trigger point in
the negative X direction and 100mm away from the limit switch in
the positive X direction, for a total travel of 120mm.
With M206 X-10 that would be considered to correspond to X coordinates
-30 to +90. With M206 X+10 that would be considered to correspond to
X coordinates -10 to +110.
fixes #200 (in ErikZalm/Marlin).
Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
2012-08-01 22:12:14 +02:00
if (target[X_AXIS] < min_pos[X_AXIS]) target[X_AXIS] = min_pos[X_AXIS];
if (target[Y_AXIS] < min_pos[Y_AXIS]) target[Y_AXIS] = min_pos[Y_AXIS];
if (target[Z_AXIS] < min_pos[Z_AXIS]) target[Z_AXIS] = min_pos[Z_AXIS];
2012-02-27 18:31:40 +01:00
}
if (max_software_endstops) {
M206: always use homing ("homeing") offsets
Previously the parameters set in M206 would only be used if a G82
command was sent with specific axis home values. This limits its
usefulness.
Really, we should have a way to adjust the XYZ homing of a machine in
the eeprom. So as the first stage of this, make M206 affect every
home command. The values set using M206 are now added to the
configuration variables [XYZ]_HOME_POS.
This is achieved by replacing all uses of [XYZ]_HOME_POS in the code
by a new home_pos[] which includes the adjustment. We also have to
adjust the uses of [XYZ]_{MIN,MAX}_POS similarly - see below.
To allow axis_is_at_home to be written as a function taking an axis
index rather than a macro taking an axis letter, we provide
constant arrays in program memory containing the values of
[XYZ]_{MIN,MAX,HOME}_POS from the compiled-in configuration.
This is done with some helper macros to deal with the declaration
(XYZ_CONSTS_FROM_CONFIG) and definition of the inline function which
does the program memory access.
We also introduce the overloaded function read_pgm_any, whose
instances are produced with DEFINE_PGM_READ_ANY, which allows the
access functions to automatically produce the correct type.
The type- and pointer-massaging code in the access function boils
down, when compiled, to a simple program memory access.
A question arises: if the M206 offset is set, should this adjustment
to the home position shift or change the possible range of movement
permitted by the software endstops ?
The documentation in Configuration.h describes these limits as:
// Travel limits after homing
Since this is a file containing physical limits, and actual suggested
values for these configuration parameters appear to include a certain
amount of slop, I've taken the view that these should be regarded as
nominal physical distances from the limit switches, and that the
permissible travel should be unaffected by M206.
So for example with the (rather unrealistic)
#define X_HOME_DIR -1
#define X_MIN_POS -20
#define X_HOME_POS 0
#define X_MAX_POS 100
no matter the setting of M206 X, the machine would be permitted
to move from 20mm "beyond" the limit switch trigger point in
the negative X direction and 100mm away from the limit switch in
the positive X direction, for a total travel of 120mm.
With M206 X-10 that would be considered to correspond to X coordinates
-30 to +90. With M206 X+10 that would be considered to correspond to
X coordinates -10 to +110.
fixes #200 (in ErikZalm/Marlin).
Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
2012-08-01 22:12:14 +02:00
if (target[X_AXIS] > max_pos[X_AXIS]) target[X_AXIS] = max_pos[X_AXIS];
if (target[Y_AXIS] > max_pos[Y_AXIS]) target[Y_AXIS] = max_pos[Y_AXIS];
if (target[Z_AXIS] > max_pos[Z_AXIS]) target[Z_AXIS] = max_pos[Z_AXIS];
2012-02-27 18:31:40 +01:00
}
2012-08-09 19:15:32 +02:00
}
void prepare_move()
{
clamp_to_software_endstops(destination);
2012-03-09 20:20:01 +01:00
previous_millis_cmd = millis();
2011-11-27 21:12:55 +01:00
plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate*feedmultiply/60/100.0, active_extruder);
2011-11-15 22:50:43 +01:00
for(int8_t i=0; i < NUM_AXIS; i++) {
current_position[i] = destination[i];
}
}
2011-11-06 12:39:00 +01:00
void prepare_arc_move(char isclockwise) {
2011-11-06 19:37:12 +01:00
float r = hypot(offset[X_AXIS], offset[Y_AXIS]); // Compute arc radius for mc_arc
2011-11-06 12:39:00 +01:00
// Trace the arc
2011-11-27 21:12:55 +01:00
mc_arc(current_position, destination, offset, X_AXIS, Y_AXIS, Z_AXIS, feedrate*feedmultiply/60/100.0, r, isclockwise, active_extruder);
2011-11-06 12:39:00 +01:00
// As far as the parser is concerned, the position is now == target. In reality the
// motion control system might still be processing the action and the real tool position
// in any intermediate location.
2011-11-06 23:21:12 +01:00
for(int8_t i=0; i < NUM_AXIS; i++) {
2011-11-06 19:37:12 +01:00
current_position[i] = destination[i];
2011-11-06 12:39:00 +01:00
}
2011-12-09 13:39:00 +01:00
previous_millis_cmd = millis();
2011-11-06 12:39:00 +01:00
}
2012-03-11 10:44:10 +01:00
#ifdef CONTROLLERFAN_PIN
unsigned long lastMotor = 0; //Save the time for when a motor was turned on last
unsigned long lastMotorCheck = 0;
void controllerFan()
{
if ((millis() - lastMotorCheck) >= 2500) //Not a time critical function, so we only check every 2500ms
{
lastMotorCheck = millis();
if(!READ(X_ENABLE_PIN) || !READ(Y_ENABLE_PIN) || !READ(Z_ENABLE_PIN)
#if EXTRUDERS > 2
|| !READ(E2_ENABLE_PIN)
#endif
#if EXTRUDER > 1
|| !READ(E2_ENABLE_PIN)
#endif
|| !READ(E0_ENABLE_PIN)) //If any of the drivers are enabled...
{
lastMotor = millis(); //... set time to NOW so the fan will turn on
}
if ((millis() - lastMotor) >= (CONTROLLERFAN_SEC*1000UL) || lastMotor == 0) //If the last time any driver was enabled, is longer since than CONTROLLERSEC...
{
WRITE(CONTROLLERFAN_PIN, LOW); //... turn the fan off
}
else
{
WRITE(CONTROLLERFAN_PIN, HIGH); //... turn the fan on
}
}
}
#endif
2011-11-06 19:23:08 +01:00
void manage_inactivity(byte debug)
{
2012-02-08 18:28:54 +01:00
if( (millis() - previous_millis_cmd) > max_inactive_time )
2011-11-06 19:23:08 +01:00
if(max_inactive_time)
kill();
2012-02-11 23:22:16 +01:00
if(stepper_inactive_time) {
if( (millis() - previous_millis_cmd) > stepper_inactive_time )
2011-12-09 15:09:52 +01:00
{
2012-03-09 20:20:01 +01:00
if(blocks_queued() == false) {
disable_x();
disable_y();
disable_z();
disable_e0();
disable_e1();
disable_e2();
}
2011-11-06 19:23:08 +01:00
}
2011-12-09 15:09:52 +01:00
}
2012-03-11 10:44:10 +01:00
#ifdef CONTROLLERFAN_PIN
controllerFan(); //Check if fan should be turned on to cool stepper drivers down
#endif
2011-12-09 13:39:00 +01:00
#ifdef EXTRUDER_RUNOUT_PREVENT
2012-02-08 18:28:54 +01:00
if( (millis() - previous_millis_cmd) > EXTRUDER_RUNOUT_SECONDS*1000 )
2011-12-09 13:39:00 +01:00
if(degHotend(active_extruder)>EXTRUDER_RUNOUT_MINTEMP)
{
2011-12-15 11:59:07 +01:00
bool oldstatus=READ(E0_ENABLE_PIN);
enable_e0();
2011-12-09 13:39:00 +01:00
float oldepos=current_position[E_AXIS];
float oldedes=destination[E_AXIS];
2011-12-09 13:56:28 +01:00
plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS],
current_position[E_AXIS]+EXTRUDER_RUNOUT_EXTRUDE*EXTRUDER_RUNOUT_ESTEPS/axis_steps_per_unit[E_AXIS],
2011-12-09 14:07:32 +01:00
EXTRUDER_RUNOUT_SPEED/60.*EXTRUDER_RUNOUT_ESTEPS/axis_steps_per_unit[E_AXIS], active_extruder);
2011-12-09 13:39:00 +01:00
current_position[E_AXIS]=oldepos;
destination[E_AXIS]=oldedes;
plan_set_e_position(oldepos);
previous_millis_cmd=millis();
2011-12-11 15:42:56 +01:00
st_synchronize();
2011-12-15 11:59:07 +01:00
WRITE(E0_ENABLE_PIN,oldstatus);
2011-12-09 13:39:00 +01:00
}
#endif
2011-11-06 12:39:00 +01:00
check_axes_activity();
}
2011-11-06 14:03:41 +01:00
2011-11-06 15:10:29 +01:00
void kill()
{
2011-12-12 19:34:37 +01:00
cli(); // Stop interrupts
2011-11-06 15:10:29 +01:00
disable_heater();
disable_x();
disable_y();
disable_z();
2011-12-06 05:33:33 +01:00
disable_e0();
disable_e1();
disable_e2();
2011-11-06 15:10:29 +01:00
if(PS_ON_PIN > -1) pinMode(PS_ON_PIN,INPUT);
2011-11-09 20:27:15 +01:00
SERIAL_ERROR_START;
2012-03-03 16:51:47 +01:00
SERIAL_ERRORLNPGM(MSG_ERR_KILLED);
LCD_MESSAGEPGM(MSG_KILLED);
2012-01-15 17:06:10 +01:00
suicide();
2011-11-06 15:10:29 +01:00
while(1); // Wait for reset
}
2012-03-25 14:36:51 +02:00
void Stop()
{
disable_heater();
if(Stopped == false) {
Stopped = true;
Stopped_gcode_LastN = gcode_LastN; // Save last g_code for restart
SERIAL_ERROR_START;
SERIAL_ERRORLNPGM(MSG_ERR_STOPPED);
LCD_MESSAGEPGM(MSG_STOPPED);
}
}
bool IsStopped() { return Stopped; };
2012-05-02 19:26:14 +02:00
#ifdef FAST_PWM_FAN
void setPwmFrequency(uint8_t pin, int val)
{
val &= 0x07;
switch(digitalPinToTimer(pin))
{
#if defined(TCCR0A)
case TIMER0A:
case TIMER0B:
2012-05-28 21:32:53 +02:00
// TCCR0B &= ~(CS00 | CS01 | CS02);
// TCCR0B |= val;
2012-05-02 19:26:14 +02:00
break;
#endif
#if defined(TCCR1A)
case TIMER1A:
case TIMER1B:
2012-05-28 21:32:53 +02:00
// TCCR1B &= ~(CS10 | CS11 | CS12);
// TCCR1B |= val;
2012-05-02 19:26:14 +02:00
break;
#endif
#if defined(TCCR2)
case TIMER2:
case TIMER2:
TCCR2 &= ~(CS10 | CS11 | CS12);
TCCR2 |= val;
break;
#endif
#if defined(TCCR2A)
case TIMER2A:
case TIMER2B:
TCCR2B &= ~(CS20 | CS21 | CS22);
TCCR2B |= val;
break;
#endif
#if defined(TCCR3A)
case TIMER3A:
case TIMER3B:
case TIMER3C:
TCCR3B &= ~(CS30 | CS31 | CS32);
TCCR3B |= val;
break;
#endif
#if defined(TCCR4A)
case TIMER4A:
case TIMER4B:
case TIMER4C:
TCCR4B &= ~(CS40 | CS41 | CS42);
TCCR4B |= val;
break;
#endif
#if defined(TCCR5A)
case TIMER5A:
case TIMER5B:
case TIMER5C:
TCCR5B &= ~(CS50 | CS51 | CS52);
TCCR5B |= val;
break;
#endif
}
}
#endif
2011-11-06 15:10:29 +01:00