RepetierMAX/Repetier/Commands.cpp
johnoly99 66834930fd Fixed merge of wrong versions
Getting compile errors from merging wrong versions, now fixed!
2013-05-01 15:45:11 -04:00

1131 lines
43 KiB
C++

/*
This file is part of Repetier-Firmware.
Repetier-Firmware 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.
Repetier-Firmware 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 Repetier-Firmware. If not, see <http://www.gnu.org/licenses/>.
This firmware is a nearly complete rewrite of the sprinter firmware
by kliment (https://github.com/kliment/Sprinter)
which based on Tonokip RepRap firmware rewrite based off of Hydra-mmm firmware.
*/
#include "Reptier.h"
#if EEPROM_MODE != 0
#include "Eeprom.h"
#endif
#include "pins_arduino.h"
#include "ui.h"
#include <SPI.h>
const int sensitive_pins[] PROGMEM = SENSITIVE_PINS; // Sensitive pin list for M42
void check_periodical() {
if(!execute_periodical) return;
execute_periodical=0;
manage_temperatures();
if(--counter_250ms==0) {
if(manage_monitor<=1+NUM_EXTRUDER)
write_monitor();
counter_250ms=5;
}
UI_SLOW;
}
/** \brief Waits until movement cache is empty.
Some commands expect no movement, before they can execute. This function
waits, until the steppers are stopped. In the meanwhile it buffers incoming
commands and manages temperatures.
*/
void wait_until_end_of_move() {
while(lines_count) {
gcode_read_serial();
check_periodical();
UI_MEDIUM;
}
}
void printPosition() {
OUT_P_F("X:",printer_state.currentPositionSteps[0]*inv_axis_steps_per_unit[0]*(unit_inches?0.03937:1));
OUT_P_F(" Y:",printer_state.currentPositionSteps[1]*inv_axis_steps_per_unit[1]*(unit_inches?0.03937:1));
OUT_P_F(" Z:",printer_state.currentPositionSteps[2]*inv_axis_steps_per_unit[2]*(unit_inches?0.03937:1));
OUT_P_F_LN(" E:",printer_state.currentPositionSteps[3]*inv_axis_steps_per_unit[3]*(unit_inches?0.03937:1));
}
void print_temperatures() {
float temp = current_extruder->tempControl.currentTemperatureC;
#if HEATED_BED_SENSOR_TYPE==0
OUT_P_F("T:",temp);
#else
OUT_P_F("T:",temp);
OUT_P_F(" B:",heated_bed_get_temperature());
#endif
#ifdef TEMP_PID
OUT_P_I(" @:",(autotuneIndex==255?pwm_pos[current_extruder->id]:pwm_pos[autotuneIndex])); // Show output of autotune when tuning!
#endif
#if NUM_EXTRUDER>1
for(byte i=0;i<NUM_EXTRUDER;i++) {
OUT_P(" T");
out.print((int)i);
OUT_P_F(":",extruder[i].tempControl.currentTemperatureC);
#ifdef TEMP_PID
OUT_P(" @");
out.print((int)i);
OUT_P_I(":",(pwm_pos[extruder[i].tempControl.pwmIndex])); // Show output of autotune when tuning!
#endif
}
#endif
OUT_LN;
}
void change_feedrate_multiply(int factor) {
if(factor<25) factor=25;
if(factor>500) factor=500;
printer_state.feedrate *= (float)factor/(float)printer_state.feedrateMultiply;
printer_state.feedrateMultiply = factor;
OUT_P_I_LN("SpeedMultiply:",factor);
}
void change_flowate_multiply(int factor) {
if(factor<25) factor=25;
if(factor>200) factor=200;
printer_state.extrudeMultiply = factor;
OUT_P_I_LN("FlowMultiply:",factor);
}
void set_fan_speed(int speed,bool wait) {
#if FAN_PIN>=0
speed = constrain(speed,0,255);
if(wait)
wait_until_end_of_move(); // use only if neededthis to change the speed exactly at that point, but it may cause blobs if you do!
pwm_pos[NUM_EXTRUDER+2] = speed;
#endif
}
#if DRIVE_SYSTEM==3
void delta_move_to_top_endstops(float feedrate) {
long up_steps = printer_state.zMaxSteps;
for (byte i=0; i<3; i++)
printer_state.currentPositionSteps[i] = 0;
calculate_delta(printer_state.currentPositionSteps, printer_state.currentDeltaPositionSteps);
move_steps(0,0,printer_state.zMaxSteps*ENDSTOP_Z_BACK_MOVE,0,feedrate, true, true);
}
void home_axis(bool xaxis,bool yaxis,bool zaxis) {
long steps;
bool homeallaxis = (xaxis && yaxis && zaxis) || (!xaxis && !yaxis && !zaxis);
if (X_MAX_PIN > -1 && Y_MAX_PIN > -1 && Z_MAX_PIN > -1 && MAX_HARDWARE_ENDSTOP_X & MAX_HARDWARE_ENDSTOP_Y && MAX_HARDWARE_ENDSTOP_Z) {
UI_STATUS_UPD(UI_TEXT_HOME_DELTA);
// Homing Z axis means that you must home X and Y
if (homeallaxis || zaxis) {
delta_move_to_top_endstops(homing_feedrate[0]);
move_steps(0,0,axis_steps_per_unit[0]*-ENDSTOP_Z_BACK_MOVE,0,homing_feedrate[0]/ENDSTOP_X_RETEST_REDUCTION_FACTOR, true, false);
delta_move_to_top_endstops(homing_feedrate[0]/ENDSTOP_X_RETEST_REDUCTION_FACTOR);
printer_state.currentPositionSteps[0] = 0;
printer_state.currentPositionSteps[1] = 0;
printer_state.currentPositionSteps[2] = printer_state.zMaxSteps;
calculate_delta(printer_state.currentPositionSteps, printer_state.currentDeltaPositionSteps);
printer_state.maxDeltaPositionSteps = printer_state.currentDeltaPositionSteps[0];
} else {
if (xaxis) printer_state.destinationSteps[0] = 0;
if (yaxis) printer_state.destinationSteps[1] = 0;
split_delta_move(true,false,false);
}
printer_state.countZSteps = 0;
UI_CLEAR_STATUS
}
}
#else
void home_axis(bool xaxis,bool yaxis,bool zaxis) {
long steps;
if(xaxis) {
if ((MIN_HARDWARE_ENDSTOP_X && X_MIN_PIN > -1 && X_HOME_DIR==-1) || (MAX_HARDWARE_ENDSTOP_X && X_MAX_PIN > -1 && X_HOME_DIR==1)){
UI_STATUS_UPD(UI_TEXT_HOME_X);
steps = (printer_state.xMaxSteps-printer_state.xMinSteps) * X_HOME_DIR;
printer_state.currentPositionSteps[0] = -steps;
move_steps(2*steps,0,0,0,homing_feedrate[0],true,true);
printer_state.currentPositionSteps[0] = 0;
move_steps(axis_steps_per_unit[0]*-ENDSTOP_X_BACK_MOVE * X_HOME_DIR,0,0,0,homing_feedrate[0]/ENDSTOP_X_RETEST_REDUCTION_FACTOR,true,false);
move_steps(axis_steps_per_unit[0]*2*ENDSTOP_X_BACK_MOVE * X_HOME_DIR,0,0,0,homing_feedrate[0]/ENDSTOP_X_RETEST_REDUCTION_FACTOR,true,true);
#if defined(ENDSTOP_X_BACK_ON_HOME)
if(ENDSTOP_X_BACK_ON_HOME > 0)
move_steps(axis_steps_per_unit[0]*-ENDSTOP_X_BACK_ON_HOME * X_HOME_DIR,0,0,0,homing_feedrate[0],true,false);
#endif
long offX = 0;
#if NUM_EXTRUDER>1
for(byte i=0;i<NUM_EXTRUDER;i++) offX = max(offX,extruder[i].xOffset);
// Reposition extruder that way, that all extruders can be selected at home pos.
#endif
printer_state.currentPositionSteps[0] = (X_HOME_DIR == -1) ? printer_state.xMinSteps-offX : printer_state.xMaxSteps+offX;
#if NUM_EXTRUDER>1
move_steps((current_extruder->xOffset-offX) * X_HOME_DIR,0,0,0,homing_feedrate[0],true,false);
#endif
}
}
if(yaxis) {
if ((MIN_HARDWARE_ENDSTOP_Y && Y_MIN_PIN > -1 && Y_HOME_DIR==-1) || (MAX_HARDWARE_ENDSTOP_Y && Y_MAX_PIN > -1 && Y_HOME_DIR==1)){
UI_STATUS_UPD(UI_TEXT_HOME_Y);
steps = (printer_state.yMaxSteps-printer_state.yMinSteps) * Y_HOME_DIR;
printer_state.currentPositionSteps[1] = -steps;
move_steps(0,2*steps,0,0,homing_feedrate[1],true,true);
printer_state.currentPositionSteps[1] = 0;
move_steps(0,axis_steps_per_unit[1]*-ENDSTOP_Y_BACK_MOVE * Y_HOME_DIR,0,0,homing_feedrate[1]/ENDSTOP_X_RETEST_REDUCTION_FACTOR,true,false);
move_steps(0,axis_steps_per_unit[1]*2*ENDSTOP_Y_BACK_MOVE * Y_HOME_DIR,0,0,homing_feedrate[1]/ENDSTOP_X_RETEST_REDUCTION_FACTOR,true,true);
#if defined(ENDSTOP_Y_BACK_ON_HOME)
if(ENDSTOP_Y_BACK_ON_HOME > 0)
move_steps(0,axis_steps_per_unit[1]*-ENDSTOP_Y_BACK_ON_HOME * Y_HOME_DIR,0,0,homing_feedrate[1],true,false);
#endif
long offY = 0;
#if NUM_EXTRUDER>1
for(byte i=0;i<NUM_EXTRUDER;i++) offY = max(offY,extruder[i].yOffset);
// Reposition extruder that way, that all extruders can be selected at home pos.
#endif
printer_state.currentPositionSteps[1] = (Y_HOME_DIR == -1) ? printer_state.yMinSteps-offY : printer_state.yMaxSteps+offY;
#if NUM_EXTRUDER>1
move_steps(0,(current_extruder->yOffset-offY) * Y_HOME_DIR,0,0,homing_feedrate[1],true,false);
#endif
}
}
if(zaxis) {
if ((MIN_HARDWARE_ENDSTOP_Z && Z_MIN_PIN > -1 && Z_HOME_DIR==-1) || (MAX_HARDWARE_ENDSTOP_Z && Z_MAX_PIN > -1 && Z_HOME_DIR==1)){
UI_STATUS_UPD(UI_TEXT_HOME_Z);
steps = (printer_state.zMaxSteps-printer_state.zMinSteps) * Z_HOME_DIR;
printer_state.currentPositionSteps[2] = -steps;
move_steps(0,0,2*steps,0,homing_feedrate[2],true,true);
printer_state.currentPositionSteps[2] = 0;
move_steps(0,0,axis_steps_per_unit[2]*-ENDSTOP_Z_BACK_MOVE * Z_HOME_DIR,0,homing_feedrate[2]/ENDSTOP_Z_RETEST_REDUCTION_FACTOR,true,false);
move_steps(0,0,axis_steps_per_unit[2]*2*ENDSTOP_Z_BACK_MOVE * Z_HOME_DIR,0,homing_feedrate[2]/ENDSTOP_Z_RETEST_REDUCTION_FACTOR,true,true);
#if defined(ENDSTOP_Z_BACK_ON_HOME)
if(ENDSTOP_Z_BACK_ON_HOME > 0)
move_steps(0,0,axis_steps_per_unit[2]*-ENDSTOP_Z_BACK_ON_HOME * Z_HOME_DIR,0,homing_feedrate[2],true,false);
#endif
printer_state.currentPositionSteps[2] = (Z_HOME_DIR == -1) ? printer_state.zMinSteps : printer_state.zMaxSteps;
}
}
UI_CLEAR_STATUS
}
#endif
#if STEPPER_CURRENT_CONTROL==CURRENT_CONTROL_DIGIPOT
// Digipot methods for controling current and microstepping
#if defined(DIGIPOTSS_PIN) && DIGIPOTSS_PIN > -1
int digitalPotWrite(int address, unsigned int value) // From Arduino DigitalPotControl example
{
digitalWrite(DIGIPOTSS_PIN,LOW); // take the SS pin low to select the chip
SPI.transfer(address); // send in the address and value via SPI:
SPI.transfer(value);
digitalWrite(DIGIPOTSS_PIN,HIGH); // take the SS pin high to de-select the chip:
//delay(10);
}
void set_current(uint8_t driver, unsigned int current)
{
const uint8_t digipot_ch[] = DIGIPOT_CHANNELS;
digitalPotWrite(digipot_ch[driver], current);
}
#endif
void current_control_init() //Initialize Digipot Motor Current
{
#if DIGIPOTSS_PIN && DIGIPOTSS_PIN > -1
const uint8_t digipot_motor_current[] = MOTOR_CURRENT;
SPI.begin();
SET_OUTPUT(DIGIPOTSS_PIN);
for(int i=0;i<=4;i++)
//digitalPotWrite(digipot_ch[i], digipot_motor_current[i]);
set_current(i,digipot_motor_current[i]);
#endif
}
#endif
#if STEPPER_CURRENT_CONTROL==CURRENT_CONTROL_LTC2600
void set_current( byte channel, unsigned short level )
{
const byte ltc_channels[] = LTC2600_CHANNELS;
if(channel>LTC2600_NUM_CHANNELS) return;
byte address = ltc_channels[channel];
char i;
// NOTE: Do not increase the current endlessly. In case the engine reaches its current saturation, the engine and the driver can heat up and loss power.
// When the saturation is reached, more current causes more heating and more power loss.
// In case of engines with lower quality, the saturation current may be reached before the nominal current.
// configure the pins
WRITE( LTC2600_CS_PIN, HIGH );
SET_OUTPUT( LTC2600_CS_PIN );
WRITE( LTC2600_SCK_PIN, LOW );
SET_OUTPUT( LTC2600_SCK_PIN );
WRITE( LTC2600_SDI_PIN, LOW );
SET_OUTPUT( LTC2600_SDI_PIN );
// enable the command interface of the LTC2600
WRITE( LTC2600_CS_PIN, LOW );
// transfer command and address
for( i=7; i>=0; i-- ) {
WRITE( LTC2600_SDI_PIN, address & (0x01 << i));
WRITE( LTC2600_SCK_PIN, 1 );
WRITE( LTC2600_SCK_PIN, 0 );
}
// transfer the data word
for( i=15; i>=0; i-- ) {
WRITE( LTC2600_SDI_PIN, level & (0x01 << i));
WRITE( LTC2600_SCK_PIN, 1 );
WRITE( LTC2600_SCK_PIN, 0 );
}
// disable the ommand interface of the LTC2600 -
// this carries out the specified command
WRITE( LTC2600_CS_PIN, HIGH );
} // setLTC2600
void current_control_init() //Initialize LTC2600 Motor Current
{
const unsigned int ltc_current[] = MOTOR_CURRENT;
byte i;
for(i=0;i<LTC2600_NUM_CHANNELS;i++) {
set_current(i, ltc_current[i] );
}
}
#endif
#if defined(X_MS1_PIN) && X_MS1_PIN > -1
void microstep_ms(uint8_t driver, int8_t ms1, int8_t ms2)
{
if(ms1 > -1) switch(driver)
{
case 0: WRITE( X_MS1_PIN,ms1); break;
case 1: WRITE( Y_MS1_PIN,ms1); break;
case 2: WRITE( Z_MS1_PIN,ms1); break;
case 3: WRITE(E0_MS1_PIN,ms1); break;
case 4: WRITE(E1_MS1_PIN,ms1); break;
}
if(ms2 > -1) switch(driver)
{
case 0: WRITE( X_MS2_PIN,ms2); break;
case 1: WRITE( Y_MS2_PIN,ms2); break;
case 2: WRITE( Z_MS2_PIN,ms2); break;
case 3: WRITE(E0_MS2_PIN,ms2); break;
case 4: WRITE(E1_MS2_PIN,ms2); break;
}
}
void microstep_mode(uint8_t driver, uint8_t stepping_mode)
{
switch(stepping_mode)
{
case 1: microstep_ms(driver,MICROSTEP1); break;
case 2: microstep_ms(driver,MICROSTEP2); break;
case 4: microstep_ms(driver,MICROSTEP4); break;
case 8: microstep_ms(driver,MICROSTEP8); break;
case 16: microstep_ms(driver,MICROSTEP16); break;
}
}
void microstep_readings()
{
out.println_P(PSTR("MS1,MS2 Pins"));
out.print_int_P(PSTR("X: "), READ(X_MS1_PIN));
out.println_int_P(PSTR(","),READ(X_MS2_PIN));
out.print_int_P(PSTR("Y: "), READ(Y_MS1_PIN));
out.println_int_P(PSTR(","),READ(Y_MS2_PIN));
out.print_int_P(PSTR("Z: "), READ(Z_MS1_PIN));
out.println_int_P(PSTR(","),READ(Z_MS2_PIN));
out.print_int_P(PSTR("E0: "), READ(E0_MS1_PIN));
out.println_int_P(PSTR(","),READ(E0_MS2_PIN));
out.print_int_P(PSTR("E1: "), READ(E1_MS1_PIN));
out.println_int_P(PSTR(","),READ(E1_MS2_PIN));
}
#endif
void microstep_init()
{
#if defined(X_MS1_PIN) && X_MS1_PIN > -1
const uint8_t microstep_modes[] = MICROSTEP_MODES;
SET_OUTPUT(X_MS2_PIN);
SET_OUTPUT(Y_MS2_PIN);
SET_OUTPUT(Z_MS2_PIN);
SET_OUTPUT(E0_MS2_PIN);
SET_OUTPUT(E1_MS2_PIN);
for(int i=0;i<=4;i++) microstep_mode(i,microstep_modes[i]);
#endif
}
/**
\brief Execute the command stored in com.
*/
void process_command(GCode *com,byte bufferedCommand)
{
unsigned long codenum; //throw away variable
#ifdef INCLUDE_DEBUG_COMMUNICATION
if(DEBUG_COMMUNICATION) {
if(GCODE_HAS_G(com) || (GCODE_HAS_M(com) && com->M!=111)) {
gcode_command_finished(com); // free command cache
previous_millis_cmd = millis();
return;
}
}
#endif
if(GCODE_HAS_G(com))
{
switch(com->G)
{
case 0: // G0 -> G1
case 1: // G1
if(get_coordinates(com)) // For X Y Z E F
#if DRIVE_SYSTEM == 3
split_delta_move(ALWAYS_CHECK_ENDSTOPS, true, true);
#else
queue_move(ALWAYS_CHECK_ENDSTOPS,true);
#endif
break;
#if ARC_SUPPORT
case 2: // CW Arc
case 3: // CCW Arc MOTION_MODE_CW_ARC: case MOTION_MODE_CCW_ARC:
{
if(!get_coordinates(com)) break; // For X Y Z E F
float offset[2] = {(GCODE_HAS_I(com)?com->I:0),(GCODE_HAS_J(com)?com->J:0)};
if(unit_inches) {
offset[0]*=25.4;
offset[1]*=25.4;
}
float position[2] = {printer_state.currentPositionSteps[0]*inv_axis_steps_per_unit[0],printer_state.currentPositionSteps[1]*inv_axis_steps_per_unit[1]};
float target[2] = {printer_state.destinationSteps[0]*inv_axis_steps_per_unit[0],printer_state.destinationSteps[1]*inv_axis_steps_per_unit[1]};
float r;
if (GCODE_HAS_R(com)) {
/*
We need to calculate the center of the circle that has the designated radius and passes
through both the current position and the target position. This method calculates the following
set of equations where [x,y] is the vector from current to target position, d == magnitude of
that vector, h == hypotenuse of the triangle formed by the radius of the circle, the distance to
the center of the travel vector. A vector perpendicular to the travel vector [-y,x] is scaled to the
length of h [-y/d*h, x/d*h] and added to the center of the travel vector [x/2,y/2] to form the new point
[i,j] at [x/2-y/d*h, y/2+x/d*h] which will be the center of our arc.
d^2 == x^2 + y^2
h^2 == r^2 - (d/2)^2
i == x/2 - y/d*h
j == y/2 + x/d*h
O <- [i,j]
- |
r - |
- |
- | h
- |
[0,0] -> C -----------------+--------------- T <- [x,y]
| <------ d/2 ---->|
C - Current position
T - Target position
O - center of circle that pass through both C and T
d - distance from C to T
r - designated radius
h - distance from center of CT to O
Expanding the equations:
d -> sqrt(x^2 + y^2)
h -> sqrt(4 * r^2 - x^2 - y^2)/2
i -> (x - (y * sqrt(4 * r^2 - x^2 - y^2)) / sqrt(x^2 + y^2)) / 2
j -> (y + (x * sqrt(4 * r^2 - x^2 - y^2)) / sqrt(x^2 + y^2)) / 2
Which can be written:
i -> (x - (y * sqrt(4 * r^2 - x^2 - y^2))/sqrt(x^2 + y^2))/2
j -> (y + (x * sqrt(4 * r^2 - x^2 - y^2))/sqrt(x^2 + y^2))/2
Which we for size and speed reasons optimize to:
h_x2_div_d = sqrt(4 * r^2 - x^2 - y^2)/sqrt(x^2 + y^2)
i = (x - (y * h_x2_div_d))/2
j = (y + (x * h_x2_div_d))/2
*/
r = com->R;
if(unit_inches) r*=25.4;
// Calculate the change in position along each selected axis
double x = target[0]-position[0];
double y = target[1]-position[1];
double h_x2_div_d = -sqrt(4 * r*r - x*x - y*y)/hypot(x,y); // == -(h * 2 / d)
// If r is smaller than d, the arc is now traversing the complex plane beyond the reach of any
// real CNC, and thus - for practical reasons - we will terminate promptly:
if(isnan(h_x2_div_d)) { OUT_P_LN("error: Invalid arc"); break; }
// Invert the sign of h_x2_div_d if the circle is counter clockwise (see sketch below)
if (com->G==3) { h_x2_div_d = -h_x2_div_d; }
/* The counter clockwise circle lies to the left of the target direction. When offset is positive,
the left hand circle will be generated - when it is negative the right hand circle is generated.
T <-- Target position
^
Clockwise circles with this center | Clockwise circles with this center will have
will have > 180 deg of angular travel | < 180 deg of angular travel, which is a good thing!
\ | /
center of arc when h_x2_div_d is positive -> x <----- | -----> x <- center of arc when h_x2_div_d is negative
|
|
C <-- Current position */
// Negative R is g-code-alese for "I want a circle with more than 180 degrees of travel" (go figure!),
// even though it is advised against ever generating such circles in a single line of g-code. By
// inverting the sign of h_x2_div_d the center of the circles is placed on the opposite side of the line of
// travel and thus we get the unadvisably long arcs as prescribed.
if (r < 0) {
h_x2_div_d = -h_x2_div_d;
r = -r; // Finished with r. Set to positive for mc_arc
}
// Complete the operation by calculating the actual center of the arc
offset[0] = 0.5*(x-(y*h_x2_div_d));
offset[1] = 0.5*(y+(x*h_x2_div_d));
} else { // Offset mode specific computations
r = hypot(offset[0], offset[1]); // Compute arc radius for mc_arc
}
// Set clockwise/counter-clockwise sign for mc_arc computations
uint8_t isclockwise = com->G == 2;
// Trace the arc
mc_arc(position, target, offset,r, isclockwise);
break;
}
#endif
case 4: // G4 dwell
wait_until_end_of_move();
codenum = 0;
if(GCODE_HAS_P(com)) codenum = com->P; // milliseconds to wait
if(GCODE_HAS_S(com)) codenum = (long)com->S * 1000; // seconds to wait
codenum += millis(); // keep track of when we started waiting
while((unsigned long)(codenum-millis()) < 2000000000 ){
gcode_read_serial();
check_periodical();
}
break;
case 20: // Units to inches
unit_inches = 1;
break;
case 21: // Units to mm
unit_inches = 0;
break;
case 28: {//G28 Home all Axis one at a time
byte home_all_axis = (GCODE_HAS_NO_XYZ(com));
home_axis(home_all_axis || GCODE_HAS_X(com),home_all_axis || GCODE_HAS_Y(com),home_all_axis || GCODE_HAS_Z(com));
}
break;
case 90: // G90
relative_mode = false;
break;
case 91: // G91
relative_mode = true;
break;
case 92: // G92
if(GCODE_HAS_X(com)) printer_state.currentPositionSteps[0] = com->X*axis_steps_per_unit[0]*(unit_inches?25.4:1.0)-printer_state.offsetX;
if(GCODE_HAS_Y(com)) printer_state.currentPositionSteps[1] = com->Y*axis_steps_per_unit[1]*(unit_inches?25.4:1.0)-printer_state.offsetY;
if(GCODE_HAS_Z(com)) printer_state.currentPositionSteps[2] = com->Z*axis_steps_per_unit[2]*(unit_inches?25.4:1.0);
if(GCODE_HAS_E(com)) {
printer_state.currentPositionSteps[3] = com->E*axis_steps_per_unit[3]*(unit_inches?25.4:1.0);
}
break;
}
previous_millis_cmd = millis();
}
else if(GCODE_HAS_M(com)) { // Process M Code
switch( com->M ) {
#if SDSUPPORT
case 20: // M20 - list SD card
sd.ls();
break;
case 21: // M21 - init SD card
sd.mount();
break;
case 22: //M22 - release SD card
sd.unmount();
break;
case 23: //M23 - Select file
if(GCODE_HAS_STRING(com))
sd.selectFile(com->text);
break;
case 24: //M24 - Start SD print
sd.startPrint();
break;
case 25: //M25 - Pause SD print
sd.pausePrint();
break;
case 26: //M26 - Set SD index
if(GCODE_HAS_S(com))
sd.setIndex(com->S);
break;
case 27: //M27 - Get SD status
sd.printStatus();
break;
case 28: //M28 - Start SD write
if(GCODE_HAS_STRING(com))
sd.startWrite(com->text);
break;
case 29: //M29 - Stop SD write
//processed in write to file routine above
//savetosd = false;
break;
case 30: // M30 filename - Delete file
if(GCODE_HAS_STRING(com))
sd.deleteFile(com->text);
break;
case 32: // M32 directoryname
if(GCODE_HAS_STRING(com))
sd.makeDirectory(com->text);
break;
#endif
case 42: //M42 -Change pin status via gcode
if (GCODE_HAS_S(com) && GCODE_HAS_P(com) && com->S>=0 && com->S<=255) {
int pin_number = com->P;
for(byte i = 0; i < (byte)sizeof(sensitive_pins); i++) {
if (pgm_read_byte(&sensitive_pins[i]) == pin_number)
{
pin_number = -1;
break;
}
}
if (pin_number > -1) {
pinMode(pin_number, OUTPUT);
digitalWrite(pin_number, com->S);
analogWrite(pin_number, com->S);
out.print_int_P(PSTR("Set output "),pin_number);
out.println_int_P(PSTR(" to "),(int)com->S);
}
}
break;
case 104: // M104
if(reportTempsensorError()) break;
previous_millis_cmd = millis();
if(DEBUG_DRYRUN) break;
#ifdef EXACT_TEMPERATURE_TIMING
wait_until_end_of_move();
#else
if(GCODE_HAS_P(com))
wait_until_end_of_move();
#endif
if (GCODE_HAS_S(com)) {
if(GCODE_HAS_T(com))
extruder_set_temperature(com->S,com->T);
else
extruder_set_temperature(com->S,current_extruder->id);
}
break;
case 140: // M140 set bed temp
if(reportTempsensorError()) break;
previous_millis_cmd = millis();
if(DEBUG_DRYRUN) break;
if (GCODE_HAS_S(com)) heated_bed_set_temperature(com->S);
break;
case 105: // M105 get temperature. Always returns the current temperature, doesn't wait until move stopped
print_temperatures();
break;
case 109: // M109 - Wait for extruder heater to reach target.
{
if(reportTempsensorError()) break;
previous_millis_cmd = millis();
if(DEBUG_DRYRUN) break;
UI_STATUS_UPD(UI_TEXT_HEATING_EXTRUDER);
wait_until_end_of_move();
Extruder *actExtruder = current_extruder;
if(GCODE_HAS_T(com) && com->T<NUM_EXTRUDER) actExtruder = &extruder[com->T];
if (GCODE_HAS_S(com)) extruder_set_temperature(com->S,actExtruder->id);
#if defined(SKIP_M109_IF_WITHIN) && SKIP_M109_IF_WITHIN>0
if(abs(actExtruder->tempControl.currentTemperatureC - actExtruder->tempControl.targetTemperatureC)<(SKIP_M109_IF_WITHIN)) break; // Already in range
#endif
bool dir = actExtruder->tempControl.targetTemperature > actExtruder->tempControl.currentTemperature;
codenum = millis();
unsigned long waituntil = 0;
#if RETRACT_DURING_HEATUP
byte retracted = 0;
#endif
unsigned long cur_time;
do {
cur_time = millis();
if( (cur_time - codenum) > 1000 ) { //Print Temp Reading every 1 second while heating up.
print_temperatures();
codenum = cur_time;
}
check_periodical();
//gcode_read_serial();
#if RETRACT_DURING_HEATUP
if (actExtruder==current_extruder && actExtruder->waitRetractUnits > 0 && !retracted && dir && actExtruder->tempControl.currentTemperatureC > actExtruder->waitRetractTemperature) {
move_steps(0,0,0,-actExtruder->waitRetractUnits * axis_steps_per_unit[3],actExtruder->maxFeedrate,false,false);
retracted = 1;
}
#endif
if((waituntil==0 && (dir ? actExtruder->tempControl.currentTemperatureC >= actExtruder->tempControl.targetTemperatureC-0.5:actExtruder->tempControl.currentTemperatureC <= actExtruder->tempControl.targetTemperatureC+0.5))
#ifdef TEMP_HYSTERESIS
|| (waituntil!=0 && (abs(actExtruder->tempControl.currentTemperatureC - actExtruder->tempControl.targetTemperatureC))>TEMP_HYSTERESIS)
#endif
) {
waituntil = cur_time+1000UL*(unsigned long)actExtruder->watchPeriod; // now wait for temp. to stabalize
}
} while(waituntil==0 || (waituntil!=0 && (unsigned long)(waituntil-cur_time)<2000000000UL));
#if RETRACT_DURING_HEATUP
if (retracted && actExtruder==current_extruder) {
move_steps(0,0,0,actExtruder->waitRetractUnits * axis_steps_per_unit[3],actExtruder->maxFeedrate,false,false);
}
#endif
}
UI_CLEAR_STATUS;
previous_millis_cmd = millis();
break;
case 190: // M190 - Wait bed for heater to reach target.
#if HAVE_HEATED_BED
if(DEBUG_DRYRUN) break;
UI_STATUS_UPD(UI_TEXT_HEATING_BED);
wait_until_end_of_move();
#if HAVE_HEATED_BED
if (GCODE_HAS_S(com)) heated_bed_set_temperature(com->S);
#if defined(SKIP_M190_IF_WITHIN) && SKIP_M190_IF_WITHIN>0
if(abs(heatedBedController.currentTemperatureC-heatedBedController.targetTemperatureC)<SKIP_M190_IF_WITHIN) break;
#endif
codenum = millis();
while(heatedBedController.currentTemperatureC+0.5<heatedBedController.targetTemperatureC) {
if( (millis()-codenum) > 1000 ) { //Print Temp Reading every 1 second while heating up.
print_temperatures();
codenum = millis();
}
check_periodical();
}
#endif
#endif
UI_CLEAR_STATUS;
previous_millis_cmd = millis();
break;
#ifdef TEMP_PID
case 303: {
int temp = 150;
int cont = 0;
if(GCODE_HAS_S(com)) temp = com->S;
if(GCODE_HAS_P(com)) cont = com->P;
if(cont>=NUM_TEMPERATURE_LOOPS) cont = NUM_TEMPERATURE_LOOPS;
autotunePID(temp,cont);
}
break;
#endif
#if FAN_PIN>-1 && FEATURE_FAN_CONTROL
case 106: //M106 Fan On
set_fan_speed(GCODE_HAS_S(com)?com->S:255,GCODE_HAS_P(com));
break;
case 107: //M107 Fan Off
set_fan_speed(0,GCODE_HAS_P(com));
break;
#endif
case 80: // M80 - ATX Power On
#if PS_ON_PIN>-1
wait_until_end_of_move();
previous_millis_cmd = millis();
SET_OUTPUT(PS_ON_PIN); //GND
WRITE(PS_ON_PIN, LOW);
#endif
break;
case 81: // M81 - ATX Power Off
#if PS_ON_PIN>-1
wait_until_end_of_move();
SET_OUTPUT(PS_ON_PIN); //GND
WRITE(PS_ON_PIN, HIGH);
#endif
break;
case 82:
relative_mode_e = false;
break;
case 83:
relative_mode_e = true;
break;
case 84:
if(GCODE_HAS_S(com)){ stepper_inactive_time = com->S * 1000; }
else{
wait_until_end_of_move();
kill(true);
}
break;
case 85: // M85
if(GCODE_HAS_S(com))
max_inactive_time = (long)com->S * 1000;
else
max_inactive_time = 0;
break;
case 92: // M92
if(GCODE_HAS_X(com)) axis_steps_per_unit[0] = com->X;
if(GCODE_HAS_Y(com)) axis_steps_per_unit[1] = com->Y;
if(GCODE_HAS_Z(com)) axis_steps_per_unit[2] = com->Z;
if(GCODE_HAS_E(com)) current_extruder->stepsPerMM = com->E;
update_ramps_parameter();
break;
case 111:
if(GCODE_HAS_S(com)) debug_level = com->S;
if(DEBUG_DRYRUN) { // simulate movements without printing
extruder_set_temperature(0,0);
#if NUM_EXTRUDER>1
extruder_set_temperature(0,1);
#endif
#if HEATED_BED_TYPE!=0
target_bed_raw = 0;
#endif
}
break;
case 115: {// M115
#if DRIVE_SYSTEM==3
out.println_P(PSTR("FIRMWARE_NAME:RepetierMAX" REPETIER_VERSION " FIRMWARE_URL:https://github.com/seemecnc/RepetierMAX PROTOCOL_VERSION:1.0 MACHINE_TYPE:RostockMAX EXTRUDER_COUNT:" XSTR(NUM_EXTRUDER) " REPETIER_PROTOCOL:2"));
#else
#if DRIVE_SYSTEM==0
out.println_P(PSTR("FIRMWARE_NAME:Repetier_" REPETIER_VERSION " FIRMWARE_URL:https://github.com/repetier/Repetier-Firmware/ PROTOCOL_VERSION:1.0 MACHINE_TYPE:Mendel EXTRUDER_COUNT:" XSTR(NUM_EXTRUDER) " REPETIER_PROTOCOL:2"));
#else
out.println_P(PSTR("FIRMWARE_NAME:Repetier_" REPETIER_VERSION " FIRMWARE_URL:https://github.com/repetier/Repetier-Firmware/ PROTOCOL_VERSION:1.0 MACHINE_TYPE:Core_XY EXTRUDER_COUNT:" XSTR(NUM_EXTRUDER) " REPETIER_PROTOCOL:2"));
#endif
#endif
#if EEPROM_MODE!=0
float dist = printer_state.filamentPrinted*0.001+epr_get_float(EPR_PRINTING_DISTANCE);
OUT_P_FX("Printed filament:",dist,2);
OUT_P_LN(" m");
bool alloff = true;
for(byte i=0;i<NUM_EXTRUDER;i++)
if(tempController[i]->targetTemperatureC>15) alloff = false;
long seconds = (alloff ? 0 : (millis()-printer_state.msecondsPrinting)/1000)+epr_get_long(EPR_PRINTING_TIME);
long tmp = seconds/86400;
seconds-=tmp*86400;
OUT_P_L("Printing time:",tmp);
tmp=seconds/3600;
OUT_P_L(" days ",tmp);
seconds-=tmp*3600;
tmp = seconds/60;
OUT_P_L(" hours ",tmp);
OUT_P_LN(" min");
#endif
}
break;
case 114: // M114
printPosition();
break;
case 117: // M117 message to lcd
if(GCODE_HAS_STRING(com)) {
UI_STATUS_UPD_RAM(com->text);
}
break;
case 119: // M119
wait_until_end_of_move();
#if (X_MIN_PIN > -1) && MIN_HARDWARE_ENDSTOP_X
out.print_P(PSTR("x_min:"));
out.print_P((READ(X_MIN_PIN)^ENDSTOP_X_MIN_INVERTING)?PSTR("H "):PSTR("L "));
#endif
#if (X_MAX_PIN > -1) && MAX_HARDWARE_ENDSTOP_X
out.print_P(PSTR("x_max:"));
out.print_P((READ(X_MAX_PIN)^ENDSTOP_X_MAX_INVERTING)?PSTR("H "):PSTR("L "));
#endif
#if (Y_MIN_PIN > -1) && MIN_HARDWARE_ENDSTOP_Y
out.print_P(PSTR("y_min:"));
out.print_P((READ(Y_MIN_PIN)^ENDSTOP_Y_MIN_INVERTING)?PSTR("H "):PSTR("L "));
#endif
#if (Y_MAX_PIN > -1) && MAX_HARDWARE_ENDSTOP_Y
out.print_P(PSTR("y_max:"));
out.print_P((READ(Y_MAX_PIN)^ENDSTOP_Y_MAX_INVERTING)?PSTR("H "):PSTR("L "));
#endif
#if (Z_MIN_PIN > -1) && MIN_HARDWARE_ENDSTOP_Z
out.print_P(PSTR("z_min:"));
out.print_P((READ(Z_MIN_PIN)^ENDSTOP_Z_MIN_INVERTING)?PSTR("H "):PSTR("L "));
#endif
#if (Z_MAX_PIN > -1) && MAX_HARDWARE_ENDSTOP_Z
out.print_P(PSTR("z_max:"));
out.print_P((READ(Z_MAX_PIN)^ENDSTOP_Z_MAX_INVERTING)?PSTR("H "):PSTR("L "));
#endif
out.println();
break;
#if BEEPER_TYPE>0
case 120: // Test beeper function
if(GCODE_HAS_S(com) && GCODE_HAS_P(com))
beep(com->S,com->P); // Beep test
break;
#endif
#ifdef RAMP_ACCELERATION
case 201: // M201
if(GCODE_HAS_X(com)) max_acceleration_units_per_sq_second[0] = com->X;
if(GCODE_HAS_Y(com)) max_acceleration_units_per_sq_second[1] = com->Y;
if(GCODE_HAS_Z(com)) max_acceleration_units_per_sq_second[2] = com->Z;
if(GCODE_HAS_E(com)) max_acceleration_units_per_sq_second[3] = com->E;
update_ramps_parameter();
break;
case 202: // M202
if(GCODE_HAS_X(com)) max_travel_acceleration_units_per_sq_second[0] = com->X;
if(GCODE_HAS_Y(com)) max_travel_acceleration_units_per_sq_second[1] = com->Y;
if(GCODE_HAS_Z(com)) max_travel_acceleration_units_per_sq_second[2] = com->Z;
if(GCODE_HAS_E(com)) max_travel_acceleration_units_per_sq_second[3] = com->E;
update_ramps_parameter();
break;
#endif
case 203: // M203 Temperature monitor
if(GCODE_HAS_S(com)) {
if(com->S<NUM_EXTRUDER) manage_monitor = com->S;
#if HAVE_HEATED_BED
else manage_monitor=NUM_EXTRUDER; // Set 100 to heated bed
#endif
}
break;
case 204:
{
TemperatureController *temp = &current_extruder->tempControl;
if(GCODE_HAS_S(com)) {
if(com->S<0) break;
if(com->S<NUM_EXTRUDER) temp = &extruder[com->S].tempControl;
#if HAVE_HEATED_BED
else temp = &heatedBedController;
#else
else break;
#endif
}
if(GCODE_HAS_X(com)) temp->pidPGain = com->X;
if(GCODE_HAS_Y(com)) temp->pidIGain = com->Y;
if(GCODE_HAS_Z(com)) temp->pidDGain = com->Z;
updateTempControlVars(temp);
}
break;
case 503:
case 205: // M205 Show EEPROM settings
#if EEPROM_MODE!=0
epr_output_settings();
#else
OUT_P_LN("Error: No EEPROM support compiled.");
#endif
break;
case 206: // M206 T[type] P[pos] [Sint(long] [Xfloat] Set eeprom value
#if EEPROM_MODE!=0
epr_update(com);
#else
OUT_P_LN("Error: No EEPROM support compiled.");
#endif
break;
case 207: // M207 X<XY jerk> Z<Z Jerk>
if(GCODE_HAS_X(com))
printer_state.maxJerk = com->X;
if(GCODE_HAS_Z(com))
printer_state.maxZJerk = com->Z;
if(GCODE_HAS_E(com)) {
current_extruder->maxStartFeedrate = com->E;
extruder_select(current_extruder->id);
}
out.print_float_P(PSTR("Jerk:"),printer_state.maxJerk);
out.println_float_P(PSTR(" ZJerk:"),printer_state.maxZJerk);
break;
case 220: // M220 S<Feedrate multiplier in percent>
if(GCODE_HAS_S(com))
change_feedrate_multiply(com->S);
else
change_feedrate_multiply(100);
break;
case 221: // M221 S<Extrusion flow multiplier in percent>
if(GCODE_HAS_S(com))
change_flowate_multiply(com->S);
else
change_flowate_multiply(100);
break;
#ifdef USE_ADVANCE
case 223: // Extruder interrupt test
if(GCODE_HAS_S(com))
printer_state.extruderStepsNeeded+=com->S;
break;
case 232:
out.print_int_P(PSTR(" linear steps:"),maxadv2);
#ifdef ENABLE_QUADRATIC_ADVANCE
out.print_int_P(PSTR(" quadratic steps:"),maxadv);
#endif
out.println_float_P(PSTR(", speed="),maxadvspeed);
#ifdef ENABLE_QUADRATIC_ADVANCE
maxadv=0;
#endif
maxadv2=0;
maxadvspeed=0;
break;
#endif
#if USE_OPS==1
case 231: // M231 S<OPS_MODE> X<Min_Distance> Y<Retract> Z<Backslash> F<ReatrctMove>
if(GCODE_HAS_S(com) && com->S>=0 && com->S<3)
printer_state.opsMode = com->S;
if(GCODE_HAS_X(com) && com->X>=0)
printer_state.opsMinDistance = com->X;
if(GCODE_HAS_Y(com) && com->Y>=0)
printer_state.opsRetractDistance = com->Y;
if(GCODE_HAS_Z(com) && com->Z>=-printer_state.opsRetractDistance)
printer_state.opsRetractBacklash = com->Z;
if(GCODE_HAS_F(com) && com->F>=0 && com->F<=100)
printer_state.opsMoveAfter = com->F;
extruder_select(current_extruder->id);
if(printer_state.opsMode==0) {
out.println_P(PSTR("OPS disabled"));
} else {
if(printer_state.opsMode==1)
out.print_P(PSTR("OPS classic mode:"));
else
out.print_P(PSTR("OPS fast mode:"));
out.print_float_P(PSTR("min distance = "),printer_state.opsMinDistance);
out.print_float_P(PSTR(", retract = "),printer_state.opsRetractDistance);
out.print_float_P(PSTR(", backslash = "),printer_state.opsRetractBacklash);
if(printer_state.opsMode==2)
out.print_float_P(PSTR(", move after = "),printer_state.opsMoveAfter);
out.println();
update_extruder_flags();
}
#ifdef DEBUG_OPS
out.println_int_P(PSTR("Ret. steps:"),printer_state.opsRetractSteps);
out.println_int_P(PSTR("PushBack Steps:"),printer_state.opsPushbackSteps);
out.println_int_P(PSTR("Move after steps:"),printer_state.opsMoveAfterSteps);
#endif
break;
#endif
#ifdef USE_ADVANCE
case 233:
if(GCODE_HAS_Y(com))
current_extruder->advanceL = com->Y;
out.print_float_P(PSTR("linear L:"),current_extruder->advanceL);
#ifdef ENABLE_QUADRATIC_ADVANCE
if(GCODE_HAS_X(com))
current_extruder->advanceK = com->X;
out.print_float_P(PSTR(" quadratic K:"),current_extruder->advanceK);
#endif
out.println();
update_extruder_flags();
break;
#endif
case 400: // Finish all moves
wait_until_end_of_move();
break;
#if FEATURE_MEMORY_POSITION
case 401: // Memory position
printer_state.memoryX = printer_state.currentPositionSteps[0];
printer_state.memoryY = printer_state.currentPositionSteps[1];
printer_state.memoryZ = printer_state.currentPositionSteps[2];
break;
case 402: // Go to stored position
{
bool all = !(GCODE_HAS_X(com) && GCODE_HAS_Y(com) && GCODE_HAS_Z(com));
move_steps((all || GCODE_HAS_X(com) ? printer_state.memoryX-printer_state.currentPositionSteps[0] : 0)
,(all || GCODE_HAS_Y(com) ? printer_state.memoryY-printer_state.currentPositionSteps[1] : 0)
,(all || GCODE_HAS_Z(com) ? printer_state.memoryZ-printer_state.currentPositionSteps[2] : 0)
,0,(GCODE_HAS_F(com) ? com->F : printer_state.feedrate),false,ALWAYS_CHECK_ENDSTOPS);
}
break;
#endif
case 908: // Control digital trimpot directly.
{
#if STEPPER_CURRENT_CONTROL != CURRENT_CONTROL_MANUAL
uint8_t channel,current;
if(GCODE_HAS_P(com) && GCODE_HAS_S(com))
set_current((uint8_t)com->P, (unsigned int)com->S);
#endif
}
break;
case 500:
{
#if EEPROM_MODE!=0
epr_data_to_eeprom(false);
OUT_P_LN("Configuration stored to EEPROM.");
#else
OUT_P_LN("Error: No EEPROM support compiled.");
#endif
}
break;
case 501:
{
#if EEPROM_MODE!=0
epr_eeprom_to_data();
OUT_P_LN("Configuration loaded from EEPROM.");
#else
OUT_P_LN("Error: No EEPROM support compiled.");
#endif
}
break;
case 502:
{
#if EEPROM_MODE!=0
epr_eeprom_reset();
OUT_P_LN("Configuration reset to defaults.");
#else
OUT_P_LN("Error: No EEPROM support compiled.");
#endif
}
break;
case 350: // Set microstepping mode. Warning: Steps per unit remains unchanged. S code sets stepping mode for all drivers.
{
OUT_P_LN("Set Microstepping");
#if defined(X_MS1_PIN) && X_MS1_PIN > -1
if(GCODE_HAS_S(com)) for(int i=0;i<=4;i++) microstep_mode(i,com->S);
if(GCODE_HAS_X(com)) microstep_mode(0,(uint8_t)com->X);
if(GCODE_HAS_Y(com)) microstep_mode(1,(uint8_t)com->Y);
if(GCODE_HAS_Z(com)) microstep_mode(2,(uint8_t)com->Z);
if(GCODE_HAS_E(com)) microstep_mode(3,(uint8_t)com->E);
if(GCODE_HAS_P(com)) microstep_mode(4,com->P); // Original B but is not supported here
microstep_readings();
#endif
}
break;
#ifdef STEP_COUNTER
#if DRIVE_SYSTEM==3
case 251:
if(GCODE_HAS_S(com)) {
if (com->S == 0) {
printer_state.countZSteps = 0;
out.println_P(PSTR("Measurement reset."));
} else if (com->S == 1) {
OUT_P_L_LN("Measure/delta (Steps) =",printer_state.countZSteps * inv_axis_steps_per_unit[2]);
OUT_P_L_LN("Measure/delta =",printer_state.countZSteps * inv_axis_steps_per_unit[2]);
} else if (com->S = 2) {
if (printer_state.countZSteps < 0)
printer_state.countZSteps = -printer_state.countZSteps;
printer_state.zMin = 0;
printer_state.zLength = inv_axis_steps_per_unit[2] * printer_state.countZSteps;
printer_state.zMaxSteps = printer_state.countZSteps;
for (byte i=0; i<3; i++) {
printer_state.currentPositionSteps[i] = 0;
}
calculate_delta(printer_state.currentPositionSteps, printer_state.currentDeltaPositionSteps);
OUT_P_LN("Measured origin set. Measurement reset.");
#if EEPROM_MODE!=0
epr_data_to_eeprom(false);
OUT_P_LN("EEPROM updated");
#endif
}
}
break;
#endif
#endif
}
} else if(GCODE_HAS_T(com)) { // Process T code
wait_until_end_of_move();
extruder_select(com->T);
} else{
if(DEBUG_ERRORS) {
OUT_P("Unknown command:");
gcode_print_command(com);
out.println();
}
}
if(bufferedCommand)
gcode_command_finished(com); // free command cache
}