Newer
Older
* Copyright (C) 2016, 2017 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* 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/>.
* About Marlin
*
* This firmware is a mashup between Sprinter and grbl.
* - https://github.com/kliment/Sprinter
* - https://github.com/simen/grbl/tree
*/
* -----------------
* G-Codes in Marlin
* -----------------
*
* Helpful G-code references:
* - http://linuxcnc.org/handbook/gcode/g-code.html
* - http://objects.reprap.org/wiki/Mendel_User_Manual:_RepRapGCodes
*
* Help to document Marlin's G-codes online:
* - https://github.com/MarlinFirmware/MarlinDocumentation
*
* -----------------
*
* "G" Codes
*
* G0 -> G1
* G1 - Coordinated Movement X Y Z E
* G2 - CW ARC
* G3 - CCW ARC
* G4 - Dwell S<seconds> or P<milliseconds>
* G5 - Cubic B-spline with XYZE destination and IJPQ offsets
* G10 - Retract filament according to settings of M207
* G11 - Retract recover filament according to settings of M208
* G12 - Clean tool
* G20 - Set input units to inches
* G21 - Set input units to millimeters
* G29 - Detailed Z probe, probes the bed at 3 or more points. Will fail if you haven't homed yet.
* G30 - Single Z probe, probes bed at X Y location (defaults to current XY location)
* G31 - Dock sled (Z_PROBE_SLED only)
* G32 - Undock sled (Z_PROBE_SLED only)
* G38 - Probe target - similar to G28 except it uses the Z_MIN_PROBE for all three axes
* G90 - Use Absolute Coordinates
* G91 - Use Relative Coordinates
* G92 - Set current position to coordinates given
*
* "M" Codes
*
* M0 - Unconditional stop - Wait for user to press a button on the LCD (Only if ULTRA_LCD is enabled)
* M1 - Same as M0
* M17 - Enable/Power all stepper motors
* M18 - Disable all stepper motors; same as M84
* M20 - List SD card. (Requires SDSUPPORT)
* M21 - Init SD card. (Requires SDSUPPORT)
* M22 - Release SD card. (Requires SDSUPPORT)
* M23 - Select SD file: "M23 /path/file.gco". (Requires SDSUPPORT)
* M24 - Start/resume SD print. (Requires SDSUPPORT)
* M25 - Pause SD print. (Requires SDSUPPORT)
* M26 - Set SD position in bytes: "M26 S12345". (Requires SDSUPPORT)
* M27 - Report SD print status. (Requires SDSUPPORT)
* M28 - Start SD write: "M28 /path/file.gco". (Requires SDSUPPORT)
* M29 - Stop SD write. (Requires SDSUPPORT)
* M30 - Delete file from SD: "M30 /path/file.gco"
* M31 - Report time since last M109 or SD card start to serial.
* M32 - Select file and start SD print: "M32 [S<bytepos>] !/path/file.gco#". (Requires SDSUPPORT)
* Use P to run other files as sub-programs: "M32 P !filename#"
* The '#' is necessary when calling from within sd files, as it stops buffer prereading
* M33 - Get the longname version of a path. (Requires LONG_FILENAME_HOST_SUPPORT)
* M34 - Set SD Card sorting options. (Requires SDCARD_SORT_ALPHA)
* M42 - Change pin status via gcode: M42 P<pin> S<value>. LED pin assumed if P is omitted.
* M43 - Display pin status, watch pins for changes, watch endstops & toggle LED, Z servo probe test, toggle pins
* M48 - Measure Z Probe repeatability: M48 P<points> X<pos> Y<pos> V<level> E<engage> L<legs>. (Requires Z_MIN_PROBE_REPEATABILITY_TEST)
* M75 - Start the print job timer.
* M76 - Pause the print job timer.
* M77 - Stop the print job timer.
* M78 - Show statistical information about the print jobs. (Requires PRINTCOUNTER)
* M80 - Turn on Power Supply. (Requires POWER_SUPPLY)
* M81 - Turn off Power Supply. (Requires POWER_SUPPLY)
* M82 - Set E codes absolute (default).
* M83 - Set E codes relative while in Absolute (G90) mode.
* M84 - Disable steppers until next move, or use S<seconds> to specify an idle
* duration after which steppers should turn off. S0 disables the timeout.
* M85 - Set inactivity shutdown timer with parameter S<seconds>. To disable set zero (default)
* M92 - Set planner.axis_steps_per_mm for one or more axes.
* M104 - Set extruder target temp.
* M105 - Report current temperatures.
* M106 - Fan on.
* M107 - Fan off.
* M108 - Break out of heating loops (M109, M190, M303). With no controller, breaks out of M0/M1. (Requires EMERGENCY_PARSER)
* M109 - Sxxx Wait for extruder current temp to reach target temp. Waits only when heating
* Rxxx Wait for extruder current temp to reach target temp. Waits when heating and cooling
* If AUTOTEMP is enabled, S<mintemp> B<maxtemp> F<factor>. Exit autotemp by any M109 without F
* M110 - Set the current line number. (Used by host printing)
* M111 - Set debug flags: "M111 S<flagbits>". See flag bits defined in enum.h.
* M112 - Emergency stop.
* M113 - Get or set the timeout interval for Host Keepalive "busy" messages. (Requires HOST_KEEPALIVE_FEATURE)
* M114 - Report current position.
* M115 - Report capabilities. (Extended capabilities requires EXTENDED_CAPABILITIES_REPORT)
* M117 - Display a message on the controller screen. (Requires an LCD)
* M119 - Report endstops status.
* M120 - Enable endstops detection.
* M121 - Disable endstops detection.
* M125 - Save current position and move to filament change position. (Requires PARK_HEAD_ON_PAUSE)
* M126 - Solenoid Air Valve Open. (Requires BARICUDA)
* M127 - Solenoid Air Valve Closed. (Requires BARICUDA)
* M128 - EtoP Open. (Requires BARICUDA)
* M129 - EtoP Closed. (Requires BARICUDA)
* M140 - Set bed target temp. S<temp>
* M145 - Set heatup values for materials on the LCD. H<hotend> B<bed> F<fan speed> for S<material> (0=PLA, 1=ABS)
* M149 - Set temperature units. (Requires TEMPERATURE_UNITS_SUPPORT)
* M150 - Set Status LED Color as R<red> U<green> B<blue>. Values 0-255. (Requires BLINKM or RGB_LED)
* M155 - Auto-report temperatures with interval of S<seconds>. (Requires AUTO_REPORT_TEMPERATURES)
* M163 - Set a single proportion for a mixing extruder. (Requires MIXING_EXTRUDER)
* M164 - Save the mix as a virtual extruder. (Requires MIXING_EXTRUDER and MIXING_VIRTUAL_TOOLS)
* M165 - Set the proportions for a mixing extruder. Use parameters ABCDHI to set the mixing factors. (Requires MIXING_EXTRUDER)
* M190 - Sxxx Wait for bed current temp to reach target temp. ** Waits only when heating! **
* Rxxx Wait for bed current temp to reach target temp. ** Waits for heating or cooling. **
* M200 - Set filament diameter, D<diameter>, setting E axis units to cubic. (Use S0 to revert to linear units.)
* M201 - Set max acceleration in units/s^2 for print moves: "M201 X<accel> Y<accel> Z<accel> E<accel>"
* M202 - Set max acceleration in units/s^2 for travel moves: "M202 X<accel> Y<accel> Z<accel> E<accel>" ** UNUSED IN MARLIN! **
* M203 - Set maximum feedrate: "M203 X<fr> Y<fr> Z<fr> E<fr>" in units/sec.
* M204 - Set default acceleration in units/sec^2: P<printing> R<extruder_only> T<travel>
* M205 - Set advanced settings. Current units apply:
S<print> T<travel> minimum speeds
B<minimum segment time>
X<max X jerk>, Y<max Y jerk>, Z<max Z jerk>, E<max E jerk>
* M206 - Set additional homing offset.
* M207 - Set Retract Length: S<length>, Feedrate: F<units/min>, and Z lift: Z<distance>. (Requires FWRETRACT)
* M208 - Set Recover (unretract) Additional (!) Length: S<length> and Feedrate: F<units/min>. (Requires FWRETRACT)
* M209 - Turn Automatic Retract Detection on/off: S<0|1> (For slicers that don't support G10/11). (Requires FWRETRACT)
Every normal extrude-only move will be classified as retract depending on the direction.
* M211 - Enable, Disable, and/or Report software endstops: S<0|1> (Requires MIN_SOFTWARE_ENDSTOPS or MAX_SOFTWARE_ENDSTOPS)
* M218 - Set a tool offset: "M218 T<index> X<offset> Y<offset>". (Requires 2 or more extruders)
* M220 - Set Feedrate Percentage: "M220 S<percent>" (i.e., "FR" on the LCD)
* M221 - Set Flow Percentage: "M221 S<percent>"
* M226 - Wait until a pin is in a given state: "M226 P<pin> S<state>"
* M240 - Trigger a camera to take a photograph. (Requires CHDK or PHOTOGRAPH_PIN)
* M250 - Set LCD contrast: "M250 C<contrast>" (0-63). (Requires LCD support)
* M260 - i2c Send Data (Requires EXPERIMENTAL_I2CBUS)
* M261 - i2c Request Data (Requires EXPERIMENTAL_I2CBUS)
* M280 - Set servo position absolute: "M280 P<index> S<angle|µs>". (Requires servos)
* M300 - Play beep sound S<frequency Hz> P<duration ms>
* M301 - Set PID parameters P I and D. (Requires PIDTEMP)
* M302 - Allow cold extrudes, or set the minimum extrude S<temperature>. (Requires PREVENT_COLD_EXTRUSION)
* M303 - PID relay autotune S<temperature> sets the target temperature. Default 150C. (Requires PIDTEMP)
* M304 - Set bed PID parameters P I and D. (Requires PIDTEMPBED)
* M355 - Turn the Case Light on/off and set its brightness. (Requires CASE_LIGHT_PIN)
* M380 - Activate solenoid on active extruder. (Requires EXT_SOLENOID)
* M381 - Disable all solenoids. (Requires EXT_SOLENOID)
* M400 - Finish all moves.
* M401 - Lower Z probe. (Requires a probe)
* M402 - Raise Z probe. (Requires a probe)
* M404 - Display or set the Nominal Filament Width: "W<diameter>". (Requires FILAMENT_WIDTH_SENSOR)
* M405 - Enable Filament Sensor flow control. "M405 D<delay_cm>". (Requires FILAMENT_WIDTH_SENSOR)
* M406 - Disable Filament Sensor flow control. (Requires FILAMENT_WIDTH_SENSOR)
* M407 - Display measured filament diameter in millimeters. (Requires FILAMENT_WIDTH_SENSOR)
* M410 - Quickstop. Abort all planned moves.
* M420 - Enable/Disable Leveling (with current values) S1=enable S0=disable (Requires MESH_BED_LEVELING or ABL)
* M421 - Set a single Z coordinate in the Mesh Leveling grid. X<units> Y<units> Z<units> (Requires MESH_BED_LEVELING or AUTO_BED_LEVELING_UBL)
* M428 - Set the home_offset based on the current_position. Nearest edge applies.
* M500 - Store parameters in EEPROM. (Requires EEPROM_SETTINGS)
* M501 - Restore parameters from EEPROM. (Requires EEPROM_SETTINGS)
* M502 - Revert to the default "factory settings". ** Does not write them to EEPROM! **
* M503 - Print the current settings (in memory): "M503 S<verbose>". S0 specifies compact output.
* M540 - Enable/disable SD card abort on endstop hit: "M540 S<state>". (Requires ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED)
* M600 - Pause for filament change: "M600 X<pos> Y<pos> Z<raise> E<first_retract> L<later_retract>". (Requires FILAMENT_CHANGE_FEATURE)
* M665 - Set delta configurations: "M665 L<diagonal rod> R<delta radius> S<segments/s> A<rod A trim mm> B<rod B trim mm> C<rod C trim mm> I<tower A trim angle> J<tower B trim angle> K<tower C trim angle>" (Requires DELTA)
* M666 - Set delta endstop adjustment. (Requires DELTA)
* M605 - Set dual x-carriage movement mode: "M605 S<mode> [X<x_offset>] [R<temp_offset>]". (Requires DUAL_X_CARRIAGE)
* M851 - Set Z probe's Z offset in current units. (Negative = below the nozzle.)
* M906 - Set or get motor current in milliamps using axis codes X, Y, Z, E. Report values if no axis codes given. (Requires HAVE_TMC2130)
* M907 - Set digital trimpot motor current using axis codes. (Requires a board with digital trimpots)
* M908 - Control digital trimpot directly. (Requires DAC_STEPPER_CURRENT or DIGIPOTSS_PIN)
* M909 - Print digipot/DAC current value. (Requires DAC_STEPPER_CURRENT)
* M910 - Commit digipot/DAC value to external EEPROM via I2C. (Requires DAC_STEPPER_CURRENT)
* M911 - Report stepper driver overtemperature pre-warn condition. (Requires HAVE_TMC2130)
* M912 - Clear stepper driver overtemperature pre-warn condition flag. (Requires HAVE_TMC2130)
* M350 - Set microstepping mode. (Requires digital microstepping pins.)
* M351 - Toggle MS1 MS2 pins directly. (Requires digital microstepping pins.)
*
* M360 - SCARA calibration: Move to cal-position ThetaA (0 deg calibration)
* M361 - SCARA calibration: Move to cal-position ThetaB (90 deg calibration - steps per degree)
* M362 - SCARA calibration: Move to cal-position PsiA (0 deg calibration)
* M363 - SCARA calibration: Move to cal-position PsiB (90 deg calibration - steps per degree)
* M364 - SCARA calibration: Move to cal-position PSIC (90 deg to Theta calibration position)
*
* ************ Custom codes - This can change to suit future G-code regulations
* M100 - Watch Free Memory (For Debugging). (Requires M100_FREE_MEMORY_WATCHER)
* M928 - Start SD logging: "M928 filename.gco". Stop with M29. (Requires SDSUPPORT)
*
* "T" Codes
*
* T0-T3 - Select an extruder (tool) by index: "T<n> F<units/min>"
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
#include "Marlin.h"
#include "ultralcd.h"
#include "planner.h"
#include "stepper.h"
#include "endstops.h"
#include "temperature.h"
#include "cardreader.h"
#include "configuration_store.h"
#include "language.h"
#include "pins_arduino.h"
#include "math.h"
#include "nozzle.h"
#include "duration_t.h"
#include "types.h"
#if HAS_ABL
#include "vector_3.h"
#if ENABLED(AUTO_BED_LEVELING_LINEAR)
#include "qr_solve.h"
#endif
#elif ENABLED(MESH_BED_LEVELING)
#include "mesh_bed_leveling.h"
#endif
#if ENABLED(BEZIER_CURVE_SUPPORT)
#include "planner_bezier.h"
#endif
#if HAS_BUZZER && DISABLED(LCD_USE_I2C_BUZZER)
#include "buzzer.h"
#endif
#if ENABLED(USE_WATCHDOG)
#include "watchdog.h"
#endif
#if ENABLED(BLINKM)
#include "blinkm.h"
#include "Wire.h"
#endif
#if HAS_SERVOS
#include "servo.h"
#endif
#if HAS_DIGIPOTSS
#include <SPI.h>
#endif
#if ENABLED(DAC_STEPPER_CURRENT)
#include "stepper_dac.h"
#endif
#if ENABLED(EXPERIMENTAL_I2CBUS)
#include "twibus.h"
#endif
#if ENABLED(ENDSTOP_INTERRUPTS_FEATURE)
#include "endstop_interrupts.h"
#endif
#if ENABLED(M100_FREE_MEMORY_WATCHER)
#if ENABLED(SDSUPPORT)
#endif
#if ENABLED(EXPERIMENTAL_I2CBUS)
TWIBus i2c;
#endif
bool G38_move = false,
G38_endstop_hit = false;
#define UBL_MESH_VALID !( ( ubl.z_values[0][0] == ubl.z_values[0][1] && ubl.z_values[0][1] == ubl.z_values[0][2] \
&& ubl.z_values[1][0] == ubl.z_values[1][1] && ubl.z_values[1][1] == ubl.z_values[1][2] \
&& ubl.z_values[2][0] == ubl.z_values[2][1] && ubl.z_values[2][1] == ubl.z_values[2][2] \
&& ubl.z_values[0][0] == 0 && ubl.z_values[1][0] == 0 && ubl.z_values[2][0] == 0 ) \
|| isnan(ubl.z_values[0][0]))
uint8_t marlin_debug_flags = DEBUG_NONE;
/**
* Cartesian Current Position
* Used to track the logical position as moves are queued.
* Used by 'line_to_current_position' to do a move after changing it.
* Used by 'SYNC_PLAN_POSITION_KINEMATIC' to update 'planner.position'.
*/
float current_position[XYZE] = { 0.0 };
/**
* Cartesian Destination
* A temporary position, usually applied to 'current_position'.
* Set with 'gcode_get_destination' or 'set_destination_to_current'.
* 'line_to_destination' sets 'current_position' to 'destination'.
*/
/**
* axis_homed
* Flags that each linear axis was homed.
* XYZ on cartesian, ABC on delta, ABZ on SCARA.
*
* axis_known_position
* Flags that the position is known in each linear axis. Set when homed.
* Cleared whenever a stepper powers off, potentially losing its position.
*/
bool axis_homed[XYZ] = { false }, axis_known_position[XYZ] = { false };
/**
* GCode line number handling. Hosts may opt to include line numbers when
* sending commands to Marlin, and lines will be checked for sequentiality.
static long gcode_N, gcode_LastN, Stopped_gcode_LastN = 0;
/**
* GCode Command Queue
* A simple ring buffer of BUFSIZE command strings.
*
* Commands are copied into this buffer by the command injectors
* (immediate, serial, sd card) and they are processed sequentially by
* the main loop. The process_next_command function parses the next
* command and hands off execution to individual handler functions.
*/
uint8_t commands_in_queue = 0; // Count of commands in the queue
static uint8_t cmd_queue_index_r = 0, // Ring buffer read position
cmd_queue_index_w = 0; // Ring buffer write position
static char command_queue[BUFSIZE][MAX_CMD_SIZE];
/**
* Current GCode Command
* When a GCode handler is running, these will be set
*/
static char *current_command, // The command currently being executed
*current_command_args, // The address where arguments begin
*seen_pointer; // Set by code_seen(), used by the code_value functions
/**
* Next Injected Command pointer. NULL if no commands are being injected.
* Used by Marlin internally to ensure that commands initiated from within
* are enqueued ahead of any pending serial or sd card commands.
*/
static const char *injected_commands_P = NULL;
#if ENABLED(INCH_MODE_SUPPORT)
float linear_unit_factor = 1.0, volumetric_unit_factor = 1.0;
#if ENABLED(TEMPERATURE_UNITS_SUPPORT)
TempUnit input_temp_units = TEMPUNIT_C;
#endif
/**
* Feed rates are often configured with mm/m
* but the planner and stepper like mm/s units.
*/
float constexpr homing_feedrate_mm_s[] = {
MMM_TO_MMS(HOMING_FEEDRATE_Z), MMM_TO_MMS(HOMING_FEEDRATE_Z),
MMM_TO_MMS(HOMING_FEEDRATE_XY), MMM_TO_MMS(HOMING_FEEDRATE_XY),
MMM_TO_MMS(HOMING_FEEDRATE_Z), 0
static float feedrate_mm_s = MMM_TO_MMS(1500.0), saved_feedrate_mm_s;
int feedrate_percentage = 100, saved_feedrate_percentage,
flow_percentage[EXTRUDERS] = ARRAY_BY_EXTRUDERS1(100);
bool axis_relative_modes[] = AXIS_RELATIVE_MODES,
#if ENABLED(VOLUMETRIC_DEFAULT_ON)
true
#else
false
#endif
float filament_size[EXTRUDERS] = ARRAY_BY_EXTRUDERS1(DEFAULT_NOMINAL_FILAMENT_DIA),
volumetric_multiplier[EXTRUDERS] = ARRAY_BY_EXTRUDERS1(1.0);
// The distance that XYZ has been offset by G92. Reset by G28.
float position_shift[XYZ] = { 0 };
// This offset is added to the configured home position.
// Set by M206, M428, or menu item. Saved to EEPROM.
float home_offset[XYZ] = { 0 };
// The above two are combined to save on computes
float workspace_offset[XYZ] = { 0 };
// Software Endstops are based on the configured limits.
bool soft_endstops_enabled = true;
#endif
float soft_endstop_min[XYZ] = { X_MIN_POS, Y_MIN_POS, Z_MIN_POS },
soft_endstop_max[XYZ] = { X_MAX_POS, Y_MAX_POS, Z_MAX_POS };
#if FAN_COUNT > 0
int fanSpeeds[FAN_COUNT] = { 0 };
#endif
// The active extruder (tool). Set with T<extruder> command.
// Relative Mode. Enable with G91, disable with G90.
static bool relative_mode = false;
// For M109 and M190, this flag may be cleared (by M108) to exit the wait loop
// For M0/M1, this flag may be cleared (by M108) to exit the wait-for-user loop
volatile bool wait_for_user = false;
const char axis_codes[XYZE] = {'X', 'Y', 'Z', 'E'};
// Number of characters read in the current line of serial input
millis_t previous_cmd_ms = 0;
static millis_t max_inactive_time = 0;
static millis_t stepper_inactive_time = (DEFAULT_STEPPER_DEACTIVE_TIME) * 1000UL;
#if ENABLED(PRINTCOUNTER)
PrintCounter print_job_timer = PrintCounter();
#else
Stopwatch print_job_timer = Stopwatch();
#endif
// Buzzer - I2C on the LCD or a BEEPER_PIN
#if ENABLED(LCD_USE_I2C_BUZZER)
#define BUZZ(d,f) lcd_buzz(d, f)
Buzzer buzzer;
#define BUZZ(d,f) buzzer.tone(d, f)
#else
#define BUZZ(d,f) NOOP
#if HAS_BED_PROBE
float zprobe_zoffset = Z_PROBE_OFFSET_FROM_EXTRUDER;
#endif
#define PLANNER_XY_FEEDRATE() (min(planner.max_feedrate_mm_s[X_AXIS], planner.max_feedrate_mm_s[Y_AXIS]))
float xy_probe_feedrate_mm_s = MMM_TO_MMS(XY_PROBE_SPEED);
#define XY_PROBE_FEEDRATE_MM_S xy_probe_feedrate_mm_s
#elif defined(XY_PROBE_SPEED)
#define XY_PROBE_FEEDRATE_MM_S MMM_TO_MMS(XY_PROBE_SPEED)
#define XY_PROBE_FEEDRATE_MM_S PLANNER_XY_FEEDRATE()
#if ENABLED(AUTO_BED_LEVELING_BILINEAR)
#if ENABLED(DELTA)
#define ADJUST_DELTA(V) \
if (planner.abl_enabled) { \
const float zadj = bilinear_z_offset(V); \
delta[A_AXIS] += zadj; \
delta[B_AXIS] += zadj; \
delta[C_AXIS] += zadj; \
}
#else
#define ADJUST_DELTA(V) if (planner.abl_enabled) { delta[Z_AXIS] += bilinear_z_offset(V); }
#endif
#elif IS_KINEMATIC
#define ADJUST_DELTA(V) NOOP
#endif
float z_endstop_adj =
#ifdef Z_DUAL_ENDSTOPS_ADJUSTMENT
Z_DUAL_ENDSTOPS_ADJUSTMENT
#else
0
#endif
;
float hotend_offset[XYZ][HOTENDS];
#endif
const int z_servo_angle[2] = Z_SERVO_ANGLES;
#if ENABLED(BARICUDA)
int baricuda_valve_pressure = 0;
int baricuda_e_to_p_pressure = 0;
#if ENABLED(FWRETRACT)
bool retracted[EXTRUDERS] = { false };
bool retracted_swap[EXTRUDERS] = { false };
float retract_length = RETRACT_LENGTH;
float retract_length_swap = RETRACT_LENGTH_SWAP;
float retract_feedrate_mm_s = RETRACT_FEEDRATE;
float retract_zlift = RETRACT_ZLIFT;
float retract_recover_length = RETRACT_RECOVER_LENGTH;
float retract_recover_length_swap = RETRACT_RECOVER_LENGTH_SWAP;
float retract_recover_feedrate_mm_s = RETRACT_RECOVER_FEEDRATE;
#if ENABLED(ULTIPANEL) && HAS_POWER_SWITCH
#if ENABLED(PS_DEFAULT_OFF)
bool case_light_on =
#if ENABLED(CASE_LIGHT_DEFAULT_ON)
true
#else
false
#endif
;
#endif
#if ENABLED(DELTA)
float delta[ABC],
endstop_adj[ABC] = { 0 };
// These values are loaded or reset at boot time when setup() calls
// settings.load(), which calls recalc_delta_settings().
float delta_radius,
delta_tower_angle_trim[ABC],
delta_tower[ABC][2],
delta_diagonal_rod,
delta_diagonal_rod_trim[ABC],
delta_diagonal_rod_2_tower[ABC],
delta_segments_per_second,
delta_clip_start_height = Z_MAX_POS;
float delta_safe_distance_from_top();
Pablo Clemente
committed
#if ENABLED(AUTO_BED_LEVELING_BILINEAR)
float bed_level_grid[GRID_MAX_POINTS_X][GRID_MAX_POINTS_Y];
#if IS_SCARA
// Float constants for SCARA calculations
const float L1 = SCARA_LINKAGE_1, L2 = SCARA_LINKAGE_2,
L1_2 = sq(float(L1)), L1_2_2 = 2.0 * L1_2,
L2_2 = sq(float(L2));
float delta_segments_per_second = SCARA_SEGMENTS_PER_SECOND,
#if ENABLED(FILAMENT_WIDTH_SENSOR)
bool filament_sensor = false; //M405 turns on filament_sensor control, M406 turns it off
float filament_width_nominal = DEFAULT_NOMINAL_FILAMENT_DIA, // Nominal filament width. Change with M404
filament_width_meas = DEFAULT_MEASURED_FILAMENT_DIA; // Measured filament diameter
int8_t measurement_delay[MAX_MEASUREMENT_DELAY + 1]; // Ring buffer to delayed measurement. Store extruder factor after subtracting 100
int filwidth_delay_index[2] = { 0, -1 }; // Indexes into ring buffer
int meas_delay_cm = MEASUREMENT_DELAY_CM; //distance delay setting
#endif
#if ENABLED(FILAMENT_RUNOUT_SENSOR)
#if ENABLED(FILAMENT_CHANGE_FEATURE)
FilamentChangeMenuResponse filament_change_menu_response;
#endif
#if ENABLED(MIXING_EXTRUDER)
float mixing_factor[MIXING_STEPPERS]; // Reciprocal of mix proportion. 0.0 = off, otherwise >= 1.0.
#if MIXING_VIRTUAL_TOOLS > 1
float mixing_virtual_tool_mix[MIXING_VIRTUAL_TOOLS][MIXING_STEPPERS];
#endif
#endif
#if HAS_Z_SERVO_ENDSTOP
#define DEPLOY_Z_SERVO() MOVE_SERVO(Z_ENDSTOP_SERVO_NR, z_servo_angle[0])
#define STOW_Z_SERVO() MOVE_SERVO(Z_ENDSTOP_SERVO_NR, z_servo_angle[1])
#endif
#if ENABLED(PID_EXTRUSION_SCALING)
#if ENABLED(HOST_KEEPALIVE_FEATURE)
MarlinBusyState busy_state = NOT_BUSY;
static millis_t next_busy_signal_ms = 0;
uint8_t host_keepalive_interval = DEFAULT_KEEPALIVE_INTERVAL;
#else
#define host_keepalive() NOOP
#endif
static inline float pgm_read_any(const float *p) { return pgm_read_float_near(p); }
static inline signed char pgm_read_any(const signed char *p) { return pgm_read_byte_near(p); }
#define XYZ_CONSTS_FROM_CONFIG(type, array, CONFIG) \
static const PROGMEM type array##_P[XYZ] = { X_##CONFIG, Y_##CONFIG, Z_##CONFIG }; \
static inline type array(AxisEnum 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)
XYZ_CONSTS_FROM_CONFIG(float, max_length, MAX_LENGTH)
XYZ_CONSTS_FROM_CONFIG(float, home_bump_mm, HOME_BUMP_MM)
XYZ_CONSTS_FROM_CONFIG(signed char, home_dir, HOME_DIR)
/**
* ***************************************************************************
* ******************************** FUNCTIONS ********************************
* ***************************************************************************
*/
void get_available_commands();
void process_next_command();
void prepare_move_to_destination();
void set_current_from_steppers_for_axis(const AxisEnum axis);
void plan_arc(float target[XYZE], float* offset, uint8_t clockwise);
#if ENABLED(BEZIER_CURVE_SUPPORT)
void plan_cubic_move(const float offset[4]);
#endif
void tool_change(const uint8_t tmp_extruder, const float fr_mm_s=0.0, bool no_move=false);
static void report_current_position();
#if ENABLED(DEBUG_LEVELING_FEATURE)
void print_xyz(const char* prefix, const char* suffix, const float x, const float y, const float z) {
serialprintPGM(prefix);
SERIAL_ECHOPAIR("(", x);
SERIAL_ECHOPAIR(", ", y);
SERIAL_ECHOPAIR(", ", z);
if (suffix) serialprintPGM(suffix);
else SERIAL_EOL;
void print_xyz(const char* prefix, const char* suffix, const float xyz[]) {
print_xyz(prefix, suffix, xyz[X_AXIS], xyz[Y_AXIS], xyz[Z_AXIS]);
void print_xyz(const char* prefix, const char* suffix, const vector_3 &xyz) {
print_xyz(prefix, suffix, xyz.x, xyz.y, xyz.z);
#define DEBUG_POS(SUFFIX,VAR) do { \
print_xyz(PSTR(" " STRINGIFY(VAR) "="), PSTR(" : " SUFFIX "\n"), VAR); } while(0)
*
* Set the planner/stepper positions directly from current_position with
* no kinematic translation. Used for homing axes and cartesian/core syncing.
*/
inline void sync_plan_position() {
#if ENABLED(DEBUG_LEVELING_FEATURE)
if (DEBUGGING(LEVELING)) DEBUG_POS("sync_plan_position", current_position);
#endif
planner.set_position_mm(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
}
inline void sync_plan_position_e() { planner.set_e_position_mm(current_position[E_AXIS]); }
inline void sync_plan_position_kinematic() {
#if ENABLED(DEBUG_LEVELING_FEATURE)
if (DEBUGGING(LEVELING)) DEBUG_POS("sync_plan_position_kinematic", current_position);
planner.set_position_mm_kinematic(current_position);
#define SYNC_PLAN_POSITION_KINEMATIC() sync_plan_position_kinematic()
#define SYNC_PLAN_POSITION_KINEMATIC() sync_plan_position()
#if ENABLED(SDSUPPORT)
#include "SdFatUtil.h"
int freeMemory() { return SdFatUtil::FreeRam(); }
#else
extern char __bss_end;
extern char __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;
}
#if ENABLED(DIGIPOT_I2C)
extern void digipot_i2c_set_current(int channel, float current);
extern void digipot_i2c_init();
#endif
* Inject the next "immediate" command, when possible, onto the front of the queue.
* Return true if any immediate commands remain to inject.
static bool drain_injected_commands_P() {
if (injected_commands_P != NULL) {
size_t i = 0;
strncpy_P(cmd, injected_commands_P, sizeof(cmd) - 1);
cmd[sizeof(cmd) - 1] = '\0';
while ((c = cmd[i]) && c != '\n') i++; // find the end of this gcode command
cmd[i] = '\0';
if (enqueue_and_echo_command(cmd)) // success?
injected_commands_P = c ? injected_commands_P + i + 1 : NULL; // next command or done
}
return (injected_commands_P != NULL); // return whether any more remain
}
/**
* Record one or many commands to run from program memory.
* Aborts the current queue, if any.
* Note: drain_injected_commands_P() must be called repeatedly to drain the commands afterwards
void enqueue_and_echo_commands_P(const char* pgcode) {
injected_commands_P = pgcode;
drain_injected_commands_P(); // first command executed asap (when possible)
}
/**
* Clear the Marlin command queue
*/
void clear_command_queue() {
cmd_queue_index_r = cmd_queue_index_w;
commands_in_queue = 0;
}
* Once a new command is in the ring buffer, call this to commit it
inline void _commit_command(bool say_ok) {
send_ok[cmd_queue_index_w] = say_ok;
cmd_queue_index_w = (cmd_queue_index_w + 1) % BUFSIZE;
commands_in_queue++;
* Copy a command from RAM into the main command buffer.
* Return true if the command was successfully added.
* Return false for a full buffer, or if the 'command' is a comment.
*/
inline bool _enqueuecommand(const char* cmd, bool say_ok=false) {
if (*cmd == ';' || commands_in_queue >= BUFSIZE) return false;
strcpy(command_queue[cmd_queue_index_w], cmd);
_commit_command(say_ok);
Jérémie FRANCOIS
committed
return true;
}
/**
* Enqueue with Serial Echo
*/
bool enqueue_and_echo_command(const char* cmd, bool say_ok/*=false*/) {
if (_enqueuecommand(cmd, say_ok)) {
SERIAL_ECHO_START;
SERIAL_ECHOPAIR(MSG_ENQUEUEING, cmd);
SERIAL_CHAR('"');
SERIAL_EOL;
return true;
}
return false;
}
#endif
}
#if ENABLED(FILAMENT_RUNOUT_SENSOR)
void setup_filrunoutpin() {
#if ENABLED(ENDSTOPPULLUP_FIL_RUNOUT)
SET_INPUT_PULLUP(FIL_RUNOUT_PIN);
#else
SET_INPUT(FIL_RUNOUT_PIN);
#if ENABLED(PS_DEFAULT_OFF)
OUT_WRITE(PS_ON_PIN, PS_ON_AWAKE);
#endif
}
servo[0].attach(SERVO0_PIN);
servo[0].detach(); // Just set up the pin. We don't have a position yet. Don't move to a random position.
servo[1].attach(SERVO1_PIN);
servo[2].attach(SERVO2_PIN);
servo[3].attach(SERVO3_PIN);
Gord Christmas
committed
*
* The servo might be deployed and positioned too low to stow
* when starting up the machine or rebooting the board.
* There's no way to know where the nozzle is positioned until
* homing has been done - no homing with z-probe without init!
*
*/
}
/**
* Stepper Reset (RigidBoard, et.al.)
*/
#if HAS_STEPPER_RESET
void disableStepperDrivers() {
OUT_WRITE(STEPPER_RESET_PIN, LOW); // drive it down to hold in reset motor driver chips
void enableStepperDrivers() { SET_INPUT(STEPPER_RESET_PIN); } // set to input, which allows it to be pulled high by pullups
#if ENABLED(EXPERIMENTAL_I2CBUS) && I2C_SLAVE_ADDRESS > 0
void i2c_on_receive(int bytes) { // just echo all bytes received to serial
i2c.receive(bytes);
}
void i2c_on_request() { // just send dummy data for now
void set_led_color(
const uint8_t r, const uint8_t g, const uint8_t b
#if ENABLED(RGBW_LED)
, const uint8_t w=0
#endif
) {
#if ENABLED(BLINKM)
// This variant uses i2c to send the RGB components to the device.
SendColors(r, g, b);
#else
// This variant uses 3 separate pins for the RGB components.
// If the pins can do PWM then their intensity will be set.
WRITE(RGB_LED_R_PIN, r ? HIGH : LOW);
WRITE(RGB_LED_G_PIN, g ? HIGH : LOW);
WRITE(RGB_LED_B_PIN, b ? HIGH : LOW);
analogWrite(RGB_LED_R_PIN, r);
analogWrite(RGB_LED_G_PIN, g);
analogWrite(RGB_LED_B_PIN, b);
WRITE(RGB_LED_W_PIN, w ? HIGH : LOW);
analogWrite(RGB_LED_W_PIN, w);
#endif
#endif
}
#endif // HAS_COLOR_LEDS
void gcode_line_error(const char* err, bool doFlush = true) {
SERIAL_ERROR_START;
serialprintPGM(err);
SERIAL_ERRORLN(gcode_LastN);
//Serial.println(gcode_N);
if (doFlush) FlushSerialRequestResend();
serial_count = 0;
}
/**
* Get all commands waiting on the serial port and queue them.
* Exit when the buffer is full or when no more characters are
* left on the serial port.
*/
inline void get_serial_commands() {
static char serial_line_buffer[MAX_CMD_SIZE];
static bool serial_comment_mode = false;