Subversion Repositories Tronxy-X3A-Marlin

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 ron 1
/**
2
 * Marlin 3D Printer Firmware
3
 * Copyright (C) 2016, 2017 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
4
 *
5
 * Based on Sprinter and grbl.
6
 * Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
7
 *
8
 * This program is free software: you can redistribute it and/or modify
9
 * it under the terms of the GNU General Public License as published by
10
 * the Free Software Foundation, either version 3 of the License, or
11
 * (at your option) any later version.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU General Public License
19
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
 *
21
 */
22
 
23
/**
24
 * About Marlin
25
 *
26
 * This firmware is a mashup between Sprinter and grbl.
27
 *  - https://github.com/kliment/Sprinter
28
 *  - https://github.com/grbl/grbl
29
 */
30
 
31
/**
32
 * -----------------
33
 * G-Codes in Marlin
34
 * -----------------
35
 *
36
 * Helpful G-code references:
37
 *  - http://linuxcnc.org/handbook/gcode/g-code.html
38
 *  - http://objects.reprap.org/wiki/Mendel_User_Manual:_RepRapGCodes
39
 *
40
 * Help to document Marlin's G-codes online:
41
 *  - http://reprap.org/wiki/G-code
42
 *  - https://github.com/MarlinFirmware/MarlinDocumentation
43
 *
44
 * -----------------
45
 *
46
 * "G" Codes
47
 *
48
 * G0   -> G1
49
 * G1   - Coordinated Movement X Y Z E
50
 * G2   - CW ARC
51
 * G3   - CCW ARC
52
 * G4   - Dwell S<seconds> or P<milliseconds>
53
 * G5   - Cubic B-spline with XYZE destination and IJPQ offsets
54
 * G6   - Direct stepper move (Requires UNREGISTERED_MOVE_SUPPORT). Hangprinter defaults to relative moves. Others default to absolute moves.
55
 * G10  - Retract filament according to settings of M207 (Requires FWRETRACT)
56
 * G11  - Retract recover filament according to settings of M208 (Requires FWRETRACT)
57
 * G12  - Clean tool (Requires NOZZLE_CLEAN_FEATURE)
58
 * G17  - Select Plane XY (Requires CNC_WORKSPACE_PLANES)
59
 * G18  - Select Plane ZX (Requires CNC_WORKSPACE_PLANES)
60
 * G19  - Select Plane YZ (Requires CNC_WORKSPACE_PLANES)
61
 * G20  - Set input units to inches (Requires INCH_MODE_SUPPORT)
62
 * G21  - Set input units to millimeters (Requires INCH_MODE_SUPPORT)
63
 * G26  - Mesh Validation Pattern (Requires G26_MESH_VALIDATION)
64
 * G27  - Park Nozzle (Requires NOZZLE_PARK_FEATURE)
65
 * G28  - Home one or more axes
66
 * G29  - Start or continue the bed leveling probe procedure (Requires bed leveling)
67
 * G30  - Single Z probe, probes bed at X Y location (defaults to current XY location)
68
 * G31  - Dock sled (Z_PROBE_SLED only)
69
 * G32  - Undock sled (Z_PROBE_SLED only)
70
 * G33  - Delta Auto-Calibration (Requires DELTA_AUTO_CALIBRATION)
71
 * G38  - Probe in any direction using the Z_MIN_PROBE (Requires G38_PROBE_TARGET)
72
 * G42  - Coordinated move to a mesh point (Requires MESH_BED_LEVELING, AUTO_BED_LEVELING_BLINEAR, or AUTO_BED_LEVELING_UBL)
73
 * G90  - Use Absolute Coordinates
74
 * G91  - Use Relative Coordinates
75
 * G92  - Set current position to coordinates given
76
 * G95  - Set torque mode (Requires MECHADUINO_I2C_COMMANDS enabled)
77
 * G96  - Set encoder reference point (Requires MECHADUINO_I2C_COMMANDS enabled)
78
 *
79
 * "M" Codes
80
 *
81
 * M0   - Unconditional stop - Wait for user to press a button on the LCD (Only if ULTRA_LCD is enabled)
82
 * M1   -> M0
83
 * M3   - Turn laser/spindle on, set spindle/laser speed/power, set rotation to clockwise
84
 * M4   - Turn laser/spindle on, set spindle/laser speed/power, set rotation to counter-clockwise
85
 * M5   - Turn laser/spindle off
86
 * M17  - Enable/Power all stepper motors
87
 * M18  - Disable all stepper motors; same as M84
88
 * M20  - List SD card. (Requires SDSUPPORT)
89
 * M21  - Init SD card. (Requires SDSUPPORT)
90
 * M22  - Release SD card. (Requires SDSUPPORT)
91
 * M23  - Select SD file: "M23 /path/file.gco". (Requires SDSUPPORT)
92
 * M24  - Start/resume SD print. (Requires SDSUPPORT)
93
 * M25  - Pause SD print. (Requires SDSUPPORT)
94
 * M26  - Set SD position in bytes: "M26 S12345". (Requires SDSUPPORT)
95
 * M27  - Report SD print status. (Requires SDSUPPORT)
96
 *        OR, with 'S<seconds>' set the SD status auto-report interval. (Requires AUTO_REPORT_SD_STATUS)
97
 *        OR, with 'C' get the current filename.
98
 * M28  - Start SD write: "M28 /path/file.gco". (Requires SDSUPPORT)
99
 * M29  - Stop SD write. (Requires SDSUPPORT)
100
 * M30  - Delete file from SD: "M30 /path/file.gco"
101
 * M31  - Report time since last M109 or SD card start to serial.
102
 * M32  - Select file and start SD print: "M32 [S<bytepos>] !/path/file.gco#". (Requires SDSUPPORT)
103
 *        Use P to run other files as sub-programs: "M32 P !filename#"
104
 *        The '#' is necessary when calling from within sd files, as it stops buffer prereading
105
 * M33  - Get the longname version of a path. (Requires LONG_FILENAME_HOST_SUPPORT)
106
 * M34  - Set SD Card sorting options. (Requires SDCARD_SORT_ALPHA)
107
 * M42  - Change pin status via gcode: M42 P<pin> S<value>. LED pin assumed if P is omitted.
108
 * M43  - Display pin status, watch pins for changes, watch endstops & toggle LED, Z servo probe test, toggle pins
109
 * M48  - Measure Z Probe repeatability: M48 P<points> X<pos> Y<pos> V<level> E<engage> L<legs> S<chizoid>. (Requires Z_MIN_PROBE_REPEATABILITY_TEST)
110
 * M75  - Start the print job timer.
111
 * M76  - Pause the print job timer.
112
 * M77  - Stop the print job timer.
113
 * M78  - Show statistical information about the print jobs. (Requires PRINTCOUNTER)
114
 * M80  - Turn on Power Supply. (Requires POWER_SUPPLY > 0)
115
 * M81  - Turn off Power Supply. (Requires POWER_SUPPLY > 0)
116
 * M82  - Set E codes absolute (default).
117
 * M83  - Set E codes relative while in Absolute (G90) mode.
118
 * M84  - Disable steppers until next move, or use S<seconds> to specify an idle
119
 *        duration after which steppers should turn off. S0 disables the timeout.
120
 * M85  - Set inactivity shutdown timer with parameter S<seconds>. To disable set zero (default)
121
 * M92  - Set planner.axis_steps_per_mm for one or more axes.
122
 * M100 - Watch Free Memory (for debugging) (Requires M100_FREE_MEMORY_WATCHER)
123
 * M104 - Set extruder target temp.
124
 * M105 - Report current temperatures.
125
 * M106 - Set print fan speed.
126
 * M107 - Print fan off.
127
 * M108 - Break out of heating loops (M109, M190, M303). With no controller, breaks out of M0/M1. (Requires EMERGENCY_PARSER)
128
 * M109 - Sxxx Wait for extruder current temp to reach target temp. Waits only when heating
129
 *        Rxxx Wait for extruder current temp to reach target temp. Waits when heating and cooling
130
 *        If AUTOTEMP is enabled, S<mintemp> B<maxtemp> F<factor>. Exit autotemp by any M109 without F
131
 * M110 - Set the current line number. (Used by host printing)
132
 * M111 - Set debug flags: "M111 S<flagbits>". See flag bits defined in enum.h.
133
 * M112 - Emergency stop.
134
 * M113 - Get or set the timeout interval for Host Keepalive "busy" messages. (Requires HOST_KEEPALIVE_FEATURE)
135
 * M114 - Report current position.
136
 *      - S1 Compute length traveled since last G96 using encoder position data (Requires MECHADUINO_I2C_COMMANDS, only kinematic axes)
137
 * M115 - Report capabilities. (Extended capabilities requires EXTENDED_CAPABILITIES_REPORT)
138
 * M117 - Display a message on the controller screen. (Requires an LCD)
139
 * M118 - Display a message in the host console.
140
 * M119 - Report endstops status.
141
 * M120 - Enable endstops detection.
142
 * M121 - Disable endstops detection.
143
 * M122 - Debug stepper (Requires at least one _DRIVER_TYPE defined as TMC2130/TMC2208/TMC2660)
144
 * M125 - Save current position and move to filament change position. (Requires PARK_HEAD_ON_PAUSE)
145
 * M126 - Solenoid Air Valve Open. (Requires BARICUDA)
146
 * M127 - Solenoid Air Valve Closed. (Requires BARICUDA)
147
 * M128 - EtoP Open. (Requires BARICUDA)
148
 * M129 - EtoP Closed. (Requires BARICUDA)
149
 * M140 - Set bed target temp. S<temp>
150
 * M145 - Set heatup values for materials on the LCD. H<hotend> B<bed> F<fan speed> for S<material> (0=PLA, 1=ABS)
151
 * M149 - Set temperature units. (Requires TEMPERATURE_UNITS_SUPPORT)
152
 * M150 - Set Status LED Color as R<red> U<green> B<blue> P<bright>. Values 0-255. (Requires BLINKM, RGB_LED, RGBW_LED, NEOPIXEL_LED, or PCA9632).
153
 * M155 - Auto-report temperatures with interval of S<seconds>. (Requires AUTO_REPORT_TEMPERATURES)
154
 * M163 - Set a single proportion for a mixing extruder. (Requires MIXING_EXTRUDER)
155
 * M164 - Commit the mix (Req. MIXING_EXTRUDER) and optionally save as a virtual tool (Req. MIXING_VIRTUAL_TOOLS > 1)
156
 * M165 - Set the mix for a mixing extruder wuth parameters ABCDHI. (Requires MIXING_EXTRUDER and DIRECT_MIXING_IN_G1)
157
 * M190 - Sxxx Wait for bed current temp to reach target temp. ** Waits only when heating! **
158
 *        Rxxx Wait for bed current temp to reach target temp. ** Waits for heating or cooling. **
159
 * M200 - Set filament diameter, D<diameter>, setting E axis units to cubic. (Use S0 to revert to linear units.)
160
 * M201 - Set max acceleration in units/s^2 for print moves: "M201 X<accel> Y<accel> Z<accel> E<accel>"
161
 * M202 - Set max acceleration in units/s^2 for travel moves: "M202 X<accel> Y<accel> Z<accel> E<accel>" ** UNUSED IN MARLIN! **
162
 * M203 - Set maximum feedrate: "M203 X<fr> Y<fr> Z<fr> E<fr>" in units/sec.
163
 * M204 - Set default acceleration in units/sec^2: P<printing> R<extruder_only> T<travel>
164
 * M205 - Set advanced settings. Current units apply:
165
            S<print> T<travel> minimum speeds
166
            Q<minimum segment time>
167
            X<max X jerk>, Y<max Y jerk>, Z<max Z jerk>, E<max E jerk>
168
 * M206 - Set additional homing offset. (Disabled by NO_WORKSPACE_OFFSETS or DELTA)
169
 * M207 - Set Retract Length: S<length>, Feedrate: F<units/min>, and Z lift: Z<distance>. (Requires FWRETRACT)
170
 * M208 - Set Recover (unretract) Additional (!) Length: S<length> and Feedrate: F<units/min>. (Requires FWRETRACT)
171
 * M209 - Turn Automatic Retract Detection on/off: S<0|1> (For slicers that don't support G10/11). (Requires FWRETRACT)
172
          Every normal extrude-only move will be classified as retract depending on the direction.
173
 * M211 - Enable, Disable, and/or Report software endstops: S<0|1> (Requires MIN_SOFTWARE_ENDSTOPS or MAX_SOFTWARE_ENDSTOPS)
174
 * M218 - Set/get a tool offset: "M218 T<index> X<offset> Y<offset>". (Requires 2 or more extruders)
175
 * M220 - Set Feedrate Percentage: "M220 S<percent>" (i.e., "FR" on the LCD)
176
 * M221 - Set Flow Percentage: "M221 S<percent>"
177
 * M226 - Wait until a pin is in a given state: "M226 P<pin> S<state>"
178
 * M240 - Trigger a camera to take a photograph. (Requires CHDK or PHOTOGRAPH_PIN)
179
 * M250 - Set LCD contrast: "M250 C<contrast>" (0-63). (Requires LCD support)
180
 * M260 - i2c Send Data (Requires EXPERIMENTAL_I2CBUS)
181
 * M261 - i2c Request Data (Requires EXPERIMENTAL_I2CBUS)
182
 * M280 - Set servo position absolute: "M280 P<index> S<angle|µs>". (Requires servos)
183
 * M290 - Babystepping (Requires BABYSTEPPING)
184
 * M300 - Play beep sound S<frequency Hz> P<duration ms>
185
 * M301 - Set PID parameters P I and D. (Requires PIDTEMP)
186
 * M302 - Allow cold extrudes, or set the minimum extrude S<temperature>. (Requires PREVENT_COLD_EXTRUSION)
187
 * M303 - PID relay autotune S<temperature> sets the target temperature. Default 150C. (Requires PIDTEMP)
188
 * M304 - Set bed PID parameters P I and D. (Requires PIDTEMPBED)
189
 * M350 - Set microstepping mode. (Requires digital microstepping pins.)
190
 * M351 - Toggle MS1 MS2 pins directly. (Requires digital microstepping pins.)
191
 * M355 - Set Case Light on/off and set brightness. (Requires CASE_LIGHT_PIN)
192
 * M380 - Activate solenoid on active extruder. (Requires EXT_SOLENOID)
193
 * M381 - Disable all solenoids. (Requires EXT_SOLENOID)
194
 * M400 - Finish all moves.
195
 * M401 - Deploy and activate Z probe. (Requires a probe)
196
 * M402 - Deactivate and stow Z probe. (Requires a probe)
197
 * M404 - Display or set the Nominal Filament Width: "W<diameter>". (Requires FILAMENT_WIDTH_SENSOR)
198
 * M405 - Enable Filament Sensor flow control. "M405 D<delay_cm>". (Requires FILAMENT_WIDTH_SENSOR)
199
 * M406 - Disable Filament Sensor flow control. (Requires FILAMENT_WIDTH_SENSOR)
200
 * M407 - Display measured filament diameter in millimeters. (Requires FILAMENT_WIDTH_SENSOR)
201
 * M410 - Quickstop. Abort all planned moves.
202
 * M420 - Enable/Disable Leveling (with current values) S1=enable S0=disable (Requires MESH_BED_LEVELING or ABL)
203
 * M421 - Set a single Z coordinate in the Mesh Leveling grid. X<units> Y<units> Z<units> (Requires MESH_BED_LEVELING, AUTO_BED_LEVELING_BILINEAR, or AUTO_BED_LEVELING_UBL)
204
 * M428 - Set the home_offset based on the current_position. Nearest edge applies. (Disabled by NO_WORKSPACE_OFFSETS or DELTA)
205
 * M500 - Store parameters in EEPROM. (Requires EEPROM_SETTINGS)
206
 * M501 - Restore parameters from EEPROM. (Requires EEPROM_SETTINGS)
207
 * M502 - Revert to the default "factory settings". ** Does not write them to EEPROM! **
208
 * M503 - Print the current settings (in memory): "M503 S<verbose>". S0 specifies compact output.
209
 * M524 - Abort SD card print job started with M24 (Requires SDSUPPORT)
210
 * M540 - Enable/disable SD card abort on endstop hit: "M540 S<state>". (Requires ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED)
211
 * M600 - Pause for filament change: "M600 X<pos> Y<pos> Z<raise> E<first_retract> L<later_retract>". (Requires ADVANCED_PAUSE_FEATURE)
212
 * M603 - Configure filament change: "M603 T<tool> U<unload_length> L<load_length>". (Requires ADVANCED_PAUSE_FEATURE)
213
 * M605 - Set Dual X-Carriage movement mode: "M605 S<mode> [X<x_offset>] [R<temp_offset>]". (Requires DUAL_X_CARRIAGE)
214
 * M665 - Set Delta configurations: "M665 H<delta height> L<diagonal rod> R<delta radius> S<segments/s> B<calibration radius> X<Alpha angle trim> Y<Beta angle trim> Z<Gamma angle trim> (Requires DELTA)
215
 * M665 - Set Hangprinter configurations: "M665 W<Ay> E<Az> R<Bx> T<By> Y<Bz> U<Cx> I<Cy> O<Cz> P<Dz> S<segments/s>" (Requires HANGPRINTER)
216
 * M666 - Set/get endstop offsets for delta (Requires DELTA) or dual endstops (Requires [XYZ]_DUAL_ENDSTOPS).
217
 * M701 - Load filament (requires FILAMENT_LOAD_UNLOAD_GCODES)
218
 * M702 - Unload filament (requires FILAMENT_LOAD_UNLOAD_GCODES)
219
 * M851 - Set Z probe's Z offset in current units. (Negative = below the nozzle.)
220
 * M852 - Set skew factors: "M852 [I<xy>] [J<xz>] [K<yz>]". (Requires SKEW_CORRECTION_GCODE, and SKEW_CORRECTION_FOR_Z for IJ)
221
 * M860 - Report the position of position encoder modules.
222
 * M861 - Report the status of position encoder modules.
223
 * M862 - Perform an axis continuity test for position encoder modules.
224
 * M863 - Perform steps-per-mm calibration for position encoder modules.
225
 * M864 - Change position encoder module I2C address.
226
 * M865 - Check position encoder module firmware version.
227
 * M866 - Report or reset position encoder module error count.
228
 * M867 - Enable/disable or toggle error correction for position encoder modules.
229
 * M868 - Report or set position encoder module error correction threshold.
230
 * M869 - Report position encoder module error.
231
 * M900 - Get or Set Linear Advance K-factor. (Requires LIN_ADVANCE)
232
 * M906 - Set or get motor current in milliamps using axis codes X, Y, Z, E. Report values if no axis codes given. (Requires at least one _DRIVER_TYPE defined as TMC2130/TMC2208/TMC2660)
233
 * M907 - Set digital trimpot motor current using axis codes. (Requires a board with digital trimpots)
234
 * M908 - Control digital trimpot directly. (Requires DAC_STEPPER_CURRENT or DIGIPOTSS_PIN)
235
 * M909 - Print digipot/DAC current value. (Requires DAC_STEPPER_CURRENT)
236
 * M910 - Commit digipot/DAC value to external EEPROM via I2C. (Requires DAC_STEPPER_CURRENT)
237
 * M911 - Report stepper driver overtemperature pre-warn condition. (Requires at least one _DRIVER_TYPE defined as TMC2130/TMC2208/TMC2660)
238
 * M912 - Clear stepper driver overtemperature pre-warn condition flag. (Requires at least one _DRIVER_TYPE defined as TMC2130/TMC2208/TMC2660)
239
 * M913 - Set HYBRID_THRESHOLD speed. (Requires HYBRID_THRESHOLD)
240
 * M914 - Set SENSORLESS_HOMING sensitivity. (Requires SENSORLESS_HOMING)
241
 *
242
 * M360 - SCARA calibration: Move to cal-position ThetaA (0 deg calibration)
243
 * M361 - SCARA calibration: Move to cal-position ThetaB (90 deg calibration - steps per degree)
244
 * M362 - SCARA calibration: Move to cal-position PsiA (0 deg calibration)
245
 * M363 - SCARA calibration: Move to cal-position PsiB (90 deg calibration - steps per degree)
246
 * M364 - SCARA calibration: Move to cal-position PSIC (90 deg to Theta calibration position)
247
 *
248
 * ************ Custom codes - This can change to suit future G-code regulations
249
 * M928 - Start SD logging: "M928 filename.gco". Stop with M29. (Requires SDSUPPORT)
250
 * M999 - Restart after being stopped by error
251
 *
252
 * "T" Codes
253
 *
254
 * T0-T3 - Select an extruder (tool) by index: "T<n> F<units/min>"
255
 *
256
 */
257
 
258
#include "Marlin.h"
259
 
260
#include "ultralcd.h"
261
#include "planner.h"
262
#include "stepper.h"
263
#include "endstops.h"
264
#include "temperature.h"
265
#include "cardreader.h"
266
#include "configuration_store.h"
267
#include "language.h"
268
#include "pins_arduino.h"
269
#include "math.h"
270
#include "nozzle.h"
271
#include "printcounter.h"
272
#include "duration_t.h"
273
#include "types.h"
274
#include "parser.h"
275
 
276
#if ENABLED(AUTO_POWER_CONTROL)
277
  #include "power.h"
278
#endif
279
 
280
#if ABL_PLANAR
281
  #include "vector_3.h"
282
  #if ENABLED(AUTO_BED_LEVELING_LINEAR)
283
    #include "least_squares_fit.h"
284
  #endif
285
#elif ENABLED(MESH_BED_LEVELING)
286
  #include "mesh_bed_leveling.h"
287
#endif
288
 
289
#if ENABLED(BEZIER_CURVE_SUPPORT)
290
  #include "planner_bezier.h"
291
#endif
292
 
293
#if ENABLED(FWRETRACT)
294
  #include "fwretract.h"
295
#endif
296
 
297
#if ENABLED(POWER_LOSS_RECOVERY)
298
  #include "power_loss_recovery.h"
299
#endif
300
 
301
#if ENABLED(FILAMENT_RUNOUT_SENSOR)
302
  #include "runout.h"
303
#endif
304
 
305
#if HAS_BUZZER && DISABLED(LCD_USE_I2C_BUZZER)
306
  #include "buzzer.h"
307
#endif
308
 
309
#if ENABLED(USE_WATCHDOG)
310
  #include "watchdog.h"
311
#endif
312
 
313
#if ENABLED(MAX7219_DEBUG)
314
  #include "Max7219_Debug_LEDs.h"
315
#endif
316
 
317
#if HAS_COLOR_LEDS
318
  #include "leds.h"
319
#endif
320
 
321
#if HAS_SERVOS
322
  #include "servo.h"
323
#endif
324
 
325
#if HAS_DIGIPOTSS
326
  #include <SPI.h>
327
#endif
328
 
329
#if HAS_TRINAMIC
330
  #include "tmc_util.h"
331
#endif
332
 
333
#if ENABLED(DAC_STEPPER_CURRENT)
334
  #include "stepper_dac.h"
335
#endif
336
 
337
#if ENABLED(EXPERIMENTAL_I2CBUS)
338
  #include "twibus.h"
339
#endif
340
 
341
#if ENABLED(I2C_POSITION_ENCODERS)
342
  #include "I2CPositionEncoder.h"
343
#endif
344
 
345
#if ENABLED(M100_FREE_MEMORY_WATCHER)
346
  void gcode_M100();
347
  void M100_dump_routine(const char * const title, const char *start, const char *end);
348
#endif
349
 
350
#if ENABLED(G26_MESH_VALIDATION)
351
  bool g26_debug_flag; // =false
352
  void gcode_G26();
353
#endif
354
 
355
#if ENABLED(SDSUPPORT)
356
  CardReader card;
357
#endif
358
 
359
#if ENABLED(EXPERIMENTAL_I2CBUS)
360
  TWIBus i2c;
361
#endif
362
 
363
#if ENABLED(G38_PROBE_TARGET)
364
  bool G38_move = false,
365
       G38_endstop_hit = false;
366
#endif
367
 
368
#if ENABLED(AUTO_BED_LEVELING_UBL)
369
  #include "ubl.h"
370
#endif
371
 
372
#if ENABLED(CNC_COORDINATE_SYSTEMS)
373
  int8_t active_coordinate_system = -1; // machine space
374
  float coordinate_system[MAX_COORDINATE_SYSTEMS][XYZ];
375
#endif
376
 
377
bool Running = true;
378
 
379
uint8_t marlin_debug_flags = DEBUG_NONE;
380
 
381
/**
382
 * Cartesian Current Position
383
 *   Used to track the native machine position as moves are queued.
384
 *   Used by 'buffer_line_to_current_position' to do a move after changing it.
385
 *   Used by 'SYNC_PLAN_POSITION_KINEMATIC' to update 'planner.position'.
386
 */
387
float current_position[XYZE] = { 0 };
388
 
389
/**
390
 * Cartesian Destination
391
 *   The destination for a move, filled in by G-code movement commands,
392
 *   and expected by functions like 'prepare_move_to_destination'.
393
 *   Set with 'gcode_get_destination' or 'set_destination_from_current'.
394
 */
395
float destination[XYZE] = { 0 };
396
 
397
/**
398
 * axis_homed
399
 *   Flags that each linear axis was homed.
400
 *   XYZ on cartesian, ABC on delta, ABZ on SCARA.
401
 *
402
 * axis_known_position
403
 *   Flags that the position is known in each linear axis. Set when homed.
404
 *   Cleared whenever a stepper powers off, potentially losing its position.
405
 */
406
uint8_t axis_homed, axis_known_position; // = 0
407
 
408
/**
409
 * GCode line number handling. Hosts may opt to include line numbers when
410
 * sending commands to Marlin, and lines will be checked for sequentiality.
411
 * M110 N<int> sets the current line number.
412
 */
413
static long gcode_N, gcode_LastN, Stopped_gcode_LastN = 0;
414
 
415
/**
416
 * GCode Command Queue
417
 * A simple ring buffer of BUFSIZE command strings.
418
 *
419
 * Commands are copied into this buffer by the command injectors
420
 * (immediate, serial, sd card) and they are processed sequentially by
421
 * the main loop. The process_next_command function parses the next
422
 * command and hands off execution to individual handler functions.
423
 */
424
uint8_t commands_in_queue = 0, // Count of commands in the queue
425
        cmd_queue_index_r = 0, // Ring buffer read (out) position
426
        cmd_queue_index_w = 0; // Ring buffer write (in) position
427
 
428
char command_queue[BUFSIZE][MAX_CMD_SIZE];
429
 
430
/**
431
 * Next Injected Command pointer. NULL if no commands are being injected.
432
 * Used by Marlin internally to ensure that commands initiated from within
433
 * are enqueued ahead of any pending serial or sd card commands.
434
 */
435
static const char *injected_commands_P = NULL;
436
 
437
#if ENABLED(TEMPERATURE_UNITS_SUPPORT)
438
  TempUnit input_temp_units = TEMPUNIT_C;
439
#endif
440
 
441
/**
442
 * Feed rates are often configured with mm/m
443
 * but the planner and stepper like mm/s units.
444
 */
445
static const float homing_feedrate_mm_s[] PROGMEM = {
446
  #if ENABLED(HANGPRINTER)
447
    MMM_TO_MMS(DUMMY_HOMING_FEEDRATE), MMM_TO_MMS(DUMMY_HOMING_FEEDRATE),
448
    MMM_TO_MMS(DUMMY_HOMING_FEEDRATE), MMM_TO_MMS(DUMMY_HOMING_FEEDRATE), 0
449
  #else
450
    #if ENABLED(DELTA)
451
      MMM_TO_MMS(HOMING_FEEDRATE_Z), MMM_TO_MMS(HOMING_FEEDRATE_Z),
452
    #else
453
      MMM_TO_MMS(HOMING_FEEDRATE_XY), MMM_TO_MMS(HOMING_FEEDRATE_XY),
454
    #endif
455
    MMM_TO_MMS(HOMING_FEEDRATE_Z), 0
456
  #endif
457
};
458
FORCE_INLINE float homing_feedrate(const AxisEnum a) { return pgm_read_float(&homing_feedrate_mm_s[a]); }
459
 
460
float feedrate_mm_s = MMM_TO_MMS(1500.0f);
461
static float saved_feedrate_mm_s;
462
int16_t feedrate_percentage = 100, saved_feedrate_percentage;
463
 
464
// Initialized by settings.load()
465
bool axis_relative_modes[XYZE] = AXIS_RELATIVE_MODES;
466
 
467
#if HAS_WORKSPACE_OFFSET
468
  #if HAS_POSITION_SHIFT
469
    // The distance that XYZ has been offset by G92. Reset by G28.
470
    float position_shift[XYZ] = { 0 };
471
  #endif
472
  #if HAS_HOME_OFFSET
473
    // This offset is added to the configured home position.
474
    // Set by M206, M428, or menu item. Saved to EEPROM.
475
    float home_offset[XYZ] = { 0 };
476
  #endif
477
  #if HAS_HOME_OFFSET && HAS_POSITION_SHIFT
478
    // The above two are combined to save on computes
479
    float workspace_offset[XYZ] = { 0 };
480
  #endif
481
#endif
482
 
483
// Software Endstops are based on the configured limits.
484
float soft_endstop_min[XYZ] = { X_MIN_BED, Y_MIN_BED, Z_MIN_POS },
485
      soft_endstop_max[XYZ] = { X_MAX_BED, Y_MAX_BED, Z_MAX_POS };
486
#if HAS_SOFTWARE_ENDSTOPS
487
  bool soft_endstops_enabled = true;
488
  #if IS_KINEMATIC
489
    float soft_endstop_radius, soft_endstop_radius_2;
490
  #endif
491
#endif
492
 
493
#if FAN_COUNT > 0
494
  int16_t fanSpeeds[FAN_COUNT] = { 0 };
495
  #if ENABLED(EXTRA_FAN_SPEED)
496
    int16_t old_fanSpeeds[FAN_COUNT],
497
            new_fanSpeeds[FAN_COUNT];
498
  #endif
499
  #if ENABLED(PROBING_FANS_OFF)
500
    bool fans_paused; // = false;
501
    int16_t paused_fanSpeeds[FAN_COUNT] = { 0 };
502
  #endif
503
#endif
504
 
505
#if ENABLED(USE_CONTROLLER_FAN)
506
  int controllerFanSpeed; // = 0;
507
#endif
508
 
509
// The active extruder (tool). Set with T<extruder> command.
510
uint8_t active_extruder; // = 0;
511
 
512
// Relative Mode. Enable with G91, disable with G90.
513
static bool relative_mode; // = false;
514
 
515
// For M109 and M190, this flag may be cleared (by M108) to exit the wait loop
516
volatile bool wait_for_heatup = true;
517
 
518
// For M0/M1, this flag may be cleared (by M108) to exit the wait-for-user loop
519
#if HAS_RESUME_CONTINUE
520
  volatile bool wait_for_user; // = false;
521
#endif
522
 
523
#if HAS_AUTO_REPORTING || ENABLED(HOST_KEEPALIVE_FEATURE)
524
  bool suspend_auto_report; // = false
525
#endif
526
 
527
const char axis_codes[XYZE] = { 'X', 'Y', 'Z', 'E' };
528
 
529
#if ENABLED(HANGPRINTER)
530
  const char axis_codes_hangprinter[ABCDE] = { 'A', 'B', 'C', 'D', 'E' };
531
  #define RAW_AXIS_CODES(I) axis_codes_hangprinter[I]
532
#else
533
  #define RAW_AXIS_CODES(I) axis_codes[I]
534
#endif
535
 
536
// Number of characters read in the current line of serial input
537
static int serial_count; // = 0;
538
 
539
// Inactivity shutdown
540
millis_t previous_move_ms; // = 0;
541
static millis_t max_inactive_time; // = 0;
542
static millis_t stepper_inactive_time = (DEFAULT_STEPPER_DEACTIVE_TIME) * 1000UL;
543
 
544
// Buzzer - I2C on the LCD or a BEEPER_PIN
545
#if ENABLED(LCD_USE_I2C_BUZZER)
546
  #define BUZZ(d,f) lcd_buzz(d, f)
547
#elif PIN_EXISTS(BEEPER)
548
  Buzzer buzzer;
549
  #define BUZZ(d,f) buzzer.tone(d, f)
550
#else
551
  #define BUZZ(d,f) NOOP
552
#endif
553
 
554
uint8_t target_extruder;
555
 
556
#if HAS_BED_PROBE
557
  float zprobe_zoffset; // Initialized by settings.load()
558
#endif
559
 
560
#if HAS_ABL
561
  float xy_probe_feedrate_mm_s = MMM_TO_MMS(XY_PROBE_SPEED);
562
  #define XY_PROBE_FEEDRATE_MM_S xy_probe_feedrate_mm_s
563
#elif defined(XY_PROBE_SPEED)
564
  #define XY_PROBE_FEEDRATE_MM_S MMM_TO_MMS(XY_PROBE_SPEED)
565
#else
566
  #define XY_PROBE_FEEDRATE_MM_S PLANNER_XY_FEEDRATE()
567
#endif
568
 
569
#if ENABLED(AUTO_BED_LEVELING_BILINEAR)
570
  #if ENABLED(DELTA)
571
    #define ADJUST_DELTA(V) \
572
      if (planner.leveling_active) { \
573
        const float zadj = bilinear_z_offset(V); \
574
        delta[A_AXIS] += zadj; \
575
        delta[B_AXIS] += zadj; \
576
        delta[C_AXIS] += zadj; \
577
      }
578
  #else
579
    #define ADJUST_DELTA(V) if (planner.leveling_active) { delta[Z_AXIS] += bilinear_z_offset(V); }
580
  #endif
581
#elif IS_KINEMATIC
582
  #define ADJUST_DELTA(V) NOOP
583
#endif
584
 
585
#if HAS_HEATED_BED && ENABLED(WAIT_FOR_BED_HEATER)
586
  const static char msg_wait_for_bed_heating[] PROGMEM = "Wait for bed heating...\n";
587
#endif
588
 
589
// Extruder offsets
590
#if HOTENDS > 1
591
  float hotend_offset[XYZ][HOTENDS];  // Initialized by settings.load()
592
#endif
593
 
594
#if HAS_Z_SERVO_PROBE
595
  const int z_servo_angle[2] = Z_SERVO_ANGLES;
596
#endif
597
 
598
#if ENABLED(BARICUDA)
599
  uint8_t baricuda_valve_pressure = 0,
600
          baricuda_e_to_p_pressure = 0;
601
#endif
602
 
603
#if HAS_POWER_SWITCH
604
  bool powersupply_on;
605
  #if ENABLED(AUTO_POWER_CONTROL)
606
    #define PSU_ON()  powerManager.power_on()
607
    #define PSU_OFF() powerManager.power_off()
608
  #else
609
    #define PSU_ON()  PSU_PIN_ON()
610
    #define PSU_OFF() PSU_PIN_OFF()
611
  #endif
612
#endif
613
 
614
#if ENABLED(DELTA)
615
 
616
  float delta[ABC];
617
 
618
  // Initialized by settings.load()
619
  float delta_height,
620
        delta_endstop_adj[ABC] = { 0 },
621
        delta_radius,
622
        delta_tower_angle_trim[ABC],
623
        delta_tower[ABC][2],
624
        delta_diagonal_rod,
625
        delta_calibration_radius,
626
        delta_diagonal_rod_2_tower[ABC],
627
        delta_segments_per_second,
628
        delta_clip_start_height = Z_MAX_POS;
629
 
630
  float delta_safe_distance_from_top();
631
 
632
#elif ENABLED(HANGPRINTER)
633
 
634
  float anchor_A_y,
635
        anchor_A_z,
636
        anchor_B_x,
637
        anchor_B_y,
638
        anchor_B_z,
639
        anchor_C_x,
640
        anchor_C_y,
641
        anchor_C_z,
642
        anchor_D_z,
643
        line_lengths[ABCD],
644
        line_lengths_origin[ABCD],
645
        delta_segments_per_second;
646
 
647
#endif
648
 
649
#if ENABLED(AUTO_BED_LEVELING_BILINEAR)
650
  int bilinear_grid_spacing[2], bilinear_start[2];
651
  float bilinear_grid_factor[2],
652
        z_values[GRID_MAX_POINTS_X][GRID_MAX_POINTS_Y];
653
  #if ENABLED(ABL_BILINEAR_SUBDIVISION)
654
    #define ABL_BG_SPACING(A) bilinear_grid_spacing_virt[A]
655
    #define ABL_BG_FACTOR(A)  bilinear_grid_factor_virt[A]
656
    #define ABL_BG_POINTS_X   ABL_GRID_POINTS_VIRT_X
657
    #define ABL_BG_POINTS_Y   ABL_GRID_POINTS_VIRT_Y
658
    #define ABL_BG_GRID(X,Y)  z_values_virt[X][Y]
659
  #else
660
    #define ABL_BG_SPACING(A) bilinear_grid_spacing[A]
661
    #define ABL_BG_FACTOR(A)  bilinear_grid_factor[A]
662
    #define ABL_BG_POINTS_X   GRID_MAX_POINTS_X
663
    #define ABL_BG_POINTS_Y   GRID_MAX_POINTS_Y
664
    #define ABL_BG_GRID(X,Y)  z_values[X][Y]
665
  #endif
666
#endif
667
 
668
#if IS_SCARA
669
  // Float constants for SCARA calculations
670
  const float L1 = SCARA_LINKAGE_1, L2 = SCARA_LINKAGE_2,
671
              L1_2 = sq(float(L1)), L1_2_2 = 2.0 * L1_2,
672
              L2_2 = sq(float(L2));
673
 
674
  float delta_segments_per_second = SCARA_SEGMENTS_PER_SECOND,
675
        delta[ABC];
676
#endif
677
 
678
float cartes[XYZ] = { 0 };
679
 
680
#if ENABLED(FILAMENT_WIDTH_SENSOR)
681
  bool filament_sensor; // = false;                             // M405 turns on filament sensor control. M406 turns it off.
682
  float filament_width_nominal = DEFAULT_NOMINAL_FILAMENT_DIA,  // Nominal filament width. Change with M404.
683
        filament_width_meas = DEFAULT_MEASURED_FILAMENT_DIA;    // Measured filament diameter
684
  uint8_t meas_delay_cm = MEASUREMENT_DELAY_CM;                 // Distance delay setting
685
  int8_t measurement_delay[MAX_MEASUREMENT_DELAY + 1],          // Ring buffer to delayed measurement. Store extruder factor after subtracting 100
686
         filwidth_delay_index[2] = { 0, -1 };                   // Indexes into ring buffer
687
#endif
688
 
689
#if ENABLED(ADVANCED_PAUSE_FEATURE)
690
  AdvancedPauseMenuResponse advanced_pause_menu_response;
691
  float filament_change_unload_length[EXTRUDERS],
692
        filament_change_load_length[EXTRUDERS];
693
#endif
694
 
695
#if ENABLED(MIXING_EXTRUDER)
696
  float mixing_factor[MIXING_STEPPERS]; // Reciprocal of mix proportion. 0.0 = off, otherwise >= 1.0.
697
  #if MIXING_VIRTUAL_TOOLS > 1
698
    float mixing_virtual_tool_mix[MIXING_VIRTUAL_TOOLS][MIXING_STEPPERS];
699
  #endif
700
#endif
701
 
702
static bool send_ok[BUFSIZE];
703
 
704
#if HAS_SERVOS
705
  Servo servo[NUM_SERVOS];
706
  #define MOVE_SERVO(I, P) servo[I].move(P)
707
  #if HAS_Z_SERVO_PROBE
708
    #define DEPLOY_Z_SERVO() MOVE_SERVO(Z_PROBE_SERVO_NR, z_servo_angle[0])
709
    #define STOW_Z_SERVO() MOVE_SERVO(Z_PROBE_SERVO_NR, z_servo_angle[1])
710
  #endif
711
#endif
712
 
713
#ifdef CHDK
714
  millis_t chdkHigh = 0;
715
  bool chdkActive = false;
716
#endif
717
 
718
#if ENABLED(HOST_KEEPALIVE_FEATURE)
719
  MarlinBusyState busy_state = NOT_BUSY;
720
  static millis_t next_busy_signal_ms = 0;
721
  uint8_t host_keepalive_interval = DEFAULT_KEEPALIVE_INTERVAL;
722
#else
723
  #define host_keepalive() NOOP
724
#endif
725
 
726
#if ENABLED(I2C_POSITION_ENCODERS)
727
  I2CPositionEncodersMgr I2CPEM;
728
#endif
729
 
730
#if ENABLED(CNC_WORKSPACE_PLANES)
731
  static WorkspacePlane workspace_plane = PLANE_XY;
732
#endif
733
 
734
FORCE_INLINE float pgm_read_any(const float *p) { return pgm_read_float_near(p); }
735
FORCE_INLINE signed char pgm_read_any(const signed char *p) { return pgm_read_byte_near(p); }
736
 
737
#define XYZ_CONSTS_FROM_CONFIG(type, array, CONFIG) \
738
  static const PROGMEM type array##_P[XYZ] = { X_##CONFIG, Y_##CONFIG, Z_##CONFIG }; \
739
  static inline type array(const AxisEnum axis) { return pgm_read_any(&array##_P[axis]); } \
740
  typedef void __void_##CONFIG##__
741
 
742
XYZ_CONSTS_FROM_CONFIG(float, base_min_pos,   MIN_POS);
743
XYZ_CONSTS_FROM_CONFIG(float, base_max_pos,   MAX_POS);
744
XYZ_CONSTS_FROM_CONFIG(float, base_home_pos,  HOME_POS);
745
XYZ_CONSTS_FROM_CONFIG(float, max_length,     MAX_LENGTH);
746
XYZ_CONSTS_FROM_CONFIG(float, home_bump_mm,   HOME_BUMP_MM);
747
XYZ_CONSTS_FROM_CONFIG(signed char, home_dir, HOME_DIR);
748
 
749
/**
750
 * ***************************************************************************
751
 * ******************************** FUNCTIONS ********************************
752
 * ***************************************************************************
753
 */
754
 
755
void stop();
756
 
757
void get_available_commands();
758
void process_next_command();
759
void process_parsed_command();
760
 
761
void get_cartesian_from_steppers();
762
void set_current_from_steppers_for_axis(const AxisEnum axis);
763
 
764
#if ENABLED(ARC_SUPPORT)
765
  void plan_arc(const float (&cart)[XYZE], const float (&offset)[2], const bool clockwise);
766
#endif
767
 
768
#if ENABLED(BEZIER_CURVE_SUPPORT)
769
  void plan_cubic_move(const float (&cart)[XYZE], const float (&offset)[4]);
770
#endif
771
 
772
void report_current_position();
773
void report_current_position_detail();
774
 
775
#if ENABLED(DEBUG_LEVELING_FEATURE)
776
  void print_xyz(const char* prefix, const char* suffix, const float x, const float y, const float z) {
777
    serialprintPGM(prefix);
778
    SERIAL_CHAR('(');
779
    SERIAL_ECHO(x);
780
    SERIAL_ECHOPAIR(", ", y);
781
    SERIAL_ECHOPAIR(", ", z);
782
    SERIAL_CHAR(')');
783
    if (suffix) serialprintPGM(suffix); else SERIAL_EOL();
784
  }
785
 
786
  void print_xyz(const char* prefix, const char* suffix, const float xyz[]) {
787
    print_xyz(prefix, suffix, xyz[X_AXIS], xyz[Y_AXIS], xyz[Z_AXIS]);
788
  }
789
 
790
  #define DEBUG_POS(SUFFIX,VAR) do { \
791
    print_xyz(PSTR("  " STRINGIFY(VAR) "="), PSTR(" : " SUFFIX "\n"), VAR); }while(0)
792
#endif
793
 
794
/**
795
 * sync_plan_position
796
 *
797
 * Set the planner/stepper positions directly from current_position with
798
 * no kinematic translation. Used for homing axes and cartesian/core syncing.
799
 *
800
 * This is not possible for Hangprinter because current_position and position are different sizes
801
 */
802
void sync_plan_position() {
803
  #if DISABLED(HANGPRINTER)
804
    #if ENABLED(DEBUG_LEVELING_FEATURE)
805
      if (DEBUGGING(LEVELING)) DEBUG_POS("sync_plan_position", current_position);
806
    #endif
807
    planner.set_position_mm(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_CART]);
808
  #endif
809
}
810
void sync_plan_position_e() { planner.set_e_position_mm(current_position[E_CART]); }
811
 
812
#if IS_KINEMATIC
813
  inline void sync_plan_position_kinematic() {
814
    #if ENABLED(DEBUG_LEVELING_FEATURE)
815
      if (DEBUGGING(LEVELING)) DEBUG_POS("sync_plan_position_kinematic", current_position);
816
    #endif
817
    planner.set_position_mm_kinematic(current_position);
818
  }
819
#endif
820
 
821
#if ENABLED(SDSUPPORT)
822
  #include "SdFatUtil.h"
823
  int freeMemory() { return SdFatUtil::FreeRam(); }
824
#else
825
extern "C" {
826
  extern char __bss_end;
827
  extern char __heap_start;
828
  extern void* __brkval;
829
 
830
  int freeMemory() {
831
    int free_memory;
832
    if (int(__brkval) == 0)
833
      free_memory = (int(&free_memory)) - (int(&__bss_end));
834
    else
835
      free_memory = (int(&free_memory)) - (int(__brkval));
836
    return free_memory;
837
  }
838
}
839
#endif // !SDSUPPORT
840
 
841
#if ENABLED(DIGIPOT_I2C)
842
  extern void digipot_i2c_set_current(uint8_t channel, float current);
843
  extern void digipot_i2c_init();
844
#endif
845
 
846
/**
847
 * Inject the next "immediate" command, when possible, onto the front of the queue.
848
 * Return true if any immediate commands remain to inject.
849
 */
850
static bool drain_injected_commands_P() {
851
  if (injected_commands_P != NULL) {
852
    size_t i = 0;
853
    char c, cmd[30];
854
    strncpy_P(cmd, injected_commands_P, sizeof(cmd) - 1);
855
    cmd[sizeof(cmd) - 1] = '\0';
856
    while ((c = cmd[i]) && c != '\n') i++; // find the end of this gcode command
857
    cmd[i] = '\0';
858
    if (enqueue_and_echo_command(cmd))     // success?
859
      injected_commands_P = c ? injected_commands_P + i + 1 : NULL; // next command or done
860
  }
861
  return (injected_commands_P != NULL);    // return whether any more remain
862
}
863
 
864
/**
865
 * Record one or many commands to run from program memory.
866
 * Aborts the current queue, if any.
867
 * Note: drain_injected_commands_P() must be called repeatedly to drain the commands afterwards
868
 */
869
void enqueue_and_echo_commands_P(const char * const pgcode) {
870
  injected_commands_P = pgcode;
871
  (void)drain_injected_commands_P(); // first command executed asap (when possible)
872
}
873
 
874
/**
875
 * Clear the Marlin command queue
876
 */
877
void clear_command_queue() {
878
  cmd_queue_index_r = cmd_queue_index_w = commands_in_queue = 0;
879
}
880
 
881
/**
882
 * Once a new command is in the ring buffer, call this to commit it
883
 */
884
inline void _commit_command(bool say_ok) {
885
  send_ok[cmd_queue_index_w] = say_ok;
886
  if (++cmd_queue_index_w >= BUFSIZE) cmd_queue_index_w = 0;
887
  commands_in_queue++;
888
}
889
 
890
/**
891
 * Copy a command from RAM into the main command buffer.
892
 * Return true if the command was successfully added.
893
 * Return false for a full buffer, or if the 'command' is a comment.
894
 */
895
inline bool _enqueuecommand(const char* cmd, bool say_ok=false) {
896
  if (*cmd == ';' || commands_in_queue >= BUFSIZE) return false;
897
  strcpy(command_queue[cmd_queue_index_w], cmd);
898
  _commit_command(say_ok);
899
  return true;
900
}
901
 
902
/**
903
 * Enqueue with Serial Echo
904
 */
905
bool enqueue_and_echo_command(const char* cmd) {
906
  if (_enqueuecommand(cmd)) {
907
    SERIAL_ECHO_START();
908
    SERIAL_ECHOPAIR(MSG_ENQUEUEING, cmd);
909
    SERIAL_CHAR('"');
910
    SERIAL_EOL();
911
    return true;
912
  }
913
  return false;
914
}
915
 
916
#if HAS_QUEUE_NOW
917
  void enqueue_and_echo_command_now(const char* cmd) {
918
    while (!enqueue_and_echo_command(cmd)) idle();
919
  }
920
  #if HAS_LCD_QUEUE_NOW
921
    void enqueue_and_echo_commands_now_P(const char * const pgcode) {
922
      enqueue_and_echo_commands_P(pgcode);
923
      while (drain_injected_commands_P()) idle();
924
    }
925
  #endif
926
#endif
927
 
928
void setup_killpin() {
929
  #if HAS_KILL
930
    SET_INPUT_PULLUP(KILL_PIN);
931
  #endif
932
}
933
 
934
void setup_powerhold() {
935
  #if HAS_SUICIDE
936
    OUT_WRITE(SUICIDE_PIN, HIGH);
937
  #endif
938
  #if HAS_POWER_SWITCH
939
    #if ENABLED(PS_DEFAULT_OFF)
940
      powersupply_on = true;  PSU_OFF();
941
    #else
942
      powersupply_on = false; PSU_ON();
943
    #endif
944
  #endif
945
}
946
 
947
void suicide() {
948
  #if HAS_SUICIDE
949
    OUT_WRITE(SUICIDE_PIN, LOW);
950
  #endif
951
}
952
 
953
void servo_init() {
954
  #if NUM_SERVOS >= 1 && HAS_SERVO_0
955
    servo[0].attach(SERVO0_PIN);
956
    servo[0].detach(); // Just set up the pin. We don't have a position yet. Don't move to a random position.
957
  #endif
958
  #if NUM_SERVOS >= 2 && HAS_SERVO_1
959
    servo[1].attach(SERVO1_PIN);
960
    servo[1].detach();
961
  #endif
962
  #if NUM_SERVOS >= 3 && HAS_SERVO_2
963
    servo[2].attach(SERVO2_PIN);
964
    servo[2].detach();
965
  #endif
966
  #if NUM_SERVOS >= 4 && HAS_SERVO_3
967
    servo[3].attach(SERVO3_PIN);
968
    servo[3].detach();
969
  #endif
970
 
971
  #if HAS_Z_SERVO_PROBE
972
    /**
973
     * Set position of Z Servo Endstop
974
     *
975
     * The servo might be deployed and positioned too low to stow
976
     * when starting up the machine or rebooting the board.
977
     * There's no way to know where the nozzle is positioned until
978
     * homing has been done - no homing with z-probe without init!
979
     *
980
     */
981
    STOW_Z_SERVO();
982
  #endif
983
}
984
 
985
/**
986
 * Stepper Reset (RigidBoard, et.al.)
987
 */
988
#if HAS_STEPPER_RESET
989
  void disableStepperDrivers() {
990
    OUT_WRITE(STEPPER_RESET_PIN, LOW);  // drive it down to hold in reset motor driver chips
991
  }
992
  void enableStepperDrivers() { SET_INPUT(STEPPER_RESET_PIN); }  // set to input, which allows it to be pulled high by pullups
993
#endif
994
 
995
#if ENABLED(EXPERIMENTAL_I2CBUS) && I2C_SLAVE_ADDRESS > 0
996
 
997
  void i2c_on_receive(int bytes) { // just echo all bytes received to serial
998
    i2c.receive(bytes);
999
  }
1000
 
1001
  void i2c_on_request() {          // just send dummy data for now
1002
    i2c.reply("Hello World!\n");
1003
  }
1004
 
1005
#endif
1006
 
1007
void gcode_line_error(const char* err, bool doFlush = true) {
1008
  SERIAL_ERROR_START();
1009
  serialprintPGM(err);
1010
  SERIAL_ERRORLN(gcode_LastN);
1011
  //Serial.println(gcode_N);
1012
  if (doFlush) flush_and_request_resend();
1013
  serial_count = 0;
1014
}
1015
 
1016
/**
1017
 * Get all commands waiting on the serial port and queue them.
1018
 * Exit when the buffer is full or when no more characters are
1019
 * left on the serial port.
1020
 */
1021
inline void get_serial_commands() {
1022
  static char serial_line_buffer[MAX_CMD_SIZE];
1023
  static bool serial_comment_mode = false;
1024
 
1025
  // If the command buffer is empty for too long,
1026
  // send "wait" to indicate Marlin is still waiting.
1027
  #if NO_TIMEOUTS > 0
1028
    static millis_t last_command_time = 0;
1029
    const millis_t ms = millis();
1030
    if (commands_in_queue == 0 && !MYSERIAL0.available() && ELAPSED(ms, last_command_time + NO_TIMEOUTS)) {
1031
      SERIAL_ECHOLNPGM(MSG_WAIT);
1032
      last_command_time = ms;
1033
    }
1034
  #endif
1035
 
1036
  /**
1037
   * Loop while serial characters are incoming and the queue is not full
1038
   */
1039
  int c;
1040
  while (commands_in_queue < BUFSIZE && (c = MYSERIAL0.read()) >= 0) {
1041
 
1042
    char serial_char = c;
1043
 
1044
    /**
1045
     * If the character ends the line
1046
     */
1047
    if (serial_char == '\n' || serial_char == '\r') {
1048
 
1049
      serial_comment_mode = false;                      // end of line == end of comment
1050
 
1051
      // Skip empty lines and comments
1052
      if (!serial_count) { thermalManager.manage_heater(); continue; }
1053
 
1054
      serial_line_buffer[serial_count] = 0;             // Terminate string
1055
      serial_count = 0;                                 // Reset buffer
1056
 
1057
      char* command = serial_line_buffer;
1058
 
1059
      while (*command == ' ') command++;                // Skip leading spaces
1060
      char *npos = (*command == 'N') ? command : NULL;  // Require the N parameter to start the line
1061
 
1062
      if (npos) {
1063
 
1064
        bool M110 = strstr_P(command, PSTR("M110")) != NULL;
1065
 
1066
        if (M110) {
1067
          char* n2pos = strchr(command + 4, 'N');
1068
          if (n2pos) npos = n2pos;
1069
        }
1070
 
1071
        gcode_N = strtol(npos + 1, NULL, 10);
1072
 
1073
        if (gcode_N != gcode_LastN + 1 && !M110)
1074
          return gcode_line_error(PSTR(MSG_ERR_LINE_NO));
1075
 
1076
        char *apos = strrchr(command, '*');
1077
        if (apos) {
1078
          uint8_t checksum = 0, count = uint8_t(apos - command);
1079
          while (count) checksum ^= command[--count];
1080
          if (strtol(apos + 1, NULL, 10) != checksum)
1081
            return gcode_line_error(PSTR(MSG_ERR_CHECKSUM_MISMATCH));
1082
        }
1083
        else
1084
          return gcode_line_error(PSTR(MSG_ERR_NO_CHECKSUM));
1085
 
1086
        gcode_LastN = gcode_N;
1087
      }
1088
      #if ENABLED(SDSUPPORT)
1089
        else if (card.saving && strcmp(command, "M29") != 0) // No line number with M29 in Pronterface
1090
          return gcode_line_error(PSTR(MSG_ERR_NO_CHECKSUM));
1091
      #endif
1092
 
1093
      // Movement commands alert when stopped
1094
      if (IsStopped()) {
1095
        char* gpos = strchr(command, 'G');
1096
        if (gpos) {
1097
          switch (strtol(gpos + 1, NULL, 10)) {
1098
            case 0:
1099
            case 1:
1100
            #if ENABLED(ARC_SUPPORT)
1101
              case 2:
1102
              case 3:
1103
            #endif
1104
            #if ENABLED(BEZIER_CURVE_SUPPORT)
1105
              case 5:
1106
            #endif
1107
              SERIAL_ERRORLNPGM(MSG_ERR_STOPPED);
1108
              LCD_MESSAGEPGM(MSG_STOPPED);
1109
              break;
1110
          }
1111
        }
1112
      }
1113
 
1114
      #if DISABLED(EMERGENCY_PARSER)
1115
        // Process critical commands early
1116
        if (strcmp(command, "M108") == 0) {
1117
          wait_for_heatup = false;
1118
          #if ENABLED(NEWPANEL)
1119
            wait_for_user = false;
1120
          #endif
1121
        }
1122
        if (strcmp(command, "M112") == 0) kill(PSTR(MSG_KILLED));
1123
        if (strcmp(command, "M410") == 0) quickstop_stepper();
1124
      #endif
1125
 
1126
      #if defined(NO_TIMEOUTS) && NO_TIMEOUTS > 0
1127
        last_command_time = ms;
1128
      #endif
1129
 
1130
      // Add the command to the queue
1131
      _enqueuecommand(serial_line_buffer, true);
1132
    }
1133
    else if (serial_count >= MAX_CMD_SIZE - 1) {
1134
      // Keep fetching, but ignore normal characters beyond the max length
1135
      // The command will be injected when EOL is reached
1136
    }
1137
    else if (serial_char == '\\') {   // Handle escapes
1138
      if ((c = MYSERIAL0.read()) >= 0 && !serial_comment_mode) // if we have one more character, copy it over
1139
        serial_line_buffer[serial_count++] = (char)c;
1140
      // otherwise do nothing
1141
    }
1142
    else { // it's not a newline, carriage return or escape char
1143
      if (serial_char == ';') serial_comment_mode = true;
1144
      if (!serial_comment_mode) serial_line_buffer[serial_count++] = serial_char;
1145
    }
1146
 
1147
  } // queue has space, serial has data
1148
}
1149
 
1150
#if ENABLED(SDSUPPORT)
1151
 
1152
  #if ENABLED(PRINTER_EVENT_LEDS) && HAS_RESUME_CONTINUE
1153
    static bool lights_off_after_print; // = false
1154
  #endif
1155
 
1156
  /**
1157
   * Get commands from the SD Card until the command buffer is full
1158
   * or until the end of the file is reached. The special character '#'
1159
   * can also interrupt buffering.
1160
   */
1161
  inline void get_sdcard_commands() {
1162
    static bool stop_buffering = false,
1163
                sd_comment_mode = false;
1164
 
1165
    if (!card.sdprinting) return;
1166
 
1167
    /**
1168
     * '#' stops reading from SD to the buffer prematurely, so procedural
1169
     * macro calls are possible. If it occurs, stop_buffering is triggered
1170
     * and the buffer is run dry; this character _can_ occur in serial com
1171
     * due to checksums, however, no checksums are used in SD printing.
1172
     */
1173
 
1174
    if (commands_in_queue == 0) stop_buffering = false;
1175
 
1176
    uint16_t sd_count = 0;
1177
    bool card_eof = card.eof();
1178
    while (commands_in_queue < BUFSIZE && !card_eof && !stop_buffering) {
1179
      const int16_t n = card.get();
1180
      char sd_char = (char)n;
1181
      card_eof = card.eof();
1182
      if (card_eof || n == -1
1183
          || sd_char == '\n' || sd_char == '\r'
1184
          || ((sd_char == '#' || sd_char == ':') && !sd_comment_mode)
1185
      ) {
1186
        if (card_eof) {
1187
 
1188
          card.printingHasFinished();
1189
 
1190
          if (card.sdprinting)
1191
            sd_count = 0; // If a sub-file was printing, continue from call point
1192
          else {
1193
            SERIAL_PROTOCOLLNPGM(MSG_FILE_PRINTED);
1194
            #if ENABLED(PRINTER_EVENT_LEDS)
1195
              LCD_MESSAGEPGM(MSG_INFO_COMPLETED_PRINTS);
1196
              leds.set_green();
1197
              #if HAS_RESUME_CONTINUE
1198
                lights_off_after_print = true;
1199
                enqueue_and_echo_commands_P(PSTR("M0 S"
1200
                  #if ENABLED(NEWPANEL)
1201
                    "1800"
1202
                  #else
1203
                    "60"
1204
                  #endif
1205
                ));
1206
              #else
1207
                safe_delay(2000);
1208
                leds.set_off();
1209
              #endif
1210
            #endif // PRINTER_EVENT_LEDS
1211
          }
1212
        }
1213
        else if (n == -1) {
1214
          SERIAL_ERROR_START();
1215
          SERIAL_ECHOLNPGM(MSG_SD_ERR_READ);
1216
        }
1217
        if (sd_char == '#') stop_buffering = true;
1218
 
1219
        sd_comment_mode = false; // for new command
1220
 
1221
        // Skip empty lines and comments
1222
        if (!sd_count) { thermalManager.manage_heater(); continue; }
1223
 
1224
        command_queue[cmd_queue_index_w][sd_count] = '\0'; // terminate string
1225
        sd_count = 0; // clear sd line buffer
1226
 
1227
        _commit_command(false);
1228
      }
1229
      else if (sd_count >= MAX_CMD_SIZE - 1) {
1230
        /**
1231
         * Keep fetching, but ignore normal characters beyond the max length
1232
         * The command will be injected when EOL is reached
1233
         */
1234
      }
1235
      else {
1236
        if (sd_char == ';') sd_comment_mode = true;
1237
        if (!sd_comment_mode) command_queue[cmd_queue_index_w][sd_count++] = sd_char;
1238
      }
1239
    }
1240
  }
1241
 
1242
  #if ENABLED(POWER_LOSS_RECOVERY)
1243
 
1244
    inline bool drain_job_recovery_commands() {
1245
      static uint8_t job_recovery_commands_index = 0; // Resets on reboot
1246
      if (job_recovery_commands_count) {
1247
        if (_enqueuecommand(job_recovery_commands[job_recovery_commands_index])) {
1248
          ++job_recovery_commands_index;
1249
          if (!--job_recovery_commands_count) job_recovery_phase = JOB_RECOVERY_DONE;
1250
        }
1251
        return true;
1252
      }
1253
      return false;
1254
    }
1255
 
1256
  #endif
1257
 
1258
#endif // SDSUPPORT
1259
 
1260
/**
1261
 * Add to the circular command queue the next command from:
1262
 *  - The command-injection queue (injected_commands_P)
1263
 *  - The active serial input (usually USB)
1264
 *  - Commands left in the queue after power-loss
1265
 *  - The SD card file being actively printed
1266
 */
1267
void get_available_commands() {
1268
 
1269
  // Immediate commands block the other queues
1270
  if (drain_injected_commands_P()) return;
1271
 
1272
  get_serial_commands();
1273
 
1274
  #if ENABLED(POWER_LOSS_RECOVERY)
1275
    // Commands for power-loss recovery take precedence
1276
    if (job_recovery_phase == JOB_RECOVERY_YES && drain_job_recovery_commands()) return;
1277
  #endif
1278
 
1279
  #if ENABLED(SDSUPPORT)
1280
    get_sdcard_commands();
1281
  #endif
1282
}
1283
 
1284
/**
1285
 * Set target_extruder from the T parameter or the active_extruder
1286
 *
1287
 * Returns TRUE if the target is invalid
1288
 */
1289
bool get_target_extruder_from_command(const uint16_t code) {
1290
  if (parser.seenval('T')) {
1291
    const int8_t e = parser.value_byte();
1292
    if (e >= EXTRUDERS) {
1293
      SERIAL_ECHO_START();
1294
      SERIAL_CHAR('M');
1295
      SERIAL_ECHO(code);
1296
      SERIAL_ECHOLNPAIR(" " MSG_INVALID_EXTRUDER " ", e);
1297
      return true;
1298
    }
1299
    target_extruder = e;
1300
  }
1301
  else
1302
    target_extruder = active_extruder;
1303
 
1304
  return false;
1305
}
1306
 
1307
#if ENABLED(DUAL_X_CARRIAGE) || ENABLED(DUAL_NOZZLE_DUPLICATION_MODE)
1308
  bool extruder_duplication_enabled = false; // Used in Dual X mode 2
1309
#endif
1310
 
1311
#if ENABLED(DUAL_X_CARRIAGE)
1312
 
1313
  static DualXMode dual_x_carriage_mode = DEFAULT_DUAL_X_CARRIAGE_MODE;
1314
 
1315
  static float x_home_pos(const int extruder) {
1316
    if (extruder == 0)
1317
      return base_home_pos(X_AXIS);
1318
    else
1319
      /**
1320
       * In dual carriage mode the extruder offset provides an override of the
1321
       * second X-carriage position when homed - otherwise X2_HOME_POS is used.
1322
       * This allows soft recalibration of the second extruder home position
1323
       * without firmware reflash (through the M218 command).
1324
       */
1325
      return hotend_offset[X_AXIS][1] > 0 ? hotend_offset[X_AXIS][1] : X2_HOME_POS;
1326
  }
1327
 
1328
  static int x_home_dir(const int extruder) { return extruder ? X2_HOME_DIR : X_HOME_DIR; }
1329
 
1330
  static float inactive_extruder_x_pos = X2_MAX_POS; // used in mode 0 & 1
1331
  static bool active_extruder_parked = false;        // used in mode 1 & 2
1332
  static float raised_parked_position[XYZE];         // used in mode 1
1333
  static millis_t delayed_move_time = 0;             // used in mode 1
1334
  static float duplicate_extruder_x_offset = DEFAULT_DUPLICATION_X_OFFSET; // used in mode 2
1335
  static int16_t duplicate_extruder_temp_offset = 0; // used in mode 2
1336
 
1337
#endif // DUAL_X_CARRIAGE
1338
 
1339
#if HAS_WORKSPACE_OFFSET || ENABLED(DUAL_X_CARRIAGE) || ENABLED(DELTA)
1340
 
1341
  /**
1342
   * Software endstops can be used to monitor the open end of
1343
   * an axis that has a hardware endstop on the other end. Or
1344
   * they can prevent axes from moving past endstops and grinding.
1345
   *
1346
   * To keep doing their job as the coordinate system changes,
1347
   * the software endstop positions must be refreshed to remain
1348
   * at the same positions relative to the machine.
1349
   */
1350
  void update_software_endstops(const AxisEnum axis) {
1351
    #if HAS_HOME_OFFSET && HAS_POSITION_SHIFT
1352
      workspace_offset[axis] = home_offset[axis] + position_shift[axis];
1353
    #endif
1354
 
1355
    #if ENABLED(DUAL_X_CARRIAGE)
1356
      if (axis == X_AXIS) {
1357
 
1358
        // In Dual X mode hotend_offset[X] is T1's home position
1359
        const float dual_max_x = MAX(hotend_offset[X_AXIS][1], X2_MAX_POS);
1360
 
1361
        if (active_extruder != 0) {
1362
          // T1 can move from X2_MIN_POS to X2_MAX_POS or X2 home position (whichever is larger)
1363
          soft_endstop_min[X_AXIS] = X2_MIN_POS;
1364
          soft_endstop_max[X_AXIS] = dual_max_x;
1365
        }
1366
        else if (dual_x_carriage_mode == DXC_DUPLICATION_MODE) {
1367
          // In Duplication Mode, T0 can move as far left as X_MIN_POS
1368
          // but not so far to the right that T1 would move past the end
1369
          soft_endstop_min[X_AXIS] = base_min_pos(X_AXIS);
1370
          soft_endstop_max[X_AXIS] = MIN(base_max_pos(X_AXIS), dual_max_x - duplicate_extruder_x_offset);
1371
        }
1372
        else {
1373
          // In other modes, T0 can move from X_MIN_POS to X_MAX_POS
1374
          soft_endstop_min[axis] = base_min_pos(axis);
1375
          soft_endstop_max[axis] = base_max_pos(axis);
1376
        }
1377
      }
1378
    #elif ENABLED(DELTA)
1379
      soft_endstop_min[axis] = base_min_pos(axis);
1380
      soft_endstop_max[axis] = axis == Z_AXIS ? delta_height
1381
      #if HAS_BED_PROBE
1382
        - zprobe_zoffset
1383
      #endif
1384
      : base_max_pos(axis);
1385
    #else
1386
      soft_endstop_min[axis] = base_min_pos(axis);
1387
      soft_endstop_max[axis] = base_max_pos(axis);
1388
    #endif
1389
 
1390
    #if ENABLED(DEBUG_LEVELING_FEATURE)
1391
      if (DEBUGGING(LEVELING)) {
1392
        SERIAL_ECHOPAIR("For ", axis_codes[axis]);
1393
        #if HAS_HOME_OFFSET
1394
          SERIAL_ECHOPAIR(" axis:\n home_offset = ", home_offset[axis]);
1395
        #endif
1396
        #if HAS_POSITION_SHIFT
1397
          SERIAL_ECHOPAIR("\n position_shift = ", position_shift[axis]);
1398
        #endif
1399
        SERIAL_ECHOPAIR("\n soft_endstop_min = ", soft_endstop_min[axis]);
1400
        SERIAL_ECHOLNPAIR("\n soft_endstop_max = ", soft_endstop_max[axis]);
1401
      }
1402
    #endif
1403
 
1404
    #if ENABLED(DELTA)
1405
      switch (axis) {
1406
        #if HAS_SOFTWARE_ENDSTOPS
1407
          case X_AXIS:
1408
          case Y_AXIS:
1409
            // Get a minimum radius for clamping
1410
            soft_endstop_radius = MIN3(ABS(MAX(soft_endstop_min[X_AXIS], soft_endstop_min[Y_AXIS])), soft_endstop_max[X_AXIS], soft_endstop_max[Y_AXIS]);
1411
            soft_endstop_radius_2 = sq(soft_endstop_radius);
1412
            break;
1413
        #endif
1414
        case Z_AXIS:
1415
          delta_clip_start_height = soft_endstop_max[axis] - delta_safe_distance_from_top();
1416
        default: break;
1417
      }
1418
    #endif
1419
  }
1420
 
1421
#endif // HAS_WORKSPACE_OFFSET || DUAL_X_CARRIAGE || DELTA
1422
 
1423
#if HAS_M206_COMMAND
1424
  /**
1425
   * Change the home offset for an axis.
1426
   * Also refreshes the workspace offset.
1427
   */
1428
  static void set_home_offset(const AxisEnum axis, const float v) {
1429
    home_offset[axis] = v;
1430
    update_software_endstops(axis);
1431
  }
1432
#endif // HAS_M206_COMMAND
1433
 
1434
/**
1435
 * Set an axis' current position to its home position (after homing).
1436
 *
1437
 * For Core and Cartesian robots this applies one-to-one when an
1438
 * individual axis has been homed.
1439
 *
1440
 * DELTA should wait until all homing is done before setting the XYZ
1441
 * current_position to home, because homing is a single operation.
1442
 * In the case where the axis positions are already known and previously
1443
 * homed, DELTA could home to X or Y individually by moving either one
1444
 * to the center. However, homing Z always homes XY and Z.
1445
 *
1446
 * SCARA should wait until all XY homing is done before setting the XY
1447
 * current_position to home, because neither X nor Y is at home until
1448
 * both are at home. Z can however be homed individually.
1449
 *
1450
 * Callers must sync the planner position after calling this!
1451
 */
1452
static void set_axis_is_at_home(const AxisEnum axis) {
1453
  #if ENABLED(DEBUG_LEVELING_FEATURE)
1454
    if (DEBUGGING(LEVELING)) {
1455
      SERIAL_ECHOPAIR(">>> set_axis_is_at_home(", axis_codes[axis]);
1456
      SERIAL_CHAR(')');
1457
      SERIAL_EOL();
1458
    }
1459
  #endif
1460
 
1461
  SBI(axis_known_position, axis);
1462
  SBI(axis_homed, axis);
1463
 
1464
  #if HAS_POSITION_SHIFT
1465
    position_shift[axis] = 0;
1466
    update_software_endstops(axis);
1467
  #endif
1468
 
1469
  #if ENABLED(DUAL_X_CARRIAGE)
1470
    if (axis == X_AXIS && (active_extruder == 1 || dual_x_carriage_mode == DXC_DUPLICATION_MODE)) {
1471
      current_position[X_AXIS] = x_home_pos(active_extruder);
1472
      return;
1473
    }
1474
  #endif
1475
 
1476
  #if ENABLED(MORGAN_SCARA)
1477
 
1478
    /**
1479
     * Morgan SCARA homes XY at the same time
1480
     */
1481
    if (axis == X_AXIS || axis == Y_AXIS) {
1482
 
1483
      float homeposition[XYZ] = {
1484
        base_home_pos(X_AXIS),
1485
        base_home_pos(Y_AXIS),
1486
        base_home_pos(Z_AXIS)
1487
      };
1488
 
1489
      // SERIAL_ECHOPAIR("homeposition X:", homeposition[X_AXIS]);
1490
      // SERIAL_ECHOLNPAIR(" Y:", homeposition[Y_AXIS]);
1491
 
1492
      /**
1493
       * Get Home position SCARA arm angles using inverse kinematics,
1494
       * and calculate homing offset using forward kinematics
1495
       */
1496
      inverse_kinematics(homeposition);
1497
      forward_kinematics_SCARA(delta[A_AXIS], delta[B_AXIS]);
1498
 
1499
      // SERIAL_ECHOPAIR("Cartesian X:", cartes[X_AXIS]);
1500
      // SERIAL_ECHOLNPAIR(" Y:", cartes[Y_AXIS]);
1501
 
1502
      current_position[axis] = cartes[axis];
1503
 
1504
      /**
1505
       * SCARA home positions are based on configuration since the actual
1506
       * limits are determined by the inverse kinematic transform.
1507
       */
1508
      soft_endstop_min[axis] = base_min_pos(axis); // + (cartes[axis] - base_home_pos(axis));
1509
      soft_endstop_max[axis] = base_max_pos(axis); // + (cartes[axis] - base_home_pos(axis));
1510
    }
1511
    else
1512
  #elif ENABLED(DELTA)
1513
    current_position[axis] = (axis == Z_AXIS ? delta_height
1514
    #if HAS_BED_PROBE
1515
      - zprobe_zoffset
1516
    #endif
1517
    : base_home_pos(axis));
1518
  #else
1519
    current_position[axis] = base_home_pos(axis);
1520
  #endif
1521
 
1522
  /**
1523
   * Z Probe Z Homing? Account for the probe's Z offset.
1524
   */
1525
  #if HAS_BED_PROBE && Z_HOME_DIR < 0
1526
    if (axis == Z_AXIS) {
1527
      #if HOMING_Z_WITH_PROBE
1528
 
1529
        current_position[Z_AXIS] -= zprobe_zoffset;
1530
 
1531
        #if ENABLED(DEBUG_LEVELING_FEATURE)
1532
          if (DEBUGGING(LEVELING)) {
1533
            SERIAL_ECHOLNPGM("*** Z HOMED WITH PROBE (Z_MIN_PROBE_USES_Z_MIN_ENDSTOP_PIN) ***");
1534
            SERIAL_ECHOLNPAIR("> zprobe_zoffset = ", zprobe_zoffset);
1535
          }
1536
        #endif
1537
 
1538
      #elif ENABLED(DEBUG_LEVELING_FEATURE)
1539
 
1540
        if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("*** Z HOMED TO ENDSTOP (Z_MIN_PROBE_ENDSTOP) ***");
1541
 
1542
      #endif
1543
    }
1544
  #endif
1545
 
1546
  #if ENABLED(DEBUG_LEVELING_FEATURE)
1547
    if (DEBUGGING(LEVELING)) {
1548
      #if HAS_HOME_OFFSET
1549
        SERIAL_ECHOPAIR("> home_offset[", axis_codes[axis]);
1550
        SERIAL_ECHOLNPAIR("] = ", home_offset[axis]);
1551
      #endif
1552
      DEBUG_POS("", current_position);
1553
      SERIAL_ECHOPAIR("<<< set_axis_is_at_home(", axis_codes[axis]);
1554
      SERIAL_CHAR(')');
1555
      SERIAL_EOL();
1556
    }
1557
  #endif
1558
 
1559
  #if ENABLED(I2C_POSITION_ENCODERS)
1560
    I2CPEM.homed(axis);
1561
  #endif
1562
}
1563
 
1564
/**
1565
 * Homing bump feedrate (mm/s)
1566
 */
1567
inline float get_homing_bump_feedrate(const AxisEnum axis) {
1568
  #if HOMING_Z_WITH_PROBE
1569
    if (axis == Z_AXIS) return MMM_TO_MMS(Z_PROBE_SPEED_SLOW);
1570
  #endif
1571
  static const uint8_t homing_bump_divisor[] PROGMEM = HOMING_BUMP_DIVISOR;
1572
  uint8_t hbd = pgm_read_byte(&homing_bump_divisor[axis]);
1573
  if (hbd < 1) {
1574
    hbd = 10;
1575
    SERIAL_ECHO_START();
1576
    SERIAL_ECHOLNPGM("Warning: Homing Bump Divisor < 1");
1577
  }
1578
  return homing_feedrate(axis) / hbd;
1579
}
1580
 
1581
/**
1582
 * Some planner shorthand inline functions
1583
 */
1584
 
1585
/**
1586
 * Move the planner to the current position from wherever it last moved
1587
 * (or from wherever it has been told it is located).
1588
 *
1589
 * Impossible on Hangprinter because current_position and position are of different sizes
1590
 */
1591
inline void buffer_line_to_current_position() {
1592
  #if DISABLED(HANGPRINTER) // emptying this function probably breaks do_blocking_move_to()
1593
    planner.buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_CART], feedrate_mm_s, active_extruder);
1594
  #endif
1595
}
1596
 
1597
/**
1598
 * Move the planner to the position stored in the destination array, which is
1599
 * used by G0/G1/G2/G3/G5 and many other functions to set a destination.
1600
 */
1601
inline void buffer_line_to_destination(const float &fr_mm_s) {
1602
  #if ENABLED(HANGPRINTER)
1603
    UNUSED(fr_mm_s);
1604
  #else
1605
    planner.buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_CART], fr_mm_s, active_extruder);
1606
  #endif
1607
}
1608
 
1609
#if IS_KINEMATIC
1610
  /**
1611
   * Calculate delta, start a line, and set current_position to destination
1612
   */
1613
  void prepare_uninterpolated_move_to_destination(const float fr_mm_s=0) {
1614
    #if ENABLED(DEBUG_LEVELING_FEATURE)
1615
      if (DEBUGGING(LEVELING)) DEBUG_POS("prepare_uninterpolated_move_to_destination", destination);
1616
    #endif
1617
 
1618
    #if UBL_SEGMENTED
1619
      // ubl segmented line will do z-only moves in single segment
1620
      ubl.prepare_segmented_line_to(destination, MMS_SCALED(fr_mm_s ? fr_mm_s : feedrate_mm_s));
1621
    #else
1622
      if ( current_position[X_AXIS] == destination[X_AXIS]
1623
        && current_position[Y_AXIS] == destination[Y_AXIS]
1624
        && current_position[Z_AXIS] == destination[Z_AXIS]
1625
        && current_position[E_CART] == destination[E_CART]
1626
      ) return;
1627
 
1628
      planner.buffer_line_kinematic(destination, MMS_SCALED(fr_mm_s ? fr_mm_s : feedrate_mm_s), active_extruder);
1629
    #endif
1630
 
1631
    set_current_from_destination();
1632
  }
1633
#endif // IS_KINEMATIC
1634
 
1635
/**
1636
 * Plan a move to (X, Y, Z) and set the current_position.
1637
 * The final current_position may not be the one that was requested
1638
 * Caution: 'destination' is modified by this function.
1639
 */
1640
void do_blocking_move_to(const float rx, const float ry, const float rz, const float &fr_mm_s/*=0.0*/) {
1641
  const float old_feedrate_mm_s = feedrate_mm_s;
1642
 
1643
  #if ENABLED(DEBUG_LEVELING_FEATURE)
1644
    if (DEBUGGING(LEVELING)) print_xyz(PSTR(">>> do_blocking_move_to"), NULL, LOGICAL_X_POSITION(rx), LOGICAL_Y_POSITION(ry), LOGICAL_Z_POSITION(rz));
1645
  #endif
1646
 
1647
  const float z_feedrate = fr_mm_s ? fr_mm_s : homing_feedrate(Z_AXIS);
1648
 
1649
  #if ENABLED(DELTA)
1650
 
1651
    if (!position_is_reachable(rx, ry)) return;
1652
 
1653
    feedrate_mm_s = fr_mm_s ? fr_mm_s : XY_PROBE_FEEDRATE_MM_S;
1654
 
1655
    set_destination_from_current();          // sync destination at the start
1656
 
1657
    #if ENABLED(DEBUG_LEVELING_FEATURE)
1658
      if (DEBUGGING(LEVELING)) DEBUG_POS("set_destination_from_current", destination);
1659
    #endif
1660
 
1661
    // when in the danger zone
1662
    if (current_position[Z_AXIS] > delta_clip_start_height) {
1663
      if (rz > delta_clip_start_height) {   // staying in the danger zone
1664
        destination[X_AXIS] = rx;           // move directly (uninterpolated)
1665
        destination[Y_AXIS] = ry;
1666
        destination[Z_AXIS] = rz;
1667
        prepare_uninterpolated_move_to_destination(); // set_current_from_destination
1668
        #if ENABLED(DEBUG_LEVELING_FEATURE)
1669
          if (DEBUGGING(LEVELING)) DEBUG_POS("danger zone move", current_position);
1670
        #endif
1671
        return;
1672
      }
1673
      destination[Z_AXIS] = delta_clip_start_height;
1674
      prepare_uninterpolated_move_to_destination(); // set_current_from_destination
1675
      #if ENABLED(DEBUG_LEVELING_FEATURE)
1676
        if (DEBUGGING(LEVELING)) DEBUG_POS("zone border move", current_position);
1677
      #endif
1678
    }
1679
 
1680
    if (rz > current_position[Z_AXIS]) {    // raising?
1681
      destination[Z_AXIS] = rz;
1682
      prepare_uninterpolated_move_to_destination(z_feedrate);   // set_current_from_destination
1683
      #if ENABLED(DEBUG_LEVELING_FEATURE)
1684
        if (DEBUGGING(LEVELING)) DEBUG_POS("z raise move", current_position);
1685
      #endif
1686
    }
1687
 
1688
    destination[X_AXIS] = rx;
1689
    destination[Y_AXIS] = ry;
1690
    prepare_move_to_destination();         // set_current_from_destination
1691
    #if ENABLED(DEBUG_LEVELING_FEATURE)
1692
      if (DEBUGGING(LEVELING)) DEBUG_POS("xy move", current_position);
1693
    #endif
1694
 
1695
    if (rz < current_position[Z_AXIS]) {    // lowering?
1696
      destination[Z_AXIS] = rz;
1697
      prepare_uninterpolated_move_to_destination(z_feedrate);   // set_current_from_destination
1698
      #if ENABLED(DEBUG_LEVELING_FEATURE)
1699
        if (DEBUGGING(LEVELING)) DEBUG_POS("z lower move", current_position);
1700
      #endif
1701
    }
1702
 
1703
  #elif IS_SCARA
1704
 
1705
    if (!position_is_reachable(rx, ry)) return;
1706
 
1707
    set_destination_from_current();
1708
 
1709
    // If Z needs to raise, do it before moving XY
1710
    if (destination[Z_AXIS] < rz) {
1711
      destination[Z_AXIS] = rz;
1712
      prepare_uninterpolated_move_to_destination(z_feedrate);
1713
    }
1714
 
1715
    destination[X_AXIS] = rx;
1716
    destination[Y_AXIS] = ry;
1717
    prepare_uninterpolated_move_to_destination(fr_mm_s ? fr_mm_s : XY_PROBE_FEEDRATE_MM_S);
1718
 
1719
    // If Z needs to lower, do it after moving XY
1720
    if (destination[Z_AXIS] > rz) {
1721
      destination[Z_AXIS] = rz;
1722
      prepare_uninterpolated_move_to_destination(z_feedrate);
1723
    }
1724
 
1725
  #else
1726
 
1727
    // If Z needs to raise, do it before moving XY
1728
    if (current_position[Z_AXIS] < rz) {
1729
      feedrate_mm_s = z_feedrate;
1730
      current_position[Z_AXIS] = rz;
1731
      buffer_line_to_current_position();
1732
    }
1733
 
1734
    feedrate_mm_s = fr_mm_s ? fr_mm_s : XY_PROBE_FEEDRATE_MM_S;
1735
    current_position[X_AXIS] = rx;
1736
    current_position[Y_AXIS] = ry;
1737
    buffer_line_to_current_position();
1738
 
1739
    // If Z needs to lower, do it after moving XY
1740
    if (current_position[Z_AXIS] > rz) {
1741
      feedrate_mm_s = z_feedrate;
1742
      current_position[Z_AXIS] = rz;
1743
      buffer_line_to_current_position();
1744
    }
1745
 
1746
  #endif
1747
 
1748
  planner.synchronize();
1749
 
1750
  feedrate_mm_s = old_feedrate_mm_s;
1751
 
1752
  #if ENABLED(DEBUG_LEVELING_FEATURE)
1753
    if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("<<< do_blocking_move_to");
1754
  #endif
1755
}
1756
void do_blocking_move_to_x(const float &rx, const float &fr_mm_s/*=0.0*/) {
1757
  do_blocking_move_to(rx, current_position[Y_AXIS], current_position[Z_AXIS], fr_mm_s);
1758
}
1759
void do_blocking_move_to_z(const float &rz, const float &fr_mm_s/*=0.0*/) {
1760
  do_blocking_move_to(current_position[X_AXIS], current_position[Y_AXIS], rz, fr_mm_s);
1761
}
1762
void do_blocking_move_to_xy(const float &rx, const float &ry, const float &fr_mm_s/*=0.0*/) {
1763
  do_blocking_move_to(rx, ry, current_position[Z_AXIS], fr_mm_s);
1764
}
1765
 
1766
//
1767
// Prepare to do endstop or probe moves
1768
// with custom feedrates.
1769
//
1770
//  - Save current feedrates
1771
//  - Reset the rate multiplier
1772
//  - Reset the command timeout
1773
//  - Enable the endstops (for endstop moves)
1774
//
1775
void setup_for_endstop_or_probe_move() {
1776
  #if ENABLED(DEBUG_LEVELING_FEATURE)
1777
    if (DEBUGGING(LEVELING)) DEBUG_POS("setup_for_endstop_or_probe_move", current_position);
1778
  #endif
1779
  saved_feedrate_mm_s = feedrate_mm_s;
1780
  saved_feedrate_percentage = feedrate_percentage;
1781
  feedrate_percentage = 100;
1782
}
1783
 
1784
void clean_up_after_endstop_or_probe_move() {
1785
  #if ENABLED(DEBUG_LEVELING_FEATURE)
1786
    if (DEBUGGING(LEVELING)) DEBUG_POS("clean_up_after_endstop_or_probe_move", current_position);
1787
  #endif
1788
  feedrate_mm_s = saved_feedrate_mm_s;
1789
  feedrate_percentage = saved_feedrate_percentage;
1790
}
1791
 
1792
#if HAS_AXIS_UNHOMED_ERR
1793
 
1794
  bool axis_unhomed_error(const bool x/*=true*/, const bool y/*=true*/, const bool z/*=true*/) {
1795
    #if ENABLED(HOME_AFTER_DEACTIVATE)
1796
      const bool xx = x && !TEST(axis_known_position, X_AXIS),
1797
                 yy = y && !TEST(axis_known_position, Y_AXIS),
1798
                 zz = z && !TEST(axis_known_position, Z_AXIS);
1799
    #else
1800
      const bool xx = x && !TEST(axis_homed, X_AXIS),
1801
                 yy = y && !TEST(axis_homed, Y_AXIS),
1802
                 zz = z && !TEST(axis_homed, Z_AXIS);
1803
    #endif
1804
    if (xx || yy || zz) {
1805
      SERIAL_ECHO_START();
1806
      SERIAL_ECHOPGM(MSG_HOME " ");
1807
      if (xx) SERIAL_ECHOPGM(MSG_X);
1808
      if (yy) SERIAL_ECHOPGM(MSG_Y);
1809
      if (zz) SERIAL_ECHOPGM(MSG_Z);
1810
      SERIAL_ECHOLNPGM(" " MSG_FIRST);
1811
 
1812
      #if ENABLED(ULTRA_LCD)
1813
        lcd_status_printf_P(0, PSTR(MSG_HOME " %s%s%s " MSG_FIRST), xx ? MSG_X : "", yy ? MSG_Y : "", zz ? MSG_Z : "");
1814
      #endif
1815
      return true;
1816
    }
1817
    return false;
1818
  }
1819
 
1820
#endif // HAS_AXIS_UNHOMED_ERR
1821
 
1822
#if ENABLED(Z_PROBE_SLED)
1823
 
1824
  #ifndef SLED_DOCKING_OFFSET
1825
    #define SLED_DOCKING_OFFSET 0
1826
  #endif
1827
 
1828
  /**
1829
   * Method to dock/undock a sled designed by Charles Bell.
1830
   *
1831
   * stow[in]     If false, move to MAX_X and engage the solenoid
1832
   *              If true, move to MAX_X and release the solenoid
1833
   */
1834
  static void dock_sled(bool stow) {
1835
    #if ENABLED(DEBUG_LEVELING_FEATURE)
1836
      if (DEBUGGING(LEVELING)) {
1837
        SERIAL_ECHOPAIR("dock_sled(", stow);
1838
        SERIAL_CHAR(')');
1839
        SERIAL_EOL();
1840
      }
1841
    #endif
1842
 
1843
    // Dock sled a bit closer to ensure proper capturing
1844
    do_blocking_move_to_x(X_MAX_POS + SLED_DOCKING_OFFSET - ((stow) ? 1 : 0));
1845
 
1846
    #if HAS_SOLENOID_1 && DISABLED(EXT_SOLENOID)
1847
      WRITE(SOL1_PIN, !stow); // switch solenoid
1848
    #endif
1849
  }
1850
 
1851
#elif ENABLED(Z_PROBE_ALLEN_KEY)
1852
 
1853
  FORCE_INLINE void do_blocking_move_to(const float (&raw)[XYZ], const float &fr_mm_s) {
1854
    do_blocking_move_to(raw[X_AXIS], raw[Y_AXIS], raw[Z_AXIS], fr_mm_s);
1855
  }
1856
 
1857
  void run_deploy_moves_script() {
1858
    #if defined(Z_PROBE_ALLEN_KEY_DEPLOY_1_X) || defined(Z_PROBE_ALLEN_KEY_DEPLOY_1_Y) || defined(Z_PROBE_ALLEN_KEY_DEPLOY_1_Z)
1859
      #ifndef Z_PROBE_ALLEN_KEY_DEPLOY_1_X
1860
        #define Z_PROBE_ALLEN_KEY_DEPLOY_1_X current_position[X_AXIS]
1861
      #endif
1862
      #ifndef Z_PROBE_ALLEN_KEY_DEPLOY_1_Y
1863
        #define Z_PROBE_ALLEN_KEY_DEPLOY_1_Y current_position[Y_AXIS]
1864
      #endif
1865
      #ifndef Z_PROBE_ALLEN_KEY_DEPLOY_1_Z
1866
        #define Z_PROBE_ALLEN_KEY_DEPLOY_1_Z current_position[Z_AXIS]
1867
      #endif
1868
      #ifndef Z_PROBE_ALLEN_KEY_DEPLOY_1_FEEDRATE
1869
        #define Z_PROBE_ALLEN_KEY_DEPLOY_1_FEEDRATE 0.0
1870
      #endif
1871
      const float deploy_1[] = { Z_PROBE_ALLEN_KEY_DEPLOY_1_X, Z_PROBE_ALLEN_KEY_DEPLOY_1_Y, Z_PROBE_ALLEN_KEY_DEPLOY_1_Z };
1872
      do_blocking_move_to(deploy_1, MMM_TO_MMS(Z_PROBE_ALLEN_KEY_DEPLOY_1_FEEDRATE));
1873
    #endif
1874
    #if defined(Z_PROBE_ALLEN_KEY_DEPLOY_2_X) || defined(Z_PROBE_ALLEN_KEY_DEPLOY_2_Y) || defined(Z_PROBE_ALLEN_KEY_DEPLOY_2_Z)
1875
      #ifndef Z_PROBE_ALLEN_KEY_DEPLOY_2_X
1876
        #define Z_PROBE_ALLEN_KEY_DEPLOY_2_X current_position[X_AXIS]
1877
      #endif
1878
      #ifndef Z_PROBE_ALLEN_KEY_DEPLOY_2_Y
1879
        #define Z_PROBE_ALLEN_KEY_DEPLOY_2_Y current_position[Y_AXIS]
1880
      #endif
1881
      #ifndef Z_PROBE_ALLEN_KEY_DEPLOY_2_Z
1882
        #define Z_PROBE_ALLEN_KEY_DEPLOY_2_Z current_position[Z_AXIS]
1883
      #endif
1884
      #ifndef Z_PROBE_ALLEN_KEY_DEPLOY_2_FEEDRATE
1885
        #define Z_PROBE_ALLEN_KEY_DEPLOY_2_FEEDRATE 0.0
1886
      #endif
1887
      const float deploy_2[] = { Z_PROBE_ALLEN_KEY_DEPLOY_2_X, Z_PROBE_ALLEN_KEY_DEPLOY_2_Y, Z_PROBE_ALLEN_KEY_DEPLOY_2_Z };
1888
      do_blocking_move_to(deploy_2, MMM_TO_MMS(Z_PROBE_ALLEN_KEY_DEPLOY_2_FEEDRATE));
1889
    #endif
1890
    #if defined(Z_PROBE_ALLEN_KEY_DEPLOY_3_X) || defined(Z_PROBE_ALLEN_KEY_DEPLOY_3_Y) || defined(Z_PROBE_ALLEN_KEY_DEPLOY_3_Z)
1891
      #ifndef Z_PROBE_ALLEN_KEY_DEPLOY_3_X
1892
        #define Z_PROBE_ALLEN_KEY_DEPLOY_3_X current_position[X_AXIS]
1893
      #endif
1894
      #ifndef Z_PROBE_ALLEN_KEY_DEPLOY_3_Y
1895
        #define Z_PROBE_ALLEN_KEY_DEPLOY_3_Y current_position[Y_AXIS]
1896
      #endif
1897
      #ifndef Z_PROBE_ALLEN_KEY_DEPLOY_3_Z
1898
        #define Z_PROBE_ALLEN_KEY_DEPLOY_3_Z current_position[Z_AXIS]
1899
      #endif
1900
      #ifndef Z_PROBE_ALLEN_KEY_DEPLOY_3_FEEDRATE
1901
        #define Z_PROBE_ALLEN_KEY_DEPLOY_3_FEEDRATE 0.0
1902
      #endif
1903
      const float deploy_3[] = { Z_PROBE_ALLEN_KEY_DEPLOY_3_X, Z_PROBE_ALLEN_KEY_DEPLOY_3_Y, Z_PROBE_ALLEN_KEY_DEPLOY_3_Z };
1904
      do_blocking_move_to(deploy_3, MMM_TO_MMS(Z_PROBE_ALLEN_KEY_DEPLOY_3_FEEDRATE));
1905
    #endif
1906
    #if defined(Z_PROBE_ALLEN_KEY_DEPLOY_4_X) || defined(Z_PROBE_ALLEN_KEY_DEPLOY_4_Y) || defined(Z_PROBE_ALLEN_KEY_DEPLOY_4_Z)
1907
      #ifndef Z_PROBE_ALLEN_KEY_DEPLOY_4_X
1908
        #define Z_PROBE_ALLEN_KEY_DEPLOY_4_X current_position[X_AXIS]
1909
      #endif
1910
      #ifndef Z_PROBE_ALLEN_KEY_DEPLOY_4_Y
1911
        #define Z_PROBE_ALLEN_KEY_DEPLOY_4_Y current_position[Y_AXIS]
1912
      #endif
1913
      #ifndef Z_PROBE_ALLEN_KEY_DEPLOY_4_Z
1914
        #define Z_PROBE_ALLEN_KEY_DEPLOY_4_Z current_position[Z_AXIS]
1915
      #endif
1916
      #ifndef Z_PROBE_ALLEN_KEY_DEPLOY_4_FEEDRATE
1917
        #define Z_PROBE_ALLEN_KEY_DEPLOY_4_FEEDRATE 0.0
1918
      #endif
1919
      const float deploy_4[] = { Z_PROBE_ALLEN_KEY_DEPLOY_4_X, Z_PROBE_ALLEN_KEY_DEPLOY_4_Y, Z_PROBE_ALLEN_KEY_DEPLOY_4_Z };
1920
      do_blocking_move_to(deploy_4, MMM_TO_MMS(Z_PROBE_ALLEN_KEY_DEPLOY_4_FEEDRATE));
1921
    #endif
1922
    #if defined(Z_PROBE_ALLEN_KEY_DEPLOY_5_X) || defined(Z_PROBE_ALLEN_KEY_DEPLOY_5_Y) || defined(Z_PROBE_ALLEN_KEY_DEPLOY_5_Z)
1923
      #ifndef Z_PROBE_ALLEN_KEY_DEPLOY_5_X
1924
        #define Z_PROBE_ALLEN_KEY_DEPLOY_5_X current_position[X_AXIS]
1925
      #endif
1926
      #ifndef Z_PROBE_ALLEN_KEY_DEPLOY_5_Y
1927
        #define Z_PROBE_ALLEN_KEY_DEPLOY_5_Y current_position[Y_AXIS]
1928
      #endif
1929
      #ifndef Z_PROBE_ALLEN_KEY_DEPLOY_5_Z
1930
        #define Z_PROBE_ALLEN_KEY_DEPLOY_5_Z current_position[Z_AXIS]
1931
      #endif
1932
      #ifndef Z_PROBE_ALLEN_KEY_DEPLOY_5_FEEDRATE
1933
        #define Z_PROBE_ALLEN_KEY_DEPLOY_5_FEEDRATE 0.0
1934
      #endif
1935
      const float deploy_5[] = { Z_PROBE_ALLEN_KEY_DEPLOY_5_X, Z_PROBE_ALLEN_KEY_DEPLOY_5_Y, Z_PROBE_ALLEN_KEY_DEPLOY_5_Z };
1936
      do_blocking_move_to(deploy_5, MMM_TO_MMS(Z_PROBE_ALLEN_KEY_DEPLOY_5_FEEDRATE));
1937
    #endif
1938
  }
1939
 
1940
  void run_stow_moves_script() {
1941
    #if defined(Z_PROBE_ALLEN_KEY_STOW_1_X) || defined(Z_PROBE_ALLEN_KEY_STOW_1_Y) || defined(Z_PROBE_ALLEN_KEY_STOW_1_Z)
1942
      #ifndef Z_PROBE_ALLEN_KEY_STOW_1_X
1943
        #define Z_PROBE_ALLEN_KEY_STOW_1_X current_position[X_AXIS]
1944
      #endif
1945
      #ifndef Z_PROBE_ALLEN_KEY_STOW_1_Y
1946
        #define Z_PROBE_ALLEN_KEY_STOW_1_Y current_position[Y_AXIS]
1947
      #endif
1948
      #ifndef Z_PROBE_ALLEN_KEY_STOW_1_Z
1949
        #define Z_PROBE_ALLEN_KEY_STOW_1_Z current_position[Z_AXIS]
1950
      #endif
1951
      #ifndef Z_PROBE_ALLEN_KEY_STOW_1_FEEDRATE
1952
        #define Z_PROBE_ALLEN_KEY_STOW_1_FEEDRATE 0.0
1953
      #endif
1954
      const float stow_1[] = { Z_PROBE_ALLEN_KEY_STOW_1_X, Z_PROBE_ALLEN_KEY_STOW_1_Y, Z_PROBE_ALLEN_KEY_STOW_1_Z };
1955
      do_blocking_move_to(stow_1, MMM_TO_MMS(Z_PROBE_ALLEN_KEY_STOW_1_FEEDRATE));
1956
    #endif
1957
    #if defined(Z_PROBE_ALLEN_KEY_STOW_2_X) || defined(Z_PROBE_ALLEN_KEY_STOW_2_Y) || defined(Z_PROBE_ALLEN_KEY_STOW_2_Z)
1958
      #ifndef Z_PROBE_ALLEN_KEY_STOW_2_X
1959
        #define Z_PROBE_ALLEN_KEY_STOW_2_X current_position[X_AXIS]
1960
      #endif
1961
      #ifndef Z_PROBE_ALLEN_KEY_STOW_2_Y
1962
        #define Z_PROBE_ALLEN_KEY_STOW_2_Y current_position[Y_AXIS]
1963
      #endif
1964
      #ifndef Z_PROBE_ALLEN_KEY_STOW_2_Z
1965
        #define Z_PROBE_ALLEN_KEY_STOW_2_Z current_position[Z_AXIS]
1966
      #endif
1967
      #ifndef Z_PROBE_ALLEN_KEY_STOW_2_FEEDRATE
1968
        #define Z_PROBE_ALLEN_KEY_STOW_2_FEEDRATE 0.0
1969
      #endif
1970
      const float stow_2[] = { Z_PROBE_ALLEN_KEY_STOW_2_X, Z_PROBE_ALLEN_KEY_STOW_2_Y, Z_PROBE_ALLEN_KEY_STOW_2_Z };
1971
      do_blocking_move_to(stow_2, MMM_TO_MMS(Z_PROBE_ALLEN_KEY_STOW_2_FEEDRATE));
1972
    #endif
1973
    #if defined(Z_PROBE_ALLEN_KEY_STOW_3_X) || defined(Z_PROBE_ALLEN_KEY_STOW_3_Y) || defined(Z_PROBE_ALLEN_KEY_STOW_3_Z)
1974
      #ifndef Z_PROBE_ALLEN_KEY_STOW_3_X
1975
        #define Z_PROBE_ALLEN_KEY_STOW_3_X current_position[X_AXIS]
1976
      #endif
1977
      #ifndef Z_PROBE_ALLEN_KEY_STOW_3_Y
1978
        #define Z_PROBE_ALLEN_KEY_STOW_3_Y current_position[Y_AXIS]
1979
      #endif
1980
      #ifndef Z_PROBE_ALLEN_KEY_STOW_3_Z
1981
        #define Z_PROBE_ALLEN_KEY_STOW_3_Z current_position[Z_AXIS]
1982
      #endif
1983
      #ifndef Z_PROBE_ALLEN_KEY_STOW_3_FEEDRATE
1984
        #define Z_PROBE_ALLEN_KEY_STOW_3_FEEDRATE 0.0
1985
      #endif
1986
      const float stow_3[] = { Z_PROBE_ALLEN_KEY_STOW_3_X, Z_PROBE_ALLEN_KEY_STOW_3_Y, Z_PROBE_ALLEN_KEY_STOW_3_Z };
1987
      do_blocking_move_to(stow_3, MMM_TO_MMS(Z_PROBE_ALLEN_KEY_STOW_3_FEEDRATE));
1988
    #endif
1989
    #if defined(Z_PROBE_ALLEN_KEY_STOW_4_X) || defined(Z_PROBE_ALLEN_KEY_STOW_4_Y) || defined(Z_PROBE_ALLEN_KEY_STOW_4_Z)
1990
      #ifndef Z_PROBE_ALLEN_KEY_STOW_4_X
1991
        #define Z_PROBE_ALLEN_KEY_STOW_4_X current_position[X_AXIS]
1992
      #endif
1993
      #ifndef Z_PROBE_ALLEN_KEY_STOW_4_Y
1994
        #define Z_PROBE_ALLEN_KEY_STOW_4_Y current_position[Y_AXIS]
1995
      #endif
1996
      #ifndef Z_PROBE_ALLEN_KEY_STOW_4_Z
1997
        #define Z_PROBE_ALLEN_KEY_STOW_4_Z current_position[Z_AXIS]
1998
      #endif
1999
      #ifndef Z_PROBE_ALLEN_KEY_STOW_4_FEEDRATE
2000
        #define Z_PROBE_ALLEN_KEY_STOW_4_FEEDRATE 0.0
2001
      #endif
2002
      const float stow_4[] = { Z_PROBE_ALLEN_KEY_STOW_4_X, Z_PROBE_ALLEN_KEY_STOW_4_Y, Z_PROBE_ALLEN_KEY_STOW_4_Z };
2003
      do_blocking_move_to(stow_4, MMM_TO_MMS(Z_PROBE_ALLEN_KEY_STOW_4_FEEDRATE));
2004
    #endif
2005
    #if defined(Z_PROBE_ALLEN_KEY_STOW_5_X) || defined(Z_PROBE_ALLEN_KEY_STOW_5_Y) || defined(Z_PROBE_ALLEN_KEY_STOW_5_Z)
2006
      #ifndef Z_PROBE_ALLEN_KEY_STOW_5_X
2007
        #define Z_PROBE_ALLEN_KEY_STOW_5_X current_position[X_AXIS]
2008
      #endif
2009
      #ifndef Z_PROBE_ALLEN_KEY_STOW_5_Y
2010
        #define Z_PROBE_ALLEN_KEY_STOW_5_Y current_position[Y_AXIS]
2011
      #endif
2012
      #ifndef Z_PROBE_ALLEN_KEY_STOW_5_Z
2013
        #define Z_PROBE_ALLEN_KEY_STOW_5_Z current_position[Z_AXIS]
2014
      #endif
2015
      #ifndef Z_PROBE_ALLEN_KEY_STOW_5_FEEDRATE
2016
        #define Z_PROBE_ALLEN_KEY_STOW_5_FEEDRATE 0.0
2017
      #endif
2018
      const float stow_5[] = { Z_PROBE_ALLEN_KEY_STOW_5_X, Z_PROBE_ALLEN_KEY_STOW_5_Y, Z_PROBE_ALLEN_KEY_STOW_5_Z };
2019
      do_blocking_move_to(stow_5, MMM_TO_MMS(Z_PROBE_ALLEN_KEY_STOW_5_FEEDRATE));
2020
    #endif
2021
  }
2022
 
2023
#endif // Z_PROBE_ALLEN_KEY
2024
 
2025
#if ENABLED(PROBING_FANS_OFF)
2026
 
2027
  void fans_pause(const bool p) {
2028
    if (p != fans_paused) {
2029
      fans_paused = p;
2030
      if (p)
2031
        for (uint8_t x = 0; x < FAN_COUNT; x++) {
2032
          paused_fanSpeeds[x] = fanSpeeds[x];
2033
          fanSpeeds[x] = 0;
2034
        }
2035
      else
2036
        for (uint8_t x = 0; x < FAN_COUNT; x++)
2037
          fanSpeeds[x] = paused_fanSpeeds[x];
2038
    }
2039
  }
2040
 
2041
#endif // PROBING_FANS_OFF
2042
 
2043
#if HAS_BED_PROBE
2044
 
2045
  // TRIGGERED_WHEN_STOWED_TEST can easily be extended to servo probes, ... if needed.
2046
  #if ENABLED(PROBE_IS_TRIGGERED_WHEN_STOWED_TEST)
2047
    #if ENABLED(Z_MIN_PROBE_ENDSTOP)
2048
      #define _TRIGGERED_WHEN_STOWED_TEST (READ(Z_MIN_PROBE_PIN) != Z_MIN_PROBE_ENDSTOP_INVERTING)
2049
    #else
2050
      #define _TRIGGERED_WHEN_STOWED_TEST (READ(Z_MIN_PIN) != Z_MIN_ENDSTOP_INVERTING)
2051
    #endif
2052
  #endif
2053
 
2054
  #if QUIET_PROBING
2055
    void probing_pause(const bool p) {
2056
      #if ENABLED(PROBING_HEATERS_OFF)
2057
        thermalManager.pause(p);
2058
      #endif
2059
      #if ENABLED(PROBING_FANS_OFF)
2060
        fans_pause(p);
2061
      #endif
2062
      if (p) safe_delay(
2063
        #if DELAY_BEFORE_PROBING > 25
2064
          DELAY_BEFORE_PROBING
2065
        #else
2066
          25
2067
        #endif
2068
      );
2069
    }
2070
  #endif // QUIET_PROBING
2071
 
2072
  #if ENABLED(BLTOUCH)
2073
 
2074
    typedef unsigned char BLTCommand;
2075
    void bltouch_init(const bool set_voltage=false);
2076
    bool bltouch_last_written_mode; // Initialized by settings.load, 0 = Open Drain; 1 = 5V Drain
2077
 
2078
    bool bltouch_triggered() {
2079
      return (
2080
        #if ENABLED(Z_MIN_PROBE_USES_Z_MIN_ENDSTOP_PIN)
2081
          READ(Z_MIN_PIN) != Z_MIN_ENDSTOP_INVERTING
2082
        #else
2083
          READ(Z_MIN_PROBE_PIN) != Z_MIN_PROBE_ENDSTOP_INVERTING
2084
        #endif
2085
      );
2086
    }
2087
 
2088
    bool bltouch_command(const BLTCommand cmd, const millis_t &ms) {
2089
      #if ENABLED(DEBUG_LEVELING_FEATURE)
2090
        if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPAIR("BLTouch Command :", cmd);
2091
      #endif
2092
      MOVE_SERVO(Z_PROBE_SERVO_NR, cmd);
2093
      safe_delay(MAX(ms, (uint32_t)BLTOUCH_DELAY)); // BLTOUCH_DELAY is also the *minimum* delay
2094
      return bltouch_triggered();
2095
    }
2096
 
2097
    // Native BLTouch commands ("Underscore"...), used in lcd menus and internally
2098
    void _bltouch_reset()              { bltouch_command(BLTOUCH_RESET, BLTOUCH_RESET_DELAY); }
2099
 
2100
    void _bltouch_selftest()           { bltouch_command(BLTOUCH_SELFTEST, BLTOUCH_DELAY); }
2101
 
2102
    void _bltouch_set_SW_mode()        { bltouch_command(BLTOUCH_SW_MODE, BLTOUCH_DELAY); }
2103
 
2104
    void _bltouch_set_5V_mode()        { bltouch_command(BLTOUCH_5V_MODE, BLTOUCH_SET5V_DELAY); }
2105
    void _bltouch_set_OD_mode()        { bltouch_command(BLTOUCH_OD_MODE, BLTOUCH_SETOD_DELAY); }
2106
    void _bltouch_mode_store()         { bltouch_command(BLTOUCH_MODE_STORE, BLTOUCH_MODE_STORE_DELAY); }
2107
 
2108
    void _bltouch_deploy()             { bltouch_command(BLTOUCH_DEPLOY, BLTOUCH_DEPLOY_DELAY); }
2109
    void _bltouch_stow()               { bltouch_command(BLTOUCH_STOW, BLTOUCH_STOW_DELAY); }
2110
 
2111
    void _bltouch_reset_SW_mode()      { if (bltouch_triggered()) _bltouch_stow(); else _bltouch_deploy(); }
2112
 
2113
    bool _bltouch_deploy_query_alarm() { return bltouch_command(BLTOUCH_DEPLOY, BLTOUCH_DEPLOY_DELAY); }
2114
    bool _bltouch_stow_query_alarm()   { return bltouch_command(BLTOUCH_STOW, BLTOUCH_STOW_DELAY); }
2115
 
2116
    void bltouch_clear() {
2117
      _bltouch_reset();    // RESET or RESET_SW will clear an alarm condition but...
2118
                  // ...it will not clear a triggered condition in SW mode when the pin is currently up
2119
                  // ANTClabs <-- CODE ERROR
2120
      _bltouch_stow();     // STOW will pull up the pin and clear any triggered condition unless it fails, don't care
2121
      _bltouch_deploy();   // DEPLOY to test the probe. Could fail, don't care
2122
      _bltouch_stow();     // STOW to be ready for meaningful work. Could fail, don't care
2123
    }
2124
 
2125
    bool bltouch_deploy_proc() {
2126
      // Do a DEPLOY
2127
      #if ENABLED(DEBUG_LEVELING_FEATURE)
2128
        if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("BLTouch DEPLOY requested");
2129
      #endif
2130
 
2131
      // Attempt to DEPLOY, wait for DEPLOY_DELAY or ALARM
2132
      if (_bltouch_deploy_query_alarm()) {
2133
        // The deploy might have failed or the probe is already triggered (nozzle too low?)
2134
        #if ENABLED(DEBUG_LEVELING_FEATURE)
2135
          if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("BLTouch ALARM or TRIGGER after DEPLOY, recovering");
2136
        #endif
2137
 
2138
        bltouch_clear();                               // Get the probe into start condition
2139
 
2140
        // Last attempt to DEPLOY
2141
        if (_bltouch_deploy_query_alarm()) {
2142
          // The deploy might have failed or the probe is actually triggered (nozzle too low?) again
2143
          #if ENABLED(DEBUG_LEVELING_FEATURE)
2144
            if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("BLTouch Recovery Failed");
2145
          #endif
2146
 
2147
          SERIAL_ECHOLN(MSG_STOP_BLTOUCH);  // Tell the user something is wrong, needs action
2148
          stop();                              // but it's not too bad, no need to kill, allow restart
2149
 
2150
          return true;                         // Tell our caller we goofed in case he cares to know
2151
        }
2152
      }
2153
 
2154
      // One of the recommended ANTClabs ways to probe, using SW MODE
2155
      #if ENABLED(BLTOUCH_FORCE_SW_MODE)
2156
      _bltouch_set_SW_mode();
2157
      #endif
2158
 
2159
      // Now the probe is ready to issue a 10ms pulse when the pin goes up.
2160
      // The trigger STOW (see motion.cpp for example) will pull up the probes pin as soon as the pulse
2161
      // is registered.
2162
      #if ENABLED(DEBUG_LEVELING_FEATURE)
2163
        if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("bltouch.deploy_proc() end");
2164
      #endif
2165
 
2166
      return false; // report success to caller
2167
    }
2168
 
2169
    bool bltouch_stow_proc() {
2170
      // Do a STOW
2171
      #if ENABLED(DEBUG_LEVELING_FEATURE)
2172
        if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("BLTouch STOW requested");
2173
      #endif
2174
 
2175
      // A STOW will clear a triggered condition in the probe (10ms pulse).
2176
      // At the moment that we come in here, we might (pulse) or will (SW mode) see the trigger on the pin.
2177
      // So even though we know a STOW will be ignored if an ALARM condition is active, we will STOW.
2178
      // Note: If the probe is deployed AND in an ALARM condition, this STOW will not pull up the pin
2179
      // and the ALARM condition will still be there. --> ANTClabs should change this behavior maybe
2180
 
2181
      // Attempt to STOW, wait for STOW_DELAY or ALARM
2182
      if (_bltouch_stow_query_alarm()) {
2183
        // The stow might have failed
2184
        #if ENABLED(DEBUG_LEVELING_FEATURE)
2185
          if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("BLTouch ALARM or TRIGGER after STOW, recovering");
2186
        #endif
2187
 
2188
        _bltouch_reset();                              // This RESET will then also pull up the pin. If it doesn't
2189
                                              // work and the pin is still down, there will no longer be
2190
                                              // an ALARM condition though.
2191
                                              // But one more STOW will catch that
2192
        // Last attempt to STOW
2193
        if (_bltouch_stow_query_alarm()) {             // so if there is now STILL an ALARM condition:
2194
          #if ENABLED(DEBUG_LEVELING_FEATURE)
2195
            if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("BLTouch Recovery Failed");
2196
          #endif
2197
 
2198
          SERIAL_ECHOLN(MSG_STOP_BLTOUCH);  // Tell the user something is wrong, needs action
2199
          stop();                              // but it's not too bad, no need to kill, allow restart
2200
 
2201
          return true;                         // Tell our caller we goofed in case he cares to know
2202
        }
2203
      }
2204
 
2205
      #if ENABLED(DEBUG_LEVELING_FEATURE)
2206
        if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("bltouch.stow_proc() end");
2207
      #endif
2208
 
2209
      return false; // report success to caller
2210
    }
2211
 
2212
    bool bltouch_status_proc() {
2213
      /**
2214
       * Return a TRUE for "YES, it is DEPLOYED"
2215
       * This function will ensure switch state is reset after execution
2216
       */
2217
 
2218
      #if ENABLED(DEBUG_LEVELING_FEATURE)
2219
        if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("BLTouch STATUS requested");
2220
      #endif
2221
 
2222
      _bltouch_set_SW_mode();              // Incidentally, _set_SW_mode() will also RESET any active alarm
2223
      const bool tr = bltouch_triggered(); // If triggered in SW mode, the pin is up, it is STOWED
2224
 
2225
      #if ENABLED(DEBUG_LEVELING_FEATURE)
2226
        if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPAIR("BLTouch is ", (int)tr);
2227
      #endif
2228
 
2229
      if (tr) _bltouch_stow(); else _bltouch_deploy();  // Turn off SW mode, reset any trigger, honor pin state
2230
      return !tr;
2231
    }
2232
 
2233
    void bltouch_mode_conv_proc(const bool M5V) {
2234
      /**
2235
       * BLTOUCH pre V3.0 and clones: No reaction at all to this sequence apart from a DEPLOY -> STOW
2236
       * BLTOUCH V3.0: This will set the mode (twice) and sadly, a STOW is needed at the end, because of the deploy
2237
       * BLTOUCH V3.1: This will set the mode and store it in the eeprom. The STOW is not needed but does not hurt
2238
       */
2239
      #if ENABLED(DEBUG_LEVELING_FEATURE)
2240
        if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPAIR("BLTouch Set Mode - ", (int)M5V);
2241
      #endif
2242
      _bltouch_deploy();
2243
      if (M5V) _bltouch_set_5V_mode(); else _bltouch_set_OD_mode();
2244
      _bltouch_mode_store();
2245
      if (M5V) _bltouch_set_5V_mode(); else _bltouch_set_OD_mode();
2246
      _bltouch_stow();
2247
      bltouch_last_written_mode = M5V;
2248
    }
2249
 
2250
    bool set_bltouch_deployed(const bool deploy) {
2251
      if (deploy) _bltouch_deploy(); else _bltouch_stow();
2252
      return false;
2253
    }
2254
 
2255
    void bltouch_mode_conv_5V()        { bltouch_mode_conv_proc(true); }
2256
    void bltouch_mode_conv_OD()        { bltouch_mode_conv_proc(false); }
2257
 
2258
    // DEPLOY and STOW are wrapped for error handling - these are used by homing and by probing
2259
    bool bltouch_deploy()              { return bltouch_deploy_proc(); }
2260
    bool bltouch_stow()                { return bltouch_stow_proc(); }
2261
    bool bltouch_status()              { return bltouch_status_proc(); }
2262
 
2263
    // Init the class and device. Call from setup().
2264
    void bltouch_init(const bool set_voltage/*=false*/) {
2265
      // Voltage Setting (if enabled). At every Marlin initialization:
2266
      // BLTOUCH < V3.0 and clones: This will be ignored by the probe
2267
      // BLTOUCH V3.0: SET_5V_MODE or SET_OD_MODE (if enabled).
2268
      //               OD_MODE is the default on power on, but setting it does not hurt
2269
      //               This mode will stay active until manual SET_OD_MODE or power cycle
2270
      // BLTOUCH V3.1: SET_5V_MODE or SET_OD_MODE (if enabled).
2271
      //               At power on, the probe will default to the eeprom settings configured by the user
2272
      _bltouch_reset();
2273
      _bltouch_stow();
2274
 
2275
      #if ENABLED(BLTOUCH_FORCE_MODE_SET)
2276
 
2277
        constexpr bool should_set = true;
2278
 
2279
      #else
2280
        #if ENABLED(DEBUG_LEVELING_FEATURE)
2281
          if (DEBUGGING(LEVELING)) {
2282
            SERIAL_ECHOLNPAIR("last_written_mode - ", int(bltouch_last_written_mode));
2283
            SERIAL_ECHOLNPGM("config mode - "
2284
              #if ENABLED(BLTOUCH_SET_5V_MODE)
2285
                "BLTOUCH_SET_5V_MODE"
2286
              #else
2287
                "OD"
2288
              #endif
2289
            );
2290
          }
2291
        #endif
2292
 
2293
        const bool should_set = bltouch_last_written_mode != (false
2294
          #if ENABLED(BLTOUCH_SET_5V_MODE)
2295
            || true
2296
          #endif
2297
        );
2298
 
2299
      #endif
2300
 
2301
      if (should_set && set_voltage)
2302
        bltouch_mode_conv_proc((false
2303
          #if ENABLED(BLTOUCH_SET_5V_MODE)
2304
            || true
2305
          #endif
2306
        ));
2307
    }
2308
  #endif // BLTOUCH
2309
 
2310
  /**
2311
   * Raise Z to a minimum height to make room for a probe to move
2312
   */
2313
  inline void do_probe_raise(const float z_raise) {
2314
    #if ENABLED(DEBUG_LEVELING_FEATURE)
2315
      if (DEBUGGING(LEVELING)) {
2316
        SERIAL_ECHOPAIR("do_probe_raise(", z_raise);
2317
        SERIAL_CHAR(')');
2318
        SERIAL_EOL();
2319
      }
2320
    #endif
2321
 
2322
    float z_dest = z_raise;
2323
    if (zprobe_zoffset < 0) z_dest -= zprobe_zoffset;
2324
 
2325
    NOMORE(z_dest, Z_MAX_POS);
2326
 
2327
    if (z_dest > current_position[Z_AXIS])
2328
      do_blocking_move_to_z(z_dest);
2329
  }
2330
 
2331
  // returns false for ok and true for failure
2332
  bool set_probe_deployed(const bool deploy) {
2333
 
2334
    #if ENABLED(DEBUG_LEVELING_FEATURE)
2335
      if (DEBUGGING(LEVELING)) {
2336
        DEBUG_POS("set_probe_deployed", current_position);
2337
        SERIAL_ECHOLNPAIR("deploy: ", deploy);
2338
      }
2339
    #endif
2340
 
2341
    if (endstops.z_probe_enabled == deploy) return false;
2342
 
2343
    // Make room for probe to deploy (or stow)
2344
    // Fix-mounted probe should only raise for deploy
2345
    #if ENABLED(FIX_MOUNTED_PROBE)
2346
      const bool deploy_stow_condition = deploy;
2347
    #else
2348
      constexpr bool deploy_stow_condition = true;
2349
    #endif
2350
 
2351
    // For beds that fall when Z is powered off only raise for trusted Z
2352
    #if ENABLED(UNKNOWN_Z_NO_RAISE)
2353
      const bool unknown_condition = TEST(axis_known_position, Z_AXIS);
2354
    #else
2355
      constexpr float unknown_condition = true;
2356
    #endif
2357
 
2358
    if (deploy_stow_condition && unknown_condition)
2359
      do_probe_raise(MAX(Z_CLEARANCE_BETWEEN_PROBES, Z_CLEARANCE_DEPLOY_PROBE));
2360
 
2361
    #if ENABLED(Z_PROBE_SLED) || ENABLED(Z_PROBE_ALLEN_KEY)
2362
      #if ENABLED(Z_PROBE_SLED)
2363
        #define _AUE_ARGS true, false, false
2364
      #else
2365
        #define _AUE_ARGS
2366
      #endif
2367
      if (axis_unhomed_error(_AUE_ARGS)) {
2368
        SERIAL_ERROR_START();
2369
        SERIAL_ERRORLNPGM(MSG_STOP_UNHOMED);
2370
        stop();
2371
        return true;
2372
      }
2373
    #endif
2374
 
2375
    const float oldXpos = current_position[X_AXIS],
2376
                oldYpos = current_position[Y_AXIS];
2377
 
2378
    #ifdef _TRIGGERED_WHEN_STOWED_TEST
2379
 
2380
      // If endstop is already false, the Z probe is deployed
2381
      if (_TRIGGERED_WHEN_STOWED_TEST == deploy) {     // closed after the probe specific actions.
2382
                                                       // Would a goto be less ugly?
2383
        //while (!_TRIGGERED_WHEN_STOWED_TEST) idle(); // would offer the opportunity
2384
                                                       // for a triggered when stowed manual probe.
2385
 
2386
        if (!deploy) endstops.enable_z_probe(false); // Switch off triggered when stowed probes early
2387
                                                     // otherwise an Allen-Key probe can't be stowed.
2388
    #endif
2389
 
2390
        #if ENABLED(SOLENOID_PROBE)
2391
 
2392
          #if HAS_SOLENOID_1
2393
            WRITE(SOL1_PIN, deploy);
2394
          #endif
2395
 
2396
        #elif ENABLED(Z_PROBE_SLED)
2397
 
2398
          dock_sled(!deploy);
2399
 
2400
        #elif HAS_Z_SERVO_PROBE && DISABLED(BLTOUCH)
2401
 
2402
          MOVE_SERVO(Z_PROBE_SERVO_NR, z_servo_angle[deploy ? 0 : 1]);
2403
 
2404
        #elif ENABLED(Z_PROBE_ALLEN_KEY)
2405
 
2406
          deploy ? run_deploy_moves_script() : run_stow_moves_script();
2407
 
2408
        #endif
2409
 
2410
    #ifdef _TRIGGERED_WHEN_STOWED_TEST
2411
      } // _TRIGGERED_WHEN_STOWED_TEST == deploy
2412
 
2413
      if (_TRIGGERED_WHEN_STOWED_TEST == deploy) { // State hasn't changed?
2414
 
2415
        if (IsRunning()) {
2416
          SERIAL_ERROR_START();
2417
          SERIAL_ERRORLNPGM("Z-Probe failed");
2418
          LCD_ALERTMESSAGEPGM("Err: ZPROBE");
2419
        }
2420
        stop();
2421
        return true;
2422
 
2423
      } // _TRIGGERED_WHEN_STOWED_TEST == deploy
2424
 
2425
    #endif
2426
 
2427
    do_blocking_move_to(oldXpos, oldYpos, current_position[Z_AXIS]); // return to position before deploy
2428
    endstops.enable_z_probe(deploy);
2429
    return false;
2430
  }
2431
 
2432
  /**
2433
   * @brief Used by run_z_probe to do a single Z probe move.
2434
   *
2435
   * @param  z        Z destination
2436
   * @param  fr_mm_s  Feedrate in mm/s
2437
   * @return true to indicate an error
2438
   */
2439
  static bool do_probe_move(const float z, const float fr_mm_s) {
2440
    #if ENABLED(DEBUG_LEVELING_FEATURE)
2441
      if (DEBUGGING(LEVELING)) DEBUG_POS(">>> do_probe_move", current_position);
2442
    #endif
2443
 
2444
    #if HAS_HEATED_BED && ENABLED(WAIT_FOR_BED_HEATER)
2445
      // Wait for bed to heat back up between probing points
2446
      if (thermalManager.isHeatingBed()) {
2447
        serialprintPGM(msg_wait_for_bed_heating);
2448
        LCD_MESSAGEPGM(MSG_BED_HEATING);
2449
        while (thermalManager.isHeatingBed()) safe_delay(200);
2450
        lcd_reset_status();
2451
      }
2452
    #endif
2453
 
2454
    // Deploy BLTouch at the start of any probe
2455
    #if ENABLED(BLTOUCH)
2456
      if (set_bltouch_deployed(true)) return true;
2457
    #endif
2458
 
2459
    #if QUIET_PROBING
2460
      probing_pause(true);
2461
    #endif
2462
 
2463
    // Move down until probe triggered
2464
    do_blocking_move_to_z(z, fr_mm_s);
2465
 
2466
    // Check to see if the probe was triggered
2467
    const bool probe_triggered = TEST(endstops.trigger_state(),
2468
      #if ENABLED(Z_MIN_PROBE_USES_Z_MIN_ENDSTOP_PIN)
2469
        Z_MIN
2470
      #else
2471
        Z_MIN_PROBE
2472
      #endif
2473
    );
2474
 
2475
    #if QUIET_PROBING
2476
      probing_pause(false);
2477
    #endif
2478
 
2479
    // Retract BLTouch immediately after a probe if it was triggered
2480
    #if ENABLED(BLTOUCH)
2481
      if (probe_triggered && set_bltouch_deployed(false)) return true;
2482
    #endif
2483
 
2484
    endstops.hit_on_purpose();
2485
 
2486
    // Get Z where the steppers were interrupted
2487
    set_current_from_steppers_for_axis(Z_AXIS);
2488
 
2489
    // Tell the planner where we actually are
2490
    SYNC_PLAN_POSITION_KINEMATIC();
2491
 
2492
    #if ENABLED(DEBUG_LEVELING_FEATURE)
2493
      if (DEBUGGING(LEVELING)) DEBUG_POS("<<< do_probe_move", current_position);
2494
    #endif
2495
 
2496
    return !probe_triggered;
2497
  }
2498
 
2499
  /**
2500
   * @details Used by probe_pt to do a single Z probe at the current position.
2501
   *          Leaves current_position[Z_AXIS] at the height where the probe triggered.
2502
   *
2503
   * @return The raw Z position where the probe was triggered
2504
   */
2505
  static float run_z_probe() {
2506
 
2507
    #if ENABLED(DEBUG_LEVELING_FEATURE)
2508
      if (DEBUGGING(LEVELING)) DEBUG_POS(">>> run_z_probe", current_position);
2509
    #endif
2510
 
2511
    // Stop the probe before it goes too low to prevent damage.
2512
    // If Z isn't known then probe to -10mm.
2513
    const float z_probe_low_point = TEST(axis_known_position, Z_AXIS) ? -zprobe_zoffset + Z_PROBE_LOW_POINT : -10.0;
2514
 
2515
    // Double-probing does a fast probe followed by a slow probe
2516
    #if MULTIPLE_PROBING == 2
2517
 
2518
      // Do a first probe at the fast speed
2519
      if (do_probe_move(z_probe_low_point, MMM_TO_MMS(Z_PROBE_SPEED_FAST))) {
2520
        #if ENABLED(DEBUG_LEVELING_FEATURE)
2521
          if (DEBUGGING(LEVELING)) {
2522
            SERIAL_ECHOLNPGM("FAST Probe fail!");
2523
            DEBUG_POS("<<< run_z_probe", current_position);
2524
          }
2525
        #endif
2526
        return NAN;
2527
      }
2528
 
2529
      float first_probe_z = current_position[Z_AXIS];
2530
 
2531
      #if ENABLED(DEBUG_LEVELING_FEATURE)
2532
        if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPAIR("1st Probe Z:", first_probe_z);
2533
      #endif
2534
 
2535
      // move up to make clearance for the probe
2536
      do_blocking_move_to_z(current_position[Z_AXIS] + Z_CLEARANCE_MULTI_PROBE, MMM_TO_MMS(Z_PROBE_SPEED_FAST));
2537
 
2538
    #else
2539
 
2540
      // If the nozzle is well over the travel height then
2541
      // move down quickly before doing the slow probe
2542
      float z = Z_CLEARANCE_DEPLOY_PROBE + 5.0;
2543
      if (zprobe_zoffset < 0) z -= zprobe_zoffset;
2544
 
2545
      if (current_position[Z_AXIS] > z) {
2546
        // If we don't make it to the z position (i.e. the probe triggered), move up to make clearance for the probe
2547
        if (!do_probe_move(z, MMM_TO_MMS(Z_PROBE_SPEED_FAST)))
2548
          do_blocking_move_to_z(current_position[Z_AXIS] + Z_CLEARANCE_BETWEEN_PROBES, MMM_TO_MMS(Z_PROBE_SPEED_FAST));
2549
      }
2550
    #endif
2551
 
2552
    #if MULTIPLE_PROBING > 2
2553
      float probes_total = 0;
2554
      for (uint8_t p = MULTIPLE_PROBING + 1; --p;) {
2555
    #endif
2556
 
2557
        // move down slowly to find bed
2558
        if (do_probe_move(z_probe_low_point, MMM_TO_MMS(Z_PROBE_SPEED_SLOW))) {
2559
          #if ENABLED(DEBUG_LEVELING_FEATURE)
2560
            if (DEBUGGING(LEVELING)) {
2561
              SERIAL_ECHOLNPGM("SLOW Probe fail!");
2562
              DEBUG_POS("<<< run_z_probe", current_position);
2563
            }
2564
          #endif
2565
          return NAN;
2566
        }
2567
 
2568
    #if MULTIPLE_PROBING > 2
2569
        probes_total += current_position[Z_AXIS];
2570
        if (p > 1) do_blocking_move_to_z(current_position[Z_AXIS] + Z_CLEARANCE_MULTI_PROBE, MMM_TO_MMS(Z_PROBE_SPEED_FAST));
2571
      }
2572
    #endif
2573
 
2574
    #if MULTIPLE_PROBING > 2
2575
 
2576
      // Return the average value of all probes
2577
      const float measured_z = probes_total * (1.0f / (MULTIPLE_PROBING));
2578
 
2579
    #elif MULTIPLE_PROBING == 2
2580
 
2581
      const float z2 = current_position[Z_AXIS];
2582
 
2583
      #if ENABLED(DEBUG_LEVELING_FEATURE)
2584
        if (DEBUGGING(LEVELING)) {
2585
          SERIAL_ECHOPAIR("2nd Probe Z:", z2);
2586
          SERIAL_ECHOLNPAIR(" Discrepancy:", first_probe_z - z2);
2587
        }
2588
      #endif
2589
 
2590
      // Return a weighted average of the fast and slow probes
2591
      const float measured_z = (z2 * 3.0 + first_probe_z * 2.0) * 0.2;
2592
 
2593
    #else
2594
 
2595
      // Return the single probe result
2596
      const float measured_z = current_position[Z_AXIS];
2597
 
2598
    #endif
2599
 
2600
    #if ENABLED(DEBUG_LEVELING_FEATURE)
2601
      if (DEBUGGING(LEVELING)) DEBUG_POS("<<< run_z_probe", current_position);
2602
    #endif
2603
 
2604
    return measured_z;
2605
  }
2606
 
2607
  /**
2608
   * - Move to the given XY
2609
   * - Deploy the probe, if not already deployed
2610
   * - Probe the bed, get the Z position
2611
   * - Depending on the 'stow' flag
2612
   *   - Stow the probe, or
2613
   *   - Raise to the BETWEEN height
2614
   * - Return the probed Z position
2615
   */
2616
  float probe_pt(const float &rx, const float &ry, const ProbePtRaise raise_after/*=PROBE_PT_NONE*/, const uint8_t verbose_level/*=0*/, const bool probe_relative/*=true*/) {
2617
    #if ENABLED(DEBUG_LEVELING_FEATURE)
2618
      if (DEBUGGING(LEVELING)) {
2619
        SERIAL_ECHOPAIR(">>> probe_pt(", LOGICAL_X_POSITION(rx));
2620
        SERIAL_ECHOPAIR(", ", LOGICAL_Y_POSITION(ry));
2621
        SERIAL_ECHOPAIR(", ", raise_after == PROBE_PT_RAISE ? "raise" : raise_after == PROBE_PT_STOW ? "stow" : "none");
2622
        SERIAL_ECHOPAIR(", ", int(verbose_level));
2623
        SERIAL_ECHOPAIR(", ", probe_relative ? "probe" : "nozzle");
2624
        SERIAL_ECHOLNPGM("_relative)");
2625
        DEBUG_POS("", current_position);
2626
      }
2627
    #endif
2628
 
2629
    // TODO: Adapt for SCARA, where the offset rotates
2630
    float nx = rx, ny = ry;
2631
    if (probe_relative) {
2632
      if (!position_is_reachable_by_probe(rx, ry)) return NAN;  // The given position is in terms of the probe
2633
      nx -= (X_PROBE_OFFSET_FROM_EXTRUDER);                     // Get the nozzle position
2634
      ny -= (Y_PROBE_OFFSET_FROM_EXTRUDER);
2635
    }
2636
    else if (!position_is_reachable(nx, ny)) return NAN;        // The given position is in terms of the nozzle
2637
 
2638
    const float nz =
2639
      #if ENABLED(DELTA)
2640
        // Move below clip height or xy move will be aborted by do_blocking_move_to
2641
        MIN(current_position[Z_AXIS], delta_clip_start_height)
2642
      #else
2643
        current_position[Z_AXIS]
2644
      #endif
2645
    ;
2646
 
2647
    const float old_feedrate_mm_s = feedrate_mm_s;
2648
    feedrate_mm_s = XY_PROBE_FEEDRATE_MM_S;
2649
 
2650
    // Move the probe to the starting XYZ
2651
    do_blocking_move_to(nx, ny, nz);
2652
 
2653
    float measured_z = NAN;
2654
    if (!DEPLOY_PROBE()) {
2655
      measured_z = run_z_probe() + zprobe_zoffset;
2656
 
2657
      const bool big_raise = raise_after == PROBE_PT_BIG_RAISE;
2658
      if (big_raise || raise_after == PROBE_PT_RAISE)
2659
        do_blocking_move_to_z(current_position[Z_AXIS] + (big_raise ? 25 : Z_CLEARANCE_BETWEEN_PROBES), MMM_TO_MMS(Z_PROBE_SPEED_FAST));
2660
      else if (raise_after == PROBE_PT_STOW)
2661
        if (STOW_PROBE()) measured_z = NAN;
2662
    }
2663
 
2664
    if (verbose_level > 2) {
2665
      SERIAL_PROTOCOLPGM("Bed X: ");
2666
      SERIAL_PROTOCOL_F(LOGICAL_X_POSITION(rx), 3);
2667
      SERIAL_PROTOCOLPGM(" Y: ");
2668
      SERIAL_PROTOCOL_F(LOGICAL_Y_POSITION(ry), 3);
2669
      SERIAL_PROTOCOLPGM(" Z: ");
2670
      SERIAL_PROTOCOL_F(measured_z, 3);
2671
      SERIAL_EOL();
2672
    }
2673
 
2674
    feedrate_mm_s = old_feedrate_mm_s;
2675
 
2676
    if (isnan(measured_z)) {
2677
      LCD_MESSAGEPGM(MSG_ERR_PROBING_FAILED);
2678
      SERIAL_ERROR_START();
2679
      SERIAL_ERRORLNPGM(MSG_ERR_PROBING_FAILED);
2680
    }
2681
 
2682
    #if ENABLED(DEBUG_LEVELING_FEATURE)
2683
      if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("<<< probe_pt");
2684
    #endif
2685
 
2686
    return measured_z;
2687
  }
2688
 
2689
#endif // HAS_BED_PROBE
2690
 
2691
#if HAS_LEVELING
2692
 
2693
  bool leveling_is_valid() {
2694
    return
2695
      #if ENABLED(MESH_BED_LEVELING)
2696
        mbl.has_mesh()
2697
      #elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
2698
        !!bilinear_grid_spacing[X_AXIS]
2699
      #elif ENABLED(AUTO_BED_LEVELING_UBL)
2700
        ubl.mesh_is_valid()
2701
      #else // 3POINT, LINEAR
2702
        true
2703
      #endif
2704
    ;
2705
  }
2706
 
2707
  /**
2708
   * Turn bed leveling on or off, fixing the current
2709
   * position as-needed.
2710
   *
2711
   * Disable: Current position = physical position
2712
   *  Enable: Current position = "unleveled" physical position
2713
   */
2714
  void set_bed_leveling_enabled(const bool enable/*=true*/) {
2715
 
2716
    #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
2717
      const bool can_change = (!enable || leveling_is_valid());
2718
    #else
2719
      constexpr bool can_change = true;
2720
    #endif
2721
 
2722
    if (can_change && enable != planner.leveling_active) {
2723
 
2724
      planner.synchronize();
2725
 
2726
      #if ENABLED(MESH_BED_LEVELING)
2727
 
2728
        if (!enable)
2729
          planner.apply_leveling(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS]);
2730
 
2731
        const bool enabling = enable && leveling_is_valid();
2732
        planner.leveling_active = enabling;
2733
        if (enabling) planner.unapply_leveling(current_position);
2734
 
2735
      #elif ENABLED(AUTO_BED_LEVELING_UBL)
2736
        #if PLANNER_LEVELING
2737
          if (planner.leveling_active) {                       // leveling from on to off
2738
            // change unleveled current_position to physical current_position without moving steppers.
2739
            planner.apply_leveling(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS]);
2740
            planner.leveling_active = false;                   // disable only AFTER calling apply_leveling
2741
          }
2742
          else {                                               // leveling from off to on
2743
            planner.leveling_active = true;                    // enable BEFORE calling unapply_leveling, otherwise ignored
2744
            // change physical current_position to unleveled current_position without moving steppers.
2745
            planner.unapply_leveling(current_position);
2746
          }
2747
        #else
2748
          // UBL equivalents for apply/unapply_leveling
2749
          #if ENABLED(SKEW_CORRECTION)
2750
            float pos[XYZ] = { current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS] };
2751
            planner.skew(pos[X_AXIS], pos[Y_AXIS], pos[Z_AXIS]);
2752
          #else
2753
            const float (&pos)[XYZE] = current_position;
2754
          #endif
2755
          if (planner.leveling_active) {
2756
            current_position[Z_AXIS] += ubl.get_z_correction(pos[X_AXIS], pos[Y_AXIS]);
2757
            planner.leveling_active = false;
2758
          }
2759
          else {
2760
            planner.leveling_active = true;
2761
            current_position[Z_AXIS] -= ubl.get_z_correction(pos[X_AXIS], pos[Y_AXIS]);
2762
          }
2763
        #endif
2764
 
2765
      #else // ABL
2766
 
2767
        #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
2768
          // Force bilinear_z_offset to re-calculate next time
2769
          const float reset[XYZ] = { -9999.999, -9999.999, 0 };
2770
          (void)bilinear_z_offset(reset);
2771
        #endif
2772
 
2773
        // Enable or disable leveling compensation in the planner
2774
        planner.leveling_active = enable;
2775
 
2776
        if (!enable)
2777
          // When disabling just get the current position from the steppers.
2778
          // This will yield the smallest error when first converted back to steps.
2779
          set_current_from_steppers_for_axis(
2780
            #if ABL_PLANAR
2781
              ALL_AXES
2782
            #else
2783
              Z_AXIS
2784
            #endif
2785
          );
2786
        else
2787
          // When enabling, remove compensation from the current position,
2788
          // so compensation will give the right stepper counts.
2789
          planner.unapply_leveling(current_position);
2790
 
2791
        SYNC_PLAN_POSITION_KINEMATIC();
2792
 
2793
      #endif // ABL
2794
    }
2795
  }
2796
 
2797
  #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
2798
 
2799
    void set_z_fade_height(const float zfh, const bool do_report/*=true*/) {
2800
 
2801
      if (planner.z_fade_height == zfh) return;
2802
 
2803
      const bool leveling_was_active = planner.leveling_active;
2804
      set_bed_leveling_enabled(false);
2805
 
2806
      planner.set_z_fade_height(zfh);
2807
 
2808
      if (leveling_was_active) {
2809
        const float oldpos[] = { current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS] };
2810
        set_bed_leveling_enabled(true);
2811
        if (do_report && memcmp(oldpos, current_position, sizeof(oldpos)))
2812
          report_current_position();
2813
      }
2814
    }
2815
 
2816
  #endif // LEVELING_FADE_HEIGHT
2817
 
2818
  /**
2819
   * Reset calibration results to zero.
2820
   */
2821
  void reset_bed_level() {
2822
    #if ENABLED(DEBUG_LEVELING_FEATURE)
2823
      if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("reset_bed_level");
2824
    #endif
2825
    set_bed_leveling_enabled(false);
2826
    #if ENABLED(MESH_BED_LEVELING)
2827
      mbl.reset();
2828
    #elif ENABLED(AUTO_BED_LEVELING_UBL)
2829
      ubl.reset();
2830
    #elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
2831
      bilinear_start[X_AXIS] = bilinear_start[Y_AXIS] =
2832
      bilinear_grid_spacing[X_AXIS] = bilinear_grid_spacing[Y_AXIS] = 0;
2833
      for (uint8_t x = 0; x < GRID_MAX_POINTS_X; x++)
2834
        for (uint8_t y = 0; y < GRID_MAX_POINTS_Y; y++)
2835
          z_values[x][y] = NAN;
2836
    #elif ABL_PLANAR
2837
      planner.bed_level_matrix.set_to_identity();
2838
    #endif
2839
  }
2840
 
2841
#endif // HAS_LEVELING
2842
 
2843
#if ENABLED(AUTO_BED_LEVELING_BILINEAR) || ENABLED(MESH_BED_LEVELING)
2844
 
2845
  /**
2846
   * Enable to produce output in JSON format suitable
2847
   * for SCAD or JavaScript mesh visualizers.
2848
   *
2849
   * Visualize meshes in OpenSCAD using the included script.
2850
   *
2851
   *   buildroot/shared/scripts/MarlinMesh.scad
2852
   */
2853
  //#define SCAD_MESH_OUTPUT
2854
 
2855
  /**
2856
   * Print calibration results for plotting or manual frame adjustment.
2857
   */
2858
  void print_2d_array(const uint8_t sx, const uint8_t sy, const uint8_t precision, const element_2d_fn fn) {
2859
    #ifndef SCAD_MESH_OUTPUT
2860
      for (uint8_t x = 0; x < sx; x++) {
2861
        for (uint8_t i = 0; i < precision + 2 + (x < 10 ? 1 : 0); i++)
2862
          SERIAL_PROTOCOLCHAR(' ');
2863
        SERIAL_PROTOCOL(int(x));
2864
      }
2865
      SERIAL_EOL();
2866
    #endif
2867
    #ifdef SCAD_MESH_OUTPUT
2868
      SERIAL_PROTOCOLLNPGM("measured_z = ["); // open 2D array
2869
    #endif
2870
    for (uint8_t y = 0; y < sy; y++) {
2871
      #ifdef SCAD_MESH_OUTPUT
2872
        SERIAL_PROTOCOLPGM(" [");           // open sub-array
2873
      #else
2874
        if (y < 10) SERIAL_PROTOCOLCHAR(' ');
2875
        SERIAL_PROTOCOL(int(y));
2876
      #endif
2877
      for (uint8_t x = 0; x < sx; x++) {
2878
        SERIAL_PROTOCOLCHAR(' ');
2879
        const float offset = fn(x, y);
2880
        if (!isnan(offset)) {
2881
          if (offset >= 0) SERIAL_PROTOCOLCHAR('+');
2882
          SERIAL_PROTOCOL_F(offset, int(precision));
2883
        }
2884
        else {
2885
          #ifdef SCAD_MESH_OUTPUT
2886
            for (uint8_t i = 3; i < precision + 3; i++)
2887
              SERIAL_PROTOCOLCHAR(' ');
2888
            SERIAL_PROTOCOLPGM("NAN");
2889
          #else
2890
            for (uint8_t i = 0; i < precision + 3; i++)
2891
              SERIAL_PROTOCOLCHAR(i ? '=' : ' ');
2892
          #endif
2893
        }
2894
        #ifdef SCAD_MESH_OUTPUT
2895
          if (x < sx - 1) SERIAL_PROTOCOLCHAR(',');
2896
        #endif
2897
      }
2898
      #ifdef SCAD_MESH_OUTPUT
2899
        SERIAL_PROTOCOLCHAR(' ');
2900
        SERIAL_PROTOCOLCHAR(']');                     // close sub-array
2901
        if (y < sy - 1) SERIAL_PROTOCOLCHAR(',');
2902
      #endif
2903
      SERIAL_EOL();
2904
    }
2905
    #ifdef SCAD_MESH_OUTPUT
2906
      SERIAL_PROTOCOLPGM("];");                       // close 2D array
2907
    #endif
2908
    SERIAL_EOL();
2909
  }
2910
 
2911
#endif
2912
 
2913
#if ENABLED(AUTO_BED_LEVELING_BILINEAR)
2914
 
2915
  /**
2916
   * Extrapolate a single point from its neighbors
2917
   */
2918
  static void extrapolate_one_point(const uint8_t x, const uint8_t y, const int8_t xdir, const int8_t ydir) {
2919
    #if ENABLED(DEBUG_LEVELING_FEATURE)
2920
      if (DEBUGGING(LEVELING)) {
2921
        SERIAL_ECHOPGM("Extrapolate [");
2922
        if (x < 10) SERIAL_CHAR(' ');
2923
        SERIAL_ECHO(int(x));
2924
        SERIAL_CHAR(xdir ? (xdir > 0 ? '+' : '-') : ' ');
2925
        SERIAL_CHAR(' ');
2926
        if (y < 10) SERIAL_CHAR(' ');
2927
        SERIAL_ECHO(int(y));
2928
        SERIAL_CHAR(ydir ? (ydir > 0 ? '+' : '-') : ' ');
2929
        SERIAL_CHAR(']');
2930
      }
2931
    #endif
2932
    if (!isnan(z_values[x][y])) {
2933
      #if ENABLED(DEBUG_LEVELING_FEATURE)
2934
        if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM(" (done)");
2935
      #endif
2936
      return;  // Don't overwrite good values.
2937
    }
2938
    SERIAL_EOL();
2939
 
2940
    // Get X neighbors, Y neighbors, and XY neighbors
2941
    const uint8_t x1 = x + xdir, y1 = y + ydir, x2 = x1 + xdir, y2 = y1 + ydir;
2942
    float a1 = z_values[x1][y ], a2 = z_values[x2][y ],
2943
          b1 = z_values[x ][y1], b2 = z_values[x ][y2],
2944
          c1 = z_values[x1][y1], c2 = z_values[x2][y2];
2945
 
2946
    // Treat far unprobed points as zero, near as equal to far
2947
    if (isnan(a2)) a2 = 0.0; if (isnan(a1)) a1 = a2;
2948
    if (isnan(b2)) b2 = 0.0; if (isnan(b1)) b1 = b2;
2949
    if (isnan(c2)) c2 = 0.0; if (isnan(c1)) c1 = c2;
2950
 
2951
    const float a = 2 * a1 - a2, b = 2 * b1 - b2, c = 2 * c1 - c2;
2952
 
2953
    // Take the average instead of the median
2954
    z_values[x][y] = (a + b + c) / 3.0;
2955
 
2956
    // Median is robust (ignores outliers).
2957
    // z_values[x][y] = (a < b) ? ((b < c) ? b : (c < a) ? a : c)
2958
    //                                : ((c < b) ? b : (a < c) ? a : c);
2959
  }
2960
 
2961
  //Enable this if your SCARA uses 180° of total area
2962
  //#define EXTRAPOLATE_FROM_EDGE
2963
 
2964
  #if ENABLED(EXTRAPOLATE_FROM_EDGE)
2965
    #if GRID_MAX_POINTS_X < GRID_MAX_POINTS_Y
2966
      #define HALF_IN_X
2967
    #elif GRID_MAX_POINTS_Y < GRID_MAX_POINTS_X
2968
      #define HALF_IN_Y
2969
    #endif
2970
  #endif
2971
 
2972
  /**
2973
   * Fill in the unprobed points (corners of circular print surface)
2974
   * using linear extrapolation, away from the center.
2975
   */
2976
  static void extrapolate_unprobed_bed_level() {
2977
    #ifdef HALF_IN_X
2978
      constexpr uint8_t ctrx2 = 0, xlen = GRID_MAX_POINTS_X - 1;
2979
    #else
2980
      constexpr uint8_t ctrx1 = (GRID_MAX_POINTS_X - 1) / 2, // left-of-center
2981
                        ctrx2 = (GRID_MAX_POINTS_X) / 2,     // right-of-center
2982
                        xlen = ctrx1;
2983
    #endif
2984
 
2985
    #ifdef HALF_IN_Y
2986
      constexpr uint8_t ctry2 = 0, ylen = GRID_MAX_POINTS_Y - 1;
2987
    #else
2988
      constexpr uint8_t ctry1 = (GRID_MAX_POINTS_Y - 1) / 2, // top-of-center
2989
                        ctry2 = (GRID_MAX_POINTS_Y) / 2,     // bottom-of-center
2990
                        ylen = ctry1;
2991
    #endif
2992
 
2993
    for (uint8_t xo = 0; xo <= xlen; xo++)
2994
      for (uint8_t yo = 0; yo <= ylen; yo++) {
2995
        uint8_t x2 = ctrx2 + xo, y2 = ctry2 + yo;
2996
        #ifndef HALF_IN_X
2997
          const uint8_t x1 = ctrx1 - xo;
2998
        #endif
2999
        #ifndef HALF_IN_Y
3000
          const uint8_t y1 = ctry1 - yo;
3001
          #ifndef HALF_IN_X
3002
            extrapolate_one_point(x1, y1, +1, +1);   //  left-below + +
3003
          #endif
3004
          extrapolate_one_point(x2, y1, -1, +1);     // right-below - +
3005
        #endif
3006
        #ifndef HALF_IN_X
3007
          extrapolate_one_point(x1, y2, +1, -1);     //  left-above + -
3008
        #endif
3009
        extrapolate_one_point(x2, y2, -1, -1);       // right-above - -
3010
      }
3011
 
3012
  }
3013
 
3014
  static void print_bilinear_leveling_grid() {
3015
    SERIAL_ECHOLNPGM("Bilinear Leveling Grid:");
3016
    print_2d_array(GRID_MAX_POINTS_X, GRID_MAX_POINTS_Y, 3,
3017
      [](const uint8_t ix, const uint8_t iy) { return z_values[ix][iy]; }
3018
    );
3019
  }
3020
 
3021
  #if ENABLED(ABL_BILINEAR_SUBDIVISION)
3022
 
3023
    #define ABL_GRID_POINTS_VIRT_X (GRID_MAX_POINTS_X - 1) * (BILINEAR_SUBDIVISIONS) + 1
3024
    #define ABL_GRID_POINTS_VIRT_Y (GRID_MAX_POINTS_Y - 1) * (BILINEAR_SUBDIVISIONS) + 1
3025
    #define ABL_TEMP_POINTS_X (GRID_MAX_POINTS_X + 2)
3026
    #define ABL_TEMP_POINTS_Y (GRID_MAX_POINTS_Y + 2)
3027
    float z_values_virt[ABL_GRID_POINTS_VIRT_X][ABL_GRID_POINTS_VIRT_Y];
3028
    int bilinear_grid_spacing_virt[2] = { 0 };
3029
    float bilinear_grid_factor_virt[2] = { 0 };
3030
 
3031
    static void print_bilinear_leveling_grid_virt() {
3032
      SERIAL_ECHOLNPGM("Subdivided with CATMULL ROM Leveling Grid:");
3033
      print_2d_array(ABL_GRID_POINTS_VIRT_X, ABL_GRID_POINTS_VIRT_Y, 5,
3034
        [](const uint8_t ix, const uint8_t iy) { return z_values_virt[ix][iy]; }
3035
      );
3036
    }
3037
 
3038
    #define LINEAR_EXTRAPOLATION(E, I) ((E) * 2 - (I))
3039
    float bed_level_virt_coord(const uint8_t x, const uint8_t y) {
3040
      uint8_t ep = 0, ip = 1;
3041
      if (!x || x == ABL_TEMP_POINTS_X - 1) {
3042
        if (x) {
3043
          ep = GRID_MAX_POINTS_X - 1;
3044
          ip = GRID_MAX_POINTS_X - 2;
3045
        }
3046
        if (WITHIN(y, 1, ABL_TEMP_POINTS_Y - 2))
3047
          return LINEAR_EXTRAPOLATION(
3048
            z_values[ep][y - 1],
3049
            z_values[ip][y - 1]
3050
          );
3051
        else
3052
          return LINEAR_EXTRAPOLATION(
3053
            bed_level_virt_coord(ep + 1, y),
3054
            bed_level_virt_coord(ip + 1, y)
3055
          );
3056
      }
3057
      if (!y || y == ABL_TEMP_POINTS_Y - 1) {
3058
        if (y) {
3059
          ep = GRID_MAX_POINTS_Y - 1;
3060
          ip = GRID_MAX_POINTS_Y - 2;
3061
        }
3062
        if (WITHIN(x, 1, ABL_TEMP_POINTS_X - 2))
3063
          return LINEAR_EXTRAPOLATION(
3064
            z_values[x - 1][ep],
3065
            z_values[x - 1][ip]
3066
          );
3067
        else
3068
          return LINEAR_EXTRAPOLATION(
3069
            bed_level_virt_coord(x, ep + 1),
3070
            bed_level_virt_coord(x, ip + 1)
3071
          );
3072
      }
3073
      return z_values[x - 1][y - 1];
3074
    }
3075
 
3076
    static float bed_level_virt_cmr(const float p[4], const uint8_t i, const float t) {
3077
      return (
3078
          p[i-1] * -t * sq(1 - t)
3079
        + p[i]   * (2 - 5 * sq(t) + 3 * t * sq(t))
3080
        + p[i+1] * t * (1 + 4 * t - 3 * sq(t))
3081
        - p[i+2] * sq(t) * (1 - t)
3082
      ) * 0.5;
3083
    }
3084
 
3085
    static float bed_level_virt_2cmr(const uint8_t x, const uint8_t y, const float &tx, const float &ty) {
3086
      float row[4], column[4];
3087
      for (uint8_t i = 0; i < 4; i++) {
3088
        for (uint8_t j = 0; j < 4; j++) {
3089
          column[j] = bed_level_virt_coord(i + x - 1, j + y - 1);
3090
        }
3091
        row[i] = bed_level_virt_cmr(column, 1, ty);
3092
      }
3093
      return bed_level_virt_cmr(row, 1, tx);
3094
    }
3095
 
3096
    void bed_level_virt_interpolate() {
3097
      bilinear_grid_spacing_virt[X_AXIS] = bilinear_grid_spacing[X_AXIS] / (BILINEAR_SUBDIVISIONS);
3098
      bilinear_grid_spacing_virt[Y_AXIS] = bilinear_grid_spacing[Y_AXIS] / (BILINEAR_SUBDIVISIONS);
3099
      bilinear_grid_factor_virt[X_AXIS] = RECIPROCAL(bilinear_grid_spacing_virt[X_AXIS]);
3100
      bilinear_grid_factor_virt[Y_AXIS] = RECIPROCAL(bilinear_grid_spacing_virt[Y_AXIS]);
3101
      for (uint8_t y = 0; y < GRID_MAX_POINTS_Y; y++)
3102
        for (uint8_t x = 0; x < GRID_MAX_POINTS_X; x++)
3103
          for (uint8_t ty = 0; ty < BILINEAR_SUBDIVISIONS; ty++)
3104
            for (uint8_t tx = 0; tx < BILINEAR_SUBDIVISIONS; tx++) {
3105
              if ((ty && y == GRID_MAX_POINTS_Y - 1) || (tx && x == GRID_MAX_POINTS_X - 1))
3106
                continue;
3107
              z_values_virt[x * (BILINEAR_SUBDIVISIONS) + tx][y * (BILINEAR_SUBDIVISIONS) + ty] =
3108
                bed_level_virt_2cmr(
3109
                  x + 1,
3110
                  y + 1,
3111
                  (float)tx / (BILINEAR_SUBDIVISIONS),
3112
                  (float)ty / (BILINEAR_SUBDIVISIONS)
3113
                );
3114
            }
3115
    }
3116
  #endif // ABL_BILINEAR_SUBDIVISION
3117
 
3118
  // Refresh after other values have been updated
3119
  void refresh_bed_level() {
3120
    bilinear_grid_factor[X_AXIS] = RECIPROCAL(bilinear_grid_spacing[X_AXIS]);
3121
    bilinear_grid_factor[Y_AXIS] = RECIPROCAL(bilinear_grid_spacing[Y_AXIS]);
3122
    #if ENABLED(ABL_BILINEAR_SUBDIVISION)
3123
      bed_level_virt_interpolate();
3124
    #endif
3125
  }
3126
 
3127
#endif // AUTO_BED_LEVELING_BILINEAR
3128
 
3129
#if ENABLED(SENSORLESS_HOMING)
3130
 
3131
  /**
3132
   * Set sensorless homing if the axis has it, accounting for Core Kinematics.
3133
   */
3134
  void sensorless_homing_per_axis(const AxisEnum axis, const bool enable=true) {
3135
    switch (axis) {
3136
      #if X_SENSORLESS
3137
        case X_AXIS:
3138
          tmc_sensorless_homing(stepperX, enable);
3139
          #if CORE_IS_XY && Y_SENSORLESS
3140
            tmc_sensorless_homing(stepperY, enable);
3141
          #elif CORE_IS_XZ && Z_SENSORLESS
3142
            tmc_sensorless_homing(stepperZ, enable);
3143
          #endif
3144
          break;
3145
      #endif
3146
      #if Y_SENSORLESS
3147
        case Y_AXIS:
3148
          tmc_sensorless_homing(stepperY, enable);
3149
          #if CORE_IS_XY && X_SENSORLESS
3150
            tmc_sensorless_homing(stepperX, enable);
3151
          #elif CORE_IS_YZ && Z_SENSORLESS
3152
            tmc_sensorless_homing(stepperZ, enable);
3153
          #endif
3154
          break;
3155
      #endif
3156
      #if Z_SENSORLESS
3157
        case Z_AXIS:
3158
          tmc_sensorless_homing(stepperZ, enable);
3159
          #if CORE_IS_XZ && X_SENSORLESS
3160
            tmc_sensorless_homing(stepperX, enable);
3161
          #elif CORE_IS_YZ && Y_SENSORLESS
3162
            tmc_sensorless_homing(stepperY, enable);
3163
          #endif
3164
          break;
3165
      #endif
3166
      default: break;
3167
    }
3168
  }
3169
 
3170
#endif // SENSORLESS_HOMING
3171
 
3172
/**
3173
 * Home an individual linear axis
3174
 */
3175
static void do_homing_move(const AxisEnum axis, const float distance, const float fr_mm_s=0) {
3176
 
3177
  #if ENABLED(DEBUG_LEVELING_FEATURE)
3178
    if (DEBUGGING(LEVELING)) {
3179
      SERIAL_ECHOPAIR(">>> do_homing_move(", axis_codes[axis]);
3180
      SERIAL_ECHOPAIR(", ", distance);
3181
      SERIAL_ECHOPGM(", ");
3182
      if (fr_mm_s)
3183
        SERIAL_ECHO(fr_mm_s);
3184
      else {
3185
        SERIAL_ECHOPAIR("[", homing_feedrate(axis));
3186
        SERIAL_CHAR(']');
3187
      }
3188
      SERIAL_ECHOLNPGM(")");
3189
    }
3190
  #endif
3191
 
3192
  #if HOMING_Z_WITH_PROBE && HAS_HEATED_BED && ENABLED(WAIT_FOR_BED_HEATER)
3193
    // Wait for bed to heat back up between probing points
3194
    if (axis == Z_AXIS && distance < 0 && thermalManager.isHeatingBed()) {
3195
      serialprintPGM(msg_wait_for_bed_heating);
3196
      LCD_MESSAGEPGM(MSG_BED_HEATING);
3197
      while (thermalManager.isHeatingBed()) safe_delay(200);
3198
      lcd_reset_status();
3199
    }
3200
  #endif
3201
 
3202
  // Only do some things when moving towards an endstop
3203
  const int8_t axis_home_dir =
3204
    #if ENABLED(DUAL_X_CARRIAGE)
3205
      (axis == X_AXIS) ? x_home_dir(active_extruder) :
3206
    #endif
3207
    home_dir(axis);
3208
  const bool is_home_dir = (axis_home_dir > 0) == (distance > 0);
3209
 
3210
  if (is_home_dir) {
3211
 
3212
    #if HOMING_Z_WITH_PROBE && QUIET_PROBING
3213
      if (axis == Z_AXIS) probing_pause(true);
3214
    #endif
3215
 
3216
    // Disable stealthChop if used. Enable diag1 pin on driver.
3217
    #if ENABLED(SENSORLESS_HOMING)
3218
      sensorless_homing_per_axis(axis);
3219
    #endif
3220
  }
3221
 
3222
  // Tell the planner the axis is at 0
3223
  current_position[axis] = 0;
3224
 
3225
  // Do the move, which is required to hit an endstop
3226
  #if IS_SCARA
3227
    SYNC_PLAN_POSITION_KINEMATIC();
3228
    current_position[axis] = distance;
3229
    inverse_kinematics(current_position);
3230
    planner.buffer_line(delta[A_AXIS], delta[B_AXIS], delta[C_AXIS], current_position[E_CART], fr_mm_s ? fr_mm_s : homing_feedrate(axis), active_extruder);
3231
  #elif ENABLED(HANGPRINTER) // TODO: Hangprinter homing is not finished (Jan 7, 2018)
3232
    SYNC_PLAN_POSITION_KINEMATIC();
3233
    current_position[axis] = distance;
3234
    inverse_kinematics(current_position);
3235
    planner.buffer_line(line_lengths[A_AXIS], line_lengths[B_AXIS], line_lengths[C_AXIS], line_lengths[D_AXIS], current_position[E_CART], fr_mm_s ? fr_mm_s : homing_feedrate(axis), active_extruder);
3236
  #else
3237
    sync_plan_position();
3238
    current_position[axis] = distance; // Set delta/cartesian axes directly
3239
    planner.buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_CART], fr_mm_s ? fr_mm_s : homing_feedrate(axis), active_extruder);
3240
  #endif
3241
 
3242
  planner.synchronize();
3243
 
3244
  if (is_home_dir) {
3245
 
3246
    #if HOMING_Z_WITH_PROBE && QUIET_PROBING
3247
      if (axis == Z_AXIS) probing_pause(false);
3248
    #endif
3249
 
3250
    endstops.validate_homing_move();
3251
 
3252
    // Re-enable stealthChop if used. Disable diag1 pin on driver.
3253
    #if ENABLED(SENSORLESS_HOMING)
3254
      sensorless_homing_per_axis(axis, false);
3255
    #endif
3256
  }
3257
 
3258
  #if ENABLED(DEBUG_LEVELING_FEATURE)
3259
    if (DEBUGGING(LEVELING)) {
3260
      SERIAL_ECHOPAIR("<<< do_homing_move(", axis_codes[axis]);
3261
      SERIAL_CHAR(')');
3262
      SERIAL_EOL();
3263
    }
3264
  #endif
3265
}
3266
 
3267
/**
3268
 * Home an individual "raw axis" to its endstop.
3269
 * This applies to XYZ on Cartesian and Core robots, and
3270
 * to the individual ABC steppers on DELTA and SCARA.
3271
 *
3272
 * At the end of the procedure the axis is marked as
3273
 * homed and the current position of that axis is updated.
3274
 * Kinematic robots should wait till all axes are homed
3275
 * before updating the current position.
3276
 */
3277
 
3278
static void homeaxis(const AxisEnum axis) {
3279
 
3280
  #if IS_SCARA
3281
    // Only Z homing (with probe) is permitted
3282
    if (axis != Z_AXIS) { BUZZ(100, 880); return; }
3283
  #else
3284
    #define CAN_HOME(A) \
3285
      (axis == _AXIS(A) && ((A##_MIN_PIN > -1 && A##_HOME_DIR < 0) || (A##_MAX_PIN > -1 && A##_HOME_DIR > 0)))
3286
    if (!CAN_HOME(X) && !CAN_HOME(Y) && !CAN_HOME(Z)) return;
3287
  #endif
3288
 
3289
  #if ENABLED(DEBUG_LEVELING_FEATURE)
3290
    if (DEBUGGING(LEVELING)) {
3291
      SERIAL_ECHOPAIR(">>> homeaxis(", axis_codes[axis]);
3292
      SERIAL_CHAR(')');
3293
      SERIAL_EOL();
3294
    }
3295
  #endif
3296
 
3297
  const int axis_home_dir = (
3298
    #if ENABLED(DUAL_X_CARRIAGE)
3299
      axis == X_AXIS ? x_home_dir(active_extruder) :
3300
    #endif
3301
    home_dir(axis)
3302
  );
3303
 
3304
  // Homing Z towards the bed? Deploy the Z probe or endstop.
3305
  #if HOMING_Z_WITH_PROBE
3306
    if (axis == Z_AXIS && DEPLOY_PROBE()) return;
3307
  #endif
3308
 
3309
  // Set flags for X, Y, Z motor locking
3310
  #if ENABLED(X_DUAL_ENDSTOPS) || ENABLED(Y_DUAL_ENDSTOPS) || ENABLED(Z_DUAL_ENDSTOPS)
3311
    switch (axis) {
3312
      #if ENABLED(X_DUAL_ENDSTOPS)
3313
        case X_AXIS:
3314
      #endif
3315
      #if ENABLED(Y_DUAL_ENDSTOPS)
3316
        case Y_AXIS:
3317
      #endif
3318
      #if ENABLED(Z_DUAL_ENDSTOPS)
3319
        case Z_AXIS:
3320
      #endif
3321
      stepper.set_homing_dual_axis(true);
3322
      default: break;
3323
    }
3324
  #endif
3325
 
3326
  // Fast move towards endstop until triggered
3327
  #if ENABLED(DEBUG_LEVELING_FEATURE)
3328
    if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("Home 1 Fast:");
3329
  #endif
3330
 
3331
  #if HOMING_Z_WITH_PROBE && ENABLED(BLTOUCH)
3332
    // BLTOUCH needs to be deployed every time
3333
    if (axis == Z_AXIS && set_bltouch_deployed(true)) return;
3334
  #endif
3335
 
3336
  do_homing_move(axis, 1.5f * max_length(axis) * axis_home_dir);
3337
 
3338
  #if HOMING_Z_WITH_PROBE && ENABLED(BLTOUCH)
3339
    // BLTOUCH needs to be stowed after trigger to rearm itself
3340
    if (axis == Z_AXIS) set_bltouch_deployed(false);
3341
  #endif
3342
 
3343
  // When homing Z with probe respect probe clearance
3344
  const float bump = axis_home_dir * (
3345
    #if HOMING_Z_WITH_PROBE
3346
      (axis == Z_AXIS && (Z_HOME_BUMP_MM)) ? MAX(Z_CLEARANCE_BETWEEN_PROBES, Z_HOME_BUMP_MM) :
3347
    #endif
3348
    home_bump_mm(axis)
3349
  );
3350
 
3351
  // If a second homing move is configured...
3352
  if (bump) {
3353
    // Move away from the endstop by the axis HOME_BUMP_MM
3354
    #if ENABLED(DEBUG_LEVELING_FEATURE)
3355
      if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("Move Away:");
3356
    #endif
3357
    do_homing_move(axis, -bump
3358
      #if HOMING_Z_WITH_PROBE
3359
        , axis == Z_AXIS ? MMM_TO_MMS(Z_PROBE_SPEED_FAST) : 0.00
3360
      #endif
3361
    );
3362
 
3363
    // Slow move towards endstop until triggered
3364
    #if ENABLED(DEBUG_LEVELING_FEATURE)
3365
      if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("Home 2 Slow:");
3366
    #endif
3367
 
3368
    #if HOMING_Z_WITH_PROBE && ENABLED(BLTOUCH)
3369
      // BLTOUCH needs to be deployed every time
3370
      if (axis == Z_AXIS && set_bltouch_deployed(true)) return;
3371
    #endif
3372
 
3373
    do_homing_move(axis, 2 * bump, get_homing_bump_feedrate(axis));
3374
 
3375
    #if HOMING_Z_WITH_PROBE && ENABLED(BLTOUCH)
3376
      // BLTOUCH needs to be stowed after trigger to rearm itself
3377
      if (axis == Z_AXIS) set_bltouch_deployed(false);
3378
    #endif
3379
  }
3380
 
3381
  /**
3382
   * Home axes that have dual endstops... differently
3383
   */
3384
  #if ENABLED(X_DUAL_ENDSTOPS) || ENABLED(Y_DUAL_ENDSTOPS) || ENABLED(Z_DUAL_ENDSTOPS)
3385
    const bool pos_dir = axis_home_dir > 0;
3386
    #if ENABLED(X_DUAL_ENDSTOPS)
3387
      if (axis == X_AXIS) {
3388
        const float adj = ABS(endstops.x_endstop_adj);
3389
        if (adj) {
3390
          if (pos_dir ? (endstops.x_endstop_adj > 0) : (endstops.x_endstop_adj < 0)) stepper.set_x_lock(true); else stepper.set_x2_lock(true);
3391
          do_homing_move(axis, pos_dir ? -adj : adj);
3392
          stepper.set_x_lock(false);
3393
          stepper.set_x2_lock(false);
3394
        }
3395
      }
3396
    #endif
3397
    #if ENABLED(Y_DUAL_ENDSTOPS)
3398
      if (axis == Y_AXIS) {
3399
        const float adj = ABS(endstops.y_endstop_adj);
3400
        if (adj) {
3401
          if (pos_dir ? (endstops.y_endstop_adj > 0) : (endstops.y_endstop_adj < 0)) stepper.set_y_lock(true); else stepper.set_y2_lock(true);
3402
          do_homing_move(axis, pos_dir ? -adj : adj);
3403
          stepper.set_y_lock(false);
3404
          stepper.set_y2_lock(false);
3405
        }
3406
      }
3407
    #endif
3408
    #if ENABLED(Z_DUAL_ENDSTOPS)
3409
      if (axis == Z_AXIS) {
3410
        const float adj = ABS(endstops.z_endstop_adj);
3411
        if (adj) {
3412
          if (pos_dir ? (endstops.z_endstop_adj > 0) : (endstops.z_endstop_adj < 0)) stepper.set_z_lock(true); else stepper.set_z2_lock(true);
3413
          do_homing_move(axis, pos_dir ? -adj : adj);
3414
          stepper.set_z_lock(false);
3415
          stepper.set_z2_lock(false);
3416
        }
3417
      }
3418
    #endif
3419
    stepper.set_homing_dual_axis(false);
3420
  #endif
3421
 
3422
  #if IS_SCARA
3423
 
3424
    set_axis_is_at_home(axis);
3425
    SYNC_PLAN_POSITION_KINEMATIC();
3426
 
3427
  #elif ENABLED(DELTA)
3428
 
3429
    // Delta has already moved all three towers up in G28
3430
    // so here it re-homes each tower in turn.
3431
    // Delta homing treats the axes as normal linear axes.
3432
 
3433
    // retrace by the amount specified in delta_endstop_adj + additional dist in order to have minimum steps
3434
    if (delta_endstop_adj[axis] * Z_HOME_DIR <= 0) {
3435
      #if ENABLED(DEBUG_LEVELING_FEATURE)
3436
        if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("delta_endstop_adj:");
3437
      #endif
3438
      do_homing_move(axis, delta_endstop_adj[axis] - (MIN_STEPS_PER_SEGMENT + 1) * planner.steps_to_mm[axis] * Z_HOME_DIR);
3439
    }
3440
 
3441
  #else
3442
 
3443
    // For cartesian/core machines,
3444
    // set the axis to its home position
3445
    set_axis_is_at_home(axis);
3446
    sync_plan_position();
3447
 
3448
    destination[axis] = current_position[axis];
3449
 
3450
    #if ENABLED(DEBUG_LEVELING_FEATURE)
3451
      if (DEBUGGING(LEVELING)) DEBUG_POS("> AFTER set_axis_is_at_home", current_position);
3452
    #endif
3453
 
3454
  #endif
3455
 
3456
  // Put away the Z probe
3457
  #if HOMING_Z_WITH_PROBE
3458
    if (axis == Z_AXIS && STOW_PROBE()) return;
3459
  #endif
3460
 
3461
  // Clear retracted status if homing the Z axis
3462
  #if ENABLED(FWRETRACT)
3463
    if (axis == Z_AXIS) fwretract.hop_amount = 0.0;
3464
  #endif
3465
 
3466
  #if ENABLED(DEBUG_LEVELING_FEATURE)
3467
    if (DEBUGGING(LEVELING)) {
3468
      SERIAL_ECHOPAIR("<<< homeaxis(", axis_codes[axis]);
3469
      SERIAL_CHAR(')');
3470
      SERIAL_EOL();
3471
    }
3472
  #endif
3473
} // homeaxis()
3474
 
3475
#if ENABLED(MIXING_EXTRUDER)
3476
 
3477
  void normalize_mix() {
3478
    float mix_total = 0.0;
3479
    for (uint8_t i = 0; i < MIXING_STEPPERS; i++) mix_total += mixing_factor[i];
3480
    // Scale all values if they don't add up to ~1.0
3481
    if (!NEAR(mix_total, 1.0)) {
3482
      SERIAL_PROTOCOLLNPGM("Warning: Mix factors must add up to 1.0. Scaling.");
3483
      const float inverse_sum = RECIPROCAL(mix_total);
3484
      for (uint8_t i = 0; i < MIXING_STEPPERS; i++) mixing_factor[i] *= inverse_sum;
3485
    }
3486
  }
3487
 
3488
  #if ENABLED(DIRECT_MIXING_IN_G1)
3489
    // Get mixing parameters from the GCode
3490
    // The total "must" be 1.0 (but it will be normalized)
3491
    // If no mix factors are given, the old mix is preserved
3492
    void gcode_get_mix() {
3493
      const char mixing_codes[] = { 'A', 'B'
3494
        #if MIXING_STEPPERS > 2
3495
          , 'C'
3496
          #if MIXING_STEPPERS > 3
3497
            , 'D'
3498
            #if MIXING_STEPPERS > 4
3499
              , 'H'
3500
              #if MIXING_STEPPERS > 5
3501
                , 'I'
3502
              #endif // MIXING_STEPPERS > 5
3503
            #endif // MIXING_STEPPERS > 4
3504
          #endif // MIXING_STEPPERS > 3
3505
        #endif // MIXING_STEPPERS > 2
3506
      };
3507
      byte mix_bits = 0;
3508
      for (uint8_t i = 0; i < MIXING_STEPPERS; i++) {
3509
        if (parser.seenval(mixing_codes[i])) {
3510
          SBI(mix_bits, i);
3511
          mixing_factor[i] = MAX(parser.value_float(), 0.0);
3512
        }
3513
      }
3514
      // If any mixing factors were included, clear the rest
3515
      // If none were included, preserve the last mix
3516
      if (mix_bits) {
3517
        for (uint8_t i = 0; i < MIXING_STEPPERS; i++)
3518
          if (!TEST(mix_bits, i)) mixing_factor[i] = 0.0;
3519
        normalize_mix();
3520
      }
3521
    }
3522
  #endif
3523
 
3524
#endif
3525
 
3526
/**
3527
 * ***************************************************************************
3528
 * ***************************** G-CODE HANDLING *****************************
3529
 * ***************************************************************************
3530
 */
3531
 
3532
/**
3533
 * Set XYZE destination and feedrate from the current GCode command
3534
 *
3535
 *  - Set destination from included axis codes
3536
 *  - Set to current for missing axis codes
3537
 *  - Set the feedrate, if included
3538
 */
3539
void gcode_get_destination() {
3540
  LOOP_XYZE(i) {
3541
    if (parser.seen(axis_codes[i])) {
3542
      const float v = parser.value_axis_units((AxisEnum)i);
3543
      destination[i] = (axis_relative_modes[i] || relative_mode)
3544
        ? current_position[i] + v
3545
        : (i == E_CART) ? v : LOGICAL_TO_NATIVE(v, i);
3546
    }
3547
    else
3548
      destination[i] = current_position[i];
3549
  }
3550
 
3551
  if (parser.linearval('F') > 0)
3552
    feedrate_mm_s = MMM_TO_MMS(parser.value_feedrate());
3553
 
3554
  #if ENABLED(PRINTCOUNTER)
3555
    if (!DEBUGGING(DRYRUN))
3556
      print_job_timer.incFilamentUsed(destination[E_CART] - current_position[E_CART]);
3557
  #endif
3558
 
3559
  // Get ABCDHI mixing factors
3560
  #if ENABLED(MIXING_EXTRUDER) && ENABLED(DIRECT_MIXING_IN_G1)
3561
    gcode_get_mix();
3562
  #endif
3563
}
3564
 
3565
#if ENABLED(HOST_KEEPALIVE_FEATURE)
3566
 
3567
  /**
3568
   * Output a "busy" message at regular intervals
3569
   * while the machine is not accepting commands.
3570
   */
3571
  void host_keepalive() {
3572
    const millis_t ms = millis();
3573
    if (!suspend_auto_report && host_keepalive_interval && busy_state != NOT_BUSY) {
3574
      if (PENDING(ms, next_busy_signal_ms)) return;
3575
      switch (busy_state) {
3576
        case IN_HANDLER:
3577
        case IN_PROCESS:
3578
          SERIAL_ECHO_START();
3579
          SERIAL_ECHOLNPGM(MSG_BUSY_PROCESSING);
3580
          break;
3581
        case PAUSED_FOR_USER:
3582
          SERIAL_ECHO_START();
3583
          SERIAL_ECHOLNPGM(MSG_BUSY_PAUSED_FOR_USER);
3584
          break;
3585
        case PAUSED_FOR_INPUT:
3586
          SERIAL_ECHO_START();
3587
          SERIAL_ECHOLNPGM(MSG_BUSY_PAUSED_FOR_INPUT);
3588
          break;
3589
        default:
3590
          break;
3591
      }
3592
    }
3593
    next_busy_signal_ms = ms + host_keepalive_interval * 1000UL;
3594
  }
3595
 
3596
#endif // HOST_KEEPALIVE_FEATURE
3597
 
3598
 
3599
/**************************************************
3600
 ***************** GCode Handlers *****************
3601
 **************************************************/
3602
 
3603
#if ENABLED(NO_MOTION_BEFORE_HOMING)
3604
  #define G0_G1_CONDITION !axis_unhomed_error(parser.seen('X'), parser.seen('Y'), parser.seen('Z'))
3605
#else
3606
  #define G0_G1_CONDITION true
3607
#endif
3608
 
3609
/**
3610
 * G0, G1: Coordinated movement of X Y Z E axes
3611
 */
3612
inline void gcode_G0_G1(
3613
  #if IS_SCARA
3614
    bool fast_move=false
3615
  #endif
3616
) {
3617
  if (IsRunning() && G0_G1_CONDITION) {
3618
    gcode_get_destination(); // For X Y Z E F
3619
 
3620
    #if ENABLED(FWRETRACT)
3621
      if (MIN_AUTORETRACT <= MAX_AUTORETRACT) {
3622
        // When M209 Autoretract is enabled, convert E-only moves to firmware retract/prime moves
3623
        if (fwretract.autoretract_enabled && parser.seen('E') && !(parser.seen('X') || parser.seen('Y') || parser.seen('Z'))) {
3624
          const float echange = destination[E_CART] - current_position[E_CART];
3625
          // Is this a retract or prime move?
3626
          if (WITHIN(ABS(echange), MIN_AUTORETRACT, MAX_AUTORETRACT) && fwretract.retracted[active_extruder] == (echange > 0.0)) {
3627
            current_position[E_CART] = destination[E_CART]; // Hide a G1-based retract/prime from calculations
3628
            sync_plan_position_e();                         // AND from the planner
3629
            return fwretract.retract(echange < 0.0);        // Firmware-based retract/prime (double-retract ignored)
3630
          }
3631
        }
3632
      }
3633
    #endif // FWRETRACT
3634
 
3635
    #if IS_SCARA
3636
      fast_move ? prepare_uninterpolated_move_to_destination() : prepare_move_to_destination();
3637
    #else
3638
      prepare_move_to_destination();
3639
    #endif
3640
 
3641
    #if ENABLED(NANODLP_Z_SYNC)
3642
      #if ENABLED(NANODLP_ALL_AXIS)
3643
        #define _MOVE_SYNC parser.seenval('X') || parser.seenval('Y') || parser.seenval('Z') // For any move wait and output sync message
3644
      #else
3645
        #define _MOVE_SYNC parser.seenval('Z')  // Only for Z move
3646
      #endif
3647
      if (_MOVE_SYNC) {
3648
        planner.synchronize();
3649
        SERIAL_ECHOLNPGM(MSG_Z_MOVE_COMP);
3650
      }
3651
    #endif
3652
  }
3653
}
3654
 
3655
/**
3656
 * G2: Clockwise Arc
3657
 * G3: Counterclockwise Arc
3658
 *
3659
 * This command has two forms: IJ-form and R-form.
3660
 *
3661
 *  - I specifies an X offset. J specifies a Y offset.
3662
 *    At least one of the IJ parameters is required.
3663
 *    X and Y can be omitted to do a complete circle.
3664
 *    The given XY is not error-checked. The arc ends
3665
 *     based on the angle of the destination.
3666
 *    Mixing I or J with R will throw an error.
3667
 *
3668
 *  - R specifies the radius. X or Y is required.
3669
 *    Omitting both X and Y will throw an error.
3670
 *    X or Y must differ from the current XY.
3671
 *    Mixing R with I or J will throw an error.
3672
 *
3673
 *  - P specifies the number of full circles to do
3674
 *    before the specified arc move.
3675
 *
3676
 *  Examples:
3677
 *
3678
 *    G2 I10           ; CW circle centered at X+10
3679
 *    G3 X20 Y12 R14   ; CCW circle with r=14 ending at X20 Y12
3680
 */
3681
#if ENABLED(ARC_SUPPORT)
3682
 
3683
  inline void gcode_G2_G3(const bool clockwise) {
3684
    #if ENABLED(NO_MOTION_BEFORE_HOMING)
3685
      if (axis_unhomed_error()) return;
3686
    #endif
3687
 
3688
    if (IsRunning()) {
3689
 
3690
      #if ENABLED(SF_ARC_FIX)
3691
        const bool relative_mode_backup = relative_mode;
3692
        relative_mode = true;
3693
      #endif
3694
 
3695
      gcode_get_destination();
3696
 
3697
      #if ENABLED(SF_ARC_FIX)
3698
        relative_mode = relative_mode_backup;
3699
      #endif
3700
 
3701
      float arc_offset[2] = { 0, 0 };
3702
      if (parser.seenval('R')) {
3703
        const float r = parser.value_linear_units(),
3704
                    p1 = current_position[X_AXIS], q1 = current_position[Y_AXIS],
3705
                    p2 = destination[X_AXIS], q2 = destination[Y_AXIS];
3706
        if (r && (p2 != p1 || q2 != q1)) {
3707
          const float e = clockwise ^ (r < 0) ? -1 : 1,             // clockwise -1/1, counterclockwise 1/-1
3708
                      dx = p2 - p1, dy = q2 - q1,                   // X and Y differences
3709
                      d = HYPOT(dx, dy),                            // Linear distance between the points
3710
                      h2 = (r - 0.5f * d) * (r + 0.5f * d),         // factor to reduce rounding error
3711
                      h = (h2 >= 0) ? SQRT(h2) : 0.0f,              // Distance to the arc pivot-point
3712
                      mx = (p1 + p2) * 0.5f, my = (q1 + q2) * 0.5f, // Point between the two points
3713
                      sx = -dy / d, sy = dx / d,                    // Slope of the perpendicular bisector
3714
                      cx = mx + e * h * sx, cy = my + e * h * sy;   // Pivot-point of the arc
3715
          arc_offset[0] = cx - p1;
3716
          arc_offset[1] = cy - q1;
3717
        }
3718
      }
3719
      else {
3720
        if (parser.seenval('I')) arc_offset[0] = parser.value_linear_units();
3721
        if (parser.seenval('J')) arc_offset[1] = parser.value_linear_units();
3722
      }
3723
 
3724
      if (arc_offset[0] || arc_offset[1]) {
3725
 
3726
        #if ENABLED(ARC_P_CIRCLES)
3727
          // P indicates number of circles to do
3728
          int8_t circles_to_do = parser.byteval('P');
3729
          if (!WITHIN(circles_to_do, 0, 100)) {
3730
            SERIAL_ERROR_START();
3731
            SERIAL_ERRORLNPGM(MSG_ERR_ARC_ARGS);
3732
          }
3733
          while (circles_to_do--)
3734
            plan_arc(current_position, arc_offset, clockwise);
3735
        #endif
3736
 
3737
        // Send the arc to the planner
3738
        plan_arc(destination, arc_offset, clockwise);
3739
      }
3740
      else {
3741
        // Bad arguments
3742
        SERIAL_ERROR_START();
3743
        SERIAL_ERRORLNPGM(MSG_ERR_ARC_ARGS);
3744
      }
3745
    }
3746
  }
3747
 
3748
#endif // ARC_SUPPORT
3749
 
3750
void dwell(millis_t time) {
3751
  time += millis();
3752
  while (PENDING(millis(), time)) idle();
3753
}
3754
 
3755
/**
3756
 * G4: Dwell S<seconds> or P<milliseconds>
3757
 */
3758
inline void gcode_G4() {
3759
  millis_t dwell_ms = 0;
3760
 
3761
  if (parser.seenval('P')) dwell_ms = parser.value_millis(); // milliseconds to wait
3762
  if (parser.seenval('S')) dwell_ms = parser.value_millis_from_seconds(); // seconds to wait
3763
 
3764
  planner.synchronize();
3765
  #if ENABLED(NANODLP_Z_SYNC)
3766
    SERIAL_ECHOLNPGM(MSG_Z_MOVE_COMP);
3767
  #endif
3768
 
3769
  if (!lcd_hasstatus()) LCD_MESSAGEPGM(MSG_DWELL);
3770
 
3771
  dwell(dwell_ms);
3772
}
3773
 
3774
#if ENABLED(BEZIER_CURVE_SUPPORT)
3775
 
3776
  /**
3777
   * Parameters interpreted according to:
3778
   * http://linuxcnc.org/docs/2.6/html/gcode/gcode.html#sec:G5-Cubic-Spline
3779
   * However I, J omission is not supported at this point; all
3780
   * parameters can be omitted and default to zero.
3781
   */
3782
 
3783
  /**
3784
   * G5: Cubic B-spline
3785
   */
3786
  inline void gcode_G5() {
3787
    #if ENABLED(NO_MOTION_BEFORE_HOMING)
3788
      if (axis_unhomed_error()) return;
3789
    #endif
3790
 
3791
    if (IsRunning()) {
3792
 
3793
      #if ENABLED(CNC_WORKSPACE_PLANES)
3794
        if (workspace_plane != PLANE_XY) {
3795
          SERIAL_ERROR_START();
3796
          SERIAL_ERRORLNPGM(MSG_ERR_BAD_PLANE_MODE);
3797
          return;
3798
        }
3799
      #endif
3800
 
3801
      gcode_get_destination();
3802
 
3803
      const float offset[] = {
3804
        parser.linearval('I'),
3805
        parser.linearval('J'),
3806
        parser.linearval('P'),
3807
        parser.linearval('Q')
3808
      };
3809
 
3810
      plan_cubic_move(destination, offset);
3811
    }
3812
  }
3813
 
3814
#endif // BEZIER_CURVE_SUPPORT
3815
 
3816
#if ENABLED(UNREGISTERED_MOVE_SUPPORT)
3817
 
3818
  /**
3819
   * G6 implementation for Hangprinter based on
3820
   * http://reprap.org/wiki/GCodes#G6:_Direct_Stepper_Move
3821
   * Accessed Jan 8, 2018
3822
   *
3823
   * G6 is used frequently to tighten lines with Hangprinter, so Hangprinter default is relative moves.
3824
   * Hangprinter uses switches
3825
   *   S1 for absolute moves
3826
   *   S2 for saving recording new line length after unregistered move
3827
   *        (typically used while tuning LINE_BUILDUP_COMPENSATION_FEATURE parameters)
3828
   */
3829
 
3830
  /**
3831
   * G6: Direct Stepper Move
3832
   */
3833
  inline void gcode_G6() {
3834
    bool count_it = false;
3835
    #if ENABLED(NO_MOTION_BEFORE_HOMING)
3836
      if (axis_unhomed_error()) return;
3837
    #endif
3838
    if (IsRunning()) {
3839
      float go[MOV_AXIS] = { 0.0 },
3840
            tmp_fr_mm_s = 0.0;
3841
 
3842
      LOOP_MOV_AXIS(i)
3843
        if (parser.seen(RAW_AXIS_CODES(i)))
3844
          go[i] = parser.value_axis_units((AxisEnum)i);
3845
 
3846
      #if ENABLED(HANGPRINTER)
3847
        #define GO_SRC line_lengths
3848
      #elif ENABLED(DELTA)
3849
        #define GO_SRC delta
3850
      #else
3851
        #define GO_SRC current_position
3852
      #endif
3853
 
3854
      if (
3855
        #if ENABLED(HANGPRINTER) // Sending R to another machine is the same as not sending S1 to Hangprinter
3856
          parser.byteval('S') != 2
3857
        #else
3858
          parser.seen('R')
3859
        #endif
3860
      )
3861
        LOOP_MOV_AXIS(i) go[i] += GO_SRC[i];
3862
      else
3863
        LOOP_MOV_AXIS(i) if (!parser.seen(RAW_AXIS_CODES(i))) go[i] += GO_SRC[i];
3864
 
3865
      tmp_fr_mm_s = parser.linearval('F') > 0.0 ? MMM_TO_MMS(parser.value_feedrate()) : feedrate_mm_s;
3866
 
3867
      #if ENABLED(HANGPRINTER)
3868
        if (parser.byteval('S') == 2) {
3869
          LOOP_MOV_AXIS(i) line_lengths[i] = go[i];
3870
          count_it = true;
3871
        }
3872
      #endif
3873
 
3874
      planner.buffer_segment(go[A_AXIS], go[B_AXIS], go[C_AXIS]
3875
                              #if ENABLED(HANGPRINTER)
3876
                                , go[D_AXIS]
3877
                              #endif
3878
                              , current_position[E_CART], tmp_fr_mm_s, active_extruder, 0.0, count_it
3879
                            );
3880
    }
3881
  }
3882
#endif
3883
 
3884
#if ENABLED(FWRETRACT)
3885
 
3886
  /**
3887
   * G10 - Retract filament according to settings of M207
3888
   */
3889
  inline void gcode_G10() {
3890
    #if EXTRUDERS > 1
3891
      const bool rs = parser.boolval('S');
3892
    #endif
3893
    fwretract.retract(true
3894
      #if EXTRUDERS > 1
3895
        , rs
3896
      #endif
3897
    );
3898
  }
3899
 
3900
  /**
3901
   * G11 - Recover filament according to settings of M208
3902
   */
3903
  inline void gcode_G11() { fwretract.retract(false); }
3904
 
3905
#endif // FWRETRACT
3906
 
3907
#if ENABLED(NOZZLE_CLEAN_FEATURE)
3908
  /**
3909
   * G12: Clean the nozzle
3910
   */
3911
  inline void gcode_G12() {
3912
    // Don't allow nozzle cleaning without homing first
3913
    if (axis_unhomed_error()) return;
3914
 
3915
    const uint8_t pattern = parser.ushortval('P', 0),
3916
                  strokes = parser.ushortval('S', NOZZLE_CLEAN_STROKES),
3917
                  objects = parser.ushortval('T', NOZZLE_CLEAN_TRIANGLES);
3918
    const float radius = parser.floatval('R', NOZZLE_CLEAN_CIRCLE_RADIUS);
3919
 
3920
    Nozzle::clean(pattern, strokes, radius, objects);
3921
  }
3922
#endif
3923
 
3924
#if ENABLED(CNC_WORKSPACE_PLANES)
3925
 
3926
  inline void report_workspace_plane() {
3927
    SERIAL_ECHO_START();
3928
    SERIAL_ECHOPGM("Workspace Plane ");
3929
    serialprintPGM(
3930
      workspace_plane == PLANE_YZ ? PSTR("YZ\n") :
3931
      workspace_plane == PLANE_ZX ? PSTR("ZX\n") :
3932
                                    PSTR("XY\n")
3933
    );
3934
  }
3935
 
3936
  inline void set_workspace_plane(const WorkspacePlane plane) {
3937
    workspace_plane = plane;
3938
    if (DEBUGGING(INFO)) report_workspace_plane();
3939
  }
3940
 
3941
  /**
3942
   * G17: Select Plane XY
3943
   * G18: Select Plane ZX
3944
   * G19: Select Plane YZ
3945
   */
3946
  inline void gcode_G17() { set_workspace_plane(PLANE_XY); }
3947
  inline void gcode_G18() { set_workspace_plane(PLANE_ZX); }
3948
  inline void gcode_G19() { set_workspace_plane(PLANE_YZ); }
3949
 
3950
#endif // CNC_WORKSPACE_PLANES
3951
 
3952
#if ENABLED(CNC_COORDINATE_SYSTEMS)
3953
 
3954
  /**
3955
   * Select a coordinate system and update the workspace offset.
3956
   * System index -1 is used to specify machine-native.
3957
   */
3958
  bool select_coordinate_system(const int8_t _new) {
3959
    if (active_coordinate_system == _new) return false;
3960
    float old_offset[XYZ] = { 0 }, new_offset[XYZ] = { 0 };
3961
    if (WITHIN(active_coordinate_system, 0, MAX_COORDINATE_SYSTEMS - 1))
3962
      COPY(old_offset, coordinate_system[active_coordinate_system]);
3963
    if (WITHIN(_new, 0, MAX_COORDINATE_SYSTEMS - 1))
3964
      COPY(new_offset, coordinate_system[_new]);
3965
    active_coordinate_system = _new;
3966
    LOOP_XYZ(i) {
3967
      const float diff = new_offset[i] - old_offset[i];
3968
      if (diff) {
3969
        position_shift[i] += diff;
3970
        update_software_endstops((AxisEnum)i);
3971
      }
3972
    }
3973
    return true;
3974
  }
3975
 
3976
  /**
3977
   * G53: Apply native workspace to the current move
3978
   *
3979
   * In CNC G-code G53 is a modifier.
3980
   * It precedes a movement command (or other modifiers) on the same line.
3981
   * This is the first command to use parser.chain() to make this possible.
3982
   *
3983
   * Marlin also uses G53 on a line by itself to go back to native space.
3984
   */
3985
  inline void gcode_G53() {
3986
    const int8_t _system = active_coordinate_system;
3987
    active_coordinate_system = -1;
3988
    if (parser.chain()) { // If this command has more following...
3989
      process_parsed_command();
3990
      active_coordinate_system = _system;
3991
    }
3992
  }
3993
 
3994
  /**
3995
   * G54-G59.3: Select a new workspace
3996
   *
3997
   * A workspace is an XYZ offset to the machine native space.
3998
   * All workspaces default to 0,0,0 at start, or with EEPROM
3999
   * support they may be restored from a previous session.
4000
   *
4001
   * G92 is used to set the current workspace's offset.
4002
   */
4003
  inline void gcode_G54_59(uint8_t subcode=0) {
4004
    const int8_t _space = parser.codenum - 54 + subcode;
4005
    if (select_coordinate_system(_space)) {
4006
      SERIAL_PROTOCOLLNPAIR("Select workspace ", _space);
4007
      report_current_position();
4008
    }
4009
  }
4010
  FORCE_INLINE void gcode_G54() { gcode_G54_59(); }
4011
  FORCE_INLINE void gcode_G55() { gcode_G54_59(); }
4012
  FORCE_INLINE void gcode_G56() { gcode_G54_59(); }
4013
  FORCE_INLINE void gcode_G57() { gcode_G54_59(); }
4014
  FORCE_INLINE void gcode_G58() { gcode_G54_59(); }
4015
  FORCE_INLINE void gcode_G59() { gcode_G54_59(parser.subcode); }
4016
 
4017
#endif
4018
 
4019
#if ENABLED(INCH_MODE_SUPPORT)
4020
  /**
4021
   * G20: Set input mode to inches
4022
   */
4023
  inline void gcode_G20() { parser.set_input_linear_units(LINEARUNIT_INCH); }
4024
 
4025
  /**
4026
   * G21: Set input mode to millimeters
4027
   */
4028
  inline void gcode_G21() { parser.set_input_linear_units(LINEARUNIT_MM); }
4029
#endif
4030
 
4031
#if ENABLED(NOZZLE_PARK_FEATURE)
4032
  /**
4033
   * G27: Park the nozzle
4034
   */
4035
  inline void gcode_G27() {
4036
    // Don't allow nozzle parking without homing first
4037
    if (axis_unhomed_error()) return;
4038
    Nozzle::park(parser.ushortval('P'));
4039
  }
4040
#endif // NOZZLE_PARK_FEATURE
4041
 
4042
#if ENABLED(QUICK_HOME)
4043
 
4044
  static void quick_home_xy() {
4045
 
4046
    // Pretend the current position is 0,0
4047
    current_position[X_AXIS] = current_position[Y_AXIS] = 0.0;
4048
    sync_plan_position();
4049
 
4050
    const int x_axis_home_dir =
4051
      #if ENABLED(DUAL_X_CARRIAGE)
4052
        x_home_dir(active_extruder)
4053
      #else
4054
        home_dir(X_AXIS)
4055
      #endif
4056
    ;
4057
 
4058
    const float mlx = max_length(X_AXIS),
4059
                mly = max_length(Y_AXIS),
4060
                mlratio = mlx > mly ? mly / mlx : mlx / mly,
4061
                fr_mm_s = MIN(homing_feedrate(X_AXIS), homing_feedrate(Y_AXIS)) * SQRT(sq(mlratio) + 1.0);
4062
 
4063
    #if ENABLED(SENSORLESS_HOMING)
4064
      sensorless_homing_per_axis(X_AXIS);
4065
      sensorless_homing_per_axis(Y_AXIS);
4066
    #endif
4067
 
4068
    do_blocking_move_to_xy(1.5 * mlx * x_axis_home_dir, 1.5 * mly * home_dir(Y_AXIS), fr_mm_s);
4069
 
4070
    endstops.validate_homing_move();
4071
 
4072
    current_position[X_AXIS] = current_position[Y_AXIS] = 0.0;
4073
 
4074
    #if ENABLED(SENSORLESS_HOMING)
4075
      sensorless_homing_per_axis(X_AXIS, false);
4076
      sensorless_homing_per_axis(Y_AXIS, false);
4077
    #endif
4078
  }
4079
 
4080
#endif // QUICK_HOME
4081
 
4082
#if ENABLED(DEBUG_LEVELING_FEATURE)
4083
 
4084
  void log_machine_info() {
4085
    SERIAL_ECHOPGM("Machine Type: ");
4086
    #if ENABLED(DELTA)
4087
      SERIAL_ECHOLNPGM("Delta");
4088
    #elif IS_SCARA
4089
      SERIAL_ECHOLNPGM("SCARA");
4090
    #elif IS_CORE
4091
      SERIAL_ECHOLNPGM("Core");
4092
    #else
4093
      SERIAL_ECHOLNPGM("Cartesian");
4094
    #endif
4095
 
4096
    SERIAL_ECHOPGM("Probe: ");
4097
    #if ENABLED(PROBE_MANUALLY)
4098
      SERIAL_ECHOLNPGM("PROBE_MANUALLY");
4099
    #elif ENABLED(FIX_MOUNTED_PROBE)
4100
      SERIAL_ECHOLNPGM("FIX_MOUNTED_PROBE");
4101
    #elif ENABLED(BLTOUCH)
4102
      SERIAL_ECHOLNPGM("BLTOUCH");
4103
    #elif HAS_Z_SERVO_PROBE
4104
      SERIAL_ECHOLNPGM("SERVO PROBE");
4105
    #elif ENABLED(Z_PROBE_SLED)
4106
      SERIAL_ECHOLNPGM("Z_PROBE_SLED");
4107
    #elif ENABLED(Z_PROBE_ALLEN_KEY)
4108
      SERIAL_ECHOLNPGM("Z_PROBE_ALLEN_KEY");
4109
    #else
4110
      SERIAL_ECHOLNPGM("NONE");
4111
    #endif
4112
 
4113
    #if HAS_BED_PROBE
4114
      SERIAL_ECHOPAIR("Probe Offset X:", X_PROBE_OFFSET_FROM_EXTRUDER);
4115
      SERIAL_ECHOPAIR(" Y:", Y_PROBE_OFFSET_FROM_EXTRUDER);
4116
      SERIAL_ECHOPAIR(" Z:", zprobe_zoffset);
4117
      #if X_PROBE_OFFSET_FROM_EXTRUDER > 0
4118
        SERIAL_ECHOPGM(" (Right");
4119
      #elif X_PROBE_OFFSET_FROM_EXTRUDER < 0
4120
        SERIAL_ECHOPGM(" (Left");
4121
      #elif Y_PROBE_OFFSET_FROM_EXTRUDER != 0
4122
        SERIAL_ECHOPGM(" (Middle");
4123
      #else
4124
        SERIAL_ECHOPGM(" (Aligned With");
4125
      #endif
4126
      #if Y_PROBE_OFFSET_FROM_EXTRUDER > 0
4127
        #if IS_SCARA
4128
          SERIAL_ECHOPGM("-Distal");
4129
        #else
4130
          SERIAL_ECHOPGM("-Back");
4131
        #endif
4132
      #elif Y_PROBE_OFFSET_FROM_EXTRUDER < 0
4133
        #if IS_SCARA
4134
          SERIAL_ECHOPGM("-Proximal");
4135
        #else
4136
          SERIAL_ECHOPGM("-Front");
4137
        #endif
4138
      #elif X_PROBE_OFFSET_FROM_EXTRUDER != 0
4139
        SERIAL_ECHOPGM("-Center");
4140
      #endif
4141
      if (zprobe_zoffset < 0)
4142
        SERIAL_ECHOPGM(" & Below");
4143
      else if (zprobe_zoffset > 0)
4144
        SERIAL_ECHOPGM(" & Above");
4145
      else
4146
        SERIAL_ECHOPGM(" & Same Z as");
4147
      SERIAL_ECHOLNPGM(" Nozzle)");
4148
    #endif
4149
 
4150
    #if HAS_ABL
4151
      SERIAL_ECHOPGM("Auto Bed Leveling: ");
4152
      #if ENABLED(AUTO_BED_LEVELING_LINEAR)
4153
        SERIAL_ECHOPGM("LINEAR");
4154
      #elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
4155
        SERIAL_ECHOPGM("BILINEAR");
4156
      #elif ENABLED(AUTO_BED_LEVELING_3POINT)
4157
        SERIAL_ECHOPGM("3POINT");
4158
      #elif ENABLED(AUTO_BED_LEVELING_UBL)
4159
        SERIAL_ECHOPGM("UBL");
4160
      #endif
4161
      if (planner.leveling_active) {
4162
        SERIAL_ECHOLNPGM(" (enabled)");
4163
        #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
4164
          if (planner.z_fade_height)
4165
            SERIAL_ECHOLNPAIR("Z Fade: ", planner.z_fade_height);
4166
        #endif
4167
        #if ABL_PLANAR
4168
          const float diff[XYZ] = {
4169
            planner.get_axis_position_mm(X_AXIS) - current_position[X_AXIS],
4170
            planner.get_axis_position_mm(Y_AXIS) - current_position[Y_AXIS],
4171
            planner.get_axis_position_mm(Z_AXIS) - current_position[Z_AXIS]
4172
          };
4173
          SERIAL_ECHOPGM("ABL Adjustment X");
4174
          if (diff[X_AXIS] > 0) SERIAL_CHAR('+');
4175
          SERIAL_ECHO(diff[X_AXIS]);
4176
          SERIAL_ECHOPGM(" Y");
4177
          if (diff[Y_AXIS] > 0) SERIAL_CHAR('+');
4178
          SERIAL_ECHO(diff[Y_AXIS]);
4179
          SERIAL_ECHOPGM(" Z");
4180
          if (diff[Z_AXIS] > 0) SERIAL_CHAR('+');
4181
          SERIAL_ECHO(diff[Z_AXIS]);
4182
        #else
4183
          #if ENABLED(AUTO_BED_LEVELING_UBL)
4184
            SERIAL_ECHOPGM("UBL Adjustment Z");
4185
            const float rz = ubl.get_z_correction(current_position[X_AXIS], current_position[Y_AXIS]);
4186
          #elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
4187
            SERIAL_ECHOPAIR("Bilinear Grid X", bilinear_start[X_AXIS]);
4188
            SERIAL_ECHOPAIR(" Y", bilinear_start[Y_AXIS]);
4189
            SERIAL_ECHOPAIR(" W", ABL_BG_SPACING(X_AXIS));
4190
            SERIAL_ECHOLNPAIR(" H", ABL_BG_SPACING(Y_AXIS));
4191
            SERIAL_ECHOPGM("ABL Adjustment Z");
4192
            const float rz = bilinear_z_offset(current_position);
4193
          #endif
4194
          SERIAL_ECHO(ftostr43sign(rz, '+'));
4195
          #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
4196
            if (planner.z_fade_height) {
4197
              SERIAL_ECHOPAIR(" (", ftostr43sign(rz * planner.fade_scaling_factor_for_z(current_position[Z_AXIS]), '+'));
4198
              SERIAL_CHAR(')');
4199
            }
4200
          #endif
4201
        #endif
4202
      }
4203
      else
4204
        SERIAL_ECHOLNPGM(" (disabled)");
4205
 
4206
      SERIAL_EOL();
4207
 
4208
    #elif ENABLED(MESH_BED_LEVELING)
4209
 
4210
      SERIAL_ECHOPGM("Mesh Bed Leveling");
4211
      if (planner.leveling_active) {
4212
        SERIAL_ECHOLNPGM(" (enabled)");
4213
        SERIAL_ECHOPAIR("MBL Adjustment Z", ftostr43sign(mbl.get_z(current_position[X_AXIS], current_position[Y_AXIS]
4214
          #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
4215
            , 1.0
4216
          #endif
4217
        ), '+'));
4218
        #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
4219
          if (planner.z_fade_height) {
4220
            SERIAL_ECHOPAIR(" (", ftostr43sign(
4221
              mbl.get_z(current_position[X_AXIS], current_position[Y_AXIS], planner.fade_scaling_factor_for_z(current_position[Z_AXIS])), '+'
4222
            ));
4223
            SERIAL_CHAR(')');
4224
          }
4225
        #endif
4226
      }
4227
      else
4228
        SERIAL_ECHOPGM(" (disabled)");
4229
 
4230
      SERIAL_EOL();
4231
 
4232
    #endif // MESH_BED_LEVELING
4233
  }
4234
 
4235
#endif // DEBUG_LEVELING_FEATURE
4236
 
4237
#if ENABLED(DELTA)
4238
 
4239
  #if ENABLED(SENSORLESS_HOMING)
4240
    inline void delta_sensorless_homing(const bool on=true) {
4241
      sensorless_homing_per_axis(A_AXIS, on);
4242
      sensorless_homing_per_axis(B_AXIS, on);
4243
      sensorless_homing_per_axis(C_AXIS, on);
4244
    }
4245
  #endif
4246
 
4247
  /**
4248
   * A delta can only safely home all axes at the same time
4249
   * This is like quick_home_xy() but for 3 towers.
4250
   */
4251
  inline void home_delta() {
4252
    #if ENABLED(DEBUG_LEVELING_FEATURE)
4253
      if (DEBUGGING(LEVELING)) DEBUG_POS(">>> home_delta", current_position);
4254
    #endif
4255
    // Init the current position of all carriages to 0,0,0
4256
    ZERO(current_position);
4257
    sync_plan_position();
4258
 
4259
    // Disable stealthChop if used. Enable diag1 pin on driver.
4260
    #if ENABLED(SENSORLESS_HOMING)
4261
      delta_sensorless_homing();
4262
    #endif
4263
 
4264
    // Move all carriages together linearly until an endstop is hit.
4265
    current_position[X_AXIS] = current_position[Y_AXIS] = current_position[Z_AXIS] = (delta_height + 10
4266
      #if HAS_BED_PROBE
4267
        - zprobe_zoffset
4268
      #endif
4269
    );
4270
    feedrate_mm_s = homing_feedrate(X_AXIS);
4271
    buffer_line_to_current_position();
4272
    planner.synchronize();
4273
 
4274
    // Re-enable stealthChop if used. Disable diag1 pin on driver.
4275
    #if ENABLED(SENSORLESS_HOMING)
4276
      delta_sensorless_homing(false);
4277
    #endif
4278
 
4279
    endstops.validate_homing_move();
4280
 
4281
    // At least one carriage has reached the top.
4282
    // Now re-home each carriage separately.
4283
    homeaxis(A_AXIS);
4284
    homeaxis(B_AXIS);
4285
    homeaxis(C_AXIS);
4286
 
4287
    // Set all carriages to their home positions
4288
    // Do this here all at once for Delta, because
4289
    // XYZ isn't ABC. Applying this per-tower would
4290
    // give the impression that they are the same.
4291
    LOOP_XYZ(i) set_axis_is_at_home((AxisEnum)i);
4292
 
4293
    SYNC_PLAN_POSITION_KINEMATIC();
4294
 
4295
    #if ENABLED(DEBUG_LEVELING_FEATURE)
4296
      if (DEBUGGING(LEVELING)) DEBUG_POS("<<< home_delta", current_position);
4297
    #endif
4298
  }
4299
 
4300
#elif ENABLED(HANGPRINTER)
4301
  /**
4302
   * A hangprinter cannot home itself
4303
   */
4304
  inline void home_hangprinter() {
4305
    SERIAL_ECHOLNPGM("Warning: G28 is not implemented for Hangprinter.");
4306
  }
4307
 
4308
#endif
4309
 
4310
#ifdef Z_AFTER_PROBING
4311
  void move_z_after_probing() {
4312
    if (current_position[Z_AXIS] != Z_AFTER_PROBING) {
4313
      do_blocking_move_to_z(Z_AFTER_PROBING);
4314
      current_position[Z_AXIS] = Z_AFTER_PROBING;
4315
    }
4316
  }
4317
#endif
4318
 
4319
#if ENABLED(Z_SAFE_HOMING)
4320
 
4321
  inline void home_z_safely() {
4322
 
4323
    // Disallow Z homing if X or Y are unknown
4324
    if (!TEST(axis_known_position, X_AXIS) || !TEST(axis_known_position, Y_AXIS)) {
4325
      LCD_MESSAGEPGM(MSG_ERR_Z_HOMING);
4326
      SERIAL_ECHO_START();
4327
      SERIAL_ECHOLNPGM(MSG_ERR_Z_HOMING);
4328
      return;
4329
    }
4330
 
4331
    #if ENABLED(DEBUG_LEVELING_FEATURE)
4332
      if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("Z_SAFE_HOMING >>>");
4333
    #endif
4334
 
4335
    SYNC_PLAN_POSITION_KINEMATIC();
4336
 
4337
    /**
4338
     * Move the Z probe (or just the nozzle) to the safe homing point
4339
     */
4340
    destination[X_AXIS] = Z_SAFE_HOMING_X_POINT;
4341
    destination[Y_AXIS] = Z_SAFE_HOMING_Y_POINT;
4342
    destination[Z_AXIS] = current_position[Z_AXIS]; // Z is already at the right height
4343
 
4344
    #if HOMING_Z_WITH_PROBE
4345
      destination[X_AXIS] -= X_PROBE_OFFSET_FROM_EXTRUDER;
4346
      destination[Y_AXIS] -= Y_PROBE_OFFSET_FROM_EXTRUDER;
4347
    #endif
4348
 
4349
    if (position_is_reachable(destination[X_AXIS], destination[Y_AXIS])) {
4350
 
4351
      #if ENABLED(DEBUG_LEVELING_FEATURE)
4352
        if (DEBUGGING(LEVELING)) DEBUG_POS("Z_SAFE_HOMING", destination);
4353
      #endif
4354
 
4355
      // This causes the carriage on Dual X to unpark
4356
      #if ENABLED(DUAL_X_CARRIAGE)
4357
        active_extruder_parked = false;
4358
      #endif
4359
 
4360
      #if ENABLED(SENSORLESS_HOMING)
4361
        safe_delay(500); // Short delay needed to settle
4362
      #endif
4363
 
4364
      do_blocking_move_to_xy(destination[X_AXIS], destination[Y_AXIS]);
4365
      homeaxis(Z_AXIS);
4366
    }
4367
    else {
4368
      LCD_MESSAGEPGM(MSG_ZPROBE_OUT);
4369
      SERIAL_ECHO_START();
4370
      SERIAL_ECHOLNPGM(MSG_ZPROBE_OUT);
4371
    }
4372
 
4373
    #if ENABLED(DEBUG_LEVELING_FEATURE)
4374
      if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("<<< Z_SAFE_HOMING");
4375
    #endif
4376
  }
4377
 
4378
#endif // Z_SAFE_HOMING
4379
 
4380
#if ENABLED(PROBE_MANUALLY)
4381
  bool g29_in_progress = false;
4382
#else
4383
  constexpr bool g29_in_progress = false;
4384
#endif
4385
 
4386
/**
4387
 * G28: Home all axes according to settings
4388
 *
4389
 * Parameters
4390
 *
4391
 *  None  Home to all axes with no parameters.
4392
 *        With QUICK_HOME enabled XY will home together, then Z.
4393
 *
4394
 *  O   Home only if position is unknown
4395
 *
4396
 *  Rn  Raise by n mm/inches before homing
4397
 *
4398
 * Cartesian parameters
4399
 *
4400
 *  X   Home to the X endstop
4401
 *  Y   Home to the Y endstop
4402
 *  Z   Home to the Z endstop
4403
 *
4404
 */
4405
inline void gcode_G28(const bool always_home_all) {
4406
 
4407
  #if ENABLED(DEBUG_LEVELING_FEATURE)
4408
    if (DEBUGGING(LEVELING)) {
4409
      SERIAL_ECHOLNPGM(">>> G28");
4410
      log_machine_info();
4411
    }
4412
  #endif
4413
 
4414
  #if ENABLED(MARLIN_DEV_MODE)
4415
    if (parser.seen('S')) {
4416
      LOOP_XYZ(a) set_axis_is_at_home((AxisEnum)a);
4417
      SYNC_PLAN_POSITION_KINEMATIC();
4418
      SERIAL_ECHOLNPGM("Simulated Homing");
4419
      report_current_position();
4420
      #if ENABLED(DEBUG_LEVELING_FEATURE)
4421
        if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("<<< G28");
4422
      #endif
4423
      return;
4424
    }
4425
  #endif
4426
 
4427
  if (all_axes_known() && parser.boolval('O')) { // home only if needed
4428
    #if ENABLED(DEBUG_LEVELING_FEATURE)
4429
      if (DEBUGGING(LEVELING)) {
4430
        SERIAL_ECHOLNPGM("> homing not needed, skip");
4431
        SERIAL_ECHOLNPGM("<<< G28");
4432
      }
4433
    #endif
4434
    return;
4435
  }
4436
 
4437
  // Wait for planner moves to finish!
4438
  planner.synchronize();
4439
 
4440
  // Cancel the active G29 session
4441
  #if ENABLED(PROBE_MANUALLY)
4442
    g29_in_progress = false;
4443
  #endif
4444
 
4445
  // Disable the leveling matrix before homing
4446
  #if HAS_LEVELING
4447
    #if ENABLED(RESTORE_LEVELING_AFTER_G28)
4448
      const bool leveling_was_active = planner.leveling_active;
4449
    #endif
4450
    set_bed_leveling_enabled(false);
4451
  #endif
4452
 
4453
  #if ENABLED(CNC_WORKSPACE_PLANES)
4454
    workspace_plane = PLANE_XY;
4455
  #endif
4456
 
4457
  #if ENABLED(BLTOUCH)
4458
    // Make sure any BLTouch error condition is cleared
4459
    bltouch_command(BLTOUCH_RESET, BLTOUCH_RESET_DELAY);
4460
    set_bltouch_deployed(false);
4461
  #endif
4462
 
4463
  // Always home with tool 0 active
4464
  #if HOTENDS > 1
4465
    #if DISABLED(DELTA) || ENABLED(DELTA_HOME_TO_SAFE_ZONE)
4466
      const uint8_t old_tool_index = active_extruder;
4467
    #endif
4468
    tool_change(0, 0, true);
4469
  #endif
4470
 
4471
  #if ENABLED(DUAL_X_CARRIAGE) || ENABLED(DUAL_NOZZLE_DUPLICATION_MODE)
4472
    extruder_duplication_enabled = false;
4473
  #endif
4474
 
4475
  setup_for_endstop_or_probe_move();
4476
  #if ENABLED(DEBUG_LEVELING_FEATURE)
4477
    if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("> endstops.enable(true)");
4478
  #endif
4479
  endstops.enable(true); // Enable endstops for next homing move
4480
 
4481
  #if ENABLED(DELTA)
4482
 
4483
    home_delta();
4484
    UNUSED(always_home_all);
4485
 
4486
  #elif ENABLED(HANGPRINTER)
4487
 
4488
    home_hangprinter();
4489
    UNUSED(always_home_all);
4490
 
4491
  #else // NOT Delta or Hangprinter
4492
 
4493
    const bool homeX = always_home_all || parser.seen('X'),
4494
               homeY = always_home_all || parser.seen('Y'),
4495
               homeZ = always_home_all || parser.seen('Z'),
4496
               home_all = (!homeX && !homeY && !homeZ) || (homeX && homeY && homeZ);
4497
 
4498
    set_destination_from_current();
4499
 
4500
    #if Z_HOME_DIR > 0  // If homing away from BED do Z first
4501
 
4502
      if (home_all || homeZ) homeaxis(Z_AXIS);
4503
 
4504
    #endif
4505
 
4506
    const float z_homing_height = (
4507
      #if ENABLED(UNKNOWN_Z_NO_RAISE)
4508
        !TEST(axis_known_position, Z_AXIS) ? 0 :
4509
      #endif
4510
          (parser.seenval('R') ? parser.value_linear_units() : Z_HOMING_HEIGHT)
4511
    );
4512
 
4513
    if (z_homing_height && (home_all || homeX || homeY)) {
4514
      // Raise Z before homing any other axes and z is not already high enough (never lower z)
4515
      destination[Z_AXIS] = z_homing_height;
4516
      if (destination[Z_AXIS] > current_position[Z_AXIS]) {
4517
 
4518
        #if ENABLED(DEBUG_LEVELING_FEATURE)
4519
          if (DEBUGGING(LEVELING))
4520
            SERIAL_ECHOLNPAIR("Raise Z (before homing) to ", destination[Z_AXIS]);
4521
        #endif
4522
 
4523
        do_blocking_move_to_z(destination[Z_AXIS]);
4524
      }
4525
    }
4526
 
4527
    #if ENABLED(QUICK_HOME)
4528
 
4529
      if (home_all || (homeX && homeY)) quick_home_xy();
4530
 
4531
    #endif
4532
 
4533
    // Home Y (before X)
4534
    #if ENABLED(HOME_Y_BEFORE_X)
4535
 
4536
      if (home_all || homeY
4537
        #if ENABLED(CODEPENDENT_XY_HOMING)
4538
          || homeX
4539
        #endif
4540
      ) homeaxis(Y_AXIS);
4541
 
4542
    #endif
4543
 
4544
    // Home X
4545
    if (home_all || homeX
4546
      #if ENABLED(CODEPENDENT_XY_HOMING) && DISABLED(HOME_Y_BEFORE_X)
4547
        || homeY
4548
      #endif
4549
    ) {
4550
 
4551
      #if ENABLED(DUAL_X_CARRIAGE)
4552
 
4553
        // Always home the 2nd (right) extruder first
4554
        active_extruder = 1;
4555
        homeaxis(X_AXIS);
4556
 
4557
        // Remember this extruder's position for later tool change
4558
        inactive_extruder_x_pos = current_position[X_AXIS];
4559
 
4560
        // Home the 1st (left) extruder
4561
        active_extruder = 0;
4562
        homeaxis(X_AXIS);
4563
 
4564
        // Consider the active extruder to be parked
4565
        COPY(raised_parked_position, current_position);
4566
        delayed_move_time = 0;
4567
        active_extruder_parked = true;
4568
 
4569
      #else
4570
 
4571
        homeaxis(X_AXIS);
4572
 
4573
      #endif
4574
    }
4575
 
4576
    // Home Y (after X)
4577
    #if DISABLED(HOME_Y_BEFORE_X)
4578
      if (home_all || homeY) homeaxis(Y_AXIS);
4579
    #endif
4580
 
4581
    // Home Z last if homing towards the bed
4582
    #if Z_HOME_DIR < 0
4583
      if (home_all || homeZ) {
4584
        #if ENABLED(Z_SAFE_HOMING)
4585
          home_z_safely();
4586
        #else
4587
          homeaxis(Z_AXIS);
4588
        #endif
4589
 
4590
        #if HOMING_Z_WITH_PROBE && defined(Z_AFTER_PROBING)
4591
          move_z_after_probing();
4592
        #endif
4593
 
4594
      } // home_all || homeZ
4595
    #endif // Z_HOME_DIR < 0
4596
 
4597
    SYNC_PLAN_POSITION_KINEMATIC();
4598
 
4599
  #endif // !DELTA (gcode_G28)
4600
 
4601
  endstops.not_homing();
4602
 
4603
  #if ENABLED(DELTA) && ENABLED(DELTA_HOME_TO_SAFE_ZONE)
4604
    // move to a height where we can use the full xy-area
4605
    do_blocking_move_to_z(delta_clip_start_height);
4606
  #endif
4607
 
4608
  #if ENABLED(RESTORE_LEVELING_AFTER_G28)
4609
    set_bed_leveling_enabled(leveling_was_active);
4610
  #endif
4611
 
4612
  clean_up_after_endstop_or_probe_move();
4613
 
4614
  // Restore the active tool after homing
4615
  #if HOTENDS > 1 && (DISABLED(DELTA) || ENABLED(DELTA_HOME_TO_SAFE_ZONE))
4616
    #if ENABLED(PARKING_EXTRUDER)
4617
      #define NO_FETCH false // fetch the previous toolhead
4618
    #else
4619
      #define NO_FETCH true
4620
    #endif
4621
    tool_change(old_tool_index, 0, NO_FETCH);
4622
  #endif
4623
 
4624
  lcd_refresh();
4625
 
4626
  report_current_position();
4627
 
4628
  #if ENABLED(NANODLP_Z_SYNC)
4629
    #if ENABLED(NANODLP_ALL_AXIS)
4630
      #define _HOME_SYNC true                 // For any axis, output sync text.
4631
    #else
4632
      #define _HOME_SYNC (home_all || homeZ)  // Only for Z-axis
4633
    #endif
4634
    if (_HOME_SYNC)
4635
      SERIAL_ECHOLNPGM(MSG_Z_MOVE_COMP);
4636
  #endif
4637
 
4638
  #if ENABLED(DEBUG_LEVELING_FEATURE)
4639
    if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("<<< G28");
4640
  #endif
4641
} // G28
4642
 
4643
void home_all_axes() { gcode_G28(true); }
4644
 
4645
#if ENABLED(MESH_BED_LEVELING) || ENABLED(PROBE_MANUALLY)
4646
 
4647
  inline void _manual_goto_xy(const float &rx, const float &ry) {
4648
 
4649
    #ifdef MANUAL_PROBE_START_Z
4650
      #if MANUAL_PROBE_HEIGHT > 0
4651
        do_blocking_move_to(rx, ry, MANUAL_PROBE_HEIGHT);
4652
        do_blocking_move_to_z(MAX(0,MANUAL_PROBE_START_Z));
4653
      #else
4654
        do_blocking_move_to(rx, ry, MAX(0,MANUAL_PROBE_START_Z));
4655
      #endif
4656
    #elif MANUAL_PROBE_HEIGHT > 0
4657
      const float prev_z = current_position[Z_AXIS];
4658
      do_blocking_move_to(rx, ry, MANUAL_PROBE_HEIGHT);
4659
      do_blocking_move_to_z(prev_z);
4660
    #else
4661
      do_blocking_move_to_xy(rx, ry);
4662
    #endif
4663
 
4664
    current_position[X_AXIS] = rx;
4665
    current_position[Y_AXIS] = ry;
4666
 
4667
    #if ENABLED(LCD_BED_LEVELING)
4668
      lcd_wait_for_move = false;
4669
    #endif
4670
  }
4671
 
4672
#endif
4673
 
4674
#if ENABLED(MESH_BED_LEVELING)
4675
 
4676
  // Save 130 bytes with non-duplication of PSTR
4677
  void echo_not_entered() { SERIAL_PROTOCOLLNPGM(" not entered."); }
4678
 
4679
  /**
4680
   * G29: Mesh-based Z probe, probes a grid and produces a
4681
   *      mesh to compensate for variable bed height
4682
   *
4683
   * Parameters With MESH_BED_LEVELING:
4684
   *
4685
   *  S0              Produce a mesh report
4686
   *  S1              Start probing mesh points
4687
   *  S2              Probe the next mesh point
4688
   *  S3 Xn Yn Zn.nn  Manually modify a single point
4689
   *  S4 Zn.nn        Set z offset. Positive away from bed, negative closer to bed.
4690
   *  S5              Reset and disable mesh
4691
   *
4692
   * The S0 report the points as below
4693
   *
4694
   *  +----> X-axis  1-n
4695
   *  |
4696
   *  |
4697
   *  v Y-axis  1-n
4698
   *
4699
   */
4700
  inline void gcode_G29() {
4701
 
4702
    static int mbl_probe_index = -1;
4703
    #if HAS_SOFTWARE_ENDSTOPS
4704
      static bool enable_soft_endstops;
4705
    #endif
4706
 
4707
    MeshLevelingState state = (MeshLevelingState)parser.byteval('S', (int8_t)MeshReport);
4708
    if (!WITHIN(state, 0, 5)) {
4709
      SERIAL_PROTOCOLLNPGM("S out of range (0-5).");
4710
      return;
4711
    }
4712
 
4713
    int8_t px, py;
4714
 
4715
    switch (state) {
4716
      case MeshReport:
4717
        if (leveling_is_valid()) {
4718
          SERIAL_PROTOCOLLNPAIR("State: ", planner.leveling_active ? MSG_ON : MSG_OFF);
4719
          mbl.report_mesh();
4720
        }
4721
        else
4722
          SERIAL_PROTOCOLLNPGM("Mesh bed leveling has no data.");
4723
        break;
4724
 
4725
      case MeshStart:
4726
        mbl.reset();
4727
        mbl_probe_index = 0;
4728
        if (!lcd_wait_for_move) {
4729
          enqueue_and_echo_commands_P(PSTR("G28\nG29 S2"));
4730
          return;
4731
        }
4732
        state = MeshNext;
4733
 
4734
      case MeshNext:
4735
        if (mbl_probe_index < 0) {
4736
          SERIAL_PROTOCOLLNPGM("Start mesh probing with \"G29 S1\" first.");
4737
          return;
4738
        }
4739
        // For each G29 S2...
4740
        if (mbl_probe_index == 0) {
4741
          #if HAS_SOFTWARE_ENDSTOPS
4742
            // For the initial G29 S2 save software endstop state
4743
            enable_soft_endstops = soft_endstops_enabled;
4744
          #endif
4745
          // Move close to the bed before the first point
4746
          do_blocking_move_to_z(0);
4747
        }
4748
        else {
4749
          // Save Z for the previous mesh position
4750
          mbl.set_zigzag_z(mbl_probe_index - 1, current_position[Z_AXIS]);
4751
          #if HAS_SOFTWARE_ENDSTOPS
4752
            soft_endstops_enabled = enable_soft_endstops;
4753
          #endif
4754
        }
4755
        // If there's another point to sample, move there with optional lift.
4756
        if (mbl_probe_index < GRID_MAX_POINTS) {
4757
          #if HAS_SOFTWARE_ENDSTOPS
4758
            // Disable software endstops to allow manual adjustment
4759
            // If G29 is not completed, they will not be re-enabled
4760
            soft_endstops_enabled = false;
4761
          #endif
4762
 
4763
          mbl.zigzag(mbl_probe_index++, px, py);
4764
          _manual_goto_xy(mbl.index_to_xpos[px], mbl.index_to_ypos[py]);
4765
        }
4766
        else {
4767
          // One last "return to the bed" (as originally coded) at completion
4768
          current_position[Z_AXIS] = MANUAL_PROBE_HEIGHT;
4769
          buffer_line_to_current_position();
4770
          planner.synchronize();
4771
 
4772
          // After recording the last point, activate home and activate
4773
          mbl_probe_index = -1;
4774
          SERIAL_PROTOCOLLNPGM("Mesh probing done.");
4775
          BUZZ(100, 659);
4776
          BUZZ(100, 698);
4777
 
4778
          home_all_axes();
4779
          set_bed_leveling_enabled(true);
4780
 
4781
          #if ENABLED(MESH_G28_REST_ORIGIN)
4782
            current_position[Z_AXIS] = 0;
4783
            set_destination_from_current();
4784
            buffer_line_to_destination(homing_feedrate(Z_AXIS));
4785
            planner.synchronize();
4786
          #endif
4787
 
4788
          #if ENABLED(LCD_BED_LEVELING)
4789
            lcd_wait_for_move = false;
4790
          #endif
4791
        }
4792
        break;
4793
 
4794
      case MeshSet:
4795
        if (parser.seenval('X')) {
4796
          px = parser.value_int() - 1;
4797
          if (!WITHIN(px, 0, GRID_MAX_POINTS_X - 1)) {
4798
            SERIAL_PROTOCOLPAIR("X out of range (1-", int(GRID_MAX_POINTS_X));
4799
            SERIAL_PROTOCOLLNPGM(")");
4800
            return;
4801
          }
4802
        }
4803
        else {
4804
          SERIAL_CHAR('X'); echo_not_entered();
4805
          return;
4806
        }
4807
 
4808
        if (parser.seenval('Y')) {
4809
          py = parser.value_int() - 1;
4810
          if (!WITHIN(py, 0, GRID_MAX_POINTS_Y - 1)) {
4811
            SERIAL_PROTOCOLPAIR("Y out of range (1-", int(GRID_MAX_POINTS_Y));
4812
            SERIAL_PROTOCOLLNPGM(")");
4813
            return;
4814
          }
4815
        }
4816
        else {
4817
          SERIAL_CHAR('Y'); echo_not_entered();
4818
          return;
4819
        }
4820
 
4821
        if (parser.seenval('Z'))
4822
          mbl.z_values[px][py] = parser.value_linear_units();
4823
        else {
4824
          SERIAL_CHAR('Z'); echo_not_entered();
4825
          return;
4826
        }
4827
        break;
4828
 
4829
      case MeshSetZOffset:
4830
        if (parser.seenval('Z'))
4831
          mbl.z_offset = parser.value_linear_units();
4832
        else {
4833
          SERIAL_CHAR('Z'); echo_not_entered();
4834
          return;
4835
        }
4836
        break;
4837
 
4838
      case MeshReset:
4839
        reset_bed_level();
4840
        break;
4841
 
4842
    } // switch (state)
4843
 
4844
    if (state == MeshNext) {
4845
      SERIAL_PROTOCOLPAIR("MBL G29 point ", MIN(mbl_probe_index, GRID_MAX_POINTS));
4846
      SERIAL_PROTOCOLLNPAIR(" of ", int(GRID_MAX_POINTS));
4847
    }
4848
 
4849
    report_current_position();
4850
  }
4851
 
4852
#elif OLDSCHOOL_ABL
4853
 
4854
  #if ABL_GRID
4855
    #if ENABLED(PROBE_Y_FIRST)
4856
      #define PR_OUTER_VAR xCount
4857
      #define PR_OUTER_END abl_grid_points_x
4858
      #define PR_INNER_VAR yCount
4859
      #define PR_INNER_END abl_grid_points_y
4860
    #else
4861
      #define PR_OUTER_VAR yCount
4862
      #define PR_OUTER_END abl_grid_points_y
4863
      #define PR_INNER_VAR xCount
4864
      #define PR_INNER_END abl_grid_points_x
4865
    #endif
4866
  #endif
4867
 
4868
  /**
4869
   * G29: Detailed Z probe, probes the bed at 3 or more points.
4870
   *      Will fail if the printer has not been homed with G28.
4871
   *
4872
   * Enhanced G29 Auto Bed Leveling Probe Routine
4873
   *
4874
   *  O  Auto-level only if needed
4875
   *
4876
   *  D  Dry-Run mode. Just evaluate the bed Topology - Don't apply
4877
   *     or alter the bed level data. Useful to check the topology
4878
   *     after a first run of G29.
4879
   *
4880
   *  J  Jettison current bed leveling data
4881
   *
4882
   *  V  Set the verbose level (0-4). Example: "G29 V3"
4883
   *
4884
   * Parameters With LINEAR leveling only:
4885
   *
4886
   *  P  Set the size of the grid that will be probed (P x P points).
4887
   *     Example: "G29 P4"
4888
   *
4889
   *  X  Set the X size of the grid that will be probed (X x Y points).
4890
   *     Example: "G29 X7 Y5"
4891
   *
4892
   *  Y  Set the Y size of the grid that will be probed (X x Y points).
4893
   *
4894
   *  T  Generate a Bed Topology Report. Example: "G29 P5 T" for a detailed report.
4895
   *     This is useful for manual bed leveling and finding flaws in the bed (to
4896
   *     assist with part placement).
4897
   *     Not supported by non-linear delta printer bed leveling.
4898
   *
4899
   * Parameters With LINEAR and BILINEAR leveling only:
4900
   *
4901
   *  S  Set the XY travel speed between probe points (in units/min)
4902
   *
4903
   *  F  Set the Front limit of the probing grid
4904
   *  B  Set the Back limit of the probing grid
4905
   *  L  Set the Left limit of the probing grid
4906
   *  R  Set the Right limit of the probing grid
4907
   *
4908
   * Parameters with DEBUG_LEVELING_FEATURE only:
4909
   *
4910
   *  C  Make a totally fake grid with no actual probing.
4911
   *     For use in testing when no probing is possible.
4912
   *
4913
   * Parameters with BILINEAR leveling only:
4914
   *
4915
   *  Z  Supply an additional Z probe offset
4916
   *
4917
   * Extra parameters with PROBE_MANUALLY:
4918
   *
4919
   *  To do manual probing simply repeat G29 until the procedure is complete.
4920
   *  The first G29 accepts parameters. 'G29 Q' for status, 'G29 A' to abort.
4921
   *
4922
   *  Q  Query leveling and G29 state
4923
   *
4924
   *  A  Abort current leveling procedure
4925
   *
4926
   * Extra parameters with BILINEAR only:
4927
   *
4928
   *  W  Write a mesh point. (If G29 is idle.)
4929
   *  I  X index for mesh point
4930
   *  J  Y index for mesh point
4931
   *  X  X for mesh point, overrides I
4932
   *  Y  Y for mesh point, overrides J
4933
   *  Z  Z for mesh point. Otherwise, raw current Z.
4934
   *
4935
   * Without PROBE_MANUALLY:
4936
   *
4937
   *  E  By default G29 will engage the Z probe, test the bed, then disengage.
4938
   *     Include "E" to engage/disengage the Z probe for each sample.
4939
   *     There's no extra effect if you have a fixed Z probe.
4940
   *
4941
   */
4942
  inline void gcode_G29() {
4943
 
4944
    #if ENABLED(DEBUG_LEVELING_FEATURE) || ENABLED(PROBE_MANUALLY)
4945
      const bool seenQ = parser.seen('Q');
4946
    #else
4947
      constexpr bool seenQ = false;
4948
    #endif
4949
 
4950
    // G29 Q is also available if debugging
4951
    #if ENABLED(DEBUG_LEVELING_FEATURE)
4952
      const uint8_t old_debug_flags = marlin_debug_flags;
4953
      if (seenQ) marlin_debug_flags |= DEBUG_LEVELING;
4954
      if (DEBUGGING(LEVELING)) {
4955
        DEBUG_POS(">>> G29", current_position);
4956
        log_machine_info();
4957
      }
4958
      marlin_debug_flags = old_debug_flags;
4959
      #if DISABLED(PROBE_MANUALLY)
4960
        if (seenQ) return;
4961
      #endif
4962
    #endif
4963
 
4964
    #if ENABLED(PROBE_MANUALLY)
4965
      const bool seenA = parser.seen('A');
4966
    #else
4967
      constexpr bool seenA = false;
4968
    #endif
4969
 
4970
    const bool  no_action = seenA || seenQ,
4971
                faux =
4972
                  #if ENABLED(DEBUG_LEVELING_FEATURE) && DISABLED(PROBE_MANUALLY)
4973
                    parser.boolval('C')
4974
                  #else
4975
                    no_action
4976
                  #endif
4977
                ;
4978
 
4979
    // Don't allow auto-leveling without homing first
4980
    if (axis_unhomed_error()) return;
4981
 
4982
    if (!no_action && planner.leveling_active && parser.boolval('O')) { // Auto-level only if needed
4983
      #if ENABLED(DEBUG_LEVELING_FEATURE)
4984
        if (DEBUGGING(LEVELING)) {
4985
          SERIAL_ECHOLNPGM("> Auto-level not needed, skip");
4986
          SERIAL_ECHOLNPGM("<<< G29");
4987
        }
4988
      #endif
4989
      return;
4990
    }
4991
 
4992
    // Define local vars 'static' for manual probing, 'auto' otherwise
4993
    #if ENABLED(PROBE_MANUALLY)
4994
      #define ABL_VAR static
4995
    #else
4996
      #define ABL_VAR
4997
    #endif
4998
 
4999
    ABL_VAR int verbose_level;
5000
    ABL_VAR float xProbe, yProbe, measured_z;
5001
    ABL_VAR bool dryrun, abl_should_enable;
5002
 
5003
    #if ENABLED(PROBE_MANUALLY) || ENABLED(AUTO_BED_LEVELING_LINEAR)
5004
      ABL_VAR int16_t abl_probe_index;
5005
    #endif
5006
 
5007
    #if HAS_SOFTWARE_ENDSTOPS && ENABLED(PROBE_MANUALLY)
5008
      ABL_VAR bool enable_soft_endstops = true;
5009
    #endif
5010
 
5011
    #if ABL_GRID
5012
 
5013
      #if ENABLED(PROBE_MANUALLY)
5014
        ABL_VAR uint8_t PR_OUTER_VAR;
5015
        ABL_VAR  int8_t PR_INNER_VAR;
5016
      #endif
5017
 
5018
      ABL_VAR int left_probe_bed_position, right_probe_bed_position, front_probe_bed_position, back_probe_bed_position;
5019
      ABL_VAR float xGridSpacing = 0, yGridSpacing = 0;
5020
 
5021
      #if ENABLED(AUTO_BED_LEVELING_LINEAR)
5022
        ABL_VAR uint8_t abl_grid_points_x = GRID_MAX_POINTS_X,
5023
                        abl_grid_points_y = GRID_MAX_POINTS_Y;
5024
        ABL_VAR bool do_topography_map;
5025
      #else // Bilinear
5026
        uint8_t constexpr abl_grid_points_x = GRID_MAX_POINTS_X,
5027
                          abl_grid_points_y = GRID_MAX_POINTS_Y;
5028
      #endif
5029
 
5030
      #if ENABLED(AUTO_BED_LEVELING_LINEAR)
5031
        ABL_VAR int16_t abl_points;
5032
      #elif ENABLED(PROBE_MANUALLY) // Bilinear
5033
        int16_t constexpr abl_points = GRID_MAX_POINTS;
5034
      #endif
5035
 
5036
      #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
5037
 
5038
        ABL_VAR float zoffset;
5039
 
5040
      #elif ENABLED(AUTO_BED_LEVELING_LINEAR)
5041
 
5042
        ABL_VAR int indexIntoAB[GRID_MAX_POINTS_X][GRID_MAX_POINTS_Y];
5043
 
5044
        ABL_VAR float eqnAMatrix[GRID_MAX_POINTS * 3], // "A" matrix of the linear system of equations
5045
                      eqnBVector[GRID_MAX_POINTS],     // "B" vector of Z points
5046
                      mean;
5047
      #endif
5048
 
5049
    #elif ENABLED(AUTO_BED_LEVELING_3POINT)
5050
 
5051
      #if ENABLED(PROBE_MANUALLY)
5052
        int8_t constexpr abl_points = 3; // used to show total points
5053
      #endif
5054
 
5055
      // Probe at 3 arbitrary points
5056
      ABL_VAR vector_3 points[3] = {
5057
        vector_3(PROBE_PT_1_X, PROBE_PT_1_Y, 0),
5058
        vector_3(PROBE_PT_2_X, PROBE_PT_2_Y, 0),
5059
        vector_3(PROBE_PT_3_X, PROBE_PT_3_Y, 0)
5060
      };
5061
 
5062
    #endif // AUTO_BED_LEVELING_3POINT
5063
 
5064
    #if ENABLED(AUTO_BED_LEVELING_LINEAR)
5065
      struct linear_fit_data lsf_results;
5066
      incremental_LSF_reset(&lsf_results);
5067
    #endif
5068
 
5069
    /**
5070
     * On the initial G29 fetch command parameters.
5071
     */
5072
    if (!g29_in_progress) {
5073
 
5074
      #if ENABLED(DUAL_X_CARRIAGE)
5075
        if (active_extruder != 0) tool_change(0);
5076
      #endif
5077
 
5078
      #if ENABLED(PROBE_MANUALLY) || ENABLED(AUTO_BED_LEVELING_LINEAR)
5079
        abl_probe_index = -1;
5080
      #endif
5081
 
5082
      abl_should_enable = planner.leveling_active;
5083
 
5084
      #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
5085
 
5086
        const bool seen_w = parser.seen('W');
5087
        if (seen_w) {
5088
          if (!leveling_is_valid()) {
5089
            SERIAL_ERROR_START();
5090
            SERIAL_ERRORLNPGM("No bilinear grid");
5091
            return;
5092
          }
5093
 
5094
          const float rz = parser.seenval('Z') ? RAW_Z_POSITION(parser.value_linear_units()) : current_position[Z_AXIS];
5095
          if (!WITHIN(rz, -10, 10)) {
5096
            SERIAL_ERROR_START();
5097
            SERIAL_ERRORLNPGM("Bad Z value");
5098
            return;
5099
          }
5100
 
5101
          const float rx = RAW_X_POSITION(parser.linearval('X', NAN)),
5102
                      ry = RAW_Y_POSITION(parser.linearval('Y', NAN));
5103
          int8_t i = parser.byteval('I', -1),
5104
                 j = parser.byteval('J', -1);
5105
 
5106
          if (!isnan(rx) && !isnan(ry)) {
5107
            // Get nearest i / j from rx / ry
5108
            i = (rx - bilinear_start[X_AXIS] + 0.5f * xGridSpacing) / xGridSpacing;
5109
            j = (ry - bilinear_start[Y_AXIS] + 0.5f * yGridSpacing) / yGridSpacing;
5110
            i = constrain(i, 0, GRID_MAX_POINTS_X - 1);
5111
            j = constrain(j, 0, GRID_MAX_POINTS_Y - 1);
5112
          }
5113
          if (WITHIN(i, 0, GRID_MAX_POINTS_X - 1) && WITHIN(j, 0, GRID_MAX_POINTS_Y)) {
5114
            set_bed_leveling_enabled(false);
5115
            z_values[i][j] = rz;
5116
            #if ENABLED(ABL_BILINEAR_SUBDIVISION)
5117
              bed_level_virt_interpolate();
5118
            #endif
5119
            set_bed_leveling_enabled(abl_should_enable);
5120
            if (abl_should_enable) report_current_position();
5121
          }
5122
          return;
5123
        } // parser.seen('W')
5124
 
5125
      #else
5126
 
5127
        constexpr bool seen_w = false;
5128
 
5129
      #endif
5130
 
5131
      // Jettison bed leveling data
5132
      if (!seen_w && parser.seen('J')) {
5133
        reset_bed_level();
5134
        return;
5135
      }
5136
 
5137
      verbose_level = parser.intval('V');
5138
      if (!WITHIN(verbose_level, 0, 4)) {
5139
        SERIAL_PROTOCOLLNPGM("?(V)erbose level is implausible (0-4).");
5140
        return;
5141
      }
5142
 
5143
      dryrun = parser.boolval('D')
5144
        #if ENABLED(PROBE_MANUALLY)
5145
          || no_action
5146
        #endif
5147
      ;
5148
 
5149
      #if ENABLED(AUTO_BED_LEVELING_LINEAR)
5150
 
5151
        do_topography_map = verbose_level > 2 || parser.boolval('T');
5152
 
5153
        // X and Y specify points in each direction, overriding the default
5154
        // These values may be saved with the completed mesh
5155
        abl_grid_points_x = parser.intval('X', GRID_MAX_POINTS_X);
5156
        abl_grid_points_y = parser.intval('Y', GRID_MAX_POINTS_Y);
5157
        if (parser.seenval('P')) abl_grid_points_x = abl_grid_points_y = parser.value_int();
5158
 
5159
        if (!WITHIN(abl_grid_points_x, 2, GRID_MAX_POINTS_X)) {
5160
          SERIAL_PROTOCOLLNPGM("?Probe points (X) is implausible (2-" STRINGIFY(GRID_MAX_POINTS_X) ").");
5161
          return;
5162
        }
5163
        if (!WITHIN(abl_grid_points_y, 2, GRID_MAX_POINTS_Y)) {
5164
          SERIAL_PROTOCOLLNPGM("?Probe points (Y) is implausible (2-" STRINGIFY(GRID_MAX_POINTS_Y) ").");
5165
          return;
5166
        }
5167
 
5168
        abl_points = abl_grid_points_x * abl_grid_points_y;
5169
        mean = 0;
5170
 
5171
      #elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
5172
 
5173
        zoffset = parser.linearval('Z');
5174
 
5175
      #endif
5176
 
5177
      #if ABL_GRID
5178
 
5179
        xy_probe_feedrate_mm_s = MMM_TO_MMS(parser.linearval('S', XY_PROBE_SPEED));
5180
 
5181
        left_probe_bed_position  = parser.seenval('L') ? int(RAW_X_POSITION(parser.value_linear_units())) : LEFT_PROBE_BED_POSITION;
5182
        right_probe_bed_position = parser.seenval('R') ? int(RAW_X_POSITION(parser.value_linear_units())) : RIGHT_PROBE_BED_POSITION;
5183
        front_probe_bed_position = parser.seenval('F') ? int(RAW_Y_POSITION(parser.value_linear_units())) : FRONT_PROBE_BED_POSITION;
5184
        back_probe_bed_position  = parser.seenval('B') ? int(RAW_Y_POSITION(parser.value_linear_units())) : BACK_PROBE_BED_POSITION;
5185
 
5186
        if (
5187
          #if IS_SCARA || ENABLED(DELTA)
5188
               !position_is_reachable_by_probe(left_probe_bed_position, 0)
5189
            || !position_is_reachable_by_probe(right_probe_bed_position, 0)
5190
            || !position_is_reachable_by_probe(0, front_probe_bed_position)
5191
            || !position_is_reachable_by_probe(0, back_probe_bed_position)
5192
          #else
5193
               !position_is_reachable_by_probe(left_probe_bed_position, front_probe_bed_position)
5194
            || !position_is_reachable_by_probe(right_probe_bed_position, back_probe_bed_position)
5195
          #endif
5196
        ) {
5197
          SERIAL_PROTOCOLLNPGM("? (L,R,F,B) out of bounds.");
5198
          return;
5199
        }
5200
 
5201
        // probe at the points of a lattice grid
5202
        xGridSpacing = (right_probe_bed_position - left_probe_bed_position) / (abl_grid_points_x - 1);
5203
        yGridSpacing = (back_probe_bed_position - front_probe_bed_position) / (abl_grid_points_y - 1);
5204
 
5205
      #endif // ABL_GRID
5206
 
5207
      if (verbose_level > 0) {
5208
        SERIAL_PROTOCOLPGM("G29 Auto Bed Leveling");
5209
        if (dryrun) SERIAL_PROTOCOLPGM(" (DRYRUN)");
5210
        SERIAL_EOL();
5211
      }
5212
 
5213
      planner.synchronize();
5214
 
5215
      // Disable auto bed leveling during G29.
5216
      // Be formal so G29 can be done successively without G28.
5217
      if (!no_action) set_bed_leveling_enabled(false);
5218
 
5219
      #if HAS_BED_PROBE
5220
        // Deploy the probe. Probe will raise if needed.
5221
        if (DEPLOY_PROBE()) {
5222
          set_bed_leveling_enabled(abl_should_enable);
5223
          return;
5224
        }
5225
      #endif
5226
 
5227
      if (!faux) setup_for_endstop_or_probe_move();
5228
 
5229
      #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
5230
 
5231
        #if ENABLED(PROBE_MANUALLY)
5232
          if (!no_action)
5233
        #endif
5234
        if ( xGridSpacing != bilinear_grid_spacing[X_AXIS]
5235
          || yGridSpacing != bilinear_grid_spacing[Y_AXIS]
5236
          || left_probe_bed_position != bilinear_start[X_AXIS]
5237
          || front_probe_bed_position != bilinear_start[Y_AXIS]
5238
        ) {
5239
          // Reset grid to 0.0 or "not probed". (Also disables ABL)
5240
          reset_bed_level();
5241
 
5242
          // Initialize a grid with the given dimensions
5243
          bilinear_grid_spacing[X_AXIS] = xGridSpacing;
5244
          bilinear_grid_spacing[Y_AXIS] = yGridSpacing;
5245
          bilinear_start[X_AXIS] = left_probe_bed_position;
5246
          bilinear_start[Y_AXIS] = front_probe_bed_position;
5247
 
5248
          // Can't re-enable (on error) until the new grid is written
5249
          abl_should_enable = false;
5250
        }
5251
 
5252
      #endif // AUTO_BED_LEVELING_BILINEAR
5253
 
5254
      #if ENABLED(AUTO_BED_LEVELING_3POINT)
5255
 
5256
        #if ENABLED(DEBUG_LEVELING_FEATURE)
5257
          if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("> 3-point Leveling");
5258
        #endif
5259
 
5260
        // Probe at 3 arbitrary points
5261
        points[0].z = points[1].z = points[2].z = 0;
5262
 
5263
      #endif // AUTO_BED_LEVELING_3POINT
5264
 
5265
    } // !g29_in_progress
5266
 
5267
    #if ENABLED(PROBE_MANUALLY)
5268
 
5269
      // For manual probing, get the next index to probe now.
5270
      // On the first probe this will be incremented to 0.
5271
      if (!no_action) {
5272
        ++abl_probe_index;
5273
        g29_in_progress = true;
5274
      }
5275
 
5276
      // Abort current G29 procedure, go back to idle state
5277
      if (seenA && g29_in_progress) {
5278
        SERIAL_PROTOCOLLNPGM("Manual G29 aborted");
5279
        #if HAS_SOFTWARE_ENDSTOPS
5280
          soft_endstops_enabled = enable_soft_endstops;
5281
        #endif
5282
        set_bed_leveling_enabled(abl_should_enable);
5283
        g29_in_progress = false;
5284
        #if ENABLED(LCD_BED_LEVELING)
5285
          lcd_wait_for_move = false;
5286
        #endif
5287
      }
5288
 
5289
      // Query G29 status
5290
      if (verbose_level || seenQ) {
5291
        SERIAL_PROTOCOLPGM("Manual G29 ");
5292
        if (g29_in_progress) {
5293
          SERIAL_PROTOCOLPAIR("point ", MIN(abl_probe_index + 1, abl_points));
5294
          SERIAL_PROTOCOLLNPAIR(" of ", abl_points);
5295
        }
5296
        else
5297
          SERIAL_PROTOCOLLNPGM("idle");
5298
      }
5299
 
5300
      if (no_action) return;
5301
 
5302
      if (abl_probe_index == 0) {
5303
        // For the initial G29 save software endstop state
5304
        #if HAS_SOFTWARE_ENDSTOPS
5305
          enable_soft_endstops = soft_endstops_enabled;
5306
        #endif
5307
        // Move close to the bed before the first point
5308
        do_blocking_move_to_z(0);
5309
      }
5310
      else {
5311
 
5312
        #if ENABLED(AUTO_BED_LEVELING_LINEAR) || ENABLED(AUTO_BED_LEVELING_3POINT)
5313
          const uint16_t index = abl_probe_index - 1;
5314
        #endif
5315
 
5316
        // For G29 after adjusting Z.
5317
        // Save the previous Z before going to the next point
5318
        measured_z = current_position[Z_AXIS];
5319
 
5320
        #if ENABLED(AUTO_BED_LEVELING_LINEAR)
5321
 
5322
          mean += measured_z;
5323
          eqnBVector[index] = measured_z;
5324
          eqnAMatrix[index + 0 * abl_points] = xProbe;
5325
          eqnAMatrix[index + 1 * abl_points] = yProbe;
5326
          eqnAMatrix[index + 2 * abl_points] = 1;
5327
 
5328
          incremental_LSF(&lsf_results, xProbe, yProbe, measured_z);
5329
 
5330
        #elif ENABLED(AUTO_BED_LEVELING_3POINT)
5331
 
5332
          points[index].z = measured_z;
5333
 
5334
        #elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
5335
 
5336
          z_values[xCount][yCount] = measured_z + zoffset;
5337
 
5338
          #if ENABLED(DEBUG_LEVELING_FEATURE)
5339
            if (DEBUGGING(LEVELING)) {
5340
              SERIAL_PROTOCOLPAIR("Save X", xCount);
5341
              SERIAL_PROTOCOLPAIR(" Y", yCount);
5342
              SERIAL_PROTOCOLLNPAIR(" Z", measured_z + zoffset);
5343
            }
5344
          #endif
5345
 
5346
        #endif
5347
      }
5348
 
5349
      //
5350
      // If there's another point to sample, move there with optional lift.
5351
      //
5352
 
5353
      #if ABL_GRID
5354
 
5355
        // Skip any unreachable points
5356
        while (abl_probe_index < abl_points) {
5357
 
5358
          // Set xCount, yCount based on abl_probe_index, with zig-zag
5359
          PR_OUTER_VAR = abl_probe_index / PR_INNER_END;
5360
          PR_INNER_VAR = abl_probe_index - (PR_OUTER_VAR * PR_INNER_END);
5361
 
5362
          // Probe in reverse order for every other row/column
5363
          bool zig = (PR_OUTER_VAR & 1); // != ((PR_OUTER_END) & 1);
5364
 
5365
          if (zig) PR_INNER_VAR = (PR_INNER_END - 1) - PR_INNER_VAR;
5366
 
5367
          const float xBase = xCount * xGridSpacing + left_probe_bed_position,
5368
                      yBase = yCount * yGridSpacing + front_probe_bed_position;
5369
 
5370
          xProbe = FLOOR(xBase + (xBase < 0 ? 0 : 0.5));
5371
          yProbe = FLOOR(yBase + (yBase < 0 ? 0 : 0.5));
5372
 
5373
          #if ENABLED(AUTO_BED_LEVELING_LINEAR)
5374
            indexIntoAB[xCount][yCount] = abl_probe_index;
5375
          #endif
5376
 
5377
          // Keep looping till a reachable point is found
5378
          if (position_is_reachable(xProbe, yProbe)) break;
5379
          ++abl_probe_index;
5380
        }
5381
 
5382
        // Is there a next point to move to?
5383
        if (abl_probe_index < abl_points) {
5384
          _manual_goto_xy(xProbe, yProbe); // Can be used here too!
5385
          #if HAS_SOFTWARE_ENDSTOPS
5386
            // Disable software endstops to allow manual adjustment
5387
            // If G29 is not completed, they will not be re-enabled
5388
            soft_endstops_enabled = false;
5389
          #endif
5390
          return;
5391
        }
5392
        else {
5393
 
5394
          // Leveling done! Fall through to G29 finishing code below
5395
 
5396
          SERIAL_PROTOCOLLNPGM("Grid probing done.");
5397
 
5398
          // Re-enable software endstops, if needed
5399
          #if HAS_SOFTWARE_ENDSTOPS
5400
            soft_endstops_enabled = enable_soft_endstops;
5401
          #endif
5402
        }
5403
 
5404
      #elif ENABLED(AUTO_BED_LEVELING_3POINT)
5405
 
5406
        // Probe at 3 arbitrary points
5407
        if (abl_probe_index < abl_points) {
5408
          xProbe = points[abl_probe_index].x;
5409
          yProbe = points[abl_probe_index].y;
5410
          _manual_goto_xy(xProbe, yProbe);
5411
          #if HAS_SOFTWARE_ENDSTOPS
5412
            // Disable software endstops to allow manual adjustment
5413
            // If G29 is not completed, they will not be re-enabled
5414
            soft_endstops_enabled = false;
5415
          #endif
5416
          return;
5417
        }
5418
        else {
5419
 
5420
          SERIAL_PROTOCOLLNPGM("3-point probing done.");
5421
 
5422
          // Re-enable software endstops, if needed
5423
          #if HAS_SOFTWARE_ENDSTOPS
5424
            soft_endstops_enabled = enable_soft_endstops;
5425
          #endif
5426
 
5427
          if (!dryrun) {
5428
            vector_3 planeNormal = vector_3::cross(points[0] - points[1], points[2] - points[1]).get_normal();
5429
            if (planeNormal.z < 0) {
5430
              planeNormal.x *= -1;
5431
              planeNormal.y *= -1;
5432
              planeNormal.z *= -1;
5433
            }
5434
            planner.bed_level_matrix = matrix_3x3::create_look_at(planeNormal);
5435
 
5436
            // Can't re-enable (on error) until the new grid is written
5437
            abl_should_enable = false;
5438
          }
5439
 
5440
        }
5441
 
5442
      #endif // AUTO_BED_LEVELING_3POINT
5443
 
5444
    #else // !PROBE_MANUALLY
5445
    {
5446
      const ProbePtRaise raise_after = parser.boolval('E') ? PROBE_PT_STOW : PROBE_PT_RAISE;
5447
 
5448
      measured_z = 0;
5449
 
5450
      #if ABL_GRID
5451
 
5452
        bool zig = PR_OUTER_END & 1;  // Always end at RIGHT and BACK_PROBE_BED_POSITION
5453
 
5454
        measured_z = 0;
5455
 
5456
        // Outer loop is Y with PROBE_Y_FIRST disabled
5457
        for (uint8_t PR_OUTER_VAR = 0; PR_OUTER_VAR < PR_OUTER_END && !isnan(measured_z); PR_OUTER_VAR++) {
5458
 
5459
          int8_t inStart, inStop, inInc;
5460
 
5461
          if (zig) { // away from origin
5462
            inStart = 0;
5463
            inStop = PR_INNER_END;
5464
            inInc = 1;
5465
          }
5466
          else {     // towards origin
5467
            inStart = PR_INNER_END - 1;
5468
            inStop = -1;
5469
            inInc = -1;
5470
          }
5471
 
5472
          zig ^= true; // zag
5473
 
5474
          // Inner loop is Y with PROBE_Y_FIRST enabled
5475
          for (int8_t PR_INNER_VAR = inStart; PR_INNER_VAR != inStop; PR_INNER_VAR += inInc) {
5476
 
5477
            float xBase = left_probe_bed_position + xGridSpacing * xCount,
5478
                  yBase = front_probe_bed_position + yGridSpacing * yCount;
5479
 
5480
            xProbe = FLOOR(xBase + (xBase < 0 ? 0 : 0.5));
5481
            yProbe = FLOOR(yBase + (yBase < 0 ? 0 : 0.5));
5482
 
5483
            #if ENABLED(AUTO_BED_LEVELING_LINEAR)
5484
              indexIntoAB[xCount][yCount] = ++abl_probe_index; // 0...
5485
            #endif
5486
 
5487
            #if IS_KINEMATIC
5488
              // Avoid probing outside the round or hexagonal area
5489
              if (!position_is_reachable_by_probe(xProbe, yProbe)) continue;
5490
            #endif
5491
 
5492
            measured_z = faux ? 0.001 * random(-100, 101) : probe_pt(xProbe, yProbe, raise_after, verbose_level);
5493
 
5494
            if (isnan(measured_z)) {
5495
              set_bed_leveling_enabled(abl_should_enable);
5496
              break;
5497
            }
5498
 
5499
            #if ENABLED(AUTO_BED_LEVELING_LINEAR)
5500
 
5501
              mean += measured_z;
5502
              eqnBVector[abl_probe_index] = measured_z;
5503
              eqnAMatrix[abl_probe_index + 0 * abl_points] = xProbe;
5504
              eqnAMatrix[abl_probe_index + 1 * abl_points] = yProbe;
5505
              eqnAMatrix[abl_probe_index + 2 * abl_points] = 1;
5506
 
5507
              incremental_LSF(&lsf_results, xProbe, yProbe, measured_z);
5508
 
5509
            #elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
5510
 
5511
              z_values[xCount][yCount] = measured_z + zoffset;
5512
 
5513
            #endif
5514
 
5515
            abl_should_enable = false;
5516
            idle();
5517
 
5518
          } // inner
5519
        } // outer
5520
 
5521
      #elif ENABLED(AUTO_BED_LEVELING_3POINT)
5522
 
5523
        // Probe at 3 arbitrary points
5524
 
5525
        for (uint8_t i = 0; i < 3; ++i) {
5526
          // Retain the last probe position
5527
          xProbe = points[i].x;
5528
          yProbe = points[i].y;
5529
          measured_z = faux ? 0.001 * random(-100, 101) : probe_pt(xProbe, yProbe, raise_after, verbose_level);
5530
          if (isnan(measured_z)) {
5531
            set_bed_leveling_enabled(abl_should_enable);
5532
            break;
5533
          }
5534
          points[i].z = measured_z;
5535
        }
5536
 
5537
        if (!dryrun && !isnan(measured_z)) {
5538
          vector_3 planeNormal = vector_3::cross(points[0] - points[1], points[2] - points[1]).get_normal();
5539
          if (planeNormal.z < 0) {
5540
            planeNormal.x *= -1;
5541
            planeNormal.y *= -1;
5542
            planeNormal.z *= -1;
5543
          }
5544
          planner.bed_level_matrix = matrix_3x3::create_look_at(planeNormal);
5545
 
5546
          // Can't re-enable (on error) until the new grid is written
5547
          abl_should_enable = false;
5548
        }
5549
 
5550
      #endif // AUTO_BED_LEVELING_3POINT
5551
 
5552
      // Stow the probe. No raise for FIX_MOUNTED_PROBE.
5553
      if (STOW_PROBE()) {
5554
        set_bed_leveling_enabled(abl_should_enable);
5555
        measured_z = NAN;
5556
      }
5557
    }
5558
    #endif // !PROBE_MANUALLY
5559
 
5560
    //
5561
    // G29 Finishing Code
5562
    //
5563
    // Unless this is a dry run, auto bed leveling will
5564
    // definitely be enabled after this point.
5565
    //
5566
    // If code above wants to continue leveling, it should
5567
    // return or loop before this point.
5568
    //
5569
 
5570
    #if ENABLED(DEBUG_LEVELING_FEATURE)
5571
      if (DEBUGGING(LEVELING)) DEBUG_POS("> probing complete", current_position);
5572
    #endif
5573
 
5574
    #if ENABLED(PROBE_MANUALLY)
5575
      g29_in_progress = false;
5576
      #if ENABLED(LCD_BED_LEVELING)
5577
        lcd_wait_for_move = false;
5578
      #endif
5579
    #endif
5580
 
5581
    // Calculate leveling, print reports, correct the position
5582
    if (!isnan(measured_z)) {
5583
      #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
5584
 
5585
        if (!dryrun) extrapolate_unprobed_bed_level();
5586
        print_bilinear_leveling_grid();
5587
 
5588
        refresh_bed_level();
5589
 
5590
        #if ENABLED(ABL_BILINEAR_SUBDIVISION)
5591
          print_bilinear_leveling_grid_virt();
5592
        #endif
5593
 
5594
      #elif ENABLED(AUTO_BED_LEVELING_LINEAR)
5595
 
5596
        // For LINEAR leveling calculate matrix, print reports, correct the position
5597
 
5598
        /**
5599
         * solve the plane equation ax + by + d = z
5600
         * A is the matrix with rows [x y 1] for all the probed points
5601
         * B is the vector of the Z positions
5602
         * the normal vector to the plane is formed by the coefficients of the
5603
         * plane equation in the standard form, which is Vx*x+Vy*y+Vz*z+d = 0
5604
         * so Vx = -a Vy = -b Vz = 1 (we want the vector facing towards positive Z
5605
         */
5606
        float plane_equation_coefficients[3];
5607
 
5608
        finish_incremental_LSF(&lsf_results);
5609
        plane_equation_coefficients[0] = -lsf_results.A;  // We should be able to eliminate the '-' on these three lines and down below
5610
        plane_equation_coefficients[1] = -lsf_results.B;  // but that is not yet tested.
5611
        plane_equation_coefficients[2] = -lsf_results.D;
5612
 
5613
        mean /= abl_points;
5614
 
5615
        if (verbose_level) {
5616
          SERIAL_PROTOCOLPGM("Eqn coefficients: a: ");
5617
          SERIAL_PROTOCOL_F(plane_equation_coefficients[0], 8);
5618
          SERIAL_PROTOCOLPGM(" b: ");
5619
          SERIAL_PROTOCOL_F(plane_equation_coefficients[1], 8);
5620
          SERIAL_PROTOCOLPGM(" d: ");
5621
          SERIAL_PROTOCOL_F(plane_equation_coefficients[2], 8);
5622
          SERIAL_EOL();
5623
          if (verbose_level > 2) {
5624
            SERIAL_PROTOCOLPGM("Mean of sampled points: ");
5625
            SERIAL_PROTOCOL_F(mean, 8);
5626
            SERIAL_EOL();
5627
          }
5628
        }
5629
 
5630
        // Create the matrix but don't correct the position yet
5631
        if (!dryrun)
5632
          planner.bed_level_matrix = matrix_3x3::create_look_at(
5633
            vector_3(-plane_equation_coefficients[0], -plane_equation_coefficients[1], 1)    // We can eliminate the '-' here and up above
5634
          );
5635
 
5636
        // Show the Topography map if enabled
5637
        if (do_topography_map) {
5638
 
5639
          SERIAL_PROTOCOLLNPGM("\nBed Height Topography:\n"
5640
                                 "   +--- BACK --+\n"
5641
                                 "   |           |\n"
5642
                                 " L |    (+)    | R\n"
5643
                                 " E |           | I\n"
5644
                                 " F | (-) N (+) | G\n"
5645
                                 " T |           | H\n"
5646
                                 "   |    (-)    | T\n"
5647
                                 "   |           |\n"
5648
                                 "   O-- FRONT --+\n"
5649
                                 " (0,0)");
5650
 
5651
          float min_diff = 999;
5652
 
5653
          for (int8_t yy = abl_grid_points_y - 1; yy >= 0; yy--) {
5654
            for (uint8_t xx = 0; xx < abl_grid_points_x; xx++) {
5655
              int ind = indexIntoAB[xx][yy];
5656
              float diff = eqnBVector[ind] - mean,
5657
                    x_tmp = eqnAMatrix[ind + 0 * abl_points],
5658
                    y_tmp = eqnAMatrix[ind + 1 * abl_points],
5659
                    z_tmp = 0;
5660
 
5661
              apply_rotation_xyz(planner.bed_level_matrix, x_tmp, y_tmp, z_tmp);
5662
 
5663
              NOMORE(min_diff, eqnBVector[ind] - z_tmp);
5664
 
5665
              if (diff >= 0.0)
5666
                SERIAL_PROTOCOLPGM(" +");   // Include + for column alignment
5667
              else
5668
                SERIAL_PROTOCOLCHAR(' ');
5669
              SERIAL_PROTOCOL_F(diff, 5);
5670
            } // xx
5671
            SERIAL_EOL();
5672
          } // yy
5673
          SERIAL_EOL();
5674
 
5675
          if (verbose_level > 3) {
5676
            SERIAL_PROTOCOLLNPGM("\nCorrected Bed Height vs. Bed Topology:");
5677
 
5678
            for (int8_t yy = abl_grid_points_y - 1; yy >= 0; yy--) {
5679
              for (uint8_t xx = 0; xx < abl_grid_points_x; xx++) {
5680
                int ind = indexIntoAB[xx][yy];
5681
                float x_tmp = eqnAMatrix[ind + 0 * abl_points],
5682
                      y_tmp = eqnAMatrix[ind + 1 * abl_points],
5683
                      z_tmp = 0;
5684
 
5685
                apply_rotation_xyz(planner.bed_level_matrix, x_tmp, y_tmp, z_tmp);
5686
 
5687
                float diff = eqnBVector[ind] - z_tmp - min_diff;
5688
                if (diff >= 0.0)
5689
                  SERIAL_PROTOCOLPGM(" +");
5690
                // Include + for column alignment
5691
                else
5692
                  SERIAL_PROTOCOLCHAR(' ');
5693
                SERIAL_PROTOCOL_F(diff, 5);
5694
              } // xx
5695
              SERIAL_EOL();
5696
            } // yy
5697
            SERIAL_EOL();
5698
          }
5699
        } //do_topography_map
5700
 
5701
      #endif // AUTO_BED_LEVELING_LINEAR
5702
 
5703
      #if ABL_PLANAR
5704
 
5705
        // For LINEAR and 3POINT leveling correct the current position
5706
 
5707
        if (verbose_level > 0)
5708
          planner.bed_level_matrix.debug(PSTR("\n\nBed Level Correction Matrix:"));
5709
 
5710
        if (!dryrun) {
5711
          //
5712
          // Correct the current XYZ position based on the tilted plane.
5713
          //
5714
 
5715
          #if ENABLED(DEBUG_LEVELING_FEATURE)
5716
            if (DEBUGGING(LEVELING)) DEBUG_POS("G29 uncorrected XYZ", current_position);
5717
          #endif
5718
 
5719
          float converted[XYZ];
5720
          COPY(converted, current_position);
5721
 
5722
          planner.leveling_active = true;
5723
          planner.unapply_leveling(converted); // use conversion machinery
5724
          planner.leveling_active = false;
5725
 
5726
          // Use the last measured distance to the bed, if possible
5727
          if ( NEAR(current_position[X_AXIS], xProbe - (X_PROBE_OFFSET_FROM_EXTRUDER))
5728
            && NEAR(current_position[Y_AXIS], yProbe - (Y_PROBE_OFFSET_FROM_EXTRUDER))
5729
          ) {
5730
            const float simple_z = current_position[Z_AXIS] - measured_z;
5731
            #if ENABLED(DEBUG_LEVELING_FEATURE)
5732
              if (DEBUGGING(LEVELING)) {
5733
                SERIAL_ECHOPAIR("Z from Probe:", simple_z);
5734
                SERIAL_ECHOPAIR("  Matrix:", converted[Z_AXIS]);
5735
                SERIAL_ECHOLNPAIR("  Discrepancy:", simple_z - converted[Z_AXIS]);
5736
              }
5737
            #endif
5738
            converted[Z_AXIS] = simple_z;
5739
          }
5740
 
5741
          // The rotated XY and corrected Z are now current_position
5742
          COPY(current_position, converted);
5743
 
5744
          #if ENABLED(DEBUG_LEVELING_FEATURE)
5745
            if (DEBUGGING(LEVELING)) DEBUG_POS("G29 corrected XYZ", current_position);
5746
          #endif
5747
        }
5748
 
5749
      #elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
5750
 
5751
        if (!dryrun) {
5752
          #if ENABLED(DEBUG_LEVELING_FEATURE)
5753
            if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPAIR("G29 uncorrected Z:", current_position[Z_AXIS]);
5754
          #endif
5755
 
5756
          // Unapply the offset because it is going to be immediately applied
5757
          // and cause compensation movement in Z
5758
          #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
5759
            const float fade_scaling_factor = planner.fade_scaling_factor_for_z(current_position[Z_AXIS]);
5760
          #else
5761
            constexpr float fade_scaling_factor = 1.0f;
5762
          #endif
5763
          current_position[Z_AXIS] -= fade_scaling_factor * bilinear_z_offset(current_position);
5764
 
5765
          #if ENABLED(DEBUG_LEVELING_FEATURE)
5766
            if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPAIR(" corrected Z:", current_position[Z_AXIS]);
5767
          #endif
5768
        }
5769
 
5770
      #endif // ABL_PLANAR
5771
 
5772
      #ifdef Z_PROBE_END_SCRIPT
5773
        #if ENABLED(DEBUG_LEVELING_FEATURE)
5774
          if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPAIR("Z Probe End Script: ", Z_PROBE_END_SCRIPT);
5775
        #endif
5776
        planner.synchronize();
5777
        enqueue_and_echo_commands_P(PSTR(Z_PROBE_END_SCRIPT));
5778
      #endif
5779
 
5780
      // Auto Bed Leveling is complete! Enable if possible.
5781
      planner.leveling_active = dryrun ? abl_should_enable : true;
5782
    } // !isnan(measured_z)
5783
 
5784
    // Restore state after probing
5785
    if (!faux) clean_up_after_endstop_or_probe_move();
5786
 
5787
    #if ENABLED(DEBUG_LEVELING_FEATURE)
5788
      if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("<<< G29");
5789
    #endif
5790
 
5791
    KEEPALIVE_STATE(IN_HANDLER);
5792
 
5793
    if (planner.leveling_active)
5794
      SYNC_PLAN_POSITION_KINEMATIC();
5795
 
5796
    #if HAS_BED_PROBE && defined(Z_AFTER_PROBING)
5797
      move_z_after_probing();
5798
    #endif
5799
 
5800
    report_current_position();
5801
  }
5802
 
5803
#endif // OLDSCHOOL_ABL
5804
 
5805
#if HAS_BED_PROBE
5806
 
5807
  /**
5808
   * G30: Do a single Z probe at the current XY
5809
   *
5810
   * Parameters:
5811
   *
5812
   *   X   Probe X position (default current X)
5813
   *   Y   Probe Y position (default current Y)
5814
   *   E   Engage the probe for each probe (default 1)
5815
   */
5816
  inline void gcode_G30() {
5817
    const float xpos = parser.linearval('X', current_position[X_AXIS] + X_PROBE_OFFSET_FROM_EXTRUDER),
5818
                ypos = parser.linearval('Y', current_position[Y_AXIS] + Y_PROBE_OFFSET_FROM_EXTRUDER);
5819
 
5820
    if (!position_is_reachable_by_probe(xpos, ypos)) return;
5821
 
5822
    // Disable leveling so the planner won't mess with us
5823
    #if HAS_LEVELING
5824
      set_bed_leveling_enabled(false);
5825
    #endif
5826
 
5827
    setup_for_endstop_or_probe_move();
5828
 
5829
    const ProbePtRaise raise_after = parser.boolval('E', true) ? PROBE_PT_STOW : PROBE_PT_NONE;
5830
    const float measured_z = probe_pt(xpos, ypos, raise_after, parser.intval('V', 1));
5831
 
5832
    if (!isnan(measured_z)) {
5833
      SERIAL_PROTOCOLPAIR_F("Bed X: ", xpos);
5834
      SERIAL_PROTOCOLPAIR_F(" Y: ", ypos);
5835
      SERIAL_PROTOCOLLNPAIR_F(" Z: ", measured_z);
5836
    }
5837
 
5838
    clean_up_after_endstop_or_probe_move();
5839
 
5840
    #ifdef Z_AFTER_PROBING
5841
      if (raise_after == PROBE_PT_STOW) move_z_after_probing();
5842
    #endif
5843
 
5844
    report_current_position();
5845
  }
5846
 
5847
  #if ENABLED(Z_PROBE_SLED)
5848
 
5849
    /**
5850
     * G31: Deploy the Z probe
5851
     */
5852
    inline void gcode_G31() { DEPLOY_PROBE(); }
5853
 
5854
    /**
5855
     * G32: Stow the Z probe
5856
     */
5857
    inline void gcode_G32() { STOW_PROBE(); }
5858
 
5859
  #endif // Z_PROBE_SLED
5860
 
5861
#endif // HAS_BED_PROBE
5862
 
5863
#if ENABLED(DELTA_AUTO_CALIBRATION)
5864
 
5865
  constexpr uint8_t _7P_STEP = 1,              // 7-point step - to change number of calibration points
5866
                    _4P_STEP = _7P_STEP * 2,   // 4-point step
5867
                    NPP      = _7P_STEP * 6;   // number of calibration points on the radius
5868
  enum CalEnum : char {                        // the 7 main calibration points - add definitions if needed
5869
    CEN      = 0,
5870
    __A      = 1,
5871
    _AB      = __A + _7P_STEP,
5872
    __B      = _AB + _7P_STEP,
5873
    _BC      = __B + _7P_STEP,
5874
    __C      = _BC + _7P_STEP,
5875
    _CA      = __C + _7P_STEP,
5876
  };
5877
 
5878
  #define LOOP_CAL_PT(VAR, S, N) for (uint8_t VAR=S; VAR<=NPP; VAR+=N)
5879
  #define F_LOOP_CAL_PT(VAR, S, N) for (float VAR=S; VAR<NPP+0.9999; VAR+=N)
5880
  #define I_LOOP_CAL_PT(VAR, S, N) for (float VAR=S; VAR>CEN+0.9999; VAR-=N)
5881
  #define LOOP_CAL_ALL(VAR) LOOP_CAL_PT(VAR, CEN, 1)
5882
  #define LOOP_CAL_RAD(VAR) LOOP_CAL_PT(VAR, __A, _7P_STEP)
5883
  #define LOOP_CAL_ACT(VAR, _4P, _OP) LOOP_CAL_PT(VAR, _OP ? _AB : __A, _4P ? _4P_STEP : _7P_STEP)
5884
 
5885
  #if HOTENDS > 1
5886
    const uint8_t old_tool_index = active_extruder;
5887
    #define AC_CLEANUP() ac_cleanup(old_tool_index)
5888
  #else
5889
    #define AC_CLEANUP() ac_cleanup()
5890
  #endif
5891
 
5892
  float lcd_probe_pt(const float &rx, const float &ry);
5893
 
5894
  void ac_home() {
5895
    endstops.enable(true);
5896
    home_delta();
5897
    endstops.not_homing();
5898
  }
5899
 
5900
  void ac_setup(const bool reset_bed) {
5901
    #if HOTENDS > 1
5902
      tool_change(0, 0, true);
5903
    #endif
5904
 
5905
    planner.synchronize();
5906
    setup_for_endstop_or_probe_move();
5907
 
5908
    #if HAS_LEVELING
5909
      if (reset_bed) reset_bed_level(); // After full calibration bed-level data is no longer valid
5910
    #endif
5911
  }
5912
 
5913
  void ac_cleanup(
5914
    #if HOTENDS > 1
5915
      const uint8_t old_tool_index
5916
    #endif
5917
  ) {
5918
    #if ENABLED(DELTA_HOME_TO_SAFE_ZONE)
5919
      do_blocking_move_to_z(delta_clip_start_height);
5920
    #endif
5921
    #if HAS_BED_PROBE
5922
      STOW_PROBE();
5923
    #endif
5924
    clean_up_after_endstop_or_probe_move();
5925
    #if HOTENDS > 1
5926
      tool_change(old_tool_index, 0, true);
5927
    #endif
5928
  }
5929
 
5930
  void print_signed_float(const char * const prefix, const float &f) {
5931
    SERIAL_PROTOCOLPGM("  ");
5932
    serialprintPGM(prefix);
5933
    SERIAL_PROTOCOLCHAR(':');
5934
    if (f >= 0) SERIAL_CHAR('+');
5935
    SERIAL_PROTOCOL_F(f, 2);
5936
  }
5937
 
5938
  /**
5939
   *  - Print the delta settings
5940
   */
5941
  static void print_calibration_settings(const bool end_stops, const bool tower_angles) {
5942
    SERIAL_PROTOCOLPAIR(".Height:", delta_height);
5943
    if (end_stops) {
5944
      print_signed_float(PSTR("Ex"), delta_endstop_adj[A_AXIS]);
5945
      print_signed_float(PSTR("Ey"), delta_endstop_adj[B_AXIS]);
5946
      print_signed_float(PSTR("Ez"), delta_endstop_adj[C_AXIS]);
5947
    }
5948
    if (end_stops && tower_angles) {
5949
      SERIAL_PROTOCOLPAIR("  Radius:", delta_radius);
5950
      SERIAL_EOL();
5951
      SERIAL_CHAR('.');
5952
      SERIAL_PROTOCOL_SP(13);
5953
    }
5954
    if (tower_angles) {
5955
      print_signed_float(PSTR("Tx"), delta_tower_angle_trim[A_AXIS]);
5956
      print_signed_float(PSTR("Ty"), delta_tower_angle_trim[B_AXIS]);
5957
      print_signed_float(PSTR("Tz"), delta_tower_angle_trim[C_AXIS]);
5958
    }
5959
    if ((!end_stops && tower_angles) || (end_stops && !tower_angles)) { // XOR
5960
      SERIAL_PROTOCOLPAIR("  Radius:", delta_radius);
5961
    }
5962
    SERIAL_EOL();
5963
  }
5964
 
5965
  /**
5966
   *  - Print the probe results
5967
   */
5968
  static void print_calibration_results(const float z_pt[NPP + 1], const bool tower_points, const bool opposite_points) {
5969
    SERIAL_PROTOCOLPGM(".    ");
5970
    print_signed_float(PSTR("c"), z_pt[CEN]);
5971
    if (tower_points) {
5972
      print_signed_float(PSTR(" x"), z_pt[__A]);
5973
      print_signed_float(PSTR(" y"), z_pt[__B]);
5974
      print_signed_float(PSTR(" z"), z_pt[__C]);
5975
    }
5976
    if (tower_points && opposite_points) {
5977
      SERIAL_EOL();
5978
      SERIAL_CHAR('.');
5979
      SERIAL_PROTOCOL_SP(13);
5980
    }
5981
    if (opposite_points) {
5982
      print_signed_float(PSTR("yz"), z_pt[_BC]);
5983
      print_signed_float(PSTR("zx"), z_pt[_CA]);
5984
      print_signed_float(PSTR("xy"), z_pt[_AB]);
5985
    }
5986
    SERIAL_EOL();
5987
  }
5988
 
5989
  /**
5990
   *  - Calculate the standard deviation from the zero plane
5991
   */
5992
  static float std_dev_points(float z_pt[NPP + 1], const bool _0p_cal, const bool _1p_cal, const bool _4p_cal, const bool _4p_opp) {
5993
    if (!_0p_cal) {
5994
      float S2 = sq(z_pt[CEN]);
5995
      int16_t N = 1;
5996
      if (!_1p_cal) { // std dev from zero plane
5997
        LOOP_CAL_ACT(rad, _4p_cal, _4p_opp) {
5998
          S2 += sq(z_pt[rad]);
5999
          N++;
6000
        }
6001
        return LROUND(SQRT(S2 / N) * 1000.0) / 1000.0 + 0.00001;
6002
      }
6003
    }
6004
    return 0.00001;
6005
  }
6006
 
6007
  /**
6008
   *  - Probe a point
6009
   */
6010
  static float calibration_probe(const float &nx, const float &ny, const bool stow) {
6011
    #if HAS_BED_PROBE
6012
      return probe_pt(nx, ny, stow ? PROBE_PT_STOW : PROBE_PT_RAISE, 0, false);
6013
    #else
6014
      UNUSED(stow);
6015
      return lcd_probe_pt(nx, ny);
6016
    #endif
6017
  }
6018
 
6019
  /**
6020
   *  - Probe a grid
6021
   */
6022
  static bool probe_calibration_points(float z_pt[NPP + 1], const int8_t probe_points, const bool towers_set, const bool stow_after_each) {
6023
    const bool _0p_calibration      = probe_points == 0,
6024
               _1p_calibration      = probe_points == 1 || probe_points == -1,
6025
               _4p_calibration      = probe_points == 2,
6026
               _4p_opposite_points  = _4p_calibration && !towers_set,
6027
               _7p_calibration      = probe_points >= 3,
6028
               _7p_no_intermediates = probe_points == 3,
6029
               _7p_1_intermediates  = probe_points == 4,
6030
               _7p_2_intermediates  = probe_points == 5,
6031
               _7p_4_intermediates  = probe_points == 6,
6032
               _7p_6_intermediates  = probe_points == 7,
6033
               _7p_8_intermediates  = probe_points == 8,
6034
               _7p_11_intermediates = probe_points == 9,
6035
               _7p_14_intermediates = probe_points == 10,
6036
               _7p_intermed_points  = probe_points >= 4,
6037
               _7p_6_center         = probe_points >= 5 && probe_points <= 7,
6038
               _7p_9_center         = probe_points >= 8;
6039
 
6040
    LOOP_CAL_ALL(rad) z_pt[rad] = 0.0;
6041
 
6042
    if (!_0p_calibration) {
6043
 
6044
      if (!_7p_no_intermediates && !_7p_4_intermediates && !_7p_11_intermediates) { // probe the center
6045
        z_pt[CEN] += calibration_probe(0, 0, stow_after_each);
6046
        if (isnan(z_pt[CEN])) return false;
6047
      }
6048
 
6049
      if (_7p_calibration) { // probe extra center points
6050
        const float start  = _7p_9_center ? float(_CA) + _7P_STEP / 3.0 : _7p_6_center ? float(_CA) : float(__C),
6051
                    steps  = _7p_9_center ? _4P_STEP / 3.0 : _7p_6_center ? _7P_STEP : _4P_STEP;
6052
        I_LOOP_CAL_PT(rad, start, steps) {
6053
          const float a = RADIANS(210 + (360 / NPP) *  (rad - 1)),
6054
                      r = delta_calibration_radius * 0.1;
6055
          z_pt[CEN] += calibration_probe(cos(a) * r, sin(a) * r, stow_after_each);
6056
          if (isnan(z_pt[CEN])) return false;
6057
       }
6058
        z_pt[CEN] /= float(_7p_2_intermediates ? 7 : probe_points);
6059
      }
6060
 
6061
      if (!_1p_calibration) {  // probe the radius
6062
        const CalEnum start  = _4p_opposite_points ? _AB : __A;
6063
        const float   steps  = _7p_14_intermediates ? _7P_STEP / 15.0 : // 15r * 6 + 10c = 100
6064
                               _7p_11_intermediates ? _7P_STEP / 12.0 : // 12r * 6 +  9c = 81
6065
                               _7p_8_intermediates  ? _7P_STEP /  9.0 : //  9r * 6 + 10c = 64
6066
                               _7p_6_intermediates  ? _7P_STEP /  7.0 : //  7r * 6 +  7c = 49
6067
                               _7p_4_intermediates  ? _7P_STEP /  5.0 : //  5r * 6 +  6c = 36
6068
                               _7p_2_intermediates  ? _7P_STEP /  3.0 : //  3r * 6 +  7c = 25
6069
                               _7p_1_intermediates  ? _7P_STEP /  2.0 : //  2r * 6 +  4c = 16
6070
                               _7p_no_intermediates ? _7P_STEP :        //  1r * 6 +  3c = 9
6071
                               _4P_STEP;                                // .5r * 6 +  1c = 4
6072
        bool zig_zag = true;
6073
        F_LOOP_CAL_PT(rad, start, _7p_9_center ? steps * 3 : steps) {
6074
          const int8_t offset = _7p_9_center ? 2 : 0;
6075
          for (int8_t circle = 0; circle <= offset; circle++) {
6076
            const float a = RADIANS(210 + (360 / NPP) *  (rad - 1)),
6077
                        r = delta_calibration_radius * (1 - 0.1 * (zig_zag ? offset - circle : circle)),
6078
                        interpol = fmod(rad, 1);
6079
            const float z_temp = calibration_probe(cos(a) * r, sin(a) * r, stow_after_each);
6080
            if (isnan(z_temp)) return false;
6081
            // split probe point to neighbouring calibration points
6082
            z_pt[uint8_t(LROUND(rad - interpol + NPP - 1)) % NPP + 1] += z_temp * sq(cos(RADIANS(interpol * 90)));
6083
            z_pt[uint8_t(LROUND(rad - interpol))           % NPP + 1] += z_temp * sq(sin(RADIANS(interpol * 90)));
6084
          }
6085
          zig_zag = !zig_zag;
6086
        }
6087
        if (_7p_intermed_points)
6088
          LOOP_CAL_RAD(rad)
6089
            z_pt[rad] /= _7P_STEP / steps;
6090
 
6091
        do_blocking_move_to_xy(0.0, 0.0);
6092
      }
6093
    }
6094
    return true;
6095
  }
6096
 
6097
  /**
6098
   * kinematics routines and auto tune matrix scaling parameters:
6099
   * see https://github.com/LVD-AC/Marlin-AC/tree/1.1.x-AC/documentation for
6100
   *  - formulae for approximative forward kinematics in the end-stop displacement matrix
6101
   *  - definition of the matrix scaling parameters
6102
   */
6103
  static void reverse_kinematics_probe_points(float z_pt[NPP + 1], float mm_at_pt_axis[NPP + 1][ABC]) {
6104
    float pos[XYZ] = { 0.0 };
6105
 
6106
    LOOP_CAL_ALL(rad) {
6107
      const float a = RADIANS(210 + (360 / NPP) *  (rad - 1)),
6108
                  r = (rad == CEN ? 0.0 : delta_calibration_radius);
6109
      pos[X_AXIS] = cos(a) * r;
6110
      pos[Y_AXIS] = sin(a) * r;
6111
      pos[Z_AXIS] = z_pt[rad];
6112
      inverse_kinematics(pos);
6113
      LOOP_XYZ(axis) mm_at_pt_axis[rad][axis] = delta[axis];
6114
    }
6115
  }
6116
 
6117
  static void forward_kinematics_probe_points(float mm_at_pt_axis[NPP + 1][ABC], float z_pt[NPP + 1]) {
6118
    const float r_quot = delta_calibration_radius / delta_radius;
6119
 
6120
    #define ZPP(N,I,A) ((1 / 3.0 + r_quot * (N) / 3.0 ) * mm_at_pt_axis[I][A])
6121
    #define Z00(I, A) ZPP( 0, I, A)
6122
    #define Zp1(I, A) ZPP(+1, I, A)
6123
    #define Zm1(I, A) ZPP(-1, I, A)
6124
    #define Zp2(I, A) ZPP(+2, I, A)
6125
    #define Zm2(I, A) ZPP(-2, I, A)
6126
 
6127
    z_pt[CEN] = Z00(CEN, A_AXIS) + Z00(CEN, B_AXIS) + Z00(CEN, C_AXIS);
6128
    z_pt[__A] = Zp2(__A, A_AXIS) + Zm1(__A, B_AXIS) + Zm1(__A, C_AXIS);
6129
    z_pt[__B] = Zm1(__B, A_AXIS) + Zp2(__B, B_AXIS) + Zm1(__B, C_AXIS);
6130
    z_pt[__C] = Zm1(__C, A_AXIS) + Zm1(__C, B_AXIS) + Zp2(__C, C_AXIS);
6131
    z_pt[_BC] = Zm2(_BC, A_AXIS) + Zp1(_BC, B_AXIS) + Zp1(_BC, C_AXIS);
6132
    z_pt[_CA] = Zp1(_CA, A_AXIS) + Zm2(_CA, B_AXIS) + Zp1(_CA, C_AXIS);
6133
    z_pt[_AB] = Zp1(_AB, A_AXIS) + Zp1(_AB, B_AXIS) + Zm2(_AB, C_AXIS);
6134
  }
6135
 
6136
  static void calc_kinematics_diff_probe_points(float z_pt[NPP + 1], float delta_e[ABC], float delta_r, float delta_t[ABC]) {
6137
    const float z_center = z_pt[CEN];
6138
    float diff_mm_at_pt_axis[NPP + 1][ABC],
6139
          new_mm_at_pt_axis[NPP + 1][ABC];
6140
 
6141
    reverse_kinematics_probe_points(z_pt, diff_mm_at_pt_axis);
6142
 
6143
    delta_radius += delta_r;
6144
    LOOP_XYZ(axis) delta_tower_angle_trim[axis] += delta_t[axis];
6145
    recalc_delta_settings();
6146
    reverse_kinematics_probe_points(z_pt, new_mm_at_pt_axis);
6147
 
6148
    LOOP_XYZ(axis) LOOP_CAL_ALL(rad) diff_mm_at_pt_axis[rad][axis] -= new_mm_at_pt_axis[rad][axis] + delta_e[axis];
6149
    forward_kinematics_probe_points(diff_mm_at_pt_axis, z_pt);
6150
 
6151
    LOOP_CAL_RAD(rad) z_pt[rad] -= z_pt[CEN] - z_center;
6152
    z_pt[CEN] = z_center;
6153
 
6154
    delta_radius -= delta_r;
6155
    LOOP_XYZ(axis) delta_tower_angle_trim[axis] -= delta_t[axis];
6156
    recalc_delta_settings();
6157
  }
6158
 
6159
  static float auto_tune_h() {
6160
    const float r_quot = delta_calibration_radius / delta_radius;
6161
    float h_fac = 0.0;
6162
 
6163
    h_fac = r_quot / (2.0 / 3.0);
6164
    h_fac = 1.0f / h_fac; // (2/3)/CR
6165
    return h_fac;
6166
  }
6167
 
6168
  static float auto_tune_r() {
6169
    const float diff = 0.01;
6170
    float r_fac = 0.0,
6171
          z_pt[NPP + 1] = { 0.0 },
6172
          delta_e[ABC] = {0.0},
6173
          delta_r = {0.0},
6174
          delta_t[ABC] = {0.0};
6175
 
6176
    delta_r = diff;
6177
    calc_kinematics_diff_probe_points(z_pt, delta_e, delta_r, delta_t);
6178
    r_fac = -(z_pt[__A] + z_pt[__B] + z_pt[__C] + z_pt[_BC] + z_pt[_CA] + z_pt[_AB]) / 6.0;
6179
    r_fac = diff / r_fac / 3.0; // 1/(3*delta_Z)
6180
    return r_fac;
6181
  }
6182
 
6183
  static float auto_tune_a() {
6184
    const float diff = 0.01;
6185
    float a_fac = 0.0,
6186
          z_pt[NPP + 1] = { 0.0 },
6187
          delta_e[ABC] = {0.0},
6188
          delta_r = {0.0},
6189
          delta_t[ABC] = {0.0};
6190
 
6191
    LOOP_XYZ(axis) {
6192
      LOOP_XYZ(axis_2) delta_t[axis_2] = 0.0;
6193
      delta_t[axis] = diff;
6194
      calc_kinematics_diff_probe_points(z_pt, delta_e, delta_r, delta_t);
6195
      a_fac += z_pt[uint8_t((axis * _4P_STEP) - _7P_STEP + NPP) % NPP + 1] / 6.0;
6196
      a_fac -= z_pt[uint8_t((axis * _4P_STEP) + 1 + _7P_STEP)] / 6.0;
6197
    }
6198
    a_fac = diff / a_fac / 3.0; // 1/(3*delta_Z)
6199
    return a_fac;
6200
  }
6201
 
6202
  /**
6203
   * G33 - Delta '1-4-7-point' Auto-Calibration
6204
   *       Calibrate height, z_offset, endstops, delta radius, and tower angles.
6205
   *
6206
   * Parameters:
6207
   *
6208
   *   Pn  Number of probe points:
6209
   *      P0       Normalizes calibration.
6210
   *      P1       Calibrates height only with center probe.
6211
   *      P2       Probe center and towers. Calibrate height, endstops and delta radius.
6212
   *      P3       Probe all positions: center, towers and opposite towers. Calibrate all.
6213
   *      P4-P10   Probe all positions at different intermediate locations and average them.
6214
   *
6215
   *   T   Don't calibrate tower angle corrections
6216
   *
6217
   *   Cn.nn  Calibration precision; when omitted calibrates to maximum precision
6218
   *
6219
   *   Fn  Force to run at least n iterations and take the best result
6220
   *
6221
   *   Vn  Verbose level:
6222
   *      V0  Dry-run mode. Report settings and probe results. No calibration.
6223
   *      V1  Report start and end settings only
6224
   *      V2  Report settings at each iteration
6225
   *      V3  Report settings and probe results
6226
   *
6227
   *   E   Engage the probe for each point
6228
   */
6229
  inline void gcode_G33() {
6230
 
6231
    const int8_t probe_points = parser.intval('P', DELTA_CALIBRATION_DEFAULT_POINTS);
6232
    if (!WITHIN(probe_points, 0, 10)) {
6233
      SERIAL_PROTOCOLLNPGM("?(P)oints is implausible (0-10).");
6234
      return;
6235
    }
6236
 
6237
    const bool towers_set = !parser.seen('T');
6238
 
6239
    const float calibration_precision = parser.floatval('C', 0.0);
6240
    if (calibration_precision < 0) {
6241
      SERIAL_PROTOCOLLNPGM("?(C)alibration precision is implausible (>=0).");
6242
      return;
6243
    }
6244
 
6245
    const int8_t force_iterations = parser.intval('F', 0);
6246
    if (!WITHIN(force_iterations, 0, 30)) {
6247
      SERIAL_PROTOCOLLNPGM("?(F)orce iteration is implausible (0-30).");
6248
      return;
6249
    }
6250
 
6251
    const int8_t verbose_level = parser.byteval('V', 1);
6252
    if (!WITHIN(verbose_level, 0, 3)) {
6253
      SERIAL_PROTOCOLLNPGM("?(V)erbose level is implausible (0-3).");
6254
      return;
6255
    }
6256
 
6257
    const bool stow_after_each = parser.seen('E');
6258
 
6259
    const bool _0p_calibration      = probe_points == 0,
6260
               _1p_calibration      = probe_points == 1 || probe_points == -1,
6261
               _4p_calibration      = probe_points == 2,
6262
               _4p_opposite_points  = _4p_calibration && !towers_set,
6263
               _7p_9_center         = probe_points >= 8,
6264
               _tower_results       = (_4p_calibration && towers_set) || probe_points >= 3,
6265
               _opposite_results    = (_4p_calibration && !towers_set) || probe_points >= 3,
6266
               _endstop_results     = probe_points != 1 && probe_points != -1 && probe_points != 0,
6267
               _angle_results       = probe_points >= 3  && towers_set;
6268
    static const char save_message[] PROGMEM = "Save with M500 and/or copy to Configuration.h";
6269
    int8_t iterations = 0;
6270
    float test_precision,
6271
          zero_std_dev = (verbose_level ? 999.0 : 0.0), // 0.0 in dry-run mode : forced end
6272
          zero_std_dev_min = zero_std_dev,
6273
          zero_std_dev_old = zero_std_dev,
6274
          h_factor,
6275
          r_factor,
6276
          a_factor,
6277
          e_old[ABC] = {
6278
            delta_endstop_adj[A_AXIS],
6279
            delta_endstop_adj[B_AXIS],
6280
            delta_endstop_adj[C_AXIS]
6281
          },
6282
          r_old = delta_radius,
6283
          h_old = delta_height,
6284
          a_old[ABC] = {
6285
            delta_tower_angle_trim[A_AXIS],
6286
            delta_tower_angle_trim[B_AXIS],
6287
            delta_tower_angle_trim[C_AXIS]
6288
          };
6289
 
6290
    SERIAL_PROTOCOLLNPGM("G33 Auto Calibrate");
6291
 
6292
    if (!_1p_calibration && !_0p_calibration) { // test if the outer radius is reachable
6293
      LOOP_CAL_RAD(axis) {
6294
        const float a = RADIANS(210 + (360 / NPP) *  (axis - 1)),
6295
                    r = delta_calibration_radius;
6296
        if (!position_is_reachable(cos(a) * r, sin(a) * r)) {
6297
          SERIAL_PROTOCOLLNPGM("?(M665 B)ed radius is implausible.");
6298
          return;
6299
        }
6300
      }
6301
    }
6302
 
6303
    // Report settings
6304
    const char *checkingac = PSTR("Checking... AC");
6305
    serialprintPGM(checkingac);
6306
    if (verbose_level == 0) SERIAL_PROTOCOLPGM(" (DRY-RUN)");
6307
    SERIAL_EOL();
6308
    lcd_setstatusPGM(checkingac);
6309
 
6310
    print_calibration_settings(_endstop_results, _angle_results);
6311
 
6312
    ac_setup(!_0p_calibration && !_1p_calibration);
6313
 
6314
    if (!_0p_calibration) ac_home();
6315
 
6316
    do { // start iterations
6317
 
6318
      float z_at_pt[NPP + 1] = { 0.0 };
6319
 
6320
      test_precision = zero_std_dev_old != 999.0 ? (zero_std_dev + zero_std_dev_old) / 2 : zero_std_dev;
6321
      iterations++;
6322
 
6323
      // Probe the points
6324
      zero_std_dev_old = zero_std_dev;
6325
      if (!probe_calibration_points(z_at_pt, probe_points, towers_set, stow_after_each)) {
6326
        SERIAL_PROTOCOLLNPGM("Correct delta settings with M665 and M666");
6327
        return AC_CLEANUP();
6328
      }
6329
      zero_std_dev = std_dev_points(z_at_pt, _0p_calibration, _1p_calibration, _4p_calibration, _4p_opposite_points);
6330
 
6331
      // Solve matrices
6332
 
6333
      if ((zero_std_dev < test_precision || iterations <= force_iterations) && zero_std_dev > calibration_precision) {
6334
 
6335
        #if !HAS_BED_PROBE
6336
          test_precision = 0.00; // forced end
6337
        #endif
6338
 
6339
        if (zero_std_dev < zero_std_dev_min) {
6340
          // set roll-back point
6341
          COPY(e_old, delta_endstop_adj);
6342
          r_old = delta_radius;
6343
          h_old = delta_height;
6344
          COPY(a_old, delta_tower_angle_trim);
6345
        }
6346
 
6347
        float e_delta[ABC] = { 0.0 },
6348
              r_delta = 0.0,
6349
              t_delta[ABC] = { 0.0 };
6350
 
6351
        /**
6352
         * convergence matrices:
6353
         * see https://github.com/LVD-AC/Marlin-AC/tree/1.1.x-AC/documentation for
6354
         *  - definition of the matrix scaling parameters
6355
         *  - matrices for 4 and 7 point calibration
6356
         */
6357
        #define ZP(N,I) ((N) * z_at_pt[I] / 4.0) // 4.0 = divider to normalize to integers
6358
        #define Z12(I) ZP(12, I)
6359
        #define Z4(I) ZP(4, I)
6360
        #define Z2(I) ZP(2, I)
6361
        #define Z1(I) ZP(1, I)
6362
        #define Z0(I) ZP(0, I)
6363
 
6364
        // calculate factors
6365
        const float cr_old = delta_calibration_radius;
6366
        if (_7p_9_center) delta_calibration_radius *= 0.9;
6367
        h_factor = auto_tune_h();
6368
        r_factor = auto_tune_r();
6369
        a_factor = auto_tune_a();
6370
        delta_calibration_radius = cr_old;
6371
 
6372
        switch (probe_points) {
6373
          case 0:
6374
            test_precision = 0.00; // forced end
6375
            break;
6376
 
6377
          case 1:
6378
            test_precision = 0.00; // forced end
6379
            LOOP_XYZ(axis) e_delta[axis] = +Z4(CEN);
6380
            break;
6381
 
6382
          case 2:
6383
            if (towers_set) { // see 4 point calibration (towers) matrix
6384
              e_delta[A_AXIS] = (+Z4(__A) -Z2(__B) -Z2(__C)) * h_factor  +Z4(CEN);
6385
              e_delta[B_AXIS] = (-Z2(__A) +Z4(__B) -Z2(__C)) * h_factor  +Z4(CEN);
6386
              e_delta[C_AXIS] = (-Z2(__A) -Z2(__B) +Z4(__C)) * h_factor  +Z4(CEN);
6387
              r_delta         = (+Z4(__A) +Z4(__B) +Z4(__C) -Z12(CEN)) * r_factor;
6388
            }
6389
            else { // see 4 point calibration (opposites) matrix
6390
              e_delta[A_AXIS] = (-Z4(_BC) +Z2(_CA) +Z2(_AB)) * h_factor  +Z4(CEN);
6391
              e_delta[B_AXIS] = (+Z2(_BC) -Z4(_CA) +Z2(_AB)) * h_factor  +Z4(CEN);
6392
              e_delta[C_AXIS] = (+Z2(_BC) +Z2(_CA) -Z4(_AB)) * h_factor  +Z4(CEN);
6393
              r_delta         = (+Z4(_BC) +Z4(_CA) +Z4(_AB) -Z12(CEN)) * r_factor;
6394
            }
6395
            break;
6396
 
6397
          default: // see 7 point calibration (towers & opposites) matrix
6398
            e_delta[A_AXIS] = (+Z2(__A) -Z1(__B) -Z1(__C) -Z2(_BC) +Z1(_CA) +Z1(_AB)) * h_factor  +Z4(CEN);
6399
            e_delta[B_AXIS] = (-Z1(__A) +Z2(__B) -Z1(__C) +Z1(_BC) -Z2(_CA) +Z1(_AB)) * h_factor  +Z4(CEN);
6400
            e_delta[C_AXIS] = (-Z1(__A) -Z1(__B) +Z2(__C) +Z1(_BC) +Z1(_CA) -Z2(_AB)) * h_factor  +Z4(CEN);
6401
            r_delta         = (+Z2(__A) +Z2(__B) +Z2(__C) +Z2(_BC) +Z2(_CA) +Z2(_AB) -Z12(CEN)) * r_factor;
6402
 
6403
            if (towers_set) { // see 7 point tower angle calibration (towers & opposites) matrix
6404
              t_delta[A_AXIS] = (+Z0(__A) -Z4(__B) +Z4(__C) +Z0(_BC) -Z4(_CA) +Z4(_AB) +Z0(CEN)) * a_factor;
6405
              t_delta[B_AXIS] = (+Z4(__A) +Z0(__B) -Z4(__C) +Z4(_BC) +Z0(_CA) -Z4(_AB) +Z0(CEN)) * a_factor;
6406
              t_delta[C_AXIS] = (-Z4(__A) +Z4(__B) +Z0(__C) -Z4(_BC) +Z4(_CA) +Z0(_AB) +Z0(CEN)) * a_factor;
6407
            }
6408
            break;
6409
        }
6410
        LOOP_XYZ(axis) delta_endstop_adj[axis] += e_delta[axis];
6411
        delta_radius += r_delta;
6412
        LOOP_XYZ(axis) delta_tower_angle_trim[axis] += t_delta[axis];
6413
      }
6414
      else if (zero_std_dev >= test_precision) {
6415
        // roll back
6416
        COPY(delta_endstop_adj, e_old);
6417
        delta_radius = r_old;
6418
        delta_height = h_old;
6419
        COPY(delta_tower_angle_trim, a_old);
6420
      }
6421
 
6422
      if (verbose_level != 0) {                                    // !dry run
6423
 
6424
        // normalise angles to least squares
6425
        if (_angle_results) {
6426
          float a_sum = 0.0;
6427
          LOOP_XYZ(axis) a_sum += delta_tower_angle_trim[axis];
6428
          LOOP_XYZ(axis) delta_tower_angle_trim[axis] -= a_sum / 3.0;
6429
        }
6430
 
6431
        // adjust delta_height and endstops by the max amount
6432
        const float z_temp = MAX3(delta_endstop_adj[A_AXIS], delta_endstop_adj[B_AXIS], delta_endstop_adj[C_AXIS]);
6433
        delta_height -= z_temp;
6434
        LOOP_XYZ(axis) delta_endstop_adj[axis] -= z_temp;
6435
      }
6436
      recalc_delta_settings();
6437
      NOMORE(zero_std_dev_min, zero_std_dev);
6438
 
6439
      // print report
6440
 
6441
      if (verbose_level == 3)
6442
        print_calibration_results(z_at_pt, _tower_results, _opposite_results);
6443
 
6444
      if (verbose_level != 0) { // !dry run
6445
        if ((zero_std_dev >= test_precision && iterations > force_iterations) || zero_std_dev <= calibration_precision) { // end iterations
6446
          SERIAL_PROTOCOLPGM("Calibration OK");
6447
          SERIAL_PROTOCOL_SP(32);
6448
          #if HAS_BED_PROBE
6449
            if (zero_std_dev >= test_precision && !_1p_calibration && !_0p_calibration)
6450
              SERIAL_PROTOCOLPGM("rolling back.");
6451
            else
6452
          #endif
6453
            {
6454
              SERIAL_PROTOCOLPGM("std dev:");
6455
              SERIAL_PROTOCOL_F(zero_std_dev_min, 3);
6456
            }
6457
          SERIAL_EOL();
6458
          char mess[21];
6459
          strcpy_P(mess, PSTR("Calibration sd:"));
6460
          if (zero_std_dev_min < 1)
6461
            sprintf_P(&mess[15], PSTR("0.%03i"), int(LROUND(zero_std_dev_min * 1000.0)));
6462
          else
6463
            sprintf_P(&mess[15], PSTR("%03i.x"), int(LROUND(zero_std_dev_min)));
6464
          lcd_setstatus(mess);
6465
          print_calibration_settings(_endstop_results, _angle_results);
6466
          serialprintPGM(save_message);
6467
          SERIAL_EOL();
6468
        }
6469
        else { // !end iterations
6470
          char mess[15];
6471
          if (iterations < 31)
6472
            sprintf_P(mess, PSTR("Iteration : %02i"), int(iterations));
6473
          else
6474
            strcpy_P(mess, PSTR("No convergence"));
6475
          SERIAL_PROTOCOL(mess);
6476
          SERIAL_PROTOCOL_SP(32);
6477
          SERIAL_PROTOCOLPGM("std dev:");
6478
          SERIAL_PROTOCOL_F(zero_std_dev, 3);
6479
          SERIAL_EOL();
6480
          lcd_setstatus(mess);
6481
          if (verbose_level > 1)
6482
            print_calibration_settings(_endstop_results, _angle_results);
6483
        }
6484
      }
6485
      else { // dry run
6486
        const char *enddryrun = PSTR("End DRY-RUN");
6487
        serialprintPGM(enddryrun);
6488
        SERIAL_PROTOCOL_SP(35);
6489
        SERIAL_PROTOCOLPGM("std dev:");
6490
        SERIAL_PROTOCOL_F(zero_std_dev, 3);
6491
        SERIAL_EOL();
6492
 
6493
        char mess[21];
6494
        strcpy_P(mess, enddryrun);
6495
        strcpy_P(&mess[11], PSTR(" sd:"));
6496
        if (zero_std_dev < 1)
6497
          sprintf_P(&mess[15], PSTR("0.%03i"), int(LROUND(zero_std_dev * 1000.0)));
6498
        else
6499
          sprintf_P(&mess[15], PSTR("%03i.x"), int(LROUND(zero_std_dev)));
6500
        lcd_setstatus(mess);
6501
      }
6502
      ac_home();
6503
    }
6504
    while (((zero_std_dev < test_precision && iterations < 31) || iterations <= force_iterations) && zero_std_dev > calibration_precision);
6505
 
6506
    AC_CLEANUP();
6507
  }
6508
 
6509
#endif // DELTA_AUTO_CALIBRATION
6510
 
6511
#if ENABLED(G38_PROBE_TARGET)
6512
 
6513
  static bool G38_run_probe() {
6514
 
6515
    bool G38_pass_fail = false;
6516
 
6517
    #if MULTIPLE_PROBING > 1
6518
      // Get direction of move and retract
6519
      float retract_mm[XYZ];
6520
      LOOP_XYZ(i) {
6521
        float dist = destination[i] - current_position[i];
6522
        retract_mm[i] = ABS(dist) < G38_MINIMUM_MOVE ? 0 : home_bump_mm((AxisEnum)i) * (dist > 0 ? -1 : 1);
6523
      }
6524
    #endif
6525
 
6526
    // Move until destination reached or target hit
6527
    planner.synchronize();
6528
    endstops.enable(true);
6529
    G38_move = true;
6530
    G38_endstop_hit = false;
6531
    prepare_move_to_destination();
6532
    planner.synchronize();
6533
    G38_move = false;
6534
 
6535
    endstops.hit_on_purpose();
6536
    set_current_from_steppers_for_axis(ALL_AXES);
6537
    SYNC_PLAN_POSITION_KINEMATIC();
6538
 
6539
    if (G38_endstop_hit) {
6540
 
6541
      G38_pass_fail = true;
6542
 
6543
      #if MULTIPLE_PROBING > 1
6544
        // Move away by the retract distance
6545
        set_destination_from_current();
6546
        LOOP_XYZ(i) destination[i] += retract_mm[i];
6547
        endstops.enable(false);
6548
        prepare_move_to_destination();
6549
 
6550
        feedrate_mm_s /= 4;
6551
 
6552
        // Bump the target more slowly
6553
        LOOP_XYZ(i) destination[i] -= retract_mm[i] * 2;
6554
 
6555
        planner.synchronize();
6556
        endstops.enable(true);
6557
        G38_move = true;
6558
        prepare_move_to_destination();
6559
        planner.synchronize();
6560
        G38_move = false;
6561
 
6562
        set_current_from_steppers_for_axis(ALL_AXES);
6563
        SYNC_PLAN_POSITION_KINEMATIC();
6564
      #endif
6565
    }
6566
 
6567
    endstops.hit_on_purpose();
6568
    endstops.not_homing();
6569
    return G38_pass_fail;
6570
  }
6571
 
6572
  /**
6573
   * G38.2 - probe toward workpiece, stop on contact, signal error if failure
6574
   * G38.3 - probe toward workpiece, stop on contact
6575
   *
6576
   * Like G28 except uses Z min probe for all axes
6577
   */
6578
  inline void gcode_G38(bool is_38_2) {
6579
    // Get X Y Z E F
6580
    gcode_get_destination();
6581
 
6582
    setup_for_endstop_or_probe_move();
6583
 
6584
    // If any axis has enough movement, do the move
6585
    LOOP_XYZ(i)
6586
      if (ABS(destination[i] - current_position[i]) >= G38_MINIMUM_MOVE) {
6587
        if (!parser.seenval('F')) feedrate_mm_s = homing_feedrate((AxisEnum)i);
6588
        // If G38.2 fails throw an error
6589
        if (!G38_run_probe() && is_38_2) {
6590
          SERIAL_ERROR_START();
6591
          SERIAL_ERRORLNPGM("Failed to reach target");
6592
        }
6593
        break;
6594
      }
6595
 
6596
    clean_up_after_endstop_or_probe_move();
6597
  }
6598
 
6599
#endif // G38_PROBE_TARGET
6600
 
6601
#if HAS_MESH
6602
 
6603
  /**
6604
   * G42: Move X & Y axes to mesh coordinates (I & J)
6605
   */
6606
  inline void gcode_G42() {
6607
    #if ENABLED(NO_MOTION_BEFORE_HOMING)
6608
      if (axis_unhomed_error()) return;
6609
    #endif
6610
 
6611
    if (IsRunning()) {
6612
      const bool hasI = parser.seenval('I');
6613
      const int8_t ix = hasI ? parser.value_int() : 0;
6614
      const bool hasJ = parser.seenval('J');
6615
      const int8_t iy = hasJ ? parser.value_int() : 0;
6616
 
6617
      if ((hasI && !WITHIN(ix, 0, GRID_MAX_POINTS_X - 1)) || (hasJ && !WITHIN(iy, 0, GRID_MAX_POINTS_Y - 1))) {
6618
        SERIAL_ECHOLNPGM(MSG_ERR_MESH_XY);
6619
        return;
6620
      }
6621
 
6622
      set_destination_from_current();
6623
      if (hasI) destination[X_AXIS] = _GET_MESH_X(ix);
6624
      if (hasJ) destination[Y_AXIS] = _GET_MESH_Y(iy);
6625
      if (parser.boolval('P')) {
6626
        if (hasI) destination[X_AXIS] -= X_PROBE_OFFSET_FROM_EXTRUDER;
6627
        if (hasJ) destination[Y_AXIS] -= Y_PROBE_OFFSET_FROM_EXTRUDER;
6628
      }
6629
 
6630
      const float fval = parser.linearval('F');
6631
      if (fval > 0.0) feedrate_mm_s = MMM_TO_MMS(fval);
6632
 
6633
      // SCARA kinematic has "safe" XY raw moves
6634
      #if IS_SCARA
6635
        prepare_uninterpolated_move_to_destination();
6636
      #else
6637
        prepare_move_to_destination();
6638
      #endif
6639
    }
6640
  }
6641
 
6642
#endif // HAS_MESH
6643
 
6644
/**
6645
 * G92: Set current position to given X Y Z E
6646
 */
6647
inline void gcode_G92() {
6648
 
6649
  #if ENABLED(CNC_COORDINATE_SYSTEMS)
6650
    switch (parser.subcode) {
6651
      case 1:
6652
        // Zero the G92 values and restore current position
6653
        #if !IS_SCARA
6654
          LOOP_XYZ(i) {
6655
            const float v = position_shift[i];
6656
            if (v) {
6657
              position_shift[i] = 0;
6658
              update_software_endstops((AxisEnum)i);
6659
            }
6660
          }
6661
        #endif // Not SCARA
6662
        return;
6663
    }
6664
  #endif
6665
 
6666
  #if ENABLED(CNC_COORDINATE_SYSTEMS)
6667
    #define IS_G92_0 (parser.subcode == 0)
6668
  #else
6669
    #define IS_G92_0 true
6670
  #endif
6671
 
6672
  bool didE = false;
6673
  #if IS_SCARA || !HAS_POSITION_SHIFT || ENABLED(HANGPRINTER)
6674
    bool didXYZ = false;
6675
  #else
6676
    constexpr bool didXYZ = false;
6677
  #endif
6678
 
6679
  if (IS_G92_0) LOOP_XYZE(i) {
6680
    if (parser.seenval(axis_codes[i])) {
6681
      const float l = parser.value_axis_units((AxisEnum)i),
6682
                  v = i == E_CART ? l : LOGICAL_TO_NATIVE(l, i),
6683
                  d = v - current_position[i];
6684
      if (!NEAR_ZERO(d)
6685
        #if ENABLED(HANGPRINTER)
6686
          || true // Hangprinter needs to update its line lengths whether current_position changed or not
6687
        #endif
6688
      ) {
6689
        #if IS_SCARA || !HAS_POSITION_SHIFT || ENABLED(HANGPRINTER)
6690
          if (i == E_CART) didE = true; else didXYZ = true;
6691
          current_position[i] = v;        // Without workspaces revert to Marlin 1.0 behavior
6692
        #elif HAS_POSITION_SHIFT
6693
          if (i == E_CART) {
6694
            didE = true;
6695
            current_position[E_CART] = v; // When using coordinate spaces, only E is set directly
6696
          }
6697
          else {
6698
            position_shift[i] += d;       // Other axes simply offset the coordinate space
6699
            update_software_endstops((AxisEnum)i);
6700
          }
6701
        #endif
6702
      }
6703
    }
6704
  }
6705
 
6706
  #if ENABLED(CNC_COORDINATE_SYSTEMS)
6707
    // Apply workspace offset to the active coordinate system
6708
    if (WITHIN(active_coordinate_system, 0, MAX_COORDINATE_SYSTEMS - 1))
6709
      COPY(coordinate_system[active_coordinate_system], position_shift);
6710
  #endif
6711
 
6712
  // Update planner/steppers only if the native coordinates changed
6713
  if    (didXYZ) SYNC_PLAN_POSITION_KINEMATIC();
6714
  else if (didE) sync_plan_position_e();
6715
 
6716
  report_current_position();
6717
}
6718
 
6719
#if ENABLED(MECHADUINO_I2C_COMMANDS)
6720
  /**
6721
   * G95: Set torque mode
6722
   */
6723
  inline void gcode_G95() {
6724
    i2cFloat torques[NUM_AXIS]; // Assumes 4-byte floats here and in Mechaduino firmware
6725
    LOOP_NUM_AXIS(i)
6726
      torques[i].fval = parser.floatval(RAW_AXIS_CODES(i), 999.9); // 999.9 chosen to satisfy fabs(999.9) > 255.0
6727
 
6728
    // 0x5f == 95
6729
    #define G95_SEND(LETTER) do { \
6730
      if (fabs(torques[_AXIS(LETTER)].fval) < 255.0){ \
6731
        torques[_AXIS(LETTER)].fval = -fabs(torques[_AXIS(LETTER)].fval); \
6732
        if(!INVERT_##LETTER##_DIR) torques[_AXIS(LETTER)].fval = -torques[_AXIS(LETTER)].fval; \
6733
        i2c.address(LETTER##_MOTOR_I2C_ADDR); \
6734
        i2c.reset(); \
6735
        i2c.addbyte(0x5f); \
6736
        i2c.addbytes(torques[_AXIS(LETTER)].bval, sizeof(float)); \
6737
        i2c.send(); \
6738
      }} while(0)
6739
 
6740
    #if ENABLED(HANGPRINTER)
6741
      #if ENABLED(A_IS_MECHADUINO)
6742
        G95_SEND(A);
6743
      #endif
6744
      #if ENABLED(B_IS_MECHADUINO)
6745
        G95_SEND(B);
6746
      #endif
6747
      #if ENABLED(C_IS_MECHADUINO)
6748
        G95_SEND(C);
6749
      #endif
6750
      #if ENABLED(D_IS_MECHADUINO)
6751
        G95_SEND(D);
6752
      #endif
6753
    #else
6754
      #if ENABLED(X_IS_MECHADUINO)
6755
        G95_SEND(X);
6756
      #endif
6757
      #if ENABLED(Y_IS_MECHADUINO)
6758
        G95_SEND(Y);
6759
      #endif
6760
      #if ENABLED(Z_IS_MECHADUINO)
6761
        G95_SEND(Z);
6762
      #endif
6763
    #endif
6764
    #if ENABLED(E_IS_MECHADUINO)
6765
      G95_SEND(E);
6766
    #endif
6767
  }
6768
 
6769
  /**
6770
   * G96: Mark encoder reference point
6771
   */
6772
  inline void gcode_G96() {
6773
    bool mark[NUM_AXIS] = { false };
6774
    if (!parser.seen_any())
6775
      LOOP_NUM_AXIS(i)
6776
        mark[i] = true;
6777
    else
6778
      LOOP_NUM_AXIS(i)
6779
        if (parser.seen(RAW_AXIS_CODES(i)))
6780
          mark[i] = true;
6781
 
6782
    // 0x60 == 96
6783
    #define G96_SEND(LETTER) do {\
6784
      if (mark[LETTER##_AXIS]){ \
6785
        i2c.address(LETTER##_MOTOR_I2C_ADDR); \
6786
        i2c.reset(); \
6787
        i2c.addbyte(0x60); \
6788
        i2c.send(); \
6789
    }} while(0)
6790
 
6791
    #if ENABLED(HANGPRINTER)
6792
      #if ENABLED(A_IS_MECHADUINO)
6793
        G96_SEND(A);
6794
      #endif
6795
      #if ENABLED(B_IS_MECHADUINO)
6796
        G96_SEND(B);
6797
      #endif
6798
      #if ENABLED(C_IS_MECHADUINO)
6799
        G96_SEND(C);
6800
      #endif
6801
      #if ENABLED(D_IS_MECHADUINO)
6802
        G96_SEND(D);
6803
      #endif
6804
    #else
6805
      #if ENABLED(X_IS_MECHADUINO)
6806
        G96_SEND(X);
6807
      #endif
6808
      #if ENABLED(Y_IS_MECHADUINO)
6809
        G96_SEND(Y);
6810
      #endif
6811
      #if ENABLED(Z_IS_MECHADUINO)
6812
        G96_SEND(Z);
6813
      #endif
6814
    #endif
6815
    #if ENABLED(E_IS_MECHADUINO)
6816
      G96_SEND(E); // E ref point not used by any other commands (Feb 7, 2018)
6817
    #endif
6818
  }
6819
 
6820
  float ang_to_mm(float ang, const AxisEnum axis) {
6821
    const float abs_step_in_origin =
6822
      #if ENABLED(LINE_BUILDUP_COMPENSATION_FEATURE)
6823
        planner.k0[axis] * (SQRT(planner.k1[axis] + planner.k2[axis] * line_lengths_origin[axis]) - planner.sqrtk1[axis])
6824
      #else
6825
        line_lengths_origin[axis] * planner.axis_steps_per_mm[axis]
6826
      #endif
6827
    ;
6828
    const float c = abs_step_in_origin + ang * float(STEPS_PER_MOTOR_REVOLUTION) / 360.0; // current step count
6829
    return
6830
      #if ENABLED(LINE_BUILDUP_COMPENSATION_FEATURE)
6831
        // Inverse function found in planner.cpp, where target[AXIS_A] is calculated
6832
        ((c / planner.k0[axis] + planner.sqrtk1[axis]) * (c / planner.k0[axis] + planner.sqrtk1[axis]) - planner.k1[axis]) / planner.k2[axis] - line_lengths_origin[axis]
6833
      #else
6834
        c / planner.axis_steps_per_mm[axis] - line_lengths_origin[axis]
6835
      #endif
6836
    ;
6837
  }
6838
 
6839
  void report_axis_position_from_encoder_data() {
6840
    i2cFloat ang;
6841
 
6842
    #define M114_S1_RECEIVE(LETTER) do { \
6843
      i2c.address(LETTER##_MOTOR_I2C_ADDR); \
6844
      i2c.request(sizeof(float)); \
6845
      i2c.capture(ang.bval, sizeof(float)); \
6846
      if(LETTER##_INVERT_REPORTED_ANGLE == INVERT_##LETTER##_DIR) ang.fval = -ang.fval; \
6847
      SERIAL_PROTOCOL(ang_to_mm(ang.fval, LETTER##_AXIS)); \
6848
    } while(0)
6849
 
6850
    SERIAL_CHAR('[');
6851
    #if ENABLED(HANGPRINTER)
6852
      #if ENABLED(A_IS_MECHADUINO)
6853
        M114_S1_RECEIVE(A);
6854
      #endif
6855
      #if ENABLED(B_IS_MECHADUINO)
6856
        SERIAL_PROTOCOLPGM(", ");
6857
        M114_S1_RECEIVE(B);
6858
      #endif
6859
      #if ENABLED(C_IS_MECHADUINO)
6860
        SERIAL_PROTOCOLPGM(", ");
6861
        M114_S1_RECEIVE(C);
6862
      #endif
6863
      #if ENABLED(D_IS_MECHADUINO)
6864
        SERIAL_PROTOCOLPGM(", ");
6865
        M114_S1_RECEIVE(D);
6866
      #endif
6867
    #else
6868
      #if ENABLED(X_IS_MECHADUINO)
6869
        M114_S1_RECEIVE(X);
6870
      #endif
6871
      #if ENABLED(Y_IS_MECHADUINO)
6872
        SERIAL_PROTOCOLPGM(", ");
6873
        M114_S1_RECEIVE(Y);
6874
      #endif
6875
      #if ENABLED(Z_IS_MECHADUINO)
6876
        SERIAL_PROTOCOLPGM(", ");
6877
        M114_S1_RECEIVE(Z);
6878
      #endif
6879
    #endif
6880
    SERIAL_CHAR(']');
6881
    SERIAL_EOL();
6882
  }
6883
 
6884
#endif // MECHADUINO_I2C_COMMANDS
6885
 
6886
 
6887
void report_xyz_from_stepper_position() {
6888
  get_cartesian_from_steppers(); // writes to cartes[XYZ]
6889
  SERIAL_CHAR('[');
6890
  SERIAL_PROTOCOL(cartes[X_AXIS]);
6891
  SERIAL_PROTOCOLPAIR(", ", cartes[Y_AXIS]);
6892
  SERIAL_PROTOCOLPAIR(", ", cartes[Z_AXIS]);
6893
  SERIAL_CHAR(']');
6894
  SERIAL_EOL();
6895
}
6896
 
6897
#if HAS_RESUME_CONTINUE
6898
 
6899
  /**
6900
   * M0: Unconditional stop - Wait for user button press on LCD
6901
   * M1: Conditional stop   - Wait for user button press on LCD
6902
   */
6903
  inline void gcode_M0_M1() {
6904
    const char * const args = parser.string_arg;
6905
 
6906
    millis_t ms = 0;
6907
    bool hasP = false, hasS = false;
6908
    if (parser.seenval('P')) {
6909
      ms = parser.value_millis(); // milliseconds to wait
6910
      hasP = ms > 0;
6911
    }
6912
    if (parser.seenval('S')) {
6913
      ms = parser.value_millis_from_seconds(); // seconds to wait
6914
      hasS = ms > 0;
6915
    }
6916
 
6917
    const bool has_message = !hasP && !hasS && args && *args;
6918
 
6919
    planner.synchronize();
6920
 
6921
    #if ENABLED(ULTIPANEL)
6922
 
6923
      if (has_message)
6924
        lcd_setstatus(args, true);
6925
      else {
6926
        LCD_MESSAGEPGM(MSG_USERWAIT);
6927
        #if ENABLED(LCD_PROGRESS_BAR) && PROGRESS_MSG_EXPIRE > 0
6928
          dontExpireStatus();
6929
        #endif
6930
      }
6931
 
6932
    #else
6933
 
6934
      if (has_message) {
6935
        SERIAL_ECHO_START();
6936
        SERIAL_ECHOLN(args);
6937
      }
6938
 
6939
    #endif
6940
 
6941
    KEEPALIVE_STATE(PAUSED_FOR_USER);
6942
    wait_for_user = true;
6943
 
6944
    if (ms > 0) {
6945
      ms += millis();  // wait until this time for a click
6946
      while (PENDING(millis(), ms) && wait_for_user) idle();
6947
    }
6948
    else
6949
      while (wait_for_user) idle();
6950
 
6951
 
6952
    #if ENABLED(PRINTER_EVENT_LEDS) && ENABLED(SDSUPPORT)
6953
      if (lights_off_after_print) {
6954
        leds.set_off();
6955
        lights_off_after_print = false;
6956
      }
6957
    #endif
6958
 
6959
    lcd_reset_status();
6960
 
6961
    wait_for_user = false;
6962
    KEEPALIVE_STATE(IN_HANDLER);
6963
  }
6964
 
6965
#endif // HAS_RESUME_CONTINUE
6966
 
6967
#if ENABLED(SPINDLE_LASER_ENABLE)
6968
  /**
6969
   * M3: Spindle Clockwise
6970
   * M4: Spindle Counter-clockwise
6971
   *
6972
   *  S0 turns off spindle.
6973
   *
6974
   *  If no speed PWM output is defined then M3/M4 just turns it on.
6975
   *
6976
   *  At least 12.8KHz (50Hz * 256) is needed for spindle PWM.
6977
   *  Hardware PWM is required. ISRs are too slow.
6978
   *
6979
   * NOTE: WGM for timers 3, 4, and 5 must be either Mode 1 or Mode 5.
6980
   *       No other settings give a PWM signal that goes from 0 to 5 volts.
6981
   *
6982
   *       The system automatically sets WGM to Mode 1, so no special
6983
   *       initialization is needed.
6984
   *
6985
   *       WGM bits for timer 2 are automatically set by the system to
6986
   *       Mode 1. This produces an acceptable 0 to 5 volt signal.
6987
   *       No special initialization is needed.
6988
   *
6989
   * NOTE: A minimum PWM frequency of 50 Hz is needed. All prescaler
6990
   *       factors for timers 2, 3, 4, and 5 are acceptable.
6991
   *
6992
   *  SPINDLE_LASER_ENABLE_PIN needs an external pullup or it may power on
6993
   *  the spindle/laser during power-up or when connecting to the host
6994
   *  (usually goes through a reset which sets all I/O pins to tri-state)
6995
   *
6996
   *  PWM duty cycle goes from 0 (off) to 255 (always on).
6997
   */
6998
 
6999
  // Wait for spindle to come up to speed
7000
  inline void delay_for_power_up() { dwell(SPINDLE_LASER_POWERUP_DELAY); }
7001
 
7002
  // Wait for spindle to stop turning
7003
  inline void delay_for_power_down() { dwell(SPINDLE_LASER_POWERDOWN_DELAY); }
7004
 
7005
  /**
7006
   * ocr_val_mode() is used for debugging and to get the points needed to compute the RPM vs ocr_val line
7007
   *
7008
   * it accepts inputs of 0-255
7009
   */
7010
 
7011
  inline void ocr_val_mode() {
7012
    uint8_t spindle_laser_power = parser.value_byte();
7013
    WRITE(SPINDLE_LASER_ENABLE_PIN, SPINDLE_LASER_ENABLE_INVERT); // turn spindle on (active low)
7014
    if (SPINDLE_LASER_PWM_INVERT) spindle_laser_power = 255 - spindle_laser_power;
7015
    analogWrite(SPINDLE_LASER_PWM_PIN, spindle_laser_power);
7016
  }
7017
 
7018
  inline void gcode_M3_M4(bool is_M3) {
7019
 
7020
    planner.synchronize();   // wait until previous movement commands (G0/G0/G2/G3) have completed before playing with the spindle
7021
    #if SPINDLE_DIR_CHANGE
7022
      const bool rotation_dir = (is_M3 && !SPINDLE_INVERT_DIR || !is_M3 && SPINDLE_INVERT_DIR) ? HIGH : LOW;
7023
      if (SPINDLE_STOP_ON_DIR_CHANGE \
7024
         && READ(SPINDLE_LASER_ENABLE_PIN) == SPINDLE_LASER_ENABLE_INVERT \
7025
         && READ(SPINDLE_DIR_PIN) != rotation_dir
7026
      ) {
7027
        WRITE(SPINDLE_LASER_ENABLE_PIN, !SPINDLE_LASER_ENABLE_INVERT);  // turn spindle off
7028
        delay_for_power_down();
7029
      }
7030
      WRITE(SPINDLE_DIR_PIN, rotation_dir);
7031
    #endif
7032
 
7033
    /**
7034
     * Our final value for ocr_val is an unsigned 8 bit value between 0 and 255 which usually means uint8_t.
7035
     * Went to uint16_t because some of the uint8_t calculations would sometimes give 1000 0000 rather than 1111 1111.
7036
     * Then needed to AND the uint16_t result with 0x00FF to make sure we only wrote the byte of interest.
7037
     */
7038
    #if ENABLED(SPINDLE_LASER_PWM)
7039
      if (parser.seen('O')) ocr_val_mode();
7040
      else {
7041
        const float spindle_laser_power = parser.floatval('S');
7042
        if (spindle_laser_power == 0) {
7043
          WRITE(SPINDLE_LASER_ENABLE_PIN, !SPINDLE_LASER_ENABLE_INVERT);                                    // turn spindle off (active low)
7044
          analogWrite(SPINDLE_LASER_PWM_PIN, SPINDLE_LASER_PWM_INVERT ? 255 : 0);                           // only write low byte
7045
          delay_for_power_down();
7046
        }
7047
        else {
7048
          int16_t ocr_val = (spindle_laser_power - (SPEED_POWER_INTERCEPT)) * (1.0f / (SPEED_POWER_SLOPE)); // convert RPM to PWM duty cycle
7049
          NOMORE(ocr_val, 255);                                                                             // limit to max the Atmel PWM will support
7050
          if (spindle_laser_power <= SPEED_POWER_MIN)
7051
            ocr_val = (SPEED_POWER_MIN - (SPEED_POWER_INTERCEPT)) * (1.0f / (SPEED_POWER_SLOPE));           // minimum setting
7052
          if (spindle_laser_power >= SPEED_POWER_MAX)
7053
            ocr_val = (SPEED_POWER_MAX - (SPEED_POWER_INTERCEPT)) * (1.0f / (SPEED_POWER_SLOPE));           // limit to max RPM
7054
          if (SPINDLE_LASER_PWM_INVERT) ocr_val = 255 - ocr_val;
7055
          WRITE(SPINDLE_LASER_ENABLE_PIN, SPINDLE_LASER_ENABLE_INVERT);                                     // turn spindle on (active low)
7056
          analogWrite(SPINDLE_LASER_PWM_PIN, ocr_val & 0xFF);                                               // only write low byte
7057
          delay_for_power_up();
7058
        }
7059
      }
7060
    #else
7061
      WRITE(SPINDLE_LASER_ENABLE_PIN, SPINDLE_LASER_ENABLE_INVERT); // turn spindle on (active low) if spindle speed option not enabled
7062
      delay_for_power_up();
7063
    #endif
7064
  }
7065
 
7066
 /**
7067
  * M5 turn off spindle
7068
  */
7069
  inline void gcode_M5() {
7070
    planner.synchronize();
7071
    WRITE(SPINDLE_LASER_ENABLE_PIN, !SPINDLE_LASER_ENABLE_INVERT);
7072
    #if ENABLED(SPINDLE_LASER_PWM)
7073
      analogWrite(SPINDLE_LASER_PWM_PIN, SPINDLE_LASER_PWM_INVERT ? 255 : 0);
7074
    #endif
7075
    delay_for_power_down();
7076
  }
7077
 
7078
#endif // SPINDLE_LASER_ENABLE
7079
 
7080
/**
7081
 * M17: Enable power on all stepper motors
7082
 */
7083
inline void gcode_M17() {
7084
  LCD_MESSAGEPGM(MSG_NO_MOVE);
7085
  enable_all_steppers();
7086
}
7087
 
7088
#if ENABLED(ADVANCED_PAUSE_FEATURE)
7089
 
7090
  void do_pause_e_move(const float &length, const float &fr) {
7091
    set_destination_from_current();
7092
    destination[E_CART] += length / planner.e_factor[active_extruder];
7093
    planner.buffer_line_kinematic(destination, fr, active_extruder);
7094
    set_current_from_destination();
7095
    planner.synchronize();
7096
  }
7097
 
7098
  static float resume_position[XYZE];
7099
  int8_t did_pause_print = 0;
7100
 
7101
  #if HAS_BUZZER
7102
    static void filament_change_beep(const int8_t max_beep_count, const bool init=false) {
7103
      static millis_t next_buzz = 0;
7104
      static int8_t runout_beep = 0;
7105
 
7106
      if (init) next_buzz = runout_beep = 0;
7107
 
7108
      const millis_t ms = millis();
7109
      if (ELAPSED(ms, next_buzz)) {
7110
        if (max_beep_count < 0 || runout_beep < max_beep_count + 5) { // Only beep as long as we're supposed to
7111
          next_buzz = ms + ((max_beep_count < 0 || runout_beep < max_beep_count) ? 1000 : 500);
7112
          BUZZ(50, 880 - (runout_beep & 1) * 220);
7113
          runout_beep++;
7114
        }
7115
      }
7116
    }
7117
  #endif
7118
 
7119
  /**
7120
   * Ensure a safe temperature for extrusion
7121
   *
7122
   * - Fail if the TARGET temperature is too low
7123
   * - Display LCD placard with temperature status
7124
   * - Return when heating is done or aborted
7125
   *
7126
   * Returns 'true' if heating was completed, 'false' for abort
7127
   */
7128
  static bool ensure_safe_temperature(const AdvancedPauseMode mode=ADVANCED_PAUSE_MODE_PAUSE_PRINT) {
7129
 
7130
    #if ENABLED(PREVENT_COLD_EXTRUSION)
7131
      if (!DEBUGGING(DRYRUN) && thermalManager.targetTooColdToExtrude(active_extruder)) {
7132
        SERIAL_ERROR_START();
7133
        SERIAL_ERRORLNPGM(MSG_HOTEND_TOO_COLD);
7134
        return false;
7135
      }
7136
    #endif
7137
 
7138
    #if ENABLED(ULTIPANEL)
7139
      lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_WAIT_FOR_NOZZLES_TO_HEAT, mode);
7140
    #else
7141
      UNUSED(mode);
7142
    #endif
7143
 
7144
    wait_for_heatup = true; // M108 will clear this
7145
    while (wait_for_heatup && thermalManager.wait_for_heating(active_extruder)) idle();
7146
    const bool status = wait_for_heatup;
7147
    wait_for_heatup = false;
7148
 
7149
    return status;
7150
  }
7151
 
7152
  /**
7153
   * Load filament into the hotend
7154
   *
7155
   * - Fail if the a safe temperature was not reached
7156
   * - If pausing for confirmation, wait for a click or M108
7157
   * - Show "wait for load" placard
7158
   * - Load and purge filament
7159
   * - Show "Purge more" / "Continue" menu
7160
   * - Return when "Continue" is selected
7161
   *
7162
   * Returns 'true' if load was completed, 'false' for abort
7163
   */
7164
  static bool load_filament(const float &slow_load_length=0, const float &fast_load_length=0, const float &purge_length=0, const int8_t max_beep_count=0,
7165
                            const bool show_lcd=false, const bool pause_for_user=false,
7166
                            const AdvancedPauseMode mode=ADVANCED_PAUSE_MODE_PAUSE_PRINT
7167
  ) {
7168
    #if DISABLED(ULTIPANEL)
7169
      UNUSED(show_lcd);
7170
    #endif
7171
 
7172
    if (!ensure_safe_temperature(mode)) {
7173
      #if ENABLED(ULTIPANEL)
7174
        if (show_lcd) // Show status screen
7175
          lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_STATUS);
7176
      #endif
7177
 
7178
      return false;
7179
    }
7180
 
7181
    if (pause_for_user) {
7182
      #if ENABLED(ULTIPANEL)
7183
        if (show_lcd) // Show "insert filament"
7184
          lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_INSERT, mode);
7185
      #endif
7186
      SERIAL_ECHO_START();
7187
      SERIAL_ECHOLNPGM(MSG_FILAMENT_CHANGE_INSERT);
7188
 
7189
      #if HAS_BUZZER
7190
        filament_change_beep(max_beep_count, true);
7191
      #else
7192
        UNUSED(max_beep_count);
7193
      #endif
7194
 
7195
      KEEPALIVE_STATE(PAUSED_FOR_USER);
7196
      wait_for_user = true;    // LCD click or M108 will clear this
7197
      while (wait_for_user) {
7198
        #if HAS_BUZZER
7199
          filament_change_beep(max_beep_count);
7200
        #endif
7201
        idle(true);
7202
      }
7203
      KEEPALIVE_STATE(IN_HANDLER);
7204
    }
7205
 
7206
    #if ENABLED(ULTIPANEL)
7207
      if (show_lcd) // Show "wait for load" message
7208
        lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_LOAD, mode);
7209
    #endif
7210
 
7211
    // Slow Load filament
7212
    if (slow_load_length) do_pause_e_move(slow_load_length, FILAMENT_CHANGE_SLOW_LOAD_FEEDRATE);
7213
 
7214
    // Fast Load Filament
7215
    if (fast_load_length) {
7216
      #if FILAMENT_CHANGE_FAST_LOAD_ACCEL > 0
7217
        const float saved_acceleration = planner.retract_acceleration;
7218
        planner.retract_acceleration = FILAMENT_CHANGE_FAST_LOAD_ACCEL;
7219
      #endif
7220
 
7221
      do_pause_e_move(fast_load_length, FILAMENT_CHANGE_FAST_LOAD_FEEDRATE);
7222
 
7223
      #if FILAMENT_CHANGE_FAST_LOAD_ACCEL > 0
7224
        planner.retract_acceleration = saved_acceleration;
7225
      #endif
7226
    }
7227
 
7228
    #if ENABLED(ADVANCED_PAUSE_CONTINUOUS_PURGE)
7229
 
7230
      #if ENABLED(ULTIPANEL)
7231
        if (show_lcd)
7232
          lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_CONTINUOUS_PURGE);
7233
      #endif
7234
 
7235
      wait_for_user = true;
7236
      for (float purge_count = purge_length; purge_count > 0 && wait_for_user; --purge_count)
7237
        do_pause_e_move(1, ADVANCED_PAUSE_PURGE_FEEDRATE);
7238
      wait_for_user = false;
7239
 
7240
    #else
7241
 
7242
      do {
7243
        if (purge_length > 0) {
7244
          // "Wait for filament purge"
7245
          #if ENABLED(ULTIPANEL)
7246
            if (show_lcd)
7247
              lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_PURGE, mode);
7248
          #endif
7249
 
7250
          // Extrude filament to get into hotend
7251
          do_pause_e_move(purge_length, ADVANCED_PAUSE_PURGE_FEEDRATE);
7252
        }
7253
 
7254
        // Show "Purge More" / "Resume" menu and wait for reply
7255
        #if ENABLED(ULTIPANEL)
7256
          if (show_lcd) {
7257
            KEEPALIVE_STATE(PAUSED_FOR_USER);
7258
            wait_for_user = false;
7259
            lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_OPTION, mode);
7260
            while (advanced_pause_menu_response == ADVANCED_PAUSE_RESPONSE_WAIT_FOR) idle(true);
7261
            KEEPALIVE_STATE(IN_HANDLER);
7262
          }
7263
        #endif
7264
 
7265
        // Keep looping if "Purge More" was selected
7266
      } while (
7267
        #if ENABLED(ULTIPANEL)
7268
          show_lcd && advanced_pause_menu_response == ADVANCED_PAUSE_RESPONSE_EXTRUDE_MORE
7269
        #else
7270
 
7271
        #endif
7272
      );
7273
 
7274
    #endif
7275
 
7276
    return true;
7277
  }
7278
 
7279
  /**
7280
   * Unload filament from the hotend
7281
   *
7282
   * - Fail if the a safe temperature was not reached
7283
   * - Show "wait for unload" placard
7284
   * - Retract, pause, then unload filament
7285
   * - Disable E stepper (on most machines)
7286
   *
7287
   * Returns 'true' if unload was completed, 'false' for abort
7288
   */
7289
  static bool unload_filament(const float &unload_length, const bool show_lcd=false,
7290
                              const AdvancedPauseMode mode=ADVANCED_PAUSE_MODE_PAUSE_PRINT
7291
  ) {
7292
    if (!ensure_safe_temperature(mode)) {
7293
      #if ENABLED(ULTIPANEL)
7294
        if (show_lcd) // Show status screen
7295
          lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_STATUS);
7296
      #endif
7297
 
7298
      return false;
7299
    }
7300
 
7301
    #if DISABLED(ULTIPANEL)
7302
      UNUSED(show_lcd);
7303
    #else
7304
      if (show_lcd)
7305
        lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_UNLOAD, mode);
7306
    #endif
7307
 
7308
    // Retract filament
7309
    do_pause_e_move(-FILAMENT_UNLOAD_RETRACT_LENGTH, PAUSE_PARK_RETRACT_FEEDRATE);
7310
 
7311
    // Wait for filament to cool
7312
    safe_delay(FILAMENT_UNLOAD_DELAY);
7313
 
7314
    // Quickly purge
7315
    do_pause_e_move(FILAMENT_UNLOAD_RETRACT_LENGTH + FILAMENT_UNLOAD_PURGE_LENGTH, planner.max_feedrate_mm_s[E_AXIS]);
7316
 
7317
    // Unload filament
7318
    #if FILAMENT_CHANGE_FAST_LOAD_ACCEL > 0
7319
      const float saved_acceleration = planner.retract_acceleration;
7320
      planner.retract_acceleration = FILAMENT_CHANGE_UNLOAD_ACCEL;
7321
    #endif
7322
 
7323
    do_pause_e_move(unload_length, FILAMENT_CHANGE_UNLOAD_FEEDRATE);
7324
 
7325
    #if FILAMENT_CHANGE_FAST_LOAD_ACCEL > 0
7326
      planner.retract_acceleration = saved_acceleration;
7327
    #endif
7328
 
7329
    // Disable extruders steppers for manual filament changing (only on boards that have separate ENABLE_PINS)
7330
    #if E0_ENABLE_PIN != X_ENABLE_PIN && E1_ENABLE_PIN != Y_ENABLE_PIN
7331
      disable_e_stepper(active_extruder);
7332
      safe_delay(100);
7333
    #endif
7334
 
7335
    return true;
7336
  }
7337
 
7338
  /**
7339
   * Pause procedure
7340
   *
7341
   * - Abort if already paused
7342
   * - Send host action for pause, if configured
7343
   * - Abort if TARGET temperature is too low
7344
   * - Display "wait for start of filament change" (if a length was specified)
7345
   * - Initial retract, if current temperature is hot enough
7346
   * - Park the nozzle at the given position
7347
   * - Call unload_filament (if a length was specified)
7348
   *
7349
   * Returns 'true' if pause was completed, 'false' for abort
7350
   */
7351
  static bool pause_print(const float &retract, const point_t &park_point, const float &unload_length=0, const bool show_lcd=false) {
7352
    if (did_pause_print) return false; // already paused
7353
 
7354
    #ifdef ACTION_ON_PAUSE
7355
      SERIAL_ECHOLNPGM("//action:" ACTION_ON_PAUSE);
7356
    #endif
7357
 
7358
    if (!DEBUGGING(DRYRUN) && unload_length && thermalManager.targetTooColdToExtrude(active_extruder)) {
7359
      SERIAL_ERROR_START();
7360
      SERIAL_ERRORLNPGM(MSG_HOTEND_TOO_COLD);
7361
 
7362
      #if ENABLED(ULTIPANEL)
7363
        if (show_lcd) // Show status screen
7364
          lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_STATUS);
7365
        LCD_MESSAGEPGM(MSG_M600_TOO_COLD);
7366
      #endif
7367
 
7368
      return false; // unable to reach safe temperature
7369
    }
7370
 
7371
    // Indicate that the printer is paused
7372
    ++did_pause_print;
7373
 
7374
    // Pause the print job and timer
7375
    #if ENABLED(SDSUPPORT)
7376
      if (card.sdprinting) {
7377
        card.pauseSDPrint();
7378
        ++did_pause_print; // Indicate SD pause also
7379
      }
7380
    #endif
7381
    print_job_timer.pause();
7382
 
7383
    // Save current position
7384
    COPY(resume_position, current_position);
7385
 
7386
    // Wait for synchronize steppers
7387
    planner.synchronize();
7388
 
7389
    // Initial retract before move to filament change position
7390
    if (retract && thermalManager.hotEnoughToExtrude(active_extruder))
7391
      do_pause_e_move(retract, PAUSE_PARK_RETRACT_FEEDRATE);
7392
 
7393
    // Park the nozzle by moving up by z_lift and then moving to (x_pos, y_pos)
7394
    if (!axis_unhomed_error())
7395
      Nozzle::park(2, park_point);
7396
 
7397
    // Unload the filament
7398
    if (unload_length)
7399
      unload_filament(unload_length, show_lcd);
7400
 
7401
    return true;
7402
  }
7403
 
7404
  /**
7405
   * - Show "Insert filament and press button to continue"
7406
   * - Wait for a click before returning
7407
   * - Heaters can time out, reheated before accepting a click
7408
   *
7409
   * Used by M125 and M600
7410
   */
7411
  static void wait_for_filament_reload(const int8_t max_beep_count=0) {
7412
    bool nozzle_timed_out = false;
7413
 
7414
    #if ENABLED(ULTIPANEL)
7415
      lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_INSERT);
7416
    #endif
7417
    SERIAL_ECHO_START();
7418
    SERIAL_ERRORLNPGM(MSG_FILAMENT_CHANGE_INSERT);
7419
 
7420
    #if HAS_BUZZER
7421
      filament_change_beep(max_beep_count, true);
7422
    #endif
7423
 
7424
    // Start the heater idle timers
7425
    const millis_t nozzle_timeout = (millis_t)(PAUSE_PARK_NOZZLE_TIMEOUT) * 1000UL;
7426
 
7427
    HOTEND_LOOP()
7428
      thermalManager.start_heater_idle_timer(e, nozzle_timeout);
7429
 
7430
    // Wait for filament insert by user and press button
7431
    KEEPALIVE_STATE(PAUSED_FOR_USER);
7432
    wait_for_user = true;    // LCD click or M108 will clear this
7433
    while (wait_for_user) {
7434
      #if HAS_BUZZER
7435
        filament_change_beep(max_beep_count);
7436
      #endif
7437
 
7438
      // If the nozzle has timed out, wait for the user to press the button to re-heat the nozzle, then
7439
      // re-heat the nozzle, re-show the insert screen, restart the idle timers, and start over
7440
      if (!nozzle_timed_out)
7441
        HOTEND_LOOP()
7442
          nozzle_timed_out |= thermalManager.is_heater_idle(e);
7443
 
7444
      if (nozzle_timed_out) {
7445
        #if ENABLED(ULTIPANEL)
7446
          lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_CLICK_TO_HEAT_NOZZLE);
7447
        #endif
7448
        SERIAL_ECHO_START();
7449
        #if ENABLED(ULTIPANEL) && ENABLED(EMERGENCY_PARSER)
7450
          SERIAL_ERRORLNPGM(MSG_FILAMENT_CHANGE_HEAT);
7451
        #elif ENABLED(EMERGENCY_PARSER)
7452
          SERIAL_ERRORLNPGM(MSG_FILAMENT_CHANGE_HEAT_M108);
7453
        #else
7454
          SERIAL_ERRORLNPGM(MSG_FILAMENT_CHANGE_HEAT_LCD);
7455
        #endif
7456
 
7457
        // Wait for LCD click or M108
7458
        while (wait_for_user) idle(true);
7459
 
7460
        // Re-enable the heaters if they timed out
7461
        HOTEND_LOOP() thermalManager.reset_heater_idle_timer(e);
7462
 
7463
        // Wait for the heaters to reach the target temperatures
7464
        ensure_safe_temperature();
7465
 
7466
        #if ENABLED(ULTIPANEL)
7467
          lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_INSERT);
7468
        #endif
7469
        SERIAL_ECHO_START();
7470
        #if ENABLED(ULTIPANEL) && ENABLED(EMERGENCY_PARSER)
7471
          SERIAL_ERRORLNPGM(MSG_FILAMENT_CHANGE_INSERT);
7472
        #elif ENABLED(EMERGENCY_PARSER)
7473
          SERIAL_ERRORLNPGM(MSG_FILAMENT_CHANGE_INSERT_M108);
7474
        #else
7475
          SERIAL_ERRORLNPGM(MSG_FILAMENT_CHANGE_INSERT_LCD);
7476
        #endif
7477
 
7478
        // Start the heater idle timers
7479
        const millis_t nozzle_timeout = (millis_t)(PAUSE_PARK_NOZZLE_TIMEOUT) * 1000UL;
7480
 
7481
        HOTEND_LOOP()
7482
          thermalManager.start_heater_idle_timer(e, nozzle_timeout);
7483
 
7484
        wait_for_user = true; // Wait for user to load filament
7485
        nozzle_timed_out = false;
7486
 
7487
        #if HAS_BUZZER
7488
          filament_change_beep(max_beep_count, true);
7489
        #endif
7490
      }
7491
 
7492
      idle(true);
7493
    }
7494
    KEEPALIVE_STATE(IN_HANDLER);
7495
  }
7496
 
7497
  /**
7498
   * Resume or Start print procedure
7499
   *
7500
   * - Abort if not paused
7501
   * - Reset heater idle timers
7502
   * - Load filament if specified, but only if:
7503
   *   - a nozzle timed out, or
7504
   *   - the nozzle is already heated.
7505
   * - Display "wait for print to resume"
7506
   * - Re-prime the nozzle...
7507
   *   -  FWRETRACT: Recover/prime from the prior G10.
7508
   *   - !FWRETRACT: Retract by resume_position[E], if negative.
7509
   *                 Not sure how this logic comes into use.
7510
   * - Move the nozzle back to resume_position
7511
   * - Sync the planner E to resume_position[E]
7512
   * - Send host action for resume, if configured
7513
   * - Resume the current SD print job, if any
7514
   */
7515
  static void resume_print(const float &slow_load_length=0, const float &fast_load_length=0, const float &purge_length=ADVANCED_PAUSE_PURGE_LENGTH, const int8_t max_beep_count=0) {
7516
    if (!did_pause_print) return;
7517
 
7518
    // Re-enable the heaters if they timed out
7519
    bool nozzle_timed_out = false;
7520
    HOTEND_LOOP() {
7521
      nozzle_timed_out |= thermalManager.is_heater_idle(e);
7522
      thermalManager.reset_heater_idle_timer(e);
7523
    }
7524
 
7525
    if (nozzle_timed_out || thermalManager.hotEnoughToExtrude(active_extruder)) {
7526
      // Load the new filament
7527
      load_filament(slow_load_length, fast_load_length, purge_length, max_beep_count, true, nozzle_timed_out);
7528
    }
7529
 
7530
    #if ENABLED(ULTIPANEL)
7531
      // "Wait for print to resume"
7532
      lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_RESUME);
7533
    #endif
7534
 
7535
    // Intelligent resuming
7536
    #if ENABLED(FWRETRACT)
7537
      // If retracted before goto pause
7538
      if (fwretract.retracted[active_extruder])
7539
        do_pause_e_move(-fwretract.retract_length, fwretract.retract_feedrate_mm_s);
7540
    #endif
7541
 
7542
    // If resume_position is negative
7543
    if (resume_position[E_CART] < 0) do_pause_e_move(resume_position[E_CART], PAUSE_PARK_RETRACT_FEEDRATE);
7544
 
7545
    // Move XY to starting position, then Z
7546
    do_blocking_move_to_xy(resume_position[X_AXIS], resume_position[Y_AXIS], NOZZLE_PARK_XY_FEEDRATE);
7547
 
7548
    // Set Z_AXIS to saved position
7549
    do_blocking_move_to_z(resume_position[Z_AXIS], NOZZLE_PARK_Z_FEEDRATE);
7550
 
7551
    // Now all extrusion positions are resumed and ready to be confirmed
7552
    // Set extruder to saved position
7553
    planner.set_e_position_mm((destination[E_CART] = current_position[E_CART] = resume_position[E_CART]));
7554
 
7555
    #if ENABLED(FILAMENT_RUNOUT_SENSOR)
7556
      runout.reset();
7557
    #endif
7558
 
7559
    #if ENABLED(ULTIPANEL)
7560
      // Show status screen
7561
      lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_STATUS);
7562
    #endif
7563
 
7564
    #ifdef ACTION_ON_RESUME
7565
      SERIAL_ECHOLNPGM("//action:" ACTION_ON_RESUME);
7566
    #endif
7567
 
7568
    --did_pause_print;
7569
 
7570
    #if ENABLED(SDSUPPORT)
7571
      if (did_pause_print) {
7572
        card.startFileprint();
7573
        --did_pause_print;
7574
      }
7575
    #endif
7576
  }
7577
 
7578
#endif // ADVANCED_PAUSE_FEATURE
7579
 
7580
#if ENABLED(SDSUPPORT)
7581
 
7582
  /**
7583
   * M20: List SD card to serial output
7584
   */
7585
  inline void gcode_M20() {
7586
    SERIAL_PROTOCOLLNPGM(MSG_BEGIN_FILE_LIST);
7587
    card.ls();
7588
    SERIAL_PROTOCOLLNPGM(MSG_END_FILE_LIST);
7589
  }
7590
 
7591
  /**
7592
   * M21: Init SD Card
7593
   */
7594
  inline void gcode_M21() { card.initsd(); }
7595
 
7596
  /**
7597
   * M22: Release SD Card
7598
   */
7599
  inline void gcode_M22() { card.release(); }
7600
 
7601
  /**
7602
   * M23: Open a file
7603
   */
7604
  inline void gcode_M23() {
7605
    #if ENABLED(POWER_LOSS_RECOVERY)
7606
      card.removeJobRecoveryFile();
7607
    #endif
7608
    // Simplify3D includes the size, so zero out all spaces (#7227)
7609
    for (char *fn = parser.string_arg; *fn; ++fn) if (*fn == ' ') *fn = '\0';
7610
    card.openFile(parser.string_arg, true);
7611
  }
7612
 
7613
  /**
7614
   * M24: Start or Resume SD Print
7615
   */
7616
  inline void gcode_M24() {
7617
    #if ENABLED(PARK_HEAD_ON_PAUSE)
7618
      resume_print();
7619
    #endif
7620
 
7621
    #if ENABLED(POWER_LOSS_RECOVERY)
7622
      if (parser.seenval('S')) card.setIndex(parser.value_long());
7623
    #endif
7624
 
7625
    card.startFileprint();
7626
 
7627
    #if ENABLED(POWER_LOSS_RECOVERY)
7628
      if (parser.seenval('T'))
7629
        print_job_timer.resume(parser.value_long());
7630
      else
7631
    #endif
7632
        print_job_timer.start();
7633
  }
7634
 
7635
  /**
7636
   * M25: Pause SD Print
7637
   */
7638
  inline void gcode_M25() {
7639
    card.pauseSDPrint();
7640
    print_job_timer.pause();
7641
 
7642
    #if ENABLED(PARK_HEAD_ON_PAUSE)
7643
      enqueue_and_echo_commands_P(PSTR("M125")); // Must be enqueued with pauseSDPrint set to be last in the buffer
7644
    #endif
7645
  }
7646
 
7647
  /**
7648
   * M26: Set SD Card file index
7649
   */
7650
  inline void gcode_M26() {
7651
    if (card.cardOK && parser.seenval('S'))
7652
      card.setIndex(parser.value_long());
7653
  }
7654
 
7655
  /**
7656
   * M27: Get SD Card status
7657
   *      OR, with 'S<seconds>' set the SD status auto-report interval. (Requires AUTO_REPORT_SD_STATUS)
7658
   *      OR, with 'C' get the current filename.
7659
   */
7660
  inline void gcode_M27() {
7661
    if (parser.seen('C')) {
7662
      SERIAL_ECHOPGM("Current file: ");
7663
      card.printFilename();
7664
    }
7665
 
7666
    #if ENABLED(AUTO_REPORT_SD_STATUS)
7667
      else if (parser.seenval('S'))
7668
        card.set_auto_report_interval(parser.value_byte());
7669
    #endif
7670
 
7671
    else
7672
      card.getStatus();
7673
  }
7674
 
7675
  /**
7676
   * M28: Start SD Write
7677
   */
7678
  inline void gcode_M28() { card.openFile(parser.string_arg, false); }
7679
 
7680
  /**
7681
   * M29: Stop SD Write
7682
   * Processed in write to file routine above
7683
   */
7684
  inline void gcode_M29() {
7685
    // card.saving = false;
7686
  }
7687
 
7688
  /**
7689
   * M30 <filename>: Delete SD Card file
7690
   */
7691
  inline void gcode_M30() {
7692
    if (card.cardOK) {
7693
      card.closefile();
7694
      card.removeFile(parser.string_arg);
7695
    }
7696
  }
7697
 
7698
#endif // SDSUPPORT
7699
 
7700
/**
7701
 * M31: Get the time since the start of SD Print (or last M109)
7702
 */
7703
inline void gcode_M31() {
7704
  char buffer[21];
7705
  duration_t elapsed = print_job_timer.duration();
7706
  elapsed.toString(buffer);
7707
  lcd_setstatus(buffer);
7708
 
7709
  SERIAL_ECHO_START();
7710
  SERIAL_ECHOLNPAIR("Print time: ", buffer);
7711
}
7712
 
7713
#if ENABLED(SDSUPPORT)
7714
 
7715
  /**
7716
   * M32: Select file and start SD Print
7717
   *
7718
   * Examples:
7719
   *
7720
   *    M32 !PATH/TO/FILE.GCO#      ; Start FILE.GCO
7721
   *    M32 P !PATH/TO/FILE.GCO#    ; Start FILE.GCO as a procedure
7722
   *    M32 S60 !PATH/TO/FILE.GCO#  ; Start FILE.GCO at byte 60
7723
   *
7724
   */
7725
  inline void gcode_M32() {
7726
    if (card.sdprinting) planner.synchronize();
7727
 
7728
    if (card.cardOK) {
7729
      const bool call_procedure = parser.boolval('P');
7730
 
7731
      card.openFile(parser.string_arg, true, call_procedure);
7732
 
7733
      if (parser.seenval('S')) card.setIndex(parser.value_long());
7734
 
7735
      card.startFileprint();
7736
 
7737
      // Procedure calls count as normal print time.
7738
      if (!call_procedure) print_job_timer.start();
7739
    }
7740
  }
7741
 
7742
  #if ENABLED(LONG_FILENAME_HOST_SUPPORT)
7743
 
7744
    /**
7745
     * M33: Get the long full path of a file or folder
7746
     *
7747
     * Parameters:
7748
     *   <dospath> Case-insensitive DOS-style path to a file or folder
7749
     *
7750
     * Example:
7751
     *   M33 miscel~1/armchair/armcha~1.gco
7752
     *
7753
     * Output:
7754
     *   /Miscellaneous/Armchair/Armchair.gcode
7755
     */
7756
    inline void gcode_M33() {
7757
      card.printLongPath(parser.string_arg);
7758
    }
7759
 
7760
  #endif
7761
 
7762
  #if ENABLED(SDCARD_SORT_ALPHA) && ENABLED(SDSORT_GCODE)
7763
    /**
7764
     * M34: Set SD Card Sorting Options
7765
     */
7766
    inline void gcode_M34() {
7767
      if (parser.seen('S')) card.setSortOn(parser.value_bool());
7768
      if (parser.seenval('F')) {
7769
        const int v = parser.value_long();
7770
        card.setSortFolders(v < 0 ? -1 : v > 0 ? 1 : 0);
7771
      }
7772
      //if (parser.seen('R')) card.setSortReverse(parser.value_bool());
7773
    }
7774
  #endif // SDCARD_SORT_ALPHA && SDSORT_GCODE
7775
 
7776
  /**
7777
   * M928: Start SD Write
7778
   */
7779
  inline void gcode_M928() {
7780
    card.openLogFile(parser.string_arg);
7781
  }
7782
 
7783
#endif // SDSUPPORT
7784
 
7785
/**
7786
 * Sensitive pin test for M42, M226
7787
 */
7788
static bool pin_is_protected(const pin_t pin) {
7789
  static const pin_t sensitive_pins[] PROGMEM = SENSITIVE_PINS;
7790
  for (uint8_t i = 0; i < COUNT(sensitive_pins); i++)
7791
    if (pin == (pin_t)pgm_read_byte(&sensitive_pins[i])) return true;
7792
  return false;
7793
}
7794
 
7795
inline void protected_pin_err() {
7796
  SERIAL_ERROR_START();
7797
  SERIAL_ERRORLNPGM(MSG_ERR_PROTECTED_PIN);
7798
}
7799
 
7800
/**
7801
 * M42: Change pin status via GCode
7802
 *
7803
 *  P<pin>  Pin number (LED if omitted)
7804
 *  S<byte> Pin status from 0 - 255
7805
 *  I       Flag to ignore Marlin's pin protection
7806
 */
7807
inline void gcode_M42() {
7808
  if (!parser.seenval('S')) return;
7809
  const byte pin_status = parser.value_byte();
7810
 
7811
  const pin_t pin_number = parser.byteval('P', LED_PIN);
7812
  if (pin_number < 0) return;
7813
 
7814
  if (!parser.boolval('I') && pin_is_protected(pin_number)) return protected_pin_err();
7815
 
7816
  pinMode(pin_number, OUTPUT);
7817
  digitalWrite(pin_number, pin_status);
7818
  analogWrite(pin_number, pin_status);
7819
 
7820
  #if FAN_COUNT > 0
7821
    switch (pin_number) {
7822
      #if HAS_FAN0
7823
        case FAN_PIN: fanSpeeds[0] = pin_status; break;
7824
      #endif
7825
      #if HAS_FAN1
7826
        case FAN1_PIN: fanSpeeds[1] = pin_status; break;
7827
      #endif
7828
      #if HAS_FAN2
7829
        case FAN2_PIN: fanSpeeds[2] = pin_status; break;
7830
      #endif
7831
    }
7832
  #endif
7833
}
7834
 
7835
#if ENABLED(PINS_DEBUGGING)
7836
 
7837
  #include "pinsDebug.h"
7838
 
7839
  inline void toggle_pins() {
7840
    const bool ignore_protection = parser.boolval('I');
7841
    const int repeat = parser.intval('R', 1),
7842
              start = parser.intval('S'),
7843
              end = parser.intval('L', NUM_DIGITAL_PINS - 1),
7844
              wait = parser.intval('W', 500);
7845
 
7846
    for (uint8_t pin = start; pin <= end; pin++) {
7847
      //report_pin_state_extended(pin, ignore_protection, false);
7848
 
7849
      if (!ignore_protection && pin_is_protected(pin)) {
7850
        report_pin_state_extended(pin, ignore_protection, true, "Untouched ");
7851
        SERIAL_EOL();
7852
      }
7853
      else {
7854
        report_pin_state_extended(pin, ignore_protection, true, "Pulsing   ");
7855
        #if AVR_AT90USB1286_FAMILY // Teensy IDEs don't know about these pins so must use FASTIO
7856
          if (pin == TEENSY_E2) {
7857
            SET_OUTPUT(TEENSY_E2);
7858
            for (int16_t j = 0; j < repeat; j++) {
7859
              WRITE(TEENSY_E2, LOW);  safe_delay(wait);
7860
              WRITE(TEENSY_E2, HIGH); safe_delay(wait);
7861
              WRITE(TEENSY_E2, LOW);  safe_delay(wait);
7862
            }
7863
          }
7864
          else if (pin == TEENSY_E3) {
7865
            SET_OUTPUT(TEENSY_E3);
7866
            for (int16_t j = 0; j < repeat; j++) {
7867
              WRITE(TEENSY_E3, LOW);  safe_delay(wait);
7868
              WRITE(TEENSY_E3, HIGH); safe_delay(wait);
7869
              WRITE(TEENSY_E3, LOW);  safe_delay(wait);
7870
            }
7871
          }
7872
          else
7873
        #endif
7874
        {
7875
          pinMode(pin, OUTPUT);
7876
          for (int16_t j = 0; j < repeat; j++) {
7877
            digitalWrite(pin, 0); safe_delay(wait);
7878
            digitalWrite(pin, 1); safe_delay(wait);
7879
            digitalWrite(pin, 0); safe_delay(wait);
7880
          }
7881
        }
7882
 
7883
      }
7884
      SERIAL_EOL();
7885
    }
7886
    SERIAL_ECHOLNPGM("Done.");
7887
 
7888
  } // toggle_pins
7889
 
7890
  inline void servo_probe_test() {
7891
    #if !(NUM_SERVOS > 0 && HAS_SERVO_0)
7892
 
7893
      SERIAL_ERROR_START();
7894
      SERIAL_ERRORLNPGM("SERVO not setup");
7895
 
7896
    #elif !HAS_Z_SERVO_PROBE
7897
 
7898
      SERIAL_ERROR_START();
7899
      SERIAL_ERRORLNPGM("Z_PROBE_SERVO_NR not setup");
7900
 
7901
    #else // HAS_Z_SERVO_PROBE
7902
 
7903
      const uint8_t probe_index = parser.byteval('P', Z_PROBE_SERVO_NR);
7904
 
7905
      SERIAL_PROTOCOLLNPGM("Servo probe test");
7906
      SERIAL_PROTOCOLLNPAIR(".  using index:  ", probe_index);
7907
      SERIAL_PROTOCOLLNPAIR(".  deploy angle: ", z_servo_angle[0]);
7908
      SERIAL_PROTOCOLLNPAIR(".  stow angle:   ", z_servo_angle[1]);
7909
 
7910
      bool probe_inverting;
7911
 
7912
      #if ENABLED(Z_MIN_PROBE_USES_Z_MIN_ENDSTOP_PIN)
7913
 
7914
        #define PROBE_TEST_PIN Z_MIN_PIN
7915
 
7916
        SERIAL_PROTOCOLLNPAIR(". probe uses Z_MIN pin: ", PROBE_TEST_PIN);
7917
        SERIAL_PROTOCOLLNPGM(". uses Z_MIN_ENDSTOP_INVERTING (ignores Z_MIN_PROBE_ENDSTOP_INVERTING)");
7918
        SERIAL_PROTOCOLPGM(". Z_MIN_ENDSTOP_INVERTING: ");
7919
 
7920
        #if Z_MIN_ENDSTOP_INVERTING
7921
          SERIAL_PROTOCOLLNPGM("true");
7922
        #else
7923
          SERIAL_PROTOCOLLNPGM("false");
7924
        #endif
7925
 
7926
        probe_inverting = Z_MIN_ENDSTOP_INVERTING;
7927
 
7928
      #elif ENABLED(Z_MIN_PROBE_ENDSTOP)
7929
 
7930
        #define PROBE_TEST_PIN Z_MIN_PROBE_PIN
7931
        SERIAL_PROTOCOLLNPAIR(". probe uses Z_MIN_PROBE_PIN: ", PROBE_TEST_PIN);
7932
        SERIAL_PROTOCOLLNPGM(". uses Z_MIN_PROBE_ENDSTOP_INVERTING (ignores Z_MIN_ENDSTOP_INVERTING)");
7933
        SERIAL_PROTOCOLPGM(". Z_MIN_PROBE_ENDSTOP_INVERTING: ");
7934
 
7935
        #if Z_MIN_PROBE_ENDSTOP_INVERTING
7936
          SERIAL_PROTOCOLLNPGM("true");
7937
        #else
7938
          SERIAL_PROTOCOLLNPGM("false");
7939
        #endif
7940
 
7941
        probe_inverting = Z_MIN_PROBE_ENDSTOP_INVERTING;
7942
 
7943
      #endif
7944
 
7945
      SERIAL_PROTOCOLLNPGM(". deploy & stow 4 times");
7946
      SET_INPUT_PULLUP(PROBE_TEST_PIN);
7947
      bool deploy_state, stow_state;
7948
      for (uint8_t i = 0; i < 4; i++) {
7949
        MOVE_SERVO(probe_index, z_servo_angle[0]); //deploy
7950
        safe_delay(500);
7951
        deploy_state = READ(PROBE_TEST_PIN);
7952
        MOVE_SERVO(probe_index, z_servo_angle[1]); //stow
7953
        safe_delay(500);
7954
        stow_state = READ(PROBE_TEST_PIN);
7955
      }
7956
      if (probe_inverting != deploy_state) SERIAL_PROTOCOLLNPGM("WARNING - INVERTING setting probably backwards");
7957
 
7958
      if (deploy_state != stow_state) {
7959
        SERIAL_PROTOCOLLNPGM("BLTouch clone detected");
7960
        if (deploy_state) {
7961
          SERIAL_PROTOCOLLNPGM(".  DEPLOYED state: HIGH (logic 1)");
7962
          SERIAL_PROTOCOLLNPGM(".  STOWED (triggered) state: LOW (logic 0)");
7963
        }
7964
        else {
7965
          SERIAL_PROTOCOLLNPGM(".  DEPLOYED state: LOW (logic 0)");
7966
          SERIAL_PROTOCOLLNPGM(".  STOWED (triggered) state: HIGH (logic 1)");
7967
        }
7968
        #if ENABLED(BLTOUCH)
7969
          SERIAL_PROTOCOLLNPGM("ERROR: BLTOUCH enabled - set this device up as a Z Servo Probe with inverting as true.");
7970
        #endif
7971
 
7972
      }
7973
      else {                                           // measure active signal length
7974
        MOVE_SERVO(probe_index, z_servo_angle[0]);     // deploy
7975
        safe_delay(500);
7976
        SERIAL_PROTOCOLLNPGM("please trigger probe");
7977
        uint16_t probe_counter = 0;
7978
 
7979
        // Allow 30 seconds max for operator to trigger probe
7980
        for (uint16_t j = 0; j < 500 * 30 && probe_counter == 0 ; j++) {
7981
 
7982
          safe_delay(2);
7983
 
7984
          if (0 == j % (500 * 1)) reset_stepper_timeout(); // Keep steppers powered
7985
 
7986
          if (deploy_state != READ(PROBE_TEST_PIN)) { // probe triggered
7987
 
7988
            for (probe_counter = 1; probe_counter < 50 && deploy_state != READ(PROBE_TEST_PIN); ++probe_counter)
7989
              safe_delay(2);
7990
 
7991
            if (probe_counter == 50)
7992
              SERIAL_PROTOCOLLNPGM("Z Servo Probe detected"); // >= 100mS active time
7993
            else if (probe_counter >= 2)
7994
              SERIAL_PROTOCOLLNPAIR("BLTouch compatible probe detected - pulse width (+/- 4mS): ", probe_counter * 2); // allow 4 - 100mS pulse
7995
            else
7996
              SERIAL_PROTOCOLLNPGM("noise detected - please re-run test"); // less than 2mS pulse
7997
 
7998
            MOVE_SERVO(probe_index, z_servo_angle[1]); //stow
7999
 
8000
          }  // pulse detected
8001
 
8002
        } // for loop waiting for trigger
8003
 
8004
        if (probe_counter == 0) SERIAL_PROTOCOLLNPGM("trigger not detected");
8005
 
8006
      } // measure active signal length
8007
 
8008
    #endif
8009
 
8010
  } // servo_probe_test
8011
 
8012
  /**
8013
   * M43: Pin debug - report pin state, watch pins, toggle pins and servo probe test/report
8014
   *
8015
   *  M43         - report name and state of pin(s)
8016
   *                  P<pin>  Pin to read or watch. If omitted, reads all pins.
8017
   *                  I       Flag to ignore Marlin's pin protection.
8018
   *
8019
   *  M43 W       - Watch pins -reporting changes- until reset, click, or M108.
8020
   *                  P<pin>  Pin to read or watch. If omitted, read/watch all pins.
8021
   *                  I       Flag to ignore Marlin's pin protection.
8022
   *
8023
   *  M43 E<bool> - Enable / disable background endstop monitoring
8024
   *                  - Machine continues to operate
8025
   *                  - Reports changes to endstops
8026
   *                  - Toggles LED_PIN when an endstop changes
8027
   *                  - Can not reliably catch the 5mS pulse from BLTouch type probes
8028
   *
8029
   *  M43 T       - Toggle pin(s) and report which pin is being toggled
8030
   *                  S<pin>  - Start Pin number.   If not given, will default to 0
8031
   *                  L<pin>  - End Pin number.   If not given, will default to last pin defined for this board
8032
   *                  I<bool> - Flag to ignore Marlin's pin protection.   Use with caution!!!!
8033
   *                  R       - Repeat pulses on each pin this number of times before continueing to next pin
8034
   *                  W       - Wait time (in miliseconds) between pulses.  If not given will default to 500
8035
   *
8036
   *  M43 S       - Servo probe test
8037
   *                  P<index> - Probe index (optional - defaults to 0
8038
   */
8039
  inline void gcode_M43() {
8040
 
8041
    if (parser.seen('T')) {   // must be first or else its "S" and "E" parameters will execute endstop or servo test
8042
      toggle_pins();
8043
      return;
8044
    }
8045
 
8046
    // Enable or disable endstop monitoring
8047
    if (parser.seen('E')) {
8048
      endstops.monitor_flag = parser.value_bool();
8049
      SERIAL_PROTOCOLPGM("endstop monitor ");
8050
      serialprintPGM(endstops.monitor_flag ? PSTR("en") : PSTR("dis"));
8051
      SERIAL_PROTOCOLLNPGM("abled");
8052
      return;
8053
    }
8054
 
8055
    if (parser.seen('S')) {
8056
      servo_probe_test();
8057
      return;
8058
    }
8059
 
8060
    // Get the range of pins to test or watch
8061
    const pin_t first_pin = parser.byteval('P'),
8062
                last_pin = parser.seenval('P') ? first_pin : NUM_DIGITAL_PINS - 1;
8063
 
8064
    if (first_pin > last_pin) return;
8065
 
8066
    const bool ignore_protection = parser.boolval('I');
8067
 
8068
    // Watch until click, M108, or reset
8069
    if (parser.boolval('W')) {
8070
      SERIAL_PROTOCOLLNPGM("Watching pins");
8071
      byte pin_state[last_pin - first_pin + 1];
8072
      for (pin_t pin = first_pin; pin <= last_pin; pin++) {
8073
        if (!ignore_protection && pin_is_protected(pin)) continue;
8074
        pinMode(pin, INPUT_PULLUP);
8075
        delay(1);
8076
        /*
8077
          if (IS_ANALOG(pin))
8078
            pin_state[pin - first_pin] = analogRead(pin - analogInputToDigitalPin(0)); // int16_t pin_state[...]
8079
          else
8080
        //*/
8081
            pin_state[pin - first_pin] = digitalRead(pin);
8082
      }
8083
 
8084
      #if HAS_RESUME_CONTINUE
8085
        wait_for_user = true;
8086
        KEEPALIVE_STATE(PAUSED_FOR_USER);
8087
      #endif
8088
 
8089
      for (;;) {
8090
        for (pin_t pin = first_pin; pin <= last_pin; pin++) {
8091
          if (!ignore_protection && pin_is_protected(pin)) continue;
8092
          const byte val =
8093
            /*
8094
              IS_ANALOG(pin)
8095
                ? analogRead(pin - analogInputToDigitalPin(0)) : // int16_t val
8096
                :
8097
            //*/
8098
              digitalRead(pin);
8099
          if (val != pin_state[pin - first_pin]) {
8100
            report_pin_state_extended(pin, ignore_protection, false);
8101
            pin_state[pin - first_pin] = val;
8102
          }
8103
        }
8104
 
8105
        #if HAS_RESUME_CONTINUE
8106
          if (!wait_for_user) {
8107
            KEEPALIVE_STATE(IN_HANDLER);
8108
            break;
8109
          }
8110
        #endif
8111
 
8112
        safe_delay(200);
8113
      }
8114
      return;
8115
    }
8116
 
8117
    // Report current state of selected pin(s)
8118
    for (pin_t pin = first_pin; pin <= last_pin; pin++)
8119
      report_pin_state_extended(pin, ignore_protection, true);
8120
  }
8121
 
8122
#endif // PINS_DEBUGGING
8123
 
8124
#if ENABLED(Z_MIN_PROBE_REPEATABILITY_TEST)
8125
 
8126
  /**
8127
   * M48: Z probe repeatability measurement function.
8128
   *
8129
   * Usage:
8130
   *   M48 <P#> <X#> <Y#> <V#> <E> <L#> <S>
8131
   *     P = Number of sampled points (4-50, default 10)
8132
   *     X = Sample X position
8133
   *     Y = Sample Y position
8134
   *     V = Verbose level (0-4, default=1)
8135
   *     E = Engage Z probe for each reading
8136
   *     L = Number of legs of movement before probe
8137
   *     S = Schizoid (Or Star if you prefer)
8138
   *
8139
   * This function requires the machine to be homed before invocation.
8140
   */
8141
  inline void gcode_M48() {
8142
 
8143
    if (axis_unhomed_error()) return;
8144
 
8145
    const int8_t verbose_level = parser.byteval('V', 1);
8146
    if (!WITHIN(verbose_level, 0, 4)) {
8147
      SERIAL_PROTOCOLLNPGM("?(V)erbose level is implausible (0-4).");
8148
      return;
8149
    }
8150
 
8151
    if (verbose_level > 0)
8152
      SERIAL_PROTOCOLLNPGM("M48 Z-Probe Repeatability Test");
8153
 
8154
    const int8_t n_samples = parser.byteval('P', 10);
8155
    if (!WITHIN(n_samples, 4, 50)) {
8156
      SERIAL_PROTOCOLLNPGM("?Sample size not plausible (4-50).");
8157
      return;
8158
    }
8159
 
8160
    const ProbePtRaise raise_after = parser.boolval('E') ? PROBE_PT_STOW : PROBE_PT_RAISE;
8161
 
8162
    float X_current = current_position[X_AXIS],
8163
          Y_current = current_position[Y_AXIS];
8164
 
8165
    const float X_probe_location = parser.linearval('X', X_current + X_PROBE_OFFSET_FROM_EXTRUDER),
8166
                Y_probe_location = parser.linearval('Y', Y_current + Y_PROBE_OFFSET_FROM_EXTRUDER);
8167
 
8168
    if (!position_is_reachable_by_probe(X_probe_location, Y_probe_location)) {
8169
      SERIAL_PROTOCOLLNPGM("? (X,Y) out of bounds.");
8170
      return;
8171
    }
8172
 
8173
    bool seen_L = parser.seen('L');
8174
    uint8_t n_legs = seen_L ? parser.value_byte() : 0;
8175
    if (n_legs > 15) {
8176
      SERIAL_PROTOCOLLNPGM("?Number of legs in movement not plausible (0-15).");
8177
      return;
8178
    }
8179
    if (n_legs == 1) n_legs = 2;
8180
 
8181
    const bool schizoid_flag = parser.boolval('S');
8182
    if (schizoid_flag && !seen_L) n_legs = 7;
8183
 
8184
    /**
8185
     * Now get everything to the specified probe point So we can safely do a
8186
     * probe to get us close to the bed.  If the Z-Axis is far from the bed,
8187
     * we don't want to use that as a starting point for each probe.
8188
     */
8189
    if (verbose_level > 2)
8190
      SERIAL_PROTOCOLLNPGM("Positioning the probe...");
8191
 
8192
    // Disable bed level correction in M48 because we want the raw data when we probe
8193
 
8194
    #if HAS_LEVELING
8195
      const bool was_enabled = planner.leveling_active;
8196
      set_bed_leveling_enabled(false);
8197
    #endif
8198
 
8199
    setup_for_endstop_or_probe_move();
8200
 
8201
    float mean = 0.0, sigma = 0.0, min = 99999.9, max = -99999.9, sample_set[n_samples];
8202
 
8203
    // Move to the first point, deploy, and probe
8204
    const float t = probe_pt(X_probe_location, Y_probe_location, raise_after, verbose_level);
8205
    bool probing_good = !isnan(t);
8206
 
8207
    if (probing_good) {
8208
      randomSeed(millis());
8209
 
8210
      for (uint8_t n = 0; n < n_samples; n++) {
8211
        if (n_legs) {
8212
          const int dir = (random(0, 10) > 5.0) ? -1 : 1;  // clockwise or counter clockwise
8213
          float angle = random(0.0, 360.0);
8214
          const float radius = random(
8215
            #if ENABLED(DELTA)
8216
              0.1250000000 * (DELTA_PRINTABLE_RADIUS),
8217
              0.3333333333 * (DELTA_PRINTABLE_RADIUS)
8218
            #else
8219
              5.0, 0.125 * MIN(X_BED_SIZE, Y_BED_SIZE)
8220
            #endif
8221
          );
8222
 
8223
          if (verbose_level > 3) {
8224
            SERIAL_ECHOPAIR("Starting radius: ", radius);
8225
            SERIAL_ECHOPAIR("   angle: ", angle);
8226
            SERIAL_ECHOPGM(" Direction: ");
8227
            if (dir > 0) SERIAL_ECHOPGM("Counter-");
8228
            SERIAL_ECHOLNPGM("Clockwise");
8229
          }
8230
 
8231
          for (uint8_t l = 0; l < n_legs - 1; l++) {
8232
            float delta_angle;
8233
 
8234
            if (schizoid_flag)
8235
              // The points of a 5 point star are 72 degrees apart.  We need to
8236
              // skip a point and go to the next one on the star.
8237
              delta_angle = dir * 2.0 * 72.0;
8238
 
8239
            else
8240
              // If we do this line, we are just trying to move further
8241
              // around the circle.
8242
              delta_angle = dir * (float) random(25, 45);
8243
 
8244
            angle += delta_angle;
8245
 
8246
            while (angle > 360.0)   // We probably do not need to keep the angle between 0 and 2*PI, but the
8247
              angle -= 360.0;       // Arduino documentation says the trig functions should not be given values
8248
            while (angle < 0.0)     // outside of this range.   It looks like they behave correctly with
8249
              angle += 360.0;       // numbers outside of the range, but just to be safe we clamp them.
8250
 
8251
            X_current = X_probe_location - (X_PROBE_OFFSET_FROM_EXTRUDER) + cos(RADIANS(angle)) * radius;
8252
            Y_current = Y_probe_location - (Y_PROBE_OFFSET_FROM_EXTRUDER) + sin(RADIANS(angle)) * radius;
8253
 
8254
            #if DISABLED(DELTA)
8255
              X_current = constrain(X_current, X_MIN_POS, X_MAX_POS);
8256
              Y_current = constrain(Y_current, Y_MIN_POS, Y_MAX_POS);
8257
            #else
8258
              // If we have gone out too far, we can do a simple fix and scale the numbers
8259
              // back in closer to the origin.
8260
              while (!position_is_reachable_by_probe(X_current, Y_current)) {
8261
                X_current *= 0.8;
8262
                Y_current *= 0.8;
8263
                if (verbose_level > 3) {
8264
                  SERIAL_ECHOPAIR("Pulling point towards center:", X_current);
8265
                  SERIAL_ECHOLNPAIR(", ", Y_current);
8266
                }
8267
              }
8268
            #endif
8269
            if (verbose_level > 3) {
8270
              SERIAL_PROTOCOLPGM("Going to:");
8271
              SERIAL_ECHOPAIR(" X", X_current);
8272
              SERIAL_ECHOPAIR(" Y", Y_current);
8273
              SERIAL_ECHOLNPAIR(" Z", current_position[Z_AXIS]);
8274
            }
8275
            do_blocking_move_to_xy(X_current, Y_current);
8276
          } // n_legs loop
8277
        } // n_legs
8278
 
8279
        // Probe a single point
8280
        sample_set[n] = probe_pt(X_probe_location, Y_probe_location, raise_after);
8281
 
8282
        // Break the loop if the probe fails
8283
        probing_good = !isnan(sample_set[n]);
8284
        if (!probing_good) break;
8285
 
8286
        /**
8287
         * Get the current mean for the data points we have so far
8288
         */
8289
        float sum = 0.0;
8290
        for (uint8_t j = 0; j <= n; j++) sum += sample_set[j];
8291
        mean = sum / (n + 1);
8292
 
8293
        NOMORE(min, sample_set[n]);
8294
        NOLESS(max, sample_set[n]);
8295
 
8296
        /**
8297
         * Now, use that mean to calculate the standard deviation for the
8298
         * data points we have so far
8299
         */
8300
        sum = 0.0;
8301
        for (uint8_t j = 0; j <= n; j++)
8302
          sum += sq(sample_set[j] - mean);
8303
 
8304
        sigma = SQRT(sum / (n + 1));
8305
        if (verbose_level > 0) {
8306
          if (verbose_level > 1) {
8307
            SERIAL_PROTOCOL(n + 1);
8308
            SERIAL_PROTOCOLPGM(" of ");
8309
            SERIAL_PROTOCOL(int(n_samples));
8310
            SERIAL_PROTOCOLPGM(": z: ");
8311
            SERIAL_PROTOCOL_F(sample_set[n], 3);
8312
            if (verbose_level > 2) {
8313
              SERIAL_PROTOCOLPGM(" mean: ");
8314
              SERIAL_PROTOCOL_F(mean, 4);
8315
              SERIAL_PROTOCOLPGM(" sigma: ");
8316
              SERIAL_PROTOCOL_F(sigma, 6);
8317
              SERIAL_PROTOCOLPGM(" min: ");
8318
              SERIAL_PROTOCOL_F(min, 3);
8319
              SERIAL_PROTOCOLPGM(" max: ");
8320
              SERIAL_PROTOCOL_F(max, 3);
8321
              SERIAL_PROTOCOLPGM(" range: ");
8322
              SERIAL_PROTOCOL_F(max-min, 3);
8323
            }
8324
            SERIAL_EOL();
8325
          }
8326
        }
8327
 
8328
      } // n_samples loop
8329
    }
8330
 
8331
    STOW_PROBE();
8332
 
8333
    if (probing_good) {
8334
      SERIAL_PROTOCOLLNPGM("Finished!");
8335
 
8336
      if (verbose_level > 0) {
8337
        SERIAL_PROTOCOLPGM("Mean: ");
8338
        SERIAL_PROTOCOL_F(mean, 6);
8339
        SERIAL_PROTOCOLPGM(" Min: ");
8340
        SERIAL_PROTOCOL_F(min, 3);
8341
        SERIAL_PROTOCOLPGM(" Max: ");
8342
        SERIAL_PROTOCOL_F(max, 3);
8343
        SERIAL_PROTOCOLPGM(" Range: ");
8344
        SERIAL_PROTOCOL_F(max-min, 3);
8345
        SERIAL_EOL();
8346
      }
8347
 
8348
      SERIAL_PROTOCOLPGM("Standard Deviation: ");
8349
      SERIAL_PROTOCOL_F(sigma, 6);
8350
      SERIAL_EOL();
8351
      SERIAL_EOL();
8352
    }
8353
 
8354
    clean_up_after_endstop_or_probe_move();
8355
 
8356
    // Re-enable bed level correction if it had been on
8357
    #if HAS_LEVELING
8358
      set_bed_leveling_enabled(was_enabled);
8359
    #endif
8360
 
8361
    #ifdef Z_AFTER_PROBING
8362
      move_z_after_probing();
8363
    #endif
8364
 
8365
    report_current_position();
8366
  }
8367
 
8368
#endif // Z_MIN_PROBE_REPEATABILITY_TEST
8369
 
8370
#if ENABLED(G26_MESH_VALIDATION)
8371
 
8372
  inline void gcode_M49() {
8373
    g26_debug_flag ^= true;
8374
    SERIAL_PROTOCOLPGM("G26 Debug ");
8375
    serialprintPGM(g26_debug_flag ? PSTR("on.\n") : PSTR("off.\n"));
8376
  }
8377
 
8378
#endif // G26_MESH_VALIDATION
8379
 
8380
#if ENABLED(ULTRA_LCD) && ENABLED(LCD_SET_PROGRESS_MANUALLY)
8381
  /**
8382
   * M73: Set percentage complete (for display on LCD)
8383
   *
8384
   * Example:
8385
   *   M73 P25 ; Set progress to 25%
8386
   *
8387
   * Notes:
8388
   *   This has no effect during an SD print job
8389
   */
8390
  inline void gcode_M73() {
8391
    if (!IS_SD_PRINTING() && parser.seen('P')) {
8392
      progress_bar_percent = parser.value_byte();
8393
      NOMORE(progress_bar_percent, 100);
8394
    }
8395
  }
8396
#endif // ULTRA_LCD && LCD_SET_PROGRESS_MANUALLY
8397
 
8398
/**
8399
 * M75: Start print timer
8400
 */
8401
inline void gcode_M75() { print_job_timer.start(); }
8402
 
8403
/**
8404
 * M76: Pause print timer
8405
 */
8406
inline void gcode_M76() { print_job_timer.pause(); }
8407
 
8408
/**
8409
 * M77: Stop print timer
8410
 */
8411
inline void gcode_M77() { print_job_timer.stop(); }
8412
 
8413
#if ENABLED(PRINTCOUNTER)
8414
  /**
8415
   * M78: Show print statistics
8416
   */
8417
  inline void gcode_M78() {
8418
    // "M78 S78" will reset the statistics
8419
    if (parser.intval('S') == 78)
8420
      print_job_timer.initStats();
8421
    else
8422
      print_job_timer.showStats();
8423
  }
8424
#endif
8425
 
8426
/**
8427
 * M104: Set hot end temperature
8428
 */
8429
inline void gcode_M104() {
8430
  if (get_target_extruder_from_command(104)) return;
8431
  if (DEBUGGING(DRYRUN)) return;
8432
 
8433
  #if ENABLED(SINGLENOZZLE)
8434
    if (target_extruder != active_extruder) return;
8435
  #endif
8436
 
8437
  if (parser.seenval('S')) {
8438
    const int16_t temp = parser.value_celsius();
8439
    thermalManager.setTargetHotend(temp, target_extruder);
8440
 
8441
    #if ENABLED(DUAL_X_CARRIAGE)
8442
      if (dual_x_carriage_mode == DXC_DUPLICATION_MODE && target_extruder == 0)
8443
        thermalManager.setTargetHotend(temp ? temp + duplicate_extruder_temp_offset : 0, 1);
8444
    #endif
8445
 
8446
    #if ENABLED(PRINTJOB_TIMER_AUTOSTART)
8447
      /**
8448
       * Stop the timer at the end of print. Start is managed by 'heat and wait' M109.
8449
       * We use half EXTRUDE_MINTEMP here to allow nozzles to be put into hot
8450
       * standby mode, for instance in a dual extruder setup, without affecting
8451
       * the running print timer.
8452
       */
8453
      if (parser.value_celsius() <= (EXTRUDE_MINTEMP) / 2) {
8454
        print_job_timer.stop();
8455
        lcd_reset_status();
8456
      }
8457
    #endif
8458
  }
8459
 
8460
  #if ENABLED(AUTOTEMP)
8461
    planner.autotemp_M104_M109();
8462
  #endif
8463
}
8464
 
8465
/**
8466
 * M105: Read hot end and bed temperature
8467
 */
8468
inline void gcode_M105() {
8469
  if (get_target_extruder_from_command(105)) return;
8470
 
8471
  #if HAS_TEMP_SENSOR
8472
    SERIAL_PROTOCOLPGM(MSG_OK);
8473
    thermalManager.print_heaterstates();
8474
  #else // !HAS_TEMP_SENSOR
8475
    SERIAL_ERROR_START();
8476
    SERIAL_ERRORLNPGM(MSG_ERR_NO_THERMISTORS);
8477
  #endif
8478
 
8479
  SERIAL_EOL();
8480
}
8481
 
8482
#if ENABLED(AUTO_REPORT_TEMPERATURES)
8483
 
8484
  /**
8485
   * M155: Set temperature auto-report interval. M155 S<seconds>
8486
   */
8487
  inline void gcode_M155() {
8488
    if (parser.seenval('S'))
8489
      thermalManager.set_auto_report_interval(parser.value_byte());
8490
  }
8491
 
8492
#endif // AUTO_REPORT_TEMPERATURES
8493
 
8494
#if FAN_COUNT > 0
8495
 
8496
  /**
8497
   * M106: Set Fan Speed
8498
   *
8499
   *  S<int>   Speed between 0-255
8500
   *  P<index> Fan index, if more than one fan
8501
   *
8502
   * With EXTRA_FAN_SPEED enabled:
8503
   *
8504
   *  T<int>   Restore/Use/Set Temporary Speed:
8505
   *           1     = Restore previous speed after T2
8506
   *           2     = Use temporary speed set with T3-255
8507
   *           3-255 = Set the speed for use with T2
8508
   */
8509
  inline void gcode_M106() {
8510
    const uint8_t p = parser.byteval('P');
8511
    if (p < FAN_COUNT) {
8512
      #if ENABLED(EXTRA_FAN_SPEED)
8513
        const int16_t t = parser.intval('T');
8514
        if (t > 0) {
8515
          switch (t) {
8516
            case 1:
8517
              fanSpeeds[p] = old_fanSpeeds[p];
8518
              break;
8519
            case 2:
8520
              old_fanSpeeds[p] = fanSpeeds[p];
8521
              fanSpeeds[p] = new_fanSpeeds[p];
8522
              break;
8523
            default:
8524
              new_fanSpeeds[p] = MIN(t, 255);
8525
              break;
8526
          }
8527
          return;
8528
        }
8529
      #endif // EXTRA_FAN_SPEED
8530
      const uint16_t s = parser.ushortval('S', 255);
8531
      fanSpeeds[p] = MIN(s, 255U);
8532
    }
8533
  }
8534
 
8535
  /**
8536
   * M107: Fan Off
8537
   */
8538
  inline void gcode_M107() {
8539
    const uint16_t p = parser.ushortval('P');
8540
    if (p < FAN_COUNT) fanSpeeds[p] = 0;
8541
  }
8542
 
8543
#endif // FAN_COUNT > 0
8544
 
8545
#if DISABLED(EMERGENCY_PARSER)
8546
 
8547
  /**
8548
   * M108: Stop the waiting for heaters in M109, M190, M303. Does not affect the target temperature.
8549
   */
8550
  inline void gcode_M108() { wait_for_heatup = false; }
8551
 
8552
 
8553
  /**
8554
   * M112: Emergency Stop
8555
   */
8556
  inline void gcode_M112() { kill(PSTR(MSG_KILLED)); }
8557
 
8558
 
8559
  /**
8560
   * M410: Quickstop - Abort all planned moves
8561
   *
8562
   * This will stop the carriages mid-move, so most likely they
8563
   * will be out of sync with the stepper position after this.
8564
   */
8565
  inline void gcode_M410() { quickstop_stepper(); }
8566
 
8567
#endif
8568
 
8569
/**
8570
 * M109: Sxxx Wait for extruder(s) to reach temperature. Waits only when heating.
8571
 *       Rxxx Wait for extruder(s) to reach temperature. Waits when heating and cooling.
8572
 */
8573
 
8574
#ifndef MIN_COOLING_SLOPE_DEG
8575
  #define MIN_COOLING_SLOPE_DEG 1.50
8576
#endif
8577
#ifndef MIN_COOLING_SLOPE_TIME
8578
  #define MIN_COOLING_SLOPE_TIME 60
8579
#endif
8580
 
8581
inline void gcode_M109() {
8582
 
8583
  if (get_target_extruder_from_command(109)) return;
8584
  if (DEBUGGING(DRYRUN)) return;
8585
 
8586
  #if ENABLED(SINGLENOZZLE)
8587
    if (target_extruder != active_extruder) return;
8588
  #endif
8589
 
8590
  const bool no_wait_for_cooling = parser.seenval('S'),
8591
             set_temp = no_wait_for_cooling || parser.seenval('R');
8592
  if (set_temp) {
8593
    const int16_t temp = parser.value_celsius();
8594
    thermalManager.setTargetHotend(temp, target_extruder);
8595
 
8596
    #if ENABLED(DUAL_X_CARRIAGE)
8597
      if (dual_x_carriage_mode == DXC_DUPLICATION_MODE && target_extruder == 0)
8598
        thermalManager.setTargetHotend(temp ? temp + duplicate_extruder_temp_offset : 0, 1);
8599
    #endif
8600
 
8601
    #if ENABLED(PRINTJOB_TIMER_AUTOSTART)
8602
      /**
8603
       * Use half EXTRUDE_MINTEMP to allow nozzles to be put into hot
8604
       * standby mode, (e.g., in a dual extruder setup) without affecting
8605
       * the running print timer.
8606
       */
8607
      if (parser.value_celsius() <= (EXTRUDE_MINTEMP) / 2) {
8608
        print_job_timer.stop();
8609
        lcd_reset_status();
8610
      }
8611
      else
8612
        print_job_timer.start();
8613
    #endif
8614
 
8615
    #if ENABLED(ULTRA_LCD)
8616
      const bool heating = thermalManager.isHeatingHotend(target_extruder);
8617
      if (heating || !no_wait_for_cooling)
8618
        #if HOTENDS > 1
8619
          lcd_status_printf_P(0, heating ? PSTR("E%i " MSG_HEATING) : PSTR("E%i " MSG_COOLING), target_extruder + 1);
8620
        #else
8621
          lcd_setstatusPGM(heating ? PSTR("E " MSG_HEATING) : PSTR("E " MSG_COOLING));
8622
        #endif
8623
    #endif
8624
  }
8625
 
8626
  #if ENABLED(AUTOTEMP)
8627
    planner.autotemp_M104_M109();
8628
  #endif
8629
 
8630
  if (!set_temp) return;
8631
 
8632
  #if TEMP_RESIDENCY_TIME > 0
8633
    millis_t residency_start_ms = 0;
8634
    // Loop until the temperature has stabilized
8635
    #define TEMP_CONDITIONS (!residency_start_ms || PENDING(now, residency_start_ms + (TEMP_RESIDENCY_TIME) * 1000UL))
8636
  #else
8637
    // Loop until the temperature is very close target
8638
    #define TEMP_CONDITIONS (wants_to_cool ? thermalManager.isCoolingHotend(target_extruder) : thermalManager.isHeatingHotend(target_extruder))
8639
  #endif
8640
 
8641
  float target_temp = -1, old_temp = 9999;
8642
  bool wants_to_cool = false;
8643
  wait_for_heatup = true;
8644
  millis_t now, next_temp_ms = 0, next_cool_check_ms = 0;
8645
 
8646
  #if DISABLED(BUSY_WHILE_HEATING)
8647
    KEEPALIVE_STATE(NOT_BUSY);
8648
  #endif
8649
 
8650
  #if ENABLED(PRINTER_EVENT_LEDS)
8651
    const float start_temp = thermalManager.degHotend(target_extruder);
8652
    uint8_t old_blue = 0;
8653
  #endif
8654
 
8655
  do {
8656
    // Target temperature might be changed during the loop
8657
    if (target_temp != thermalManager.degTargetHotend(target_extruder)) {
8658
      wants_to_cool = thermalManager.isCoolingHotend(target_extruder);
8659
      target_temp = thermalManager.degTargetHotend(target_extruder);
8660
 
8661
      // Exit if S<lower>, continue if S<higher>, R<lower>, or R<higher>
8662
      if (no_wait_for_cooling && wants_to_cool) break;
8663
    }
8664
 
8665
    now = millis();
8666
    if (ELAPSED(now, next_temp_ms)) { //Print temp & remaining time every 1s while waiting
8667
      next_temp_ms = now + 1000UL;
8668
      thermalManager.print_heaterstates();
8669
      #if TEMP_RESIDENCY_TIME > 0
8670
        SERIAL_PROTOCOLPGM(" W:");
8671
        if (residency_start_ms)
8672
          SERIAL_PROTOCOL(long((((TEMP_RESIDENCY_TIME) * 1000UL) - (now - residency_start_ms)) / 1000UL));
8673
        else
8674
          SERIAL_PROTOCOLCHAR('?');
8675
      #endif
8676
      SERIAL_EOL();
8677
    }
8678
 
8679
    idle();
8680
    reset_stepper_timeout(); // Keep steppers powered
8681
 
8682
    const float temp = thermalManager.degHotend(target_extruder);
8683
 
8684
    #if ENABLED(PRINTER_EVENT_LEDS)
8685
      // Gradually change LED strip from violet to red as nozzle heats up
8686
      if (!wants_to_cool) {
8687
        const uint8_t blue = map(constrain(temp, start_temp, target_temp), start_temp, target_temp, 255, 0);
8688
        if (blue != old_blue) {
8689
          old_blue = blue;
8690
          leds.set_color(
8691
            MakeLEDColor(255, 0, blue, 0, pixels.getBrightness())
8692
            #if ENABLED(NEOPIXEL_IS_SEQUENTIAL)
8693
              , true
8694
            #endif
8695
          );
8696
        }
8697
      }
8698
    #endif
8699
 
8700
    #if TEMP_RESIDENCY_TIME > 0
8701
 
8702
      const float temp_diff = ABS(target_temp - temp);
8703
 
8704
      if (!residency_start_ms) {
8705
        // Start the TEMP_RESIDENCY_TIME timer when we reach target temp for the first time.
8706
        if (temp_diff < TEMP_WINDOW) residency_start_ms = now;
8707
      }
8708
      else if (temp_diff > TEMP_HYSTERESIS) {
8709
        // Restart the timer whenever the temperature falls outside the hysteresis.
8710
        residency_start_ms = now;
8711
      }
8712
 
8713
    #endif
8714
 
8715
    // Prevent a wait-forever situation if R is misused i.e. M109 R0
8716
    if (wants_to_cool) {
8717
      // break after MIN_COOLING_SLOPE_TIME seconds
8718
      // if the temperature did not drop at least MIN_COOLING_SLOPE_DEG
8719
      if (!next_cool_check_ms || ELAPSED(now, next_cool_check_ms)) {
8720
        if (old_temp - temp < float(MIN_COOLING_SLOPE_DEG)) break;
8721
        next_cool_check_ms = now + 1000UL * MIN_COOLING_SLOPE_TIME;
8722
        old_temp = temp;
8723
      }
8724
    }
8725
 
8726
  } while (wait_for_heatup && TEMP_CONDITIONS);
8727
 
8728
  if (wait_for_heatup) {
8729
    lcd_reset_status();
8730
    #if ENABLED(PRINTER_EVENT_LEDS)
8731
      leds.set_white();
8732
    #endif
8733
  }
8734
 
8735
  #if DISABLED(BUSY_WHILE_HEATING)
8736
    KEEPALIVE_STATE(IN_HANDLER);
8737
  #endif
8738
}
8739
 
8740
#if HAS_HEATED_BED
8741
 
8742
  /**
8743
   * M140: Set bed temperature
8744
   */
8745
  inline void gcode_M140() {
8746
    if (DEBUGGING(DRYRUN)) return;
8747
    if (parser.seenval('S')) thermalManager.setTargetBed(parser.value_celsius());
8748
  }
8749
 
8750
  #ifndef MIN_COOLING_SLOPE_DEG_BED
8751
    #define MIN_COOLING_SLOPE_DEG_BED 1.50
8752
  #endif
8753
  #ifndef MIN_COOLING_SLOPE_TIME_BED
8754
    #define MIN_COOLING_SLOPE_TIME_BED 60
8755
  #endif
8756
 
8757
  /**
8758
   * M190: Sxxx Wait for bed current temp to reach target temp. Waits only when heating
8759
   *       Rxxx Wait for bed current temp to reach target temp. Waits when heating and cooling
8760
   */
8761
  inline void gcode_M190() {
8762
    if (DEBUGGING(DRYRUN)) return;
8763
 
8764
    const bool no_wait_for_cooling = parser.seenval('S');
8765
    if (no_wait_for_cooling || parser.seenval('R')) {
8766
      thermalManager.setTargetBed(parser.value_celsius());
8767
      #if ENABLED(PRINTJOB_TIMER_AUTOSTART)
8768
        if (parser.value_celsius() > BED_MINTEMP)
8769
          print_job_timer.start();
8770
      #endif
8771
    }
8772
    else return;
8773
 
8774
    lcd_setstatusPGM(thermalManager.isHeatingBed() ? PSTR(MSG_BED_HEATING) : PSTR(MSG_BED_COOLING));
8775
 
8776
    #if TEMP_BED_RESIDENCY_TIME > 0
8777
      millis_t residency_start_ms = 0;
8778
      // Loop until the temperature has stabilized
8779
      #define TEMP_BED_CONDITIONS (!residency_start_ms || PENDING(now, residency_start_ms + (TEMP_BED_RESIDENCY_TIME) * 1000UL))
8780
    #else
8781
      // Loop until the temperature is very close target
8782
      #define TEMP_BED_CONDITIONS (wants_to_cool ? thermalManager.isCoolingBed() : thermalManager.isHeatingBed())
8783
    #endif
8784
 
8785
    float target_temp = -1.0, old_temp = 9999.0;
8786
    bool wants_to_cool = false;
8787
    wait_for_heatup = true;
8788
    millis_t now, next_temp_ms = 0, next_cool_check_ms = 0;
8789
 
8790
    #if DISABLED(BUSY_WHILE_HEATING)
8791
      KEEPALIVE_STATE(NOT_BUSY);
8792
    #endif
8793
 
8794
    target_extruder = active_extruder; // for print_heaterstates
8795
 
8796
    #if ENABLED(PRINTER_EVENT_LEDS)
8797
      const float start_temp = thermalManager.degBed();
8798
      uint8_t old_red = 127;
8799
    #endif
8800
 
8801
    do {
8802
      // Target temperature might be changed during the loop
8803
      if (target_temp != thermalManager.degTargetBed()) {
8804
        wants_to_cool = thermalManager.isCoolingBed();
8805
        target_temp = thermalManager.degTargetBed();
8806
 
8807
        // Exit if S<lower>, continue if S<higher>, R<lower>, or R<higher>
8808
        if (no_wait_for_cooling && wants_to_cool) break;
8809
      }
8810
 
8811
      now = millis();
8812
      if (ELAPSED(now, next_temp_ms)) { //Print Temp Reading every 1 second while heating up.
8813
        next_temp_ms = now + 1000UL;
8814
        thermalManager.print_heaterstates();
8815
        #if TEMP_BED_RESIDENCY_TIME > 0
8816
          SERIAL_PROTOCOLPGM(" W:");
8817
          if (residency_start_ms)
8818
            SERIAL_PROTOCOL(long((((TEMP_BED_RESIDENCY_TIME) * 1000UL) - (now - residency_start_ms)) / 1000UL));
8819
          else
8820
            SERIAL_PROTOCOLCHAR('?');
8821
        #endif
8822
        SERIAL_EOL();
8823
      }
8824
 
8825
      idle();
8826
      reset_stepper_timeout(); // Keep steppers powered
8827
 
8828
      const float temp = thermalManager.degBed();
8829
 
8830
      #if ENABLED(PRINTER_EVENT_LEDS)
8831
        // Gradually change LED strip from blue to violet as bed heats up
8832
        if (!wants_to_cool) {
8833
          const uint8_t red = map(constrain(temp, start_temp, target_temp), start_temp, target_temp, 0, 255);
8834
          if (red != old_red) {
8835
            old_red = red;
8836
            leds.set_color(
8837
              MakeLEDColor(red, 0, 255, 0, pixels.getBrightness())
8838
              #if ENABLED(NEOPIXEL_IS_SEQUENTIAL)
8839
                , true
8840
              #endif
8841
            );
8842
          }
8843
        }
8844
      #endif
8845
 
8846
      #if TEMP_BED_RESIDENCY_TIME > 0
8847
 
8848
        const float temp_diff = ABS(target_temp - temp);
8849
 
8850
        if (!residency_start_ms) {
8851
          // Start the TEMP_BED_RESIDENCY_TIME timer when we reach target temp for the first time.
8852
          if (temp_diff < TEMP_BED_WINDOW) residency_start_ms = now;
8853
        }
8854
        else if (temp_diff > TEMP_BED_HYSTERESIS) {
8855
          // Restart the timer whenever the temperature falls outside the hysteresis.
8856
          residency_start_ms = now;
8857
        }
8858
 
8859
      #endif // TEMP_BED_RESIDENCY_TIME > 0
8860
 
8861
      // Prevent a wait-forever situation if R is misused i.e. M190 R0
8862
      if (wants_to_cool) {
8863
        // Break after MIN_COOLING_SLOPE_TIME_BED seconds
8864
        // if the temperature did not drop at least MIN_COOLING_SLOPE_DEG_BED
8865
        if (!next_cool_check_ms || ELAPSED(now, next_cool_check_ms)) {
8866
          if (old_temp - temp < float(MIN_COOLING_SLOPE_DEG_BED)) break;
8867
          next_cool_check_ms = now + 1000UL * MIN_COOLING_SLOPE_TIME_BED;
8868
          old_temp = temp;
8869
        }
8870
      }
8871
 
8872
    } while (wait_for_heatup && TEMP_BED_CONDITIONS);
8873
 
8874
    if (wait_for_heatup) lcd_reset_status();
8875
    #if DISABLED(BUSY_WHILE_HEATING)
8876
      KEEPALIVE_STATE(IN_HANDLER);
8877
    #endif
8878
  }
8879
 
8880
#endif // HAS_HEATED_BED
8881
 
8882
/**
8883
 * M110: Set Current Line Number
8884
 */
8885
inline void gcode_M110() {
8886
  if (parser.seenval('N')) gcode_LastN = parser.value_long();
8887
}
8888
 
8889
/**
8890
 * M111: Set the debug level
8891
 */
8892
inline void gcode_M111() {
8893
  if (parser.seen('S')) marlin_debug_flags = parser.byteval('S');
8894
 
8895
  static const char str_debug_1[] PROGMEM = MSG_DEBUG_ECHO,
8896
                    str_debug_2[] PROGMEM = MSG_DEBUG_INFO,
8897
                    str_debug_4[] PROGMEM = MSG_DEBUG_ERRORS,
8898
                    str_debug_8[] PROGMEM = MSG_DEBUG_DRYRUN,
8899
                    str_debug_16[] PROGMEM = MSG_DEBUG_COMMUNICATION
8900
                    #if ENABLED(DEBUG_LEVELING_FEATURE)
8901
                      , str_debug_32[] PROGMEM = MSG_DEBUG_LEVELING
8902
                    #endif
8903
                    ;
8904
 
8905
  static const char* const debug_strings[] PROGMEM = {
8906
    str_debug_1, str_debug_2, str_debug_4, str_debug_8, str_debug_16
8907
    #if ENABLED(DEBUG_LEVELING_FEATURE)
8908
      , str_debug_32
8909
    #endif
8910
  };
8911
 
8912
  SERIAL_ECHO_START();
8913
  SERIAL_ECHOPGM(MSG_DEBUG_PREFIX);
8914
  if (marlin_debug_flags) {
8915
    uint8_t comma = 0;
8916
    for (uint8_t i = 0; i < COUNT(debug_strings); i++) {
8917
      if (TEST(marlin_debug_flags, i)) {
8918
        if (comma++) SERIAL_CHAR(',');
8919
        serialprintPGM((char*)pgm_read_ptr(&debug_strings[i]));
8920
      }
8921
    }
8922
  }
8923
  else {
8924
    SERIAL_ECHOPGM(MSG_DEBUG_OFF);
8925
    #if !defined(__AVR__) || !defined(USBCON)
8926
      #if ENABLED(SERIAL_STATS_RX_BUFFER_OVERRUNS)
8927
        SERIAL_ECHOPAIR("\nBuffer Overruns: ", customizedSerial.buffer_overruns());
8928
      #endif
8929
 
8930
      #if ENABLED(SERIAL_STATS_RX_FRAMING_ERRORS)
8931
        SERIAL_ECHOPAIR("\nFraming Errors: ", customizedSerial.framing_errors());
8932
      #endif
8933
 
8934
      #if ENABLED(SERIAL_STATS_DROPPED_RX)
8935
        SERIAL_ECHOPAIR("\nDropped bytes: ", customizedSerial.dropped());
8936
      #endif
8937
 
8938
      #if ENABLED(SERIAL_STATS_MAX_RX_QUEUED)
8939
        SERIAL_ECHOPAIR("\nMax RX Queue Size: ", customizedSerial.rxMaxEnqueued());
8940
      #endif
8941
    #endif // !__AVR__ || !USBCON
8942
  }
8943
  SERIAL_EOL();
8944
}
8945
 
8946
#if ENABLED(HOST_KEEPALIVE_FEATURE)
8947
 
8948
  /**
8949
   * M113: Get or set Host Keepalive interval (0 to disable)
8950
   *
8951
   *   S<seconds> Optional. Set the keepalive interval.
8952
   */
8953
  inline void gcode_M113() {
8954
    if (parser.seenval('S')) {
8955
      host_keepalive_interval = parser.value_byte();
8956
      NOMORE(host_keepalive_interval, 60);
8957
    }
8958
    else {
8959
      SERIAL_ECHO_START();
8960
      SERIAL_ECHOLNPAIR("M113 S", (unsigned long)host_keepalive_interval);
8961
    }
8962
  }
8963
 
8964
#endif
8965
 
8966
#if ENABLED(BARICUDA)
8967
 
8968
  #if HAS_HEATER_1
8969
    /**
8970
     * M126: Heater 1 valve open
8971
     */
8972
    inline void gcode_M126() { baricuda_valve_pressure = parser.byteval('S', 255); }
8973
    /**
8974
     * M127: Heater 1 valve close
8975
     */
8976
    inline void gcode_M127() { baricuda_valve_pressure = 0; }
8977
  #endif
8978
 
8979
  #if HAS_HEATER_2
8980
    /**
8981
     * M128: Heater 2 valve open
8982
     */
8983
    inline void gcode_M128() { baricuda_e_to_p_pressure = parser.byteval('S', 255); }
8984
    /**
8985
     * M129: Heater 2 valve close
8986
     */
8987
    inline void gcode_M129() { baricuda_e_to_p_pressure = 0; }
8988
  #endif
8989
 
8990
#endif // BARICUDA
8991
 
8992
#if ENABLED(ULTIPANEL)
8993
 
8994
  /**
8995
   * M145: Set the heatup state for a material in the LCD menu
8996
   *
8997
   *   S<material> (0=PLA, 1=ABS)
8998
   *   H<hotend temp>
8999
   *   B<bed temp>
9000
   *   F<fan speed>
9001
   */
9002
  inline void gcode_M145() {
9003
    const uint8_t material = (uint8_t)parser.intval('S');
9004
    if (material >= COUNT(lcd_preheat_hotend_temp)) {
9005
      SERIAL_ERROR_START();
9006
      SERIAL_ERRORLNPGM(MSG_ERR_MATERIAL_INDEX);
9007
    }
9008
    else {
9009
      int v;
9010
      if (parser.seenval('H')) {
9011
        v = parser.value_int();
9012
        lcd_preheat_hotend_temp[material] = constrain(v, EXTRUDE_MINTEMP, HEATER_0_MAXTEMP - 15);
9013
      }
9014
      if (parser.seenval('F')) {
9015
        v = parser.value_int();
9016
        lcd_preheat_fan_speed[material] = constrain(v, 0, 255);
9017
      }
9018
      #if TEMP_SENSOR_BED != 0
9019
        if (parser.seenval('B')) {
9020
          v = parser.value_int();
9021
          lcd_preheat_bed_temp[material] = constrain(v, BED_MINTEMP, BED_MAXTEMP - 15);
9022
        }
9023
      #endif
9024
    }
9025
  }
9026
 
9027
#endif // ULTIPANEL
9028
 
9029
#if ENABLED(TEMPERATURE_UNITS_SUPPORT)
9030
  /**
9031
   * M149: Set temperature units
9032
   */
9033
  inline void gcode_M149() {
9034
         if (parser.seenval('C')) parser.set_input_temp_units(TEMPUNIT_C);
9035
    else if (parser.seenval('K')) parser.set_input_temp_units(TEMPUNIT_K);
9036
    else if (parser.seenval('F')) parser.set_input_temp_units(TEMPUNIT_F);
9037
  }
9038
#endif
9039
 
9040
#if HAS_POWER_SWITCH
9041
 
9042
  /**
9043
   * M80   : Turn on the Power Supply
9044
   * M80 S : Report the current state and exit
9045
   */
9046
  inline void gcode_M80() {
9047
 
9048
    // S: Report the current power supply state and exit
9049
    if (parser.seen('S')) {
9050
      serialprintPGM(powersupply_on ? PSTR("PS:1\n") : PSTR("PS:0\n"));
9051
      return;
9052
    }
9053
 
9054
    PSU_ON();
9055
 
9056
    /**
9057
     * If you have a switch on suicide pin, this is useful
9058
     * if you want to start another print with suicide feature after
9059
     * a print without suicide...
9060
     */
9061
    #if HAS_SUICIDE
9062
      OUT_WRITE(SUICIDE_PIN, HIGH);
9063
    #endif
9064
 
9065
    #if DISABLED(AUTO_POWER_CONTROL)
9066
      delay(100); // Wait for power to settle
9067
      restore_stepper_drivers();
9068
    #endif
9069
 
9070
    #if ENABLED(ULTIPANEL)
9071
      lcd_reset_status();
9072
    #endif
9073
  }
9074
 
9075
#endif // HAS_POWER_SWITCH
9076
 
9077
/**
9078
 * M81: Turn off Power, including Power Supply, if there is one.
9079
 *
9080
 *      This code should ALWAYS be available for EMERGENCY SHUTDOWN!
9081
 */
9082
inline void gcode_M81() {
9083
  thermalManager.disable_all_heaters();
9084
  planner.finish_and_disable();
9085
 
9086
  #if FAN_COUNT > 0
9087
    for (uint8_t i = 0; i < FAN_COUNT; i++) fanSpeeds[i] = 0;
9088
    #if ENABLED(PROBING_FANS_OFF)
9089
      fans_paused = false;
9090
      ZERO(paused_fanSpeeds);
9091
    #endif
9092
  #endif
9093
 
9094
  safe_delay(1000); // Wait 1 second before switching off
9095
 
9096
  #if HAS_SUICIDE
9097
    suicide();
9098
  #elif HAS_POWER_SWITCH
9099
    PSU_OFF();
9100
  #endif
9101
 
9102
  #if ENABLED(ULTIPANEL)
9103
    LCD_MESSAGEPGM(MACHINE_NAME " " MSG_OFF ".");
9104
  #endif
9105
}
9106
 
9107
/**
9108
 * M82: Set E codes absolute (default)
9109
 */
9110
inline void gcode_M82() { axis_relative_modes[E_CART] = false; }
9111
 
9112
/**
9113
 * M83: Set E codes relative while in Absolute Coordinates (G90) mode
9114
 */
9115
inline void gcode_M83() { axis_relative_modes[E_CART] = true; }
9116
 
9117
/**
9118
 * M18, M84: Disable stepper motors
9119
 */
9120
inline void gcode_M18_M84() {
9121
  if (parser.seenval('S')) {
9122
    stepper_inactive_time = parser.value_millis_from_seconds();
9123
  }
9124
  else {
9125
    bool all_axis = !(parser.seen('X') || parser.seen('Y') || parser.seen('Z') || parser.seen('E'));
9126
    if (all_axis) {
9127
      planner.finish_and_disable();
9128
    }
9129
    else {
9130
      planner.synchronize();
9131
      if (parser.seen('X')) disable_X();
9132
      if (parser.seen('Y')) disable_Y();
9133
      if (parser.seen('Z')) disable_Z();
9134
      #if E0_ENABLE_PIN != X_ENABLE_PIN && E1_ENABLE_PIN != Y_ENABLE_PIN // Only disable on boards that have separate ENABLE_PINS
9135
        if (parser.seen('E')) disable_e_steppers();
9136
      #endif
9137
    }
9138
 
9139
    #if ENABLED(AUTO_BED_LEVELING_UBL) && ENABLED(ULTIPANEL)  // Only needed with an LCD
9140
      if (ubl.lcd_map_control) ubl.lcd_map_control = defer_return_to_status = false;
9141
    #endif
9142
  }
9143
}
9144
 
9145
/**
9146
 * M85: Set inactivity shutdown timer with parameter S<seconds>. To disable set zero (default)
9147
 */
9148
inline void gcode_M85() {
9149
  if (parser.seen('S')) max_inactive_time = parser.value_millis_from_seconds();
9150
}
9151
 
9152
/**
9153
 * Multi-stepper support for M92, M201, M203
9154
 */
9155
#if ENABLED(DISTINCT_E_FACTORS)
9156
  #define GET_TARGET_EXTRUDER(CMD) if (get_target_extruder_from_command(CMD)) return
9157
  #define TARGET_EXTRUDER target_extruder
9158
#else
9159
  #define GET_TARGET_EXTRUDER(CMD) NOOP
9160
  #define TARGET_EXTRUDER 0
9161
#endif
9162
 
9163
/**
9164
 * M92: Set axis steps-per-unit for one or more axes, X, Y, Z, and E.
9165
 *      (for Hangprinter: A, B, C, D, and E)
9166
 *      (Follows the same syntax as G92)
9167
 *
9168
 *      With multiple extruders use T to specify which one.
9169
 */
9170
inline void gcode_M92() {
9171
  GET_TARGET_EXTRUDER(92);
9172
 
9173
  LOOP_NUM_AXIS(i) {
9174
    if (parser.seen(RAW_AXIS_CODES(i))) {
9175
      if (i == E_AXIS) {
9176
        const float value = parser.value_per_axis_unit((AxisEnum)(E_AXIS + TARGET_EXTRUDER));
9177
        if (value < 20) {
9178
          const float factor = planner.axis_steps_per_mm[E_AXIS + TARGET_EXTRUDER] / value; // increase e constants if M92 E14 is given for netfab.
9179
          #if DISABLED(JUNCTION_DEVIATION)
9180
            planner.max_jerk[E_AXIS] *= factor;
9181
          #endif
9182
          planner.max_feedrate_mm_s[E_AXIS + TARGET_EXTRUDER] *= factor;
9183
          planner.max_acceleration_steps_per_s2[E_AXIS + TARGET_EXTRUDER] *= factor;
9184
        }
9185
        planner.axis_steps_per_mm[E_AXIS + TARGET_EXTRUDER] = value;
9186
      }
9187
      else {
9188
        #if ENABLED(LINE_BUILDUP_COMPENSATION_FEATURE)
9189
          SERIAL_ECHOLNPGM("Warning: "
9190
                           "M92 A, B, C, and D only affect acceleration planning "
9191
                           "when BUILDUP_COMPENSATION_FEATURE is enabled.");
9192
        #endif
9193
        planner.axis_steps_per_mm[i] = parser.value_per_axis_unit((AxisEnum)i);
9194
      }
9195
    }
9196
  }
9197
  planner.refresh_positioning();
9198
}
9199
 
9200
/**
9201
 * Output the current position to serial
9202
 */
9203
void report_current_position() {
9204
  SERIAL_PROTOCOLPAIR("X:", LOGICAL_X_POSITION(current_position[X_AXIS]));
9205
  SERIAL_PROTOCOLPAIR(" Y:", LOGICAL_Y_POSITION(current_position[Y_AXIS]));
9206
  SERIAL_PROTOCOLPAIR(" Z:", LOGICAL_Z_POSITION(current_position[Z_AXIS]));
9207
  SERIAL_PROTOCOLPAIR(" E:", current_position[E_CART]);
9208
 
9209
  #if ENABLED(HANGPRINTER)
9210
    SERIAL_EOL();
9211
    SERIAL_PROTOCOLPAIR("A:", line_lengths[A_AXIS]);
9212
    SERIAL_PROTOCOLPAIR(" B:", line_lengths[B_AXIS]);
9213
    SERIAL_PROTOCOLPAIR(" C:", line_lengths[C_AXIS]);
9214
    SERIAL_PROTOCOLLNPAIR(" D:", line_lengths[D_AXIS]);
9215
  #endif
9216
 
9217
  stepper.report_positions();
9218
 
9219
  #if IS_SCARA
9220
    SERIAL_PROTOCOLPAIR("SCARA Theta:", planner.get_axis_position_degrees(A_AXIS));
9221
    SERIAL_PROTOCOLLNPAIR("   Psi+Theta:", planner.get_axis_position_degrees(B_AXIS));
9222
    SERIAL_EOL();
9223
  #endif
9224
}
9225
 
9226
#ifdef M114_DETAIL
9227
 
9228
  void report_xyze(const float pos[], const uint8_t n = 4, const uint8_t precision = 3) {
9229
    char str[12];
9230
    for (uint8_t i = 0; i < n; i++) {
9231
      SERIAL_CHAR(' ');
9232
      SERIAL_CHAR(axis_codes[i]);
9233
      SERIAL_CHAR(':');
9234
      SERIAL_PROTOCOL(dtostrf(pos[i], 8, precision, str));
9235
    }
9236
    SERIAL_EOL();
9237
  }
9238
 
9239
  inline void report_xyz(const float pos[]) { report_xyze(pos, 3); }
9240
 
9241
  void report_current_position_detail() {
9242
 
9243
    SERIAL_PROTOCOLPGM("\nLogical:");
9244
    const float logical[XYZ] = {
9245
      LOGICAL_X_POSITION(current_position[X_AXIS]),
9246
      LOGICAL_Y_POSITION(current_position[Y_AXIS]),
9247
      LOGICAL_Z_POSITION(current_position[Z_AXIS])
9248
    };
9249
    report_xyz(logical);
9250
 
9251
    SERIAL_PROTOCOLPGM("Raw:    ");
9252
    report_xyz(current_position);
9253
 
9254
    float leveled[XYZ] = { current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS] };
9255
 
9256
    #if PLANNER_LEVELING
9257
      SERIAL_PROTOCOLPGM("Leveled:");
9258
      planner.apply_leveling(leveled);
9259
      report_xyz(leveled);
9260
 
9261
      SERIAL_PROTOCOLPGM("UnLevel:");
9262
      float unleveled[XYZ] = { leveled[X_AXIS], leveled[Y_AXIS], leveled[Z_AXIS] };
9263
      planner.unapply_leveling(unleveled);
9264
      report_xyz(unleveled);
9265
    #endif
9266
 
9267
    #if IS_KINEMATIC
9268
      #if IS_SCARA
9269
        SERIAL_PROTOCOLPGM("ScaraK: ");
9270
      #else
9271
        SERIAL_PROTOCOLPGM("DeltaK: ");
9272
      #endif
9273
      inverse_kinematics(leveled);  // writes delta[]
9274
      report_xyz(delta);
9275
    #endif
9276
 
9277
    planner.synchronize();
9278
 
9279
    SERIAL_PROTOCOLPGM("Stepper:");
9280
    LOOP_NUM_AXIS(i) {
9281
      SERIAL_CHAR(' ');
9282
      SERIAL_CHAR(RAW_AXIS_CODES(i));
9283
      SERIAL_CHAR(':');
9284
      SERIAL_PROTOCOL(stepper.position((AxisEnum)i));
9285
    }
9286
    SERIAL_EOL();
9287
 
9288
    #if IS_SCARA
9289
      const float deg[XYZ] = {
9290
        planner.get_axis_position_degrees(A_AXIS),
9291
        planner.get_axis_position_degrees(B_AXIS)
9292
      };
9293
      SERIAL_PROTOCOLPGM("Degrees:");
9294
      report_xyze(deg, 2);
9295
    #endif
9296
 
9297
    SERIAL_PROTOCOLPGM("FromStp:");
9298
    get_cartesian_from_steppers();  // writes cartes[XYZ] (with forward kinematics)
9299
    const float from_steppers[XYZE] = { cartes[X_AXIS], cartes[Y_AXIS], cartes[Z_AXIS], planner.get_axis_position_mm(E_AXIS) };
9300
    report_xyze(from_steppers);
9301
 
9302
    const float diff[XYZE] = {
9303
      from_steppers[X_AXIS] - leveled[X_AXIS],
9304
      from_steppers[Y_AXIS] - leveled[Y_AXIS],
9305
      from_steppers[Z_AXIS] - leveled[Z_AXIS],
9306
      from_steppers[E_CART] - current_position[E_CART]
9307
    };
9308
    SERIAL_PROTOCOLPGM("Differ: ");
9309
    report_xyze(diff);
9310
  }
9311
#endif // M114_DETAIL
9312
 
9313
/**
9314
 * M114: Report current position to host
9315
 */
9316
inline void gcode_M114() {
9317
 
9318
  #ifdef M114_DETAIL
9319
    if (parser.seen('D')) return report_current_position_detail();
9320
  #endif
9321
 
9322
  planner.synchronize();
9323
 
9324
  const uint16_t sval = parser.ushortval('S');
9325
 
9326
  #if ENABLED(MECHADUINO_I2C_COMMANDS)
9327
    if (sval == 1) return report_axis_position_from_encoder_data();
9328
  #endif
9329
 
9330
  if (sval == 2) return report_xyz_from_stepper_position();
9331
 
9332
  report_current_position();
9333
}
9334
 
9335
/**
9336
 * M115: Capabilities string
9337
 */
9338
 
9339
#if ENABLED(EXTENDED_CAPABILITIES_REPORT)
9340
  static void cap_line(const char * const name, bool ena=false) {
9341
    SERIAL_PROTOCOLPGM("Cap:");
9342
    serialprintPGM(name);
9343
    SERIAL_PROTOCOLPGM(":");
9344
    SERIAL_PROTOCOLLN(int(ena ? 1 : 0));
9345
  }
9346
#endif
9347
 
9348
inline void gcode_M115() {
9349
  SERIAL_PROTOCOLLNPGM(MSG_M115_REPORT);
9350
 
9351
  #if ENABLED(EXTENDED_CAPABILITIES_REPORT)
9352
 
9353
    // SERIAL_XON_XOFF
9354
    cap_line(PSTR("SERIAL_XON_XOFF")
9355
      #if ENABLED(SERIAL_XON_XOFF)
9356
        , true
9357
      #endif
9358
    );
9359
 
9360
    // EEPROM (M500, M501)
9361
    cap_line(PSTR("EEPROM")
9362
      #if ENABLED(EEPROM_SETTINGS)
9363
        , true
9364
      #endif
9365
    );
9366
 
9367
    // Volumetric Extrusion (M200)
9368
    cap_line(PSTR("VOLUMETRIC")
9369
      #if DISABLED(NO_VOLUMETRICS)
9370
        , true
9371
      #endif
9372
    );
9373
 
9374
    // AUTOREPORT_TEMP (M155)
9375
    cap_line(PSTR("AUTOREPORT_TEMP")
9376
      #if ENABLED(AUTO_REPORT_TEMPERATURES)
9377
        , true
9378
      #endif
9379
    );
9380
 
9381
    // PROGRESS (M530 S L, M531 <file>, M532 X L)
9382
    cap_line(PSTR("PROGRESS"));
9383
 
9384
    // Print Job timer M75, M76, M77
9385
    cap_line(PSTR("PRINT_JOB"), true);
9386
 
9387
    // AUTOLEVEL (G29)
9388
    cap_line(PSTR("AUTOLEVEL")
9389
      #if HAS_AUTOLEVEL
9390
        , true
9391
      #endif
9392
    );
9393
 
9394
    // Z_PROBE (G30)
9395
    cap_line(PSTR("Z_PROBE")
9396
      #if HAS_BED_PROBE
9397
        , true
9398
      #endif
9399
    );
9400
 
9401
    // MESH_REPORT (M420 V)
9402
    cap_line(PSTR("LEVELING_DATA")
9403
      #if HAS_LEVELING
9404
        , true
9405
      #endif
9406
    );
9407
 
9408
    // BUILD_PERCENT (M73)
9409
    cap_line(PSTR("BUILD_PERCENT")
9410
      #if ENABLED(LCD_SET_PROGRESS_MANUALLY)
9411
        , true
9412
      #endif
9413
    );
9414
 
9415
    // SOFTWARE_POWER (M80, M81)
9416
    cap_line(PSTR("SOFTWARE_POWER")
9417
      #if HAS_POWER_SWITCH
9418
        , true
9419
      #endif
9420
    );
9421
 
9422
    // CASE LIGHTS (M355)
9423
    cap_line(PSTR("TOGGLE_LIGHTS")
9424
      #if HAS_CASE_LIGHT
9425
        , true
9426
      #endif
9427
    );
9428
    cap_line(PSTR("CASE_LIGHT_BRIGHTNESS")
9429
      #if HAS_CASE_LIGHT
9430
        , USEABLE_HARDWARE_PWM(CASE_LIGHT_PIN)
9431
      #endif
9432
    );
9433
 
9434
    // EMERGENCY_PARSER (M108, M112, M410)
9435
    cap_line(PSTR("EMERGENCY_PARSER")
9436
      #if ENABLED(EMERGENCY_PARSER)
9437
        , true
9438
      #endif
9439
    );
9440
 
9441
    // AUTOREPORT_SD_STATUS (M27 extension)
9442
    cap_line(PSTR("AUTOREPORT_SD_STATUS")
9443
      #if ENABLED(AUTO_REPORT_SD_STATUS)
9444
        , true
9445
      #endif
9446
    );
9447
 
9448
    // THERMAL_PROTECTION
9449
    cap_line(PSTR("THERMAL_PROTECTION")
9450
      #if ENABLED(THERMAL_PROTECTION_HOTENDS) && ENABLED(THERMAL_PROTECTION_BED)
9451
        , true
9452
      #endif
9453
    );
9454
 
9455
  #endif // EXTENDED_CAPABILITIES_REPORT
9456
}
9457
 
9458
/**
9459
 * M117: Set LCD Status Message
9460
 */
9461
inline void gcode_M117() {
9462
  if (parser.string_arg[0])
9463
    lcd_setstatus(parser.string_arg);
9464
  else
9465
    lcd_reset_status();
9466
}
9467
 
9468
/**
9469
 * M118: Display a message in the host console.
9470
 *
9471
 *  A1  Prepend '// ' for an action command, as in OctoPrint
9472
 *  E1  Have the host 'echo:' the text
9473
 */
9474
inline void gcode_M118() {
9475
  bool hasE = false, hasA = false;
9476
  char *p = parser.string_arg;
9477
  for (uint8_t i = 2; i--;)
9478
    if ((p[0] == 'A' || p[0] == 'E') && p[1] == '1') {
9479
      if (p[0] == 'A') hasA = true;
9480
      if (p[0] == 'E') hasE = true;
9481
      p += 2;
9482
      while (*p == ' ') ++p;
9483
    }
9484
  if (hasE) SERIAL_ECHO_START();
9485
  if (hasA) SERIAL_ECHOPGM("// ");
9486
  SERIAL_ECHOLN(p);
9487
}
9488
 
9489
/**
9490
 * M119: Output endstop states to serial output
9491
 */
9492
inline void gcode_M119() { endstops.M119(); }
9493
 
9494
/**
9495
 * M120: Enable endstops and set non-homing endstop state to "enabled"
9496
 */
9497
inline void gcode_M120() { endstops.enable_globally(true); }
9498
 
9499
/**
9500
 * M121: Disable endstops and set non-homing endstop state to "disabled"
9501
 */
9502
inline void gcode_M121() { endstops.enable_globally(false); }
9503
 
9504
#if ENABLED(PARK_HEAD_ON_PAUSE)
9505
 
9506
  /**
9507
   * M125: Store current position and move to filament change position.
9508
   *       Called on pause (by M25) to prevent material leaking onto the
9509
   *       object. On resume (M24) the head will be moved back and the
9510
   *       print will resume.
9511
   *
9512
   *       If Marlin is compiled without SD Card support, M125 can be
9513
   *       used directly to pause the print and move to park position,
9514
   *       resuming with a button click or M108.
9515
   *
9516
   *    L = override retract length
9517
   *    X = override X
9518
   *    Y = override Y
9519
   *    Z = override Z raise
9520
   */
9521
  inline void gcode_M125() {
9522
 
9523
    // Initial retract before move to filament change position
9524
    const float retract = -ABS(parser.seen('L') ? parser.value_axis_units(E_AXIS) : 0
9525
      #ifdef PAUSE_PARK_RETRACT_LENGTH
9526
        + (PAUSE_PARK_RETRACT_LENGTH)
9527
      #endif
9528
    );
9529
 
9530
    point_t park_point = NOZZLE_PARK_POINT;
9531
 
9532
    // Move XY axes to filament change position or given position
9533
    if (parser.seenval('X')) park_point.x = parser.linearval('X');
9534
    if (parser.seenval('Y')) park_point.y = parser.linearval('Y');
9535
 
9536
    // Lift Z axis
9537
    if (parser.seenval('Z')) park_point.z = parser.linearval('Z');
9538
 
9539
    #if HOTENDS > 1 && DISABLED(DUAL_X_CARRIAGE) && DISABLED(DELTA)
9540
      park_point.x += (active_extruder ? hotend_offset[X_AXIS][active_extruder] : 0);
9541
      park_point.y += (active_extruder ? hotend_offset[Y_AXIS][active_extruder] : 0);
9542
    #endif
9543
 
9544
    #if DISABLED(SDSUPPORT)
9545
      const bool job_running = print_job_timer.isRunning();
9546
    #endif
9547
 
9548
    if (pause_print(retract, park_point)) {
9549
      #if DISABLED(SDSUPPORT)
9550
        // Wait for lcd click or M108
9551
        wait_for_filament_reload();
9552
 
9553
        // Return to print position and continue
9554
        resume_print();
9555
 
9556
        if (job_running) print_job_timer.start();
9557
      #endif
9558
    }
9559
  }
9560
 
9561
#endif // PARK_HEAD_ON_PAUSE
9562
 
9563
#if HAS_COLOR_LEDS
9564
 
9565
  /**
9566
   * M150: Set Status LED Color - Use R-U-B-W for R-G-B-W
9567
   *       and Brightness       - Use P (for NEOPIXEL only)
9568
   *
9569
   * Always sets all 3 or 4 components. If a component is left out, set to 0.
9570
   *                                    If brightness is left out, no value changed
9571
   *
9572
   * Examples:
9573
   *
9574
   *   M150 R255       ; Turn LED red
9575
   *   M150 R255 U127  ; Turn LED orange (PWM only)
9576
   *   M150            ; Turn LED off
9577
   *   M150 R U B      ; Turn LED white
9578
   *   M150 W          ; Turn LED white using a white LED
9579
   *   M150 P127       ; Set LED 50% brightness
9580
   *   M150 P          ; Set LED full brightness
9581
   */
9582
  inline void gcode_M150() {
9583
    leds.set_color(MakeLEDColor(
9584
      parser.seen('R') ? (parser.has_value() ? parser.value_byte() : 255) : 0,
9585
      parser.seen('U') ? (parser.has_value() ? parser.value_byte() : 255) : 0,
9586
      parser.seen('B') ? (parser.has_value() ? parser.value_byte() : 255) : 0,
9587
      parser.seen('W') ? (parser.has_value() ? parser.value_byte() : 255) : 0,
9588
      parser.seen('P') ? (parser.has_value() ? parser.value_byte() : 255) : pixels.getBrightness()
9589
    ));
9590
  }
9591
 
9592
#endif // HAS_COLOR_LEDS
9593
 
9594
#if DISABLED(NO_VOLUMETRICS)
9595
 
9596
  /**
9597
   * M200: Set filament diameter and set E axis units to cubic units
9598
   *
9599
   *    T<extruder> - Optional extruder number. Current extruder if omitted.
9600
   *    D<linear> - Diameter of the filament. Use "D0" to switch back to linear units on the E axis.
9601
   */
9602
  inline void gcode_M200() {
9603
 
9604
    if (get_target_extruder_from_command(200)) return;
9605
 
9606
    if (parser.seen('D')) {
9607
      // setting any extruder filament size disables volumetric on the assumption that
9608
      // slicers either generate in extruder values as cubic mm or as as filament feeds
9609
      // for all extruders
9610
      if ( (parser.volumetric_enabled = (parser.value_linear_units() != 0)) )
9611
        planner.set_filament_size(target_extruder, parser.value_linear_units());
9612
    }
9613
    planner.calculate_volumetric_multipliers();
9614
  }
9615
 
9616
#endif // !NO_VOLUMETRICS
9617
 
9618
/**
9619
 * M201: Set max acceleration in units/s^2 for print moves (M201 X1000 Y1000)
9620
 *
9621
 *       With multiple extruders use T to specify which one.
9622
 */
9623
inline void gcode_M201() {
9624
 
9625
  GET_TARGET_EXTRUDER(201);
9626
 
9627
  LOOP_NUM_AXIS(i) {
9628
    if (parser.seen(RAW_AXIS_CODES(i))) {
9629
      const uint8_t a = i + (i == E_AXIS ? TARGET_EXTRUDER : 0);
9630
      planner.max_acceleration_mm_per_s2[a] = parser.value_axis_units((AxisEnum)a);
9631
    }
9632
  }
9633
  // steps per sq second need to be updated to agree with the units per sq second (as they are what is used in the planner)
9634
  planner.reset_acceleration_rates();
9635
}
9636
 
9637
#if 0 // Not used for Sprinter/grbl gen6
9638
  inline void gcode_M202() {
9639
    LOOP_XYZE(i) {
9640
      if (parser.seen(axis_codes[i])) axis_travel_steps_per_sqr_second[i] = parser.value_axis_units((AxisEnum)i) * planner.axis_steps_per_mm[i];
9641
    }
9642
  }
9643
#endif
9644
 
9645
 
9646
/**
9647
 * M203: Set maximum feedrate that your machine can sustain (M203 X200 Y200 Z300 E10000) in units/sec
9648
 *
9649
 *       With multiple extruders use T to specify which one.
9650
 */
9651
inline void gcode_M203() {
9652
 
9653
  GET_TARGET_EXTRUDER(203);
9654
 
9655
  LOOP_NUM_AXIS(i)
9656
    if (parser.seen(RAW_AXIS_CODES(i))) {
9657
      const uint8_t a = i + (i == E_AXIS ? TARGET_EXTRUDER : 0);
9658
      planner.max_feedrate_mm_s[a] = parser.value_axis_units((AxisEnum)a);
9659
    }
9660
}
9661
 
9662
/**
9663
 * M204: Set Accelerations in units/sec^2 (M204 P1200 R3000 T3000)
9664
 *
9665
 *    P = Printing moves
9666
 *    R = Retract only (no X, Y, Z) moves
9667
 *    T = Travel (non printing) moves
9668
 */
9669
inline void gcode_M204() {
9670
  bool report = true;
9671
  if (parser.seenval('S')) { // Kept for legacy compatibility. Should NOT BE USED for new developments.
9672
    planner.travel_acceleration = planner.acceleration = parser.value_linear_units();
9673
    report = false;
9674
  }
9675
  if (parser.seenval('P')) {
9676
    planner.acceleration = parser.value_linear_units();
9677
    report = false;
9678
  }
9679
  if (parser.seenval('R')) {
9680
    planner.retract_acceleration = parser.value_linear_units();
9681
    report = false;
9682
  }
9683
  if (parser.seenval('T')) {
9684
    planner.travel_acceleration = parser.value_linear_units();
9685
    report = false;
9686
  }
9687
  if (report) {
9688
    SERIAL_ECHOPAIR("Acceleration: P", planner.acceleration);
9689
    SERIAL_ECHOPAIR(" R", planner.retract_acceleration);
9690
    SERIAL_ECHOLNPAIR(" T", planner.travel_acceleration);
9691
  }
9692
}
9693
 
9694
/**
9695
 * M205: Set Advanced Settings
9696
 *
9697
 *    Q = Min Segment Time (µs)
9698
 *    S = Min Feed Rate (units/s)
9699
 *    T = Min Travel Feed Rate (units/s)
9700
 *    X = Max X Jerk (units/sec^2)
9701
 *    Y = Max Y Jerk (units/sec^2)
9702
 *    Z = Max Z Jerk (units/sec^2)
9703
 *    E = Max E Jerk (units/sec^2)
9704
 *    J = Junction Deviation (mm) (Requires JUNCTION_DEVIATION)
9705
 */
9706
inline void gcode_M205() {
9707
  if (parser.seen('Q')) planner.min_segment_time_us = parser.value_ulong();
9708
  if (parser.seen('S')) planner.min_feedrate_mm_s = parser.value_linear_units();
9709
  if (parser.seen('T')) planner.min_travel_feedrate_mm_s = parser.value_linear_units();
9710
  #if ENABLED(JUNCTION_DEVIATION)
9711
    if (parser.seen('J')) {
9712
      const float junc_dev = parser.value_linear_units();
9713
      if (WITHIN(junc_dev, 0.01f, 0.3f)) {
9714
        planner.junction_deviation_mm = junc_dev;
9715
        planner.recalculate_max_e_jerk();
9716
      }
9717
      else {
9718
        SERIAL_ERROR_START();
9719
        SERIAL_ERRORLNPGM("?J out of range (0.01 to 0.3)");
9720
      }
9721
    }
9722
  #else
9723
    #if ENABLED(HANGPRINTER)
9724
      if (parser.seen('A')) planner.max_jerk[A_AXIS] = parser.value_linear_units();
9725
      if (parser.seen('B')) planner.max_jerk[B_AXIS] = parser.value_linear_units();
9726
      if (parser.seen('C')) planner.max_jerk[C_AXIS] = parser.value_linear_units();
9727
      if (parser.seen('D')) planner.max_jerk[D_AXIS] = parser.value_linear_units();
9728
    #else
9729
      if (parser.seen('X')) planner.max_jerk[X_AXIS] = parser.value_linear_units();
9730
      if (parser.seen('Y')) planner.max_jerk[Y_AXIS] = parser.value_linear_units();
9731
      if (parser.seen('Z')) {
9732
        planner.max_jerk[Z_AXIS] = parser.value_linear_units();
9733
        #if HAS_MESH
9734
          if (planner.max_jerk[Z_AXIS] <= 0.1f)
9735
            SERIAL_ECHOLNPGM("WARNING! Low Z Jerk may lead to unwanted pauses.");
9736
        #endif
9737
      }
9738
    #endif
9739
    if (parser.seen('E')) planner.max_jerk[E_AXIS] = parser.value_linear_units();
9740
  #endif
9741
}
9742
 
9743
#if HAS_M206_COMMAND
9744
 
9745
  /**
9746
   * M206: Set Additional Homing Offset (X Y Z). SCARA aliases T=X, P=Y
9747
   *
9748
   * *** @thinkyhead: I recommend deprecating M206 for SCARA in favor of M665.
9749
   * ***              M206 for SCARA will remain enabled in 1.1.x for compatibility.
9750
   * ***              In the next 1.2 release, it will simply be disabled by default.
9751
   */
9752
  inline void gcode_M206() {
9753
    LOOP_XYZ(i)
9754
      if (parser.seen(axis_codes[i]))
9755
        set_home_offset((AxisEnum)i, parser.value_linear_units());
9756
 
9757
    #if ENABLED(MORGAN_SCARA)
9758
      if (parser.seen('T')) set_home_offset(A_AXIS, parser.value_float()); // Theta
9759
      if (parser.seen('P')) set_home_offset(B_AXIS, parser.value_float()); // Psi
9760
    #endif
9761
 
9762
    report_current_position();
9763
  }
9764
 
9765
#endif // HAS_M206_COMMAND
9766
 
9767
#if ENABLED(DELTA)
9768
  /**
9769
   * M665: Set delta configurations
9770
   *
9771
   *    H = delta height
9772
   *    L = diagonal rod
9773
   *    R = delta radius
9774
   *    S = segments per second
9775
   *    B = delta calibration radius
9776
   *    X = Alpha (Tower 1) angle trim
9777
   *    Y = Beta (Tower 2) angle trim
9778
   *    Z = Gamma (Tower 3) angle trim
9779
   */
9780
  inline void gcode_M665() {
9781
    if (parser.seen('H')) delta_height                   = parser.value_linear_units();
9782
    if (parser.seen('L')) delta_diagonal_rod             = parser.value_linear_units();
9783
    if (parser.seen('R')) delta_radius                   = parser.value_linear_units();
9784
    if (parser.seen('S')) delta_segments_per_second      = parser.value_float();
9785
    if (parser.seen('B')) delta_calibration_radius       = parser.value_float();
9786
    if (parser.seen('X')) delta_tower_angle_trim[A_AXIS] = parser.value_float();
9787
    if (parser.seen('Y')) delta_tower_angle_trim[B_AXIS] = parser.value_float();
9788
    if (parser.seen('Z')) delta_tower_angle_trim[C_AXIS] = parser.value_float();
9789
    recalc_delta_settings();
9790
  }
9791
  /**
9792
   * M666: Set delta endstop adjustment
9793
   */
9794
  inline void gcode_M666() {
9795
    #if ENABLED(DEBUG_LEVELING_FEATURE)
9796
      if (DEBUGGING(LEVELING)) {
9797
        SERIAL_ECHOLNPGM(">>> gcode_M666");
9798
      }
9799
    #endif
9800
    LOOP_XYZ(i) {
9801
      if (parser.seen(axis_codes[i])) {
9802
        if (parser.value_linear_units() * Z_HOME_DIR <= 0)
9803
          delta_endstop_adj[i] = parser.value_linear_units();
9804
        #if ENABLED(DEBUG_LEVELING_FEATURE)
9805
          if (DEBUGGING(LEVELING)) {
9806
            SERIAL_ECHOPAIR("delta_endstop_adj[", axis_codes[i]);
9807
            SERIAL_ECHOLNPAIR("] = ", delta_endstop_adj[i]);
9808
          }
9809
        #endif
9810
      }
9811
    }
9812
    #if ENABLED(DEBUG_LEVELING_FEATURE)
9813
      if (DEBUGGING(LEVELING)) {
9814
        SERIAL_ECHOLNPGM("<<< gcode_M666");
9815
      }
9816
    #endif
9817
  }
9818
 
9819
#elif IS_SCARA
9820
 
9821
  /**
9822
   * M665: Set SCARA settings
9823
   *
9824
   * Parameters:
9825
   *
9826
   *   S[segments-per-second] - Segments-per-second
9827
   *   P[theta-psi-offset]    - Theta-Psi offset, added to the shoulder (A/X) angle
9828
   *   T[theta-offset]        - Theta     offset, added to the elbow    (B/Y) angle
9829
   *
9830
   *   A, P, and X are all aliases for the shoulder angle
9831
   *   B, T, and Y are all aliases for the elbow angle
9832
   */
9833
  inline void gcode_M665() {
9834
    if (parser.seen('S')) delta_segments_per_second = parser.value_float();
9835
 
9836
    const bool hasA = parser.seen('A'), hasP = parser.seen('P'), hasX = parser.seen('X');
9837
    const uint8_t sumAPX = hasA + hasP + hasX;
9838
    if (sumAPX == 1)
9839
      home_offset[A_AXIS] = parser.value_float();
9840
    else if (sumAPX > 1) {
9841
      SERIAL_ERROR_START();
9842
      SERIAL_ERRORLNPGM("Only one of A, P, or X is allowed.");
9843
      return;
9844
    }
9845
 
9846
    const bool hasB = parser.seen('B'), hasT = parser.seen('T'), hasY = parser.seen('Y');
9847
    const uint8_t sumBTY = hasB + hasT + hasY;
9848
    if (sumBTY == 1)
9849
      home_offset[B_AXIS] = parser.value_float();
9850
    else if (sumBTY > 1) {
9851
      SERIAL_ERROR_START();
9852
      SERIAL_ERRORLNPGM("Only one of B, T, or Y is allowed.");
9853
      return;
9854
    }
9855
  }
9856
 
9857
#elif ENABLED(HANGPRINTER)
9858
  /**
9859
   * M665: Set HANGPRINTER settings
9860
   *
9861
   * Parameters:
9862
   *
9863
   *   W[anchor_A_y] - A-anchor's y coordinate (see note)
9864
   *   E[anchor_A_z] - A-anchor's z coordinate (see note)
9865
   *   R[anchor_B_x] - B-anchor's x coordinate (see note)
9866
   *   T[anchor_B_y] - B-anchor's y coordinate (see note)
9867
   *   Y[anchor_B_z] - B-anchor's z coordinate (see note)
9868
   *   U[anchor_C_x] - C-anchor's x coordinate (see note)
9869
   *   I[anchor_C_y] - C-anchor's y coordinate (see note)
9870
   *   O[anchor_C_z] - C-anchor's z coordinate (see note)
9871
   *   P[anchor_D_z] - D-anchor's z coordinate (see note)
9872
   *   S[segments-per-second] - Segments-per-second
9873
   *
9874
   * Note: All xyz coordinates are measured relative to the line's pivot point in the mover,
9875
   *         when it is at its home position (nozzle in (0,0,0), and lines tight).
9876
   *       The y-axis is defined to be horizontal right above/below the A-lines when mover is at home.
9877
   *       The z-axis is along the vertical direction.
9878
   */
9879
  inline void gcode_M665() {
9880
    if (parser.seen('W')) anchor_A_y                = parser.value_float();
9881
    if (parser.seen('E')) anchor_A_z                = parser.value_float();
9882
    if (parser.seen('R')) anchor_B_x                = parser.value_float();
9883
    if (parser.seen('T')) anchor_B_y                = parser.value_float();
9884
    if (parser.seen('Y')) anchor_B_z                = parser.value_float();
9885
    if (parser.seen('U')) anchor_C_x                = parser.value_float();
9886
    if (parser.seen('I')) anchor_C_y                = parser.value_float();
9887
    if (parser.seen('O')) anchor_C_z                = parser.value_float();
9888
    if (parser.seen('P')) anchor_D_z                = parser.value_float();
9889
    if (parser.seen('S')) delta_segments_per_second = parser.value_float();
9890
    recalc_hangprinter_settings();
9891
  }
9892
 
9893
#elif ENABLED(X_DUAL_ENDSTOPS) || ENABLED(Y_DUAL_ENDSTOPS) || ENABLED(Z_DUAL_ENDSTOPS)
9894
 
9895
  /**
9896
   * M666: Set Dual Endstops offsets for X, Y, and/or Z.
9897
   *       With no parameters report current offsets.
9898
   */
9899
  inline void gcode_M666() {
9900
    bool report = true;
9901
    #if ENABLED(X_DUAL_ENDSTOPS)
9902
      if (parser.seenval('X')) {
9903
        endstops.x_endstop_adj = parser.value_linear_units();
9904
        report = false;
9905
      }
9906
    #endif
9907
    #if ENABLED(Y_DUAL_ENDSTOPS)
9908
      if (parser.seenval('Y')) {
9909
        endstops.y_endstop_adj = parser.value_linear_units();
9910
        report = false;
9911
      }
9912
    #endif
9913
    #if ENABLED(Z_DUAL_ENDSTOPS)
9914
      if (parser.seenval('Z')) {
9915
        endstops.z_endstop_adj = parser.value_linear_units();
9916
        report = false;
9917
      }
9918
    #endif
9919
    if (report) {
9920
      SERIAL_ECHOPGM("Dual Endstop Adjustment (mm): ");
9921
      #if ENABLED(X_DUAL_ENDSTOPS)
9922
        SERIAL_ECHOPAIR(" X", endstops.x_endstop_adj);
9923
      #endif
9924
      #if ENABLED(Y_DUAL_ENDSTOPS)
9925
        SERIAL_ECHOPAIR(" Y", endstops.y_endstop_adj);
9926
      #endif
9927
      #if ENABLED(Z_DUAL_ENDSTOPS)
9928
        SERIAL_ECHOPAIR(" Z", endstops.z_endstop_adj);
9929
      #endif
9930
      SERIAL_EOL();
9931
    }
9932
  }
9933
 
9934
#endif // X_DUAL_ENDSTOPS || Y_DUAL_ENDSTOPS || Z_DUAL_ENDSTOPS
9935
 
9936
#if ENABLED(FWRETRACT)
9937
 
9938
  /**
9939
   * M207: Set firmware retraction values
9940
   *
9941
   *   S[+units]    retract_length
9942
   *   W[+units]    swap_retract_length (multi-extruder)
9943
   *   F[units/min] retract_feedrate_mm_s
9944
   *   Z[units]     retract_zlift
9945
   */
9946
  inline void gcode_M207() {
9947
    if (parser.seen('S')) fwretract.retract_length = parser.value_axis_units(E_AXIS);
9948
    if (parser.seen('F')) fwretract.retract_feedrate_mm_s = MMM_TO_MMS(parser.value_axis_units(E_AXIS));
9949
    if (parser.seen('Z')) fwretract.retract_zlift = parser.value_linear_units();
9950
    if (parser.seen('W')) fwretract.swap_retract_length = parser.value_axis_units(E_AXIS);
9951
  }
9952
 
9953
  /**
9954
   * M208: Set firmware un-retraction values
9955
   *
9956
   *   S[+units]    retract_recover_length (in addition to M207 S*)
9957
   *   W[+units]    swap_retract_recover_length (multi-extruder)
9958
   *   F[units/min] retract_recover_feedrate_mm_s
9959
   *   R[units/min] swap_retract_recover_feedrate_mm_s
9960
   */
9961
  inline void gcode_M208() {
9962
    if (parser.seen('S')) fwretract.retract_recover_length = parser.value_axis_units(E_AXIS);
9963
    if (parser.seen('F')) fwretract.retract_recover_feedrate_mm_s = MMM_TO_MMS(parser.value_axis_units(E_AXIS));
9964
    if (parser.seen('R')) fwretract.swap_retract_recover_feedrate_mm_s = MMM_TO_MMS(parser.value_axis_units(E_AXIS));
9965
    if (parser.seen('W')) fwretract.swap_retract_recover_length = parser.value_axis_units(E_AXIS);
9966
  }
9967
 
9968
  /**
9969
   * M209: Enable automatic retract (M209 S1)
9970
   *   For slicers that don't support G10/11, reversed extrude-only
9971
   *   moves will be classified as retraction.
9972
   */
9973
  inline void gcode_M209() {
9974
    if (MIN_AUTORETRACT <= MAX_AUTORETRACT) {
9975
      if (parser.seen('S')) {
9976
        fwretract.autoretract_enabled = parser.value_bool();
9977
        for (uint8_t i = 0; i < EXTRUDERS; i++) fwretract.retracted[i] = false;
9978
      }
9979
    }
9980
  }
9981
 
9982
#endif // FWRETRACT
9983
 
9984
/**
9985
 * M211: Enable, Disable, and/or Report software endstops
9986
 *
9987
 * Usage: M211 S1 to enable, M211 S0 to disable, M211 alone for report
9988
 */
9989
inline void gcode_M211() {
9990
  SERIAL_ECHO_START();
9991
  #if HAS_SOFTWARE_ENDSTOPS
9992
    if (parser.seen('S')) soft_endstops_enabled = parser.value_bool();
9993
    SERIAL_ECHOPGM(MSG_SOFT_ENDSTOPS);
9994
    serialprintPGM(soft_endstops_enabled ? PSTR(MSG_ON) : PSTR(MSG_OFF));
9995
  #else
9996
    SERIAL_ECHOPGM(MSG_SOFT_ENDSTOPS);
9997
    SERIAL_ECHOPGM(MSG_OFF);
9998
  #endif
9999
  SERIAL_ECHOPGM(MSG_SOFT_MIN);
10000
  SERIAL_ECHOPAIR(    MSG_X, LOGICAL_X_POSITION(soft_endstop_min[X_AXIS]));
10001
  SERIAL_ECHOPAIR(" " MSG_Y, LOGICAL_Y_POSITION(soft_endstop_min[Y_AXIS]));
10002
  SERIAL_ECHOPAIR(" " MSG_Z, LOGICAL_Z_POSITION(soft_endstop_min[Z_AXIS]));
10003
  SERIAL_ECHOPGM(MSG_SOFT_MAX);
10004
  SERIAL_ECHOPAIR(    MSG_X, LOGICAL_X_POSITION(soft_endstop_max[X_AXIS]));
10005
  SERIAL_ECHOPAIR(" " MSG_Y, LOGICAL_Y_POSITION(soft_endstop_max[Y_AXIS]));
10006
  SERIAL_ECHOLNPAIR(" " MSG_Z, LOGICAL_Z_POSITION(soft_endstop_max[Z_AXIS]));
10007
}
10008
 
10009
#if HOTENDS > 1
10010
 
10011
  /**
10012
   * M218 - Set/get hotend offset (in linear units)
10013
   *
10014
   *   T<tool>
10015
   *   X<xoffset>
10016
   *   Y<yoffset>
10017
   *   Z<zoffset> - Available with DUAL_X_CARRIAGE, SWITCHING_NOZZLE, and PARKING_EXTRUDER
10018
   */
10019
  inline void gcode_M218() {
10020
    if (get_target_extruder_from_command(218) || target_extruder == 0) return;
10021
 
10022
    bool report = true;
10023
    if (parser.seenval('X')) {
10024
      hotend_offset[X_AXIS][target_extruder] = parser.value_linear_units();
10025
      report = false;
10026
    }
10027
    if (parser.seenval('Y')) {
10028
      hotend_offset[Y_AXIS][target_extruder] = parser.value_linear_units();
10029
      report = false;
10030
    }
10031
 
10032
    #if HAS_HOTEND_OFFSET_Z
10033
      if (parser.seenval('Z')) {
10034
        hotend_offset[Z_AXIS][target_extruder] = parser.value_linear_units();
10035
        report = false;
10036
      }
10037
    #endif
10038
 
10039
    if (report) {
10040
      SERIAL_ECHO_START();
10041
      SERIAL_ECHOPGM(MSG_HOTEND_OFFSET);
10042
      HOTEND_LOOP() {
10043
        SERIAL_CHAR(' ');
10044
        SERIAL_ECHO(hotend_offset[X_AXIS][e]);
10045
        SERIAL_CHAR(',');
10046
        SERIAL_ECHO(hotend_offset[Y_AXIS][e]);
10047
        #if HAS_HOTEND_OFFSET_Z
10048
          SERIAL_CHAR(',');
10049
          SERIAL_ECHO(hotend_offset[Z_AXIS][e]);
10050
        #endif
10051
      }
10052
      SERIAL_EOL();
10053
    }
10054
 
10055
    #if ENABLED(DELTA)
10056
      if (target_extruder == active_extruder)
10057
        do_blocking_move_to_xy(current_position[X_AXIS], current_position[Y_AXIS], planner.max_feedrate_mm_s[X_AXIS]);
10058
    #endif
10059
  }
10060
 
10061
#endif // HOTENDS > 1
10062
 
10063
/**
10064
 * M220: Set speed percentage factor, aka "Feed Rate" (M220 S95)
10065
 */
10066
inline void gcode_M220() {
10067
  if (parser.seenval('S')) feedrate_percentage = parser.value_int();
10068
}
10069
 
10070
/**
10071
 * M221: Set extrusion percentage (M221 T0 S95)
10072
 */
10073
inline void gcode_M221() {
10074
  if (get_target_extruder_from_command(221)) return;
10075
  if (parser.seenval('S')) {
10076
    planner.flow_percentage[target_extruder] = parser.value_int();
10077
    planner.refresh_e_factor(target_extruder);
10078
  }
10079
  else {
10080
    SERIAL_ECHO_START();
10081
    SERIAL_CHAR('E');
10082
    SERIAL_CHAR('0' + target_extruder);
10083
    SERIAL_ECHOPAIR(" Flow: ", planner.flow_percentage[target_extruder]);
10084
    SERIAL_CHAR('%');
10085
    SERIAL_EOL();
10086
  }
10087
}
10088
 
10089
/**
10090
 * M226: Wait until the specified pin reaches the state required (M226 P<pin> S<state>)
10091
 */
10092
inline void gcode_M226() {
10093
  if (parser.seen('P')) {
10094
    const int pin = parser.value_int(), pin_state = parser.intval('S', -1);
10095
    if (WITHIN(pin_state, -1, 1) && pin > -1) {
10096
      if (pin_is_protected(pin))
10097
        protected_pin_err();
10098
      else {
10099
        int target = LOW;
10100
        planner.synchronize();
10101
        pinMode(pin, INPUT);
10102
        switch (pin_state) {
10103
          case 1: target = HIGH; break;
10104
          case 0: target = LOW; break;
10105
          case -1: target = !digitalRead(pin); break;
10106
        }
10107
        while (digitalRead(pin) != target) idle();
10108
      }
10109
    } // pin_state -1 0 1 && pin > -1
10110
  } // parser.seen('P')
10111
}
10112
 
10113
#if ENABLED(EXPERIMENTAL_I2CBUS)
10114
 
10115
  /**
10116
   * M260: Send data to a I2C slave device
10117
   *
10118
   * This is a PoC, the formating and arguments for the GCODE will
10119
   * change to be more compatible, the current proposal is:
10120
   *
10121
   *  M260 A<slave device address base 10> ; Sets the I2C slave address the data will be sent to
10122
   *
10123
   *  M260 B<byte-1 value in base 10>
10124
   *  M260 B<byte-2 value in base 10>
10125
   *  M260 B<byte-3 value in base 10>
10126
   *
10127
   *  M260 S1 ; Send the buffered data and reset the buffer
10128
   *  M260 R1 ; Reset the buffer without sending data
10129
   *
10130
   */
10131
  inline void gcode_M260() {
10132
    // Set the target address
10133
    if (parser.seen('A')) i2c.address(parser.value_byte());
10134
 
10135
    // Add a new byte to the buffer
10136
    if (parser.seen('B')) i2c.addbyte(parser.value_byte());
10137
 
10138
    // Flush the buffer to the bus
10139
    if (parser.seen('S')) i2c.send();
10140
 
10141
    // Reset and rewind the buffer
10142
    else if (parser.seen('R')) i2c.reset();
10143
  }
10144
 
10145
  /**
10146
   * M261: Request X bytes from I2C slave device
10147
   *
10148
   * Usage: M261 A<slave device address base 10> B<number of bytes>
10149
   */
10150
  inline void gcode_M261() {
10151
    if (parser.seen('A')) i2c.address(parser.value_byte());
10152
 
10153
    uint8_t bytes = parser.byteval('B', 1);
10154
 
10155
    if (i2c.addr && bytes && bytes <= TWIBUS_BUFFER_SIZE) {
10156
      i2c.relay(bytes);
10157
    }
10158
    else {
10159
      SERIAL_ERROR_START();
10160
      SERIAL_ERRORLNPGM("Bad i2c request");
10161
    }
10162
  }
10163
 
10164
#endif // EXPERIMENTAL_I2CBUS
10165
 
10166
#if HAS_SERVOS
10167
 
10168
  /**
10169
   * M280: Get or set servo position. P<index> [S<angle>]
10170
   */
10171
  inline void gcode_M280() {
10172
    if (!parser.seen('P')) return;
10173
    const int servo_index = parser.value_int();
10174
    if (WITHIN(servo_index, 0, NUM_SERVOS - 1)) {
10175
      if (parser.seen('S'))
10176
        MOVE_SERVO(servo_index, parser.value_int());
10177
      else {
10178
        SERIAL_ECHO_START();
10179
        SERIAL_ECHOPAIR(" Servo ", servo_index);
10180
        SERIAL_ECHOLNPAIR(": ", servo[servo_index].read());
10181
      }
10182
    }
10183
    else {
10184
      SERIAL_ERROR_START();
10185
      SERIAL_ECHOPAIR("Servo ", servo_index);
10186
      SERIAL_ECHOLNPGM(" out of range");
10187
    }
10188
  }
10189
 
10190
#endif // HAS_SERVOS
10191
 
10192
#if ENABLED(BABYSTEPPING)
10193
 
10194
  #if ENABLED(BABYSTEP_ZPROBE_OFFSET)
10195
    FORCE_INLINE void mod_zprobe_zoffset(const float &offs) {
10196
      zprobe_zoffset += offs;
10197
      SERIAL_ECHO_START();
10198
      SERIAL_ECHOLNPAIR(MSG_PROBE_Z_OFFSET ": ", zprobe_zoffset);
10199
    }
10200
  #endif
10201
 
10202
  /**
10203
   * M290: Babystepping
10204
   */
10205
  inline void gcode_M290() {
10206
    #if ENABLED(BABYSTEP_XY)
10207
      for (uint8_t a = X_AXIS; a <= Z_AXIS; a++)
10208
        if (parser.seenval(axis_codes[a]) || (a == Z_AXIS && parser.seenval('S'))) {
10209
          const float offs = constrain(parser.value_axis_units((AxisEnum)a), -2, 2);
10210
          thermalManager.babystep_axis((AxisEnum)a, offs * planner.axis_steps_per_mm[a]);
10211
          #if ENABLED(BABYSTEP_ZPROBE_OFFSET)
10212
            if (a == Z_AXIS && (!parser.seen('P') || parser.value_bool())) mod_zprobe_zoffset(offs);
10213
          #endif
10214
        }
10215
    #else
10216
      if (parser.seenval('Z') || parser.seenval('S')) {
10217
        const float offs = constrain(parser.value_axis_units(Z_AXIS), -2, 2);
10218
        thermalManager.babystep_axis(Z_AXIS, offs * planner.axis_steps_per_mm[Z_AXIS]);
10219
        #if ENABLED(BABYSTEP_ZPROBE_OFFSET)
10220
          if (!parser.seen('P') || parser.value_bool()) mod_zprobe_zoffset(offs);
10221
        #endif
10222
      }
10223
    #endif
10224
  }
10225
 
10226
#endif // BABYSTEPPING
10227
 
10228
#if HAS_BUZZER
10229
 
10230
  /**
10231
   * M300: Play beep sound S<frequency Hz> P<duration ms>
10232
   */
10233
  inline void gcode_M300() {
10234
    uint16_t const frequency = parser.ushortval('S', 260);
10235
    uint16_t duration = parser.ushortval('P', 1000);
10236
 
10237
    // Limits the tone duration to 0-5 seconds.
10238
    NOMORE(duration, 5000);
10239
 
10240
    BUZZ(duration, frequency);
10241
  }
10242
 
10243
#endif // HAS_BUZZER
10244
 
10245
#if ENABLED(PIDTEMP)
10246
 
10247
  /**
10248
   * M301: Set PID parameters P I D (and optionally C, L)
10249
   *
10250
   *   P[float] Kp term
10251
   *   I[float] Ki term (unscaled)
10252
   *   D[float] Kd term (unscaled)
10253
   *
10254
   * With PID_EXTRUSION_SCALING:
10255
   *
10256
   *   C[float] Kc term
10257
   *   L[int]   LPQ length
10258
   */
10259
  inline void gcode_M301() {
10260
 
10261
    // multi-extruder PID patch: M301 updates or prints a single extruder's PID values
10262
    // default behaviour (omitting E parameter) is to update for extruder 0 only
10263
    const uint8_t e = parser.byteval('E'); // extruder being updated
10264
 
10265
    if (e < HOTENDS) { // catch bad input value
10266
      if (parser.seen('P')) PID_PARAM(Kp, e) = parser.value_float();
10267
      if (parser.seen('I')) PID_PARAM(Ki, e) = scalePID_i(parser.value_float());
10268
      if (parser.seen('D')) PID_PARAM(Kd, e) = scalePID_d(parser.value_float());
10269
      #if ENABLED(PID_EXTRUSION_SCALING)
10270
        if (parser.seen('C')) PID_PARAM(Kc, e) = parser.value_float();
10271
        if (parser.seen('L')) thermalManager.lpq_len = parser.value_float();
10272
        NOMORE(thermalManager.lpq_len, LPQ_MAX_LEN);
10273
        NOLESS(thermalManager.lpq_len, 0);
10274
      #endif
10275
 
10276
      thermalManager.update_pid();
10277
      SERIAL_ECHO_START();
10278
      #if ENABLED(PID_PARAMS_PER_HOTEND)
10279
        SERIAL_ECHOPAIR(" e:", e); // specify extruder in serial output
10280
      #endif // PID_PARAMS_PER_HOTEND
10281
      SERIAL_ECHOPAIR(" p:", PID_PARAM(Kp, e));
10282
      SERIAL_ECHOPAIR(" i:", unscalePID_i(PID_PARAM(Ki, e)));
10283
      SERIAL_ECHOPAIR(" d:", unscalePID_d(PID_PARAM(Kd, e)));
10284
      #if ENABLED(PID_EXTRUSION_SCALING)
10285
        //Kc does not have scaling applied above, or in resetting defaults
10286
        SERIAL_ECHOPAIR(" c:", PID_PARAM(Kc, e));
10287
      #endif
10288
      SERIAL_EOL();
10289
    }
10290
    else {
10291
      SERIAL_ERROR_START();
10292
      SERIAL_ERRORLNPGM(MSG_INVALID_EXTRUDER);
10293
    }
10294
  }
10295
 
10296
#endif // PIDTEMP
10297
 
10298
#if ENABLED(PIDTEMPBED)
10299
 
10300
  inline void gcode_M304() {
10301
    if (parser.seen('P')) thermalManager.bedKp = parser.value_float();
10302
    if (parser.seen('I')) thermalManager.bedKi = scalePID_i(parser.value_float());
10303
    if (parser.seen('D')) thermalManager.bedKd = scalePID_d(parser.value_float());
10304
 
10305
    SERIAL_ECHO_START();
10306
    SERIAL_ECHOPAIR(" p:", thermalManager.bedKp);
10307
    SERIAL_ECHOPAIR(" i:", unscalePID_i(thermalManager.bedKi));
10308
    SERIAL_ECHOLNPAIR(" d:", unscalePID_d(thermalManager.bedKd));
10309
  }
10310
 
10311
#endif // PIDTEMPBED
10312
 
10313
#if defined(CHDK) || HAS_PHOTOGRAPH
10314
 
10315
  /**
10316
   * M240: Trigger a camera by emulating a Canon RC-1
10317
   *       See http://www.doc-diy.net/photo/rc-1_hacked/
10318
   */
10319
  inline void gcode_M240() {
10320
    #ifdef CHDK
10321
 
10322
      OUT_WRITE(CHDK, HIGH);
10323
      chdkHigh = millis();
10324
      chdkActive = true;
10325
 
10326
    #elif HAS_PHOTOGRAPH
10327
 
10328
      const uint8_t NUM_PULSES = 16;
10329
      const float PULSE_LENGTH = 0.01524;
10330
      for (int i = 0; i < NUM_PULSES; i++) {
10331
        WRITE(PHOTOGRAPH_PIN, HIGH);
10332
        _delay_ms(PULSE_LENGTH);
10333
        WRITE(PHOTOGRAPH_PIN, LOW);
10334
        _delay_ms(PULSE_LENGTH);
10335
      }
10336
      delay(7.33);
10337
      for (int i = 0; i < NUM_PULSES; i++) {
10338
        WRITE(PHOTOGRAPH_PIN, HIGH);
10339
        _delay_ms(PULSE_LENGTH);
10340
        WRITE(PHOTOGRAPH_PIN, LOW);
10341
        _delay_ms(PULSE_LENGTH);
10342
      }
10343
 
10344
    #endif // !CHDK && HAS_PHOTOGRAPH
10345
  }
10346
 
10347
#endif // CHDK || PHOTOGRAPH_PIN
10348
 
10349
#if HAS_LCD_CONTRAST
10350
 
10351
  /**
10352
   * M250: Read and optionally set the LCD contrast
10353
   */
10354
  inline void gcode_M250() {
10355
    if (parser.seen('C')) set_lcd_contrast(parser.value_int());
10356
    SERIAL_PROTOCOLPGM("lcd contrast value: ");
10357
    SERIAL_PROTOCOL(lcd_contrast);
10358
    SERIAL_EOL();
10359
  }
10360
 
10361
#endif // HAS_LCD_CONTRAST
10362
 
10363
#if ENABLED(PREVENT_COLD_EXTRUSION)
10364
 
10365
  /**
10366
   * M302: Allow cold extrudes, or set the minimum extrude temperature
10367
   *
10368
   *       S<temperature> sets the minimum extrude temperature
10369
   *       P<bool> enables (1) or disables (0) cold extrusion
10370
   *
10371
   *  Examples:
10372
   *
10373
   *       M302         ; report current cold extrusion state
10374
   *       M302 P0      ; enable cold extrusion checking
10375
   *       M302 P1      ; disables cold extrusion checking
10376
   *       M302 S0      ; always allow extrusion (disables checking)
10377
   *       M302 S170    ; only allow extrusion above 170
10378
   *       M302 S170 P1 ; set min extrude temp to 170 but leave disabled
10379
   */
10380
  inline void gcode_M302() {
10381
    const bool seen_S = parser.seen('S');
10382
    if (seen_S) {
10383
      thermalManager.extrude_min_temp = parser.value_celsius();
10384
      thermalManager.allow_cold_extrude = (thermalManager.extrude_min_temp == 0);
10385
    }
10386
 
10387
    if (parser.seen('P'))
10388
      thermalManager.allow_cold_extrude = (thermalManager.extrude_min_temp == 0) || parser.value_bool();
10389
    else if (!seen_S) {
10390
      // Report current state
10391
      SERIAL_ECHO_START();
10392
      SERIAL_ECHOPAIR("Cold extrudes are ", (thermalManager.allow_cold_extrude ? "en" : "dis"));
10393
      SERIAL_ECHOPAIR("abled (min temp ", thermalManager.extrude_min_temp);
10394
      SERIAL_ECHOLNPGM("C)");
10395
    }
10396
  }
10397
 
10398
#endif // PREVENT_COLD_EXTRUSION
10399
 
10400
/**
10401
 * M303: PID relay autotune
10402
 *
10403
 *       S<temperature> sets the target temperature. (default 150C / 70C)
10404
 *       E<extruder> (-1 for the bed) (default 0)
10405
 *       C<cycles>
10406
 *       U<bool> with a non-zero value will apply the result to current settings
10407
 */
10408
inline void gcode_M303() {
10409
  #if HAS_PID_HEATING
10410
    const int e = parser.intval('E'), c = parser.intval('C', 5);
10411
    const bool u = parser.boolval('U');
10412
 
10413
    int16_t temp = parser.celsiusval('S', e < 0 ? 70 : 150);
10414
 
10415
    if (WITHIN(e, 0, HOTENDS - 1))
10416
      target_extruder = e;
10417
 
10418
    #if DISABLED(BUSY_WHILE_HEATING)
10419
      KEEPALIVE_STATE(NOT_BUSY);
10420
    #endif
10421
 
10422
    thermalManager.pid_autotune(temp, e, c, u);
10423
 
10424
    #if DISABLED(BUSY_WHILE_HEATING)
10425
      KEEPALIVE_STATE(IN_HANDLER);
10426
    #endif
10427
  #else
10428
    SERIAL_ERROR_START();
10429
    SERIAL_ERRORLNPGM(MSG_ERR_M303_DISABLED);
10430
  #endif
10431
}
10432
 
10433
#if ENABLED(MORGAN_SCARA)
10434
 
10435
  bool SCARA_move_to_cal(const uint8_t delta_a, const uint8_t delta_b) {
10436
    if (IsRunning()) {
10437
      forward_kinematics_SCARA(delta_a, delta_b);
10438
      destination[X_AXIS] = cartes[X_AXIS];
10439
      destination[Y_AXIS] = cartes[Y_AXIS];
10440
      destination[Z_AXIS] = current_position[Z_AXIS];
10441
      prepare_move_to_destination();
10442
      return true;
10443
    }
10444
    return false;
10445
  }
10446
 
10447
  /**
10448
   * M360: SCARA calibration: Move to cal-position ThetaA (0 deg calibration)
10449
   */
10450
  inline bool gcode_M360() {
10451
    SERIAL_ECHOLNPGM(" Cal: Theta 0");
10452
    return SCARA_move_to_cal(0, 120);
10453
  }
10454
 
10455
  /**
10456
   * M361: SCARA calibration: Move to cal-position ThetaB (90 deg calibration - steps per degree)
10457
   */
10458
  inline bool gcode_M361() {
10459
    SERIAL_ECHOLNPGM(" Cal: Theta 90");
10460
    return SCARA_move_to_cal(90, 130);
10461
  }
10462
 
10463
  /**
10464
   * M362: SCARA calibration: Move to cal-position PsiA (0 deg calibration)
10465
   */
10466
  inline bool gcode_M362() {
10467
    SERIAL_ECHOLNPGM(" Cal: Psi 0");
10468
    return SCARA_move_to_cal(60, 180);
10469
  }
10470
 
10471
  /**
10472
   * M363: SCARA calibration: Move to cal-position PsiB (90 deg calibration - steps per degree)
10473
   */
10474
  inline bool gcode_M363() {
10475
    SERIAL_ECHOLNPGM(" Cal: Psi 90");
10476
    return SCARA_move_to_cal(50, 90);
10477
  }
10478
 
10479
  /**
10480
   * M364: SCARA calibration: Move to cal-position PsiC (90 deg to Theta calibration position)
10481
   */
10482
  inline bool gcode_M364() {
10483
    SERIAL_ECHOLNPGM(" Cal: Theta-Psi 90");
10484
    return SCARA_move_to_cal(45, 135);
10485
  }
10486
 
10487
#endif // SCARA
10488
 
10489
#if ENABLED(EXT_SOLENOID)
10490
 
10491
  void enable_solenoid(const uint8_t num) {
10492
    switch (num) {
10493
      case 0:
10494
        OUT_WRITE(SOL0_PIN, HIGH);
10495
        break;
10496
        #if HAS_SOLENOID_1 && EXTRUDERS > 1
10497
          case 1:
10498
            OUT_WRITE(SOL1_PIN, HIGH);
10499
            break;
10500
        #endif
10501
        #if HAS_SOLENOID_2 && EXTRUDERS > 2
10502
          case 2:
10503
            OUT_WRITE(SOL2_PIN, HIGH);
10504
            break;
10505
        #endif
10506
        #if HAS_SOLENOID_3 && EXTRUDERS > 3
10507
          case 3:
10508
            OUT_WRITE(SOL3_PIN, HIGH);
10509
            break;
10510
        #endif
10511
        #if HAS_SOLENOID_4 && EXTRUDERS > 4
10512
          case 4:
10513
            OUT_WRITE(SOL4_PIN, HIGH);
10514
            break;
10515
        #endif
10516
      default:
10517
        SERIAL_ECHO_START();
10518
        SERIAL_ECHOLNPGM(MSG_INVALID_SOLENOID);
10519
        break;
10520
    }
10521
  }
10522
 
10523
  void enable_solenoid_on_active_extruder() { enable_solenoid(active_extruder); }
10524
 
10525
  void disable_all_solenoids() {
10526
    OUT_WRITE(SOL0_PIN, LOW);
10527
    #if HAS_SOLENOID_1 && EXTRUDERS > 1
10528
      OUT_WRITE(SOL1_PIN, LOW);
10529
    #endif
10530
    #if HAS_SOLENOID_2 && EXTRUDERS > 2
10531
      OUT_WRITE(SOL2_PIN, LOW);
10532
    #endif
10533
    #if HAS_SOLENOID_3 && EXTRUDERS > 3
10534
      OUT_WRITE(SOL3_PIN, LOW);
10535
    #endif
10536
    #if HAS_SOLENOID_4 && EXTRUDERS > 4
10537
      OUT_WRITE(SOL4_PIN, LOW);
10538
    #endif
10539
  }
10540
 
10541
  /**
10542
   * M380: Enable solenoid on the active extruder
10543
   */
10544
  inline void gcode_M380() { enable_solenoid_on_active_extruder(); }
10545
 
10546
  /**
10547
   * M381: Disable all solenoids
10548
   */
10549
  inline void gcode_M381() { disable_all_solenoids(); }
10550
 
10551
#endif // EXT_SOLENOID
10552
 
10553
/**
10554
 * M400: Finish all moves
10555
 */
10556
inline void gcode_M400() { planner.synchronize(); }
10557
 
10558
#if HAS_BED_PROBE
10559
 
10560
  /**
10561
   * M401: Deploy and activate the Z probe
10562
   */
10563
  inline void gcode_M401() {
10564
    DEPLOY_PROBE();
10565
    report_current_position();
10566
  }
10567
 
10568
  /**
10569
   * M402: Deactivate and stow the Z probe
10570
   */
10571
  inline void gcode_M402() {
10572
    STOW_PROBE();
10573
    #ifdef Z_AFTER_PROBING
10574
      move_z_after_probing();
10575
    #endif
10576
    report_current_position();
10577
  }
10578
 
10579
#endif // HAS_BED_PROBE
10580
 
10581
#if ENABLED(FILAMENT_WIDTH_SENSOR)
10582
 
10583
  /**
10584
   * M404: Display or set (in current units) the nominal filament width (3mm, 1.75mm ) W<3.0>
10585
   */
10586
  inline void gcode_M404() {
10587
    if (parser.seen('W')) {
10588
      filament_width_nominal = parser.value_linear_units();
10589
      planner.volumetric_area_nominal = CIRCLE_AREA(filament_width_nominal * 0.5);
10590
    }
10591
    else {
10592
      SERIAL_PROTOCOLPGM("Filament dia (nominal mm):");
10593
      SERIAL_PROTOCOLLN(filament_width_nominal);
10594
    }
10595
  }
10596
 
10597
  /**
10598
   * M405: Turn on filament sensor for control
10599
   */
10600
  inline void gcode_M405() {
10601
    // This is technically a linear measurement, but since it's quantized to centimeters and is a different
10602
    // unit than everything else, it uses parser.value_byte() instead of parser.value_linear_units().
10603
    if (parser.seen('D')) {
10604
      meas_delay_cm = parser.value_byte();
10605
      NOMORE(meas_delay_cm, MAX_MEASUREMENT_DELAY);
10606
    }
10607
 
10608
    if (filwidth_delay_index[1] == -1) { // Initialize the ring buffer if not done since startup
10609
      const int8_t temp_ratio = thermalManager.widthFil_to_size_ratio();
10610
 
10611
      for (uint8_t i = 0; i < COUNT(measurement_delay); ++i)
10612
        measurement_delay[i] = temp_ratio;
10613
 
10614
      filwidth_delay_index[0] = filwidth_delay_index[1] = 0;
10615
    }
10616
 
10617
    filament_sensor = true;
10618
  }
10619
 
10620
  /**
10621
   * M406: Turn off filament sensor for control
10622
   */
10623
  inline void gcode_M406() {
10624
    filament_sensor = false;
10625
    planner.calculate_volumetric_multipliers();   // Restore correct 'volumetric_multiplier' value
10626
  }
10627
 
10628
  /**
10629
   * M407: Get measured filament diameter on serial output
10630
   */
10631
  inline void gcode_M407() {
10632
    SERIAL_PROTOCOLPGM("Filament dia (measured mm):");
10633
    SERIAL_PROTOCOLLN(filament_width_meas);
10634
  }
10635
 
10636
#endif // FILAMENT_WIDTH_SENSOR
10637
 
10638
void quickstop_stepper() {
10639
  planner.quick_stop();
10640
  planner.synchronize();
10641
  set_current_from_steppers_for_axis(ALL_AXES);
10642
  SYNC_PLAN_POSITION_KINEMATIC();
10643
}
10644
 
10645
#if HAS_LEVELING
10646
 
10647
  //#define M420_C_USE_MEAN
10648
 
10649
  /**
10650
   * M420: Enable/Disable Bed Leveling and/or set the Z fade height.
10651
   *
10652
   *   S[bool]   Turns leveling on or off
10653
   *   Z[height] Sets the Z fade height (0 or none to disable)
10654
   *   V[bool]   Verbose - Print the leveling grid
10655
   *
10656
   * With AUTO_BED_LEVELING_UBL only:
10657
   *
10658
   *   L[index]  Load UBL mesh from index (0 is default)
10659
   *   T[map]    0:Human-readable 1:CSV 2:"LCD" 4:Compact
10660
   *
10661
   * With mesh-based leveling only:
10662
   *
10663
   *   C         Center mesh on the mean of the lowest and highest
10664
   */
10665
  inline void gcode_M420() {
10666
    const bool seen_S = parser.seen('S');
10667
    bool to_enable = seen_S ? parser.value_bool() : planner.leveling_active;
10668
 
10669
    // If disabling leveling do it right away
10670
    // (Don't disable for just M420 or M420 V)
10671
    if (seen_S && !to_enable) set_bed_leveling_enabled(false);
10672
 
10673
    const float oldpos[] = { current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS] };
10674
 
10675
    #if ENABLED(AUTO_BED_LEVELING_UBL)
10676
 
10677
      // L to load a mesh from the EEPROM
10678
      if (parser.seen('L')) {
10679
 
10680
        set_bed_leveling_enabled(false);
10681
 
10682
        #if ENABLED(EEPROM_SETTINGS)
10683
          const int8_t storage_slot = parser.has_value() ? parser.value_int() : ubl.storage_slot;
10684
          const int16_t a = settings.calc_num_meshes();
10685
 
10686
          if (!a) {
10687
            SERIAL_PROTOCOLLNPGM("?EEPROM storage not available.");
10688
            return;
10689
          }
10690
 
10691
          if (!WITHIN(storage_slot, 0, a - 1)) {
10692
            SERIAL_PROTOCOLLNPGM("?Invalid storage slot.");
10693
            SERIAL_PROTOCOLLNPAIR("?Use 0 to ", a - 1);
10694
            return;
10695
          }
10696
 
10697
          settings.load_mesh(storage_slot);
10698
          ubl.storage_slot = storage_slot;
10699
 
10700
        #else
10701
 
10702
          SERIAL_PROTOCOLLNPGM("?EEPROM storage not available.");
10703
          return;
10704
 
10705
        #endif
10706
      }
10707
 
10708
      // L or V display the map info
10709
      if (parser.seen('L') || parser.seen('V')) {
10710
        ubl.display_map(parser.byteval('T'));
10711
        SERIAL_ECHOPGM("Mesh is ");
10712
        if (!ubl.mesh_is_valid()) SERIAL_ECHOPGM("in");
10713
        SERIAL_ECHOLNPAIR("valid\nStorage slot: ", ubl.storage_slot);
10714
      }
10715
 
10716
    #endif // AUTO_BED_LEVELING_UBL
10717
 
10718
    #if HAS_MESH
10719
 
10720
      #if ENABLED(MESH_BED_LEVELING)
10721
        #define Z_VALUES(X,Y) mbl.z_values[X][Y]
10722
      #else
10723
        #define Z_VALUES(X,Y) z_values[X][Y]
10724
      #endif
10725
 
10726
      // Subtract the given value or the mean from all mesh values
10727
      if (leveling_is_valid() && parser.seen('C')) {
10728
        const float cval = parser.value_float();
10729
        #if ENABLED(AUTO_BED_LEVELING_UBL)
10730
 
10731
          set_bed_leveling_enabled(false);
10732
          ubl.adjust_mesh_to_mean(true, cval);
10733
 
10734
        #else
10735
 
10736
          #if ENABLED(M420_C_USE_MEAN)
10737
 
10738
            // Get the sum and average of all mesh values
10739
            float mesh_sum = 0;
10740
            for (uint8_t x = GRID_MAX_POINTS_X; x--;)
10741
              for (uint8_t y = GRID_MAX_POINTS_Y; y--;)
10742
                mesh_sum += Z_VALUES(x, y);
10743
            const float zmean = mesh_sum / float(GRID_MAX_POINTS);
10744
 
10745
          #else
10746
 
10747
            // Find the low and high mesh values
10748
            float lo_val = 100, hi_val = -100;
10749
            for (uint8_t x = GRID_MAX_POINTS_X; x--;)
10750
              for (uint8_t y = GRID_MAX_POINTS_Y; y--;) {
10751
                const float z = Z_VALUES(x, y);
10752
                NOMORE(lo_val, z);
10753
                NOLESS(hi_val, z);
10754
              }
10755
            // Take the mean of the lowest and highest
10756
            const float zmean = (lo_val + hi_val) / 2.0 + cval;
10757
 
10758
          #endif
10759
 
10760
          // If not very close to 0, adjust the mesh
10761
          if (!NEAR_ZERO(zmean)) {
10762
            set_bed_leveling_enabled(false);
10763
            // Subtract the mean from all values
10764
            for (uint8_t x = GRID_MAX_POINTS_X; x--;)
10765
              for (uint8_t y = GRID_MAX_POINTS_Y; y--;)
10766
                Z_VALUES(x, y) -= zmean;
10767
            #if ENABLED(ABL_BILINEAR_SUBDIVISION)
10768
              bed_level_virt_interpolate();
10769
            #endif
10770
          }
10771
 
10772
        #endif
10773
      }
10774
 
10775
    #endif // HAS_MESH
10776
 
10777
    // V to print the matrix or mesh
10778
    if (parser.seen('V')) {
10779
      #if ABL_PLANAR
10780
        planner.bed_level_matrix.debug(PSTR("Bed Level Correction Matrix:"));
10781
      #else
10782
        if (leveling_is_valid()) {
10783
          #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
10784
            print_bilinear_leveling_grid();
10785
            #if ENABLED(ABL_BILINEAR_SUBDIVISION)
10786
              print_bilinear_leveling_grid_virt();
10787
            #endif
10788
          #elif ENABLED(MESH_BED_LEVELING)
10789
            SERIAL_ECHOLNPGM("Mesh Bed Level data:");
10790
            mbl.report_mesh();
10791
          #endif
10792
        }
10793
      #endif
10794
    }
10795
 
10796
    #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
10797
      if (parser.seen('Z')) set_z_fade_height(parser.value_linear_units(), false);
10798
    #endif
10799
 
10800
    // Enable leveling if specified, or if previously active
10801
    set_bed_leveling_enabled(to_enable);
10802
 
10803
    // Error if leveling failed to enable or reenable
10804
    if (to_enable && !planner.leveling_active) {
10805
      SERIAL_ERROR_START();
10806
      SERIAL_ERRORLNPGM(MSG_ERR_M420_FAILED);
10807
    }
10808
 
10809
    SERIAL_ECHO_START();
10810
    SERIAL_ECHOLNPAIR("Bed Leveling ", planner.leveling_active ? MSG_ON : MSG_OFF);
10811
 
10812
    #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
10813
      SERIAL_ECHO_START();
10814
      SERIAL_ECHOPGM("Fade Height ");
10815
      if (planner.z_fade_height > 0.0)
10816
        SERIAL_ECHOLN(planner.z_fade_height);
10817
      else
10818
        SERIAL_ECHOLNPGM(MSG_OFF);
10819
    #endif
10820
 
10821
    // Report change in position
10822
    if (memcmp(oldpos, current_position, sizeof(oldpos)))
10823
      report_current_position();
10824
  }
10825
 
10826
#endif // HAS_LEVELING
10827
 
10828
#if ENABLED(MESH_BED_LEVELING)
10829
 
10830
  /**
10831
   * M421: Set a single Mesh Bed Leveling Z coordinate
10832
   *
10833
   * Usage:
10834
   *   M421 X<linear> Y<linear> Z<linear>
10835
   *   M421 X<linear> Y<linear> Q<offset>
10836
   *   M421 I<xindex> J<yindex> Z<linear>
10837
   *   M421 I<xindex> J<yindex> Q<offset>
10838
   */
10839
  inline void gcode_M421() {
10840
    const bool hasX = parser.seen('X'), hasI = parser.seen('I');
10841
    const int8_t ix = hasI ? parser.value_int() : hasX ? mbl.probe_index_x(parser.value_linear_units()) : -1;
10842
    const bool hasY = parser.seen('Y'), hasJ = parser.seen('J');
10843
    const int8_t iy = hasJ ? parser.value_int() : hasY ? mbl.probe_index_y(parser.value_linear_units()) : -1;
10844
    const bool hasZ = parser.seen('Z'), hasQ = !hasZ && parser.seen('Q');
10845
 
10846
    if (int(hasI && hasJ) + int(hasX && hasY) != 1 || !(hasZ || hasQ)) {
10847
      SERIAL_ERROR_START();
10848
      SERIAL_ERRORLNPGM(MSG_ERR_M421_PARAMETERS);
10849
    }
10850
    else if (ix < 0 || iy < 0) {
10851
      SERIAL_ERROR_START();
10852
      SERIAL_ERRORLNPGM(MSG_ERR_MESH_XY);
10853
    }
10854
    else
10855
      mbl.set_z(ix, iy, parser.value_linear_units() + (hasQ ? mbl.z_values[ix][iy] : 0));
10856
  }
10857
 
10858
#elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
10859
 
10860
  /**
10861
   * M421: Set a single Mesh Bed Leveling Z coordinate
10862
   *
10863
   * Usage:
10864
   *   M421 I<xindex> J<yindex> Z<linear>
10865
   *   M421 I<xindex> J<yindex> Q<offset>
10866
   */
10867
  inline void gcode_M421() {
10868
    int8_t ix = parser.intval('I', -1), iy = parser.intval('J', -1);
10869
    const bool hasI = ix >= 0,
10870
               hasJ = iy >= 0,
10871
               hasZ = parser.seen('Z'),
10872
               hasQ = !hasZ && parser.seen('Q');
10873
 
10874
    if (!hasI || !hasJ || !(hasZ || hasQ)) {
10875
      SERIAL_ERROR_START();
10876
      SERIAL_ERRORLNPGM(MSG_ERR_M421_PARAMETERS);
10877
    }
10878
    else if (!WITHIN(ix, 0, GRID_MAX_POINTS_X - 1) || !WITHIN(iy, 0, GRID_MAX_POINTS_Y - 1)) {
10879
      SERIAL_ERROR_START();
10880
      SERIAL_ERRORLNPGM(MSG_ERR_MESH_XY);
10881
    }
10882
    else {
10883
      z_values[ix][iy] = parser.value_linear_units() + (hasQ ? z_values[ix][iy] : 0);
10884
      #if ENABLED(ABL_BILINEAR_SUBDIVISION)
10885
        bed_level_virt_interpolate();
10886
      #endif
10887
    }
10888
  }
10889
 
10890
#elif ENABLED(AUTO_BED_LEVELING_UBL)
10891
 
10892
  /**
10893
   * M421: Set a single Mesh Bed Leveling Z coordinate
10894
   *
10895
   * Usage:
10896
   *   M421 I<xindex> J<yindex> Z<linear>
10897
   *   M421 I<xindex> J<yindex> Q<offset>
10898
   *   M421 I<xindex> J<yindex> N
10899
   *   M421 C Z<linear>
10900
   *   M421 C Q<offset>
10901
   */
10902
  inline void gcode_M421() {
10903
    int8_t ix = parser.intval('I', -1), iy = parser.intval('J', -1);
10904
    const bool hasI = ix >= 0,
10905
               hasJ = iy >= 0,
10906
               hasC = parser.seen('C'),
10907
               hasN = parser.seen('N'),
10908
               hasZ = parser.seen('Z'),
10909
               hasQ = !hasZ && parser.seen('Q');
10910
 
10911
    if (hasC) {
10912
      const mesh_index_pair location = ubl.find_closest_mesh_point_of_type(REAL, current_position[X_AXIS], current_position[Y_AXIS], USE_NOZZLE_AS_REFERENCE, NULL);
10913
      ix = location.x_index;
10914
      iy = location.y_index;
10915
    }
10916
 
10917
    if (int(hasC) + int(hasI && hasJ) != 1 || !(hasZ || hasQ || hasN)) {
10918
      SERIAL_ERROR_START();
10919
      SERIAL_ERRORLNPGM(MSG_ERR_M421_PARAMETERS);
10920
    }
10921
    else if (!WITHIN(ix, 0, GRID_MAX_POINTS_X - 1) || !WITHIN(iy, 0, GRID_MAX_POINTS_Y - 1)) {
10922
      SERIAL_ERROR_START();
10923
      SERIAL_ERRORLNPGM(MSG_ERR_MESH_XY);
10924
    }
10925
    else
10926
      ubl.z_values[ix][iy] = hasN ? NAN : parser.value_linear_units() + (hasQ ? ubl.z_values[ix][iy] : 0);
10927
  }
10928
 
10929
#endif // AUTO_BED_LEVELING_UBL
10930
 
10931
#if HAS_M206_COMMAND
10932
 
10933
  /**
10934
   * M428: Set home_offset based on the distance between the
10935
   *       current_position and the nearest "reference point."
10936
   *       If an axis is past center its endstop position
10937
   *       is the reference-point. Otherwise it uses 0. This allows
10938
   *       the Z offset to be set near the bed when using a max endstop.
10939
   *
10940
   *       M428 can't be used more than 2cm away from 0 or an endstop.
10941
   *
10942
   *       Use M206 to set these values directly.
10943
   */
10944
  inline void gcode_M428() {
10945
    if (axis_unhomed_error()) return;
10946
 
10947
    float diff[XYZ];
10948
    LOOP_XYZ(i) {
10949
      diff[i] = base_home_pos((AxisEnum)i) - current_position[i];
10950
      if (!WITHIN(diff[i], -20, 20) && home_dir((AxisEnum)i) > 0)
10951
        diff[i] = -current_position[i];
10952
      if (!WITHIN(diff[i], -20, 20)) {
10953
        SERIAL_ERROR_START();
10954
        SERIAL_ERRORLNPGM(MSG_ERR_M428_TOO_FAR);
10955
        LCD_ALERTMESSAGEPGM("Err: Too far!");
10956
        BUZZ(200, 40);
10957
        return;
10958
      }
10959
    }
10960
 
10961
    LOOP_XYZ(i) set_home_offset((AxisEnum)i, diff[i]);
10962
    report_current_position();
10963
    LCD_MESSAGEPGM(MSG_HOME_OFFSETS_APPLIED);
10964
    BUZZ(100, 659);
10965
    BUZZ(100, 698);
10966
  }
10967
 
10968
#endif // HAS_M206_COMMAND
10969
 
10970
/**
10971
 * M500: Store settings in EEPROM
10972
 */
10973
inline void gcode_M500() {
10974
  (void)settings.save();
10975
}
10976
 
10977
/**
10978
 * M501: Read settings from EEPROM
10979
 */
10980
inline void gcode_M501() {
10981
  (void)settings.load();
10982
}
10983
 
10984
/**
10985
 * M502: Revert to default settings
10986
 */
10987
inline void gcode_M502() {
10988
  (void)settings.reset();
10989
}
10990
 
10991
#if DISABLED(DISABLE_M503)
10992
  /**
10993
   * M503: print settings currently in memory
10994
   */
10995
  inline void gcode_M503() {
10996
    (void)settings.report(parser.seen('S') && !parser.value_bool());
10997
  }
10998
#endif
10999
 
11000
#if ENABLED(EEPROM_SETTINGS)
11001
  /**
11002
   * M504: Validate EEPROM Contents
11003
   */
11004
  inline void gcode_M504() {
11005
    if (settings.validate()) {
11006
      SERIAL_ECHO_START();
11007
      SERIAL_ECHOLNPGM("EEPROM OK");
11008
    }
11009
  }
11010
#endif
11011
 
11012
#if ENABLED(SDSUPPORT)
11013
 
11014
  /**
11015
   * M524: Abort the current SD print job (started with M24)
11016
   */
11017
  inline void gcode_M524() {
11018
    if (IS_SD_PRINTING()) card.abort_sd_printing = true;
11019
  }
11020
 
11021
#endif // SDSUPPORT
11022
 
11023
#if ENABLED(ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED)
11024
 
11025
  /**
11026
   * M540: Set whether SD card print should abort on endstop hit (M540 S<0|1>)
11027
   */
11028
  inline void gcode_M540() {
11029
    if (parser.seen('S')) planner.abort_on_endstop_hit = parser.value_bool();
11030
  }
11031
 
11032
#endif // ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED
11033
 
11034
#if HAS_BED_PROBE
11035
 
11036
  inline void gcode_M851() {
11037
    if (parser.seenval('Z')) {
11038
      const float value = parser.value_linear_units();
11039
      if (WITHIN(value, Z_PROBE_OFFSET_RANGE_MIN, Z_PROBE_OFFSET_RANGE_MAX))
11040
        zprobe_zoffset = value;
11041
      else {
11042
        SERIAL_ERROR_START();
11043
        SERIAL_ERRORLNPGM("?Z out of range (" STRINGIFY(Z_PROBE_OFFSET_RANGE_MIN) " to " STRINGIFY(Z_PROBE_OFFSET_RANGE_MAX) ")");
11044
      }
11045
      return;
11046
    }
11047
    SERIAL_ECHO_START();
11048
    SERIAL_ECHOPGM(MSG_PROBE_Z_OFFSET);
11049
    SERIAL_ECHOLNPAIR(": ", zprobe_zoffset);
11050
  }
11051
 
11052
#endif // HAS_BED_PROBE
11053
 
11054
#if ENABLED(SKEW_CORRECTION_GCODE)
11055
 
11056
  /**
11057
   * M852: Get or set the machine skew factors. Reports current values with no arguments.
11058
   *
11059
   *  S[xy_factor] - Alias for 'I'
11060
   *  I[xy_factor] - New XY skew factor
11061
   *  J[xz_factor] - New XZ skew factor
11062
   *  K[yz_factor] - New YZ skew factor
11063
   */
11064
  inline void gcode_M852() {
11065
    uint8_t ijk = 0, badval = 0, setval = 0;
11066
 
11067
    if (parser.seen('I') || parser.seen('S')) {
11068
      ++ijk;
11069
      const float value = parser.value_linear_units();
11070
      if (WITHIN(value, SKEW_FACTOR_MIN, SKEW_FACTOR_MAX)) {
11071
        if (planner.xy_skew_factor != value) {
11072
          planner.xy_skew_factor = value;
11073
          ++setval;
11074
        }
11075
      }
11076
      else
11077
        ++badval;
11078
    }
11079
 
11080
    #if ENABLED(SKEW_CORRECTION_FOR_Z)
11081
 
11082
      if (parser.seen('J')) {
11083
        ++ijk;
11084
        const float value = parser.value_linear_units();
11085
        if (WITHIN(value, SKEW_FACTOR_MIN, SKEW_FACTOR_MAX)) {
11086
          if (planner.xz_skew_factor != value) {
11087
            planner.xz_skew_factor = value;
11088
            ++setval;
11089
          }
11090
        }
11091
        else
11092
          ++badval;
11093
      }
11094
 
11095
      if (parser.seen('K')) {
11096
        ++ijk;
11097
        const float value = parser.value_linear_units();
11098
        if (WITHIN(value, SKEW_FACTOR_MIN, SKEW_FACTOR_MAX)) {
11099
          if (planner.yz_skew_factor != value) {
11100
            planner.yz_skew_factor = value;
11101
            ++setval;
11102
          }
11103
        }
11104
        else
11105
          ++badval;
11106
      }
11107
 
11108
    #endif
11109
 
11110
    if (badval)
11111
      SERIAL_ECHOLNPGM(MSG_SKEW_MIN " " STRINGIFY(SKEW_FACTOR_MIN) " " MSG_SKEW_MAX " " STRINGIFY(SKEW_FACTOR_MAX));
11112
 
11113
    // When skew is changed the current position changes
11114
    if (setval) {
11115
      set_current_from_steppers_for_axis(ALL_AXES);
11116
      SYNC_PLAN_POSITION_KINEMATIC();
11117
      report_current_position();
11118
    }
11119
 
11120
    if (!ijk) {
11121
      SERIAL_ECHO_START();
11122
      SERIAL_ECHOPGM(MSG_SKEW_FACTOR " XY: ");
11123
      SERIAL_ECHO_F(planner.xy_skew_factor, 6);
11124
      SERIAL_EOL();
11125
      #if ENABLED(SKEW_CORRECTION_FOR_Z)
11126
        SERIAL_ECHOPAIR(" XZ: ", planner.xz_skew_factor);
11127
        SERIAL_ECHOLNPAIR(" YZ: ", planner.yz_skew_factor);
11128
      #else
11129
        SERIAL_EOL();
11130
      #endif
11131
    }
11132
  }
11133
 
11134
#endif // SKEW_CORRECTION_GCODE
11135
 
11136
#if ENABLED(ADVANCED_PAUSE_FEATURE)
11137
 
11138
  /**
11139
   * M600: Pause for filament change
11140
   *
11141
   *  E[distance] - Retract the filament this far
11142
   *  Z[distance] - Move the Z axis by this distance
11143
   *  X[position] - Move to this X position, with Y
11144
   *  Y[position] - Move to this Y position, with X
11145
   *  U[distance] - Retract distance for removal (manual reload)
11146
   *  L[distance] - Extrude distance for insertion (manual reload)
11147
   *  B[count]    - Number of times to beep, -1 for indefinite (if equipped with a buzzer)
11148
   *  T[toolhead] - Select extruder for filament change
11149
   *
11150
   *  Default values are used for omitted arguments.
11151
   */
11152
  inline void gcode_M600() {
11153
    point_t park_point = NOZZLE_PARK_POINT;
11154
 
11155
    if (get_target_extruder_from_command(600)) return;
11156
 
11157
    // Show initial message
11158
    #if ENABLED(ULTIPANEL)
11159
      lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_INIT, ADVANCED_PAUSE_MODE_PAUSE_PRINT, target_extruder);
11160
    #endif
11161
 
11162
    #if ENABLED(HOME_BEFORE_FILAMENT_CHANGE)
11163
      // Don't allow filament change without homing first
11164
      if (axis_unhomed_error()) home_all_axes();
11165
    #endif
11166
 
11167
    #if EXTRUDERS > 1
11168
      // Change toolhead if specified
11169
      uint8_t active_extruder_before_filament_change = active_extruder;
11170
      if (active_extruder != target_extruder)
11171
        tool_change(target_extruder, 0, true);
11172
    #endif
11173
 
11174
    // Initial retract before move to filament change position
11175
    const float retract = -ABS(parser.seen('E') ? parser.value_axis_units(E_AXIS) : 0
11176
      #ifdef PAUSE_PARK_RETRACT_LENGTH
11177
        + (PAUSE_PARK_RETRACT_LENGTH)
11178
      #endif
11179
    );
11180
 
11181
    // Lift Z axis
11182
    if (parser.seenval('Z')) park_point.z = parser.linearval('Z');
11183
 
11184
    // Move XY axes to filament change position or given position
11185
    if (parser.seenval('X')) park_point.x = parser.linearval('X');
11186
    if (parser.seenval('Y')) park_point.y = parser.linearval('Y');
11187
 
11188
    #if HOTENDS > 1 && DISABLED(DUAL_X_CARRIAGE) && DISABLED(DELTA)
11189
      park_point.x += (active_extruder ? hotend_offset[X_AXIS][active_extruder] : 0);
11190
      park_point.y += (active_extruder ? hotend_offset[Y_AXIS][active_extruder] : 0);
11191
    #endif
11192
 
11193
    // Unload filament
11194
    const float unload_length = -ABS(parser.seen('U') ? parser.value_axis_units(E_AXIS) :
11195
                                                         filament_change_unload_length[active_extruder]);
11196
 
11197
    // Slow load filament
11198
    constexpr float slow_load_length = FILAMENT_CHANGE_SLOW_LOAD_LENGTH;
11199
 
11200
    // Fast load filament
11201
    const float fast_load_length = ABS(parser.seen('L') ? parser.value_axis_units(E_AXIS) :
11202
                                                      filament_change_load_length[active_extruder]);
11203
 
11204
    const int beep_count = parser.intval('B',
11205
      #ifdef FILAMENT_CHANGE_ALERT_BEEPS
11206
        FILAMENT_CHANGE_ALERT_BEEPS
11207
      #else
11208
        -1
11209
      #endif
11210
    );
11211
 
11212
    const bool job_running = print_job_timer.isRunning();
11213
 
11214
    if (pause_print(retract, park_point, unload_length, true)) {
11215
      wait_for_filament_reload(beep_count);
11216
      resume_print(slow_load_length, fast_load_length, ADVANCED_PAUSE_PURGE_LENGTH, beep_count);
11217
    }
11218
 
11219
    #if EXTRUDERS > 1
11220
      // Restore toolhead if it was changed
11221
      if (active_extruder_before_filament_change != active_extruder)
11222
        tool_change(active_extruder_before_filament_change, 0, true);
11223
    #endif
11224
 
11225
    // Resume the print job timer if it was running
11226
    if (job_running) print_job_timer.start();
11227
  }
11228
 
11229
  /**
11230
   * M603: Configure filament change
11231
   *
11232
   *  T[toolhead] - Select extruder to configure, active extruder if not specified
11233
   *  U[distance] - Retract distance for removal, for the specified extruder
11234
   *  L[distance] - Extrude distance for insertion, for the specified extruder
11235
   *
11236
   */
11237
  inline void gcode_M603() {
11238
 
11239
    if (get_target_extruder_from_command(603)) return;
11240
 
11241
    // Unload length
11242
    if (parser.seen('U')) {
11243
      filament_change_unload_length[target_extruder] = ABS(parser.value_axis_units(E_AXIS));
11244
      #if ENABLED(PREVENT_LENGTHY_EXTRUDE)
11245
        NOMORE(filament_change_unload_length[target_extruder], EXTRUDE_MAXLENGTH);
11246
      #endif
11247
    }
11248
 
11249
    // Load length
11250
    if (parser.seen('L')) {
11251
      filament_change_load_length[target_extruder] = ABS(parser.value_axis_units(E_AXIS));
11252
      #if ENABLED(PREVENT_LENGTHY_EXTRUDE)
11253
        NOMORE(filament_change_load_length[target_extruder], EXTRUDE_MAXLENGTH);
11254
      #endif
11255
    }
11256
  }
11257
 
11258
#endif // ADVANCED_PAUSE_FEATURE
11259
 
11260
#if ENABLED(MK2_MULTIPLEXER)
11261
 
11262
  inline void select_multiplexed_stepper(const uint8_t e) {
11263
    planner.synchronize();
11264
    disable_e_steppers();
11265
    WRITE(E_MUX0_PIN, TEST(e, 0) ? HIGH : LOW);
11266
    WRITE(E_MUX1_PIN, TEST(e, 1) ? HIGH : LOW);
11267
    WRITE(E_MUX2_PIN, TEST(e, 2) ? HIGH : LOW);
11268
    safe_delay(100);
11269
  }
11270
 
11271
#endif // MK2_MULTIPLEXER
11272
 
11273
#if ENABLED(DUAL_X_CARRIAGE)
11274
 
11275
  /**
11276
   * M605: Set dual x-carriage movement mode
11277
   *
11278
   *    M605 S0: Full control mode. The slicer has full control over x-carriage movement
11279
   *    M605 S1: Auto-park mode. The inactive head will auto park/unpark without slicer involvement
11280
   *    M605 S2 [Xnnn] [Rmmm]: Duplication mode. The second extruder will duplicate the first with nnn
11281
   *                         units x-offset and an optional differential hotend temperature of
11282
   *                         mmm degrees. E.g., with "M605 S2 X100 R2" the second extruder will duplicate
11283
   *                         the first with a spacing of 100mm in the x direction and 2 degrees hotter.
11284
   *
11285
   *    Note: the X axis should be homed after changing dual x-carriage mode.
11286
   */
11287
  inline void gcode_M605() {
11288
    planner.synchronize();
11289
    if (parser.seen('S')) dual_x_carriage_mode = (DualXMode)parser.value_byte();
11290
    switch (dual_x_carriage_mode) {
11291
      case DXC_FULL_CONTROL_MODE:
11292
      case DXC_AUTO_PARK_MODE:
11293
        break;
11294
      case DXC_DUPLICATION_MODE:
11295
        if (parser.seen('X')) duplicate_extruder_x_offset = MAX(parser.value_linear_units(), X2_MIN_POS - x_home_pos(0));
11296
        if (parser.seen('R')) duplicate_extruder_temp_offset = parser.value_celsius_diff();
11297
        SERIAL_ECHO_START();
11298
        SERIAL_ECHOPGM(MSG_HOTEND_OFFSET);
11299
        SERIAL_CHAR(' ');
11300
        SERIAL_ECHO(hotend_offset[X_AXIS][0]);
11301
        SERIAL_CHAR(',');
11302
        SERIAL_ECHO(hotend_offset[Y_AXIS][0]);
11303
        SERIAL_CHAR(' ');
11304
        SERIAL_ECHO(duplicate_extruder_x_offset);
11305
        SERIAL_CHAR(',');
11306
        SERIAL_ECHOLN(hotend_offset[Y_AXIS][1]);
11307
        break;
11308
      default:
11309
        dual_x_carriage_mode = DEFAULT_DUAL_X_CARRIAGE_MODE;
11310
        break;
11311
    }
11312
    active_extruder_parked = false;
11313
    extruder_duplication_enabled = false;
11314
    delayed_move_time = 0;
11315
  }
11316
 
11317
#elif ENABLED(DUAL_NOZZLE_DUPLICATION_MODE)
11318
 
11319
  inline void gcode_M605() {
11320
    planner.synchronize();
11321
    extruder_duplication_enabled = parser.intval('S') == int(DXC_DUPLICATION_MODE);
11322
    SERIAL_ECHO_START();
11323
    SERIAL_ECHOLNPAIR(MSG_DUPLICATION_MODE, extruder_duplication_enabled ? MSG_ON : MSG_OFF);
11324
  }
11325
 
11326
#endif // DUAL_NOZZLE_DUPLICATION_MODE
11327
 
11328
#if ENABLED(FILAMENT_LOAD_UNLOAD_GCODES)
11329
 
11330
  /**
11331
   * M701: Load filament
11332
   *
11333
   *  T<extruder> - Optional extruder number. Current extruder if omitted.
11334
   *  Z<distance> - Move the Z axis by this distance
11335
   *  L<distance> - Extrude distance for insertion (positive value) (manual reload)
11336
   *
11337
   *  Default values are used for omitted arguments.
11338
   */
11339
  inline void gcode_M701() {
11340
    point_t park_point = NOZZLE_PARK_POINT;
11341
 
11342
    #if ENABLED(NO_MOTION_BEFORE_HOMING)
11343
      // Only raise Z if the machine is homed
11344
      if (axis_unhomed_error()) park_point.z = 0;
11345
    #endif
11346
 
11347
    if (get_target_extruder_from_command(701)) return;
11348
 
11349
    // Z axis lift
11350
    if (parser.seenval('Z')) park_point.z = parser.linearval('Z');
11351
 
11352
    // Show initial "wait for load" message
11353
    #if ENABLED(ULTIPANEL)
11354
      lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_LOAD, ADVANCED_PAUSE_MODE_LOAD_FILAMENT, target_extruder);
11355
    #endif
11356
 
11357
    #if EXTRUDERS > 1
11358
      // Change toolhead if specified
11359
      uint8_t active_extruder_before_filament_change = active_extruder;
11360
      if (active_extruder != target_extruder)
11361
        tool_change(target_extruder, 0, true);
11362
    #endif
11363
 
11364
    // Lift Z axis
11365
    if (park_point.z > 0)
11366
      do_blocking_move_to_z(MIN(current_position[Z_AXIS] + park_point.z, Z_MAX_POS), NOZZLE_PARK_Z_FEEDRATE);
11367
 
11368
    constexpr float slow_load_length = FILAMENT_CHANGE_SLOW_LOAD_LENGTH;
11369
    const float fast_load_length = ABS(parser.seen('L') ? parser.value_axis_units(E_AXIS) : filament_change_load_length[active_extruder]);
11370
    load_filament(slow_load_length, fast_load_length, ADVANCED_PAUSE_PURGE_LENGTH, FILAMENT_CHANGE_ALERT_BEEPS,
11371
                  true, thermalManager.wait_for_heating(target_extruder), ADVANCED_PAUSE_MODE_LOAD_FILAMENT);
11372
 
11373
    // Restore Z axis
11374
    if (park_point.z > 0)
11375
      do_blocking_move_to_z(MAX(current_position[Z_AXIS] - park_point.z, 0), NOZZLE_PARK_Z_FEEDRATE);
11376
 
11377
    #if EXTRUDERS > 1
11378
      // Restore toolhead if it was changed
11379
      if (active_extruder_before_filament_change != active_extruder)
11380
        tool_change(active_extruder_before_filament_change, 0, true);
11381
    #endif
11382
 
11383
    // Show status screen
11384
    #if ENABLED(ULTIPANEL)
11385
      lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_STATUS);
11386
    #endif
11387
  }
11388
 
11389
  /**
11390
   * M702: Unload filament
11391
   *
11392
   *  T<extruder> - Optional extruder number. If omitted, current extruder
11393
   *                (or ALL extruders with FILAMENT_UNLOAD_ALL_EXTRUDERS).
11394
   *  Z<distance> - Move the Z axis by this distance
11395
   *  U<distance> - Retract distance for removal (manual reload)
11396
   *
11397
   *  Default values are used for omitted arguments.
11398
   */
11399
  inline void gcode_M702() {
11400
    point_t park_point = NOZZLE_PARK_POINT;
11401
 
11402
    #if ENABLED(NO_MOTION_BEFORE_HOMING)
11403
      // Only raise Z if the machine is homed
11404
      if (axis_unhomed_error()) park_point.z = 0;
11405
    #endif
11406
 
11407
    if (get_target_extruder_from_command(702)) return;
11408
 
11409
    // Z axis lift
11410
    if (parser.seenval('Z')) park_point.z = parser.linearval('Z');
11411
 
11412
    // Show initial message
11413
    #if ENABLED(ULTIPANEL)
11414
      lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_UNLOAD, ADVANCED_PAUSE_MODE_UNLOAD_FILAMENT, target_extruder);
11415
    #endif
11416
 
11417
    #if EXTRUDERS > 1
11418
      // Change toolhead if specified
11419
      uint8_t active_extruder_before_filament_change = active_extruder;
11420
      if (active_extruder != target_extruder)
11421
        tool_change(target_extruder, 0, true);
11422
    #endif
11423
 
11424
    // Lift Z axis
11425
    if (park_point.z > 0)
11426
      do_blocking_move_to_z(MIN(current_position[Z_AXIS] + park_point.z, Z_MAX_POS), NOZZLE_PARK_Z_FEEDRATE);
11427
 
11428
    // Unload filament
11429
    #if EXTRUDERS > 1 && ENABLED(FILAMENT_UNLOAD_ALL_EXTRUDERS)
11430
      if (!parser.seenval('T')) {
11431
        HOTEND_LOOP() {
11432
          if (e != active_extruder) tool_change(e, 0, true);
11433
          unload_filament(-filament_change_unload_length[e], true, ADVANCED_PAUSE_MODE_UNLOAD_FILAMENT);
11434
        }
11435
      }
11436
      else
11437
    #endif
11438
    {
11439
      // Unload length
11440
      const float unload_length = -ABS(parser.seen('U') ? parser.value_axis_units(E_AXIS) :
11441
                                                          filament_change_unload_length[target_extruder]);
11442
 
11443
      unload_filament(unload_length, true, ADVANCED_PAUSE_MODE_UNLOAD_FILAMENT);
11444
    }
11445
 
11446
    // Restore Z axis
11447
    if (park_point.z > 0)
11448
      do_blocking_move_to_z(MAX(current_position[Z_AXIS] - park_point.z, 0), NOZZLE_PARK_Z_FEEDRATE);
11449
 
11450
    #if EXTRUDERS > 1
11451
      // Restore toolhead if it was changed
11452
      if (active_extruder_before_filament_change != active_extruder)
11453
        tool_change(active_extruder_before_filament_change, 0, true);
11454
    #endif
11455
 
11456
    // Show status screen
11457
    #if ENABLED(ULTIPANEL)
11458
      lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_STATUS);
11459
    #endif
11460
  }
11461
 
11462
#endif // FILAMENT_LOAD_UNLOAD_GCODES
11463
 
11464
#if ENABLED(MAX7219_GCODE)
11465
  /**
11466
   * M7219: Control the Max7219 LED matrix
11467
   *
11468
   *  I         - Initialize (clear) the matrix
11469
   *  F         - Fill the matrix (set all bits)
11470
   *  P         - Dump the LEDs[] array values
11471
   *  C<column> - Set a column to the 8-bit value V
11472
   *  R<row>    - Set a row to the 8-bit value V
11473
   *  X<pos>    - X position of an LED to set or toggle
11474
   *  Y<pos>    - Y position of an LED to set or toggle
11475
   *  V<value>  - The potentially 32-bit value or on/off state to set
11476
   *              (for example: a chain of 4 Max7219 devices can have 32 bit
11477
   *               rows or columns depending upon rotation)
11478
   */
11479
  inline void gcode_M7219() {
11480
    if (parser.seen('I')) {
11481
      max7219.register_setup();
11482
      max7219.clear();
11483
    }
11484
 
11485
    if (parser.seen('F')) max7219.fill();
11486
 
11487
    const uint32_t v = parser.ulongval('V');
11488
 
11489
    if (parser.seenval('R')) {
11490
      const uint8_t r = parser.value_byte();
11491
      max7219.set_row(r, v);
11492
    }
11493
    else if (parser.seenval('C')) {
11494
      const uint8_t c = parser.value_byte();
11495
      max7219.set_column(c, v);
11496
    }
11497
    else if (parser.seenval('X') || parser.seenval('Y')) {
11498
      const uint8_t x = parser.byteval('X'), y = parser.byteval('Y');
11499
      if (parser.seenval('V'))
11500
        max7219.led_set(x, y, parser.boolval('V'));
11501
      else
11502
        max7219.led_toggle(x, y);
11503
    }
11504
    else if (parser.seen('D')) {
11505
      const uint8_t line = parser.byteval('D') + (parser.byteval('U') << 3);
11506
      if (line < MAX7219_LINES) {
11507
        max7219.led_line[line] = v;
11508
        return max7219.refresh_line(line);
11509
      }
11510
    }
11511
 
11512
    if (parser.seen('P')) {
11513
      for (uint8_t r = 0; r < MAX7219_LINES; r++) {
11514
        SERIAL_ECHOPGM("led_line[");
11515
        if (r < 10) SERIAL_CHAR(' ');
11516
        SERIAL_ECHO(int(r));
11517
        SERIAL_ECHOPGM("]=");
11518
        for (uint8_t b = 8; b--;) SERIAL_CHAR('0' + TEST(max7219.led_line[r], b));
11519
        SERIAL_EOL();
11520
      }
11521
    }
11522
  }
11523
#endif // MAX7219_GCODE
11524
 
11525
#if ENABLED(LIN_ADVANCE)
11526
  /**
11527
   * M900: Get or Set Linear Advance K-factor
11528
   *
11529
   *  K<factor>   Set advance K factor
11530
   */
11531
  inline void gcode_M900() {
11532
    if (parser.seenval('K')) {
11533
      const float newK = parser.floatval('K');
11534
      if (WITHIN(newK, 0, 10)) {
11535
        planner.synchronize();
11536
        planner.extruder_advance_K = newK;
11537
      }
11538
      else
11539
        SERIAL_PROTOCOLLNPGM("?K value out of range (0-10).");
11540
    }
11541
    else {
11542
      SERIAL_ECHO_START();
11543
      SERIAL_ECHOLNPAIR("Advance K=", planner.extruder_advance_K);
11544
    }
11545
  }
11546
#endif // LIN_ADVANCE
11547
 
11548
#if HAS_TRINAMIC
11549
  #if ENABLED(TMC_DEBUG)
11550
    inline void gcode_M122() {
11551
      if (parser.seen('S'))
11552
        tmc_set_report_status(parser.value_bool());
11553
      else
11554
        tmc_report_all();
11555
    }
11556
  #endif // TMC_DEBUG
11557
 
11558
  /**
11559
   * M906: Set motor current in milliamps using axis codes X, Y, Z, E
11560
   * Uses axis codes A, B, C, D, E for Hangprinter
11561
   * Report driver currents when no axis specified
11562
   */
11563
  inline void gcode_M906() {
11564
    #define TMC_SAY_CURRENT(Q) tmc_get_current(stepper##Q, TMC_##Q)
11565
    #define TMC_SET_CURRENT(Q) tmc_set_current(stepper##Q, value)
11566
 
11567
    bool report = true;
11568
    const uint8_t index = parser.byteval('I');
11569
    LOOP_NUM_AXIS(i) if (uint16_t value = parser.intval(RAW_AXIS_CODES(i))) {
11570
 
11571
      report = false;
11572
      switch (i) {
11573
        // Assumes {A_AXIS, B_AXIS, C_AXIS} == {X_AXIS, Y_AXIS, Z_AXIS}
11574
        case X_AXIS:
11575
          #if AXIS_IS_TMC(X)
11576
            if (index < 2) TMC_SET_CURRENT(X);
11577
          #endif
11578
          #if AXIS_IS_TMC(X2)
11579
            if (!(index & 1)) TMC_SET_CURRENT(X2);
11580
          #endif
11581
          break;
11582
        case Y_AXIS:
11583
          #if AXIS_IS_TMC(Y)
11584
            if (index < 2) TMC_SET_CURRENT(Y);
11585
          #endif
11586
          #if AXIS_IS_TMC(Y2)
11587
            if (!(index & 1)) TMC_SET_CURRENT(Y2);
11588
          #endif
11589
          break;
11590
        case Z_AXIS:
11591
          #if AXIS_IS_TMC(Z)
11592
            if (index < 2) TMC_SET_CURRENT(Z);
11593
          #endif
11594
          #if AXIS_IS_TMC(Z2)
11595
            if (!(index & 1)) TMC_SET_CURRENT(Z2);
11596
          #endif
11597
          break;
11598
        case E_AXIS: {
11599
          if (get_target_extruder_from_command(906)) return;
11600
          switch (target_extruder) {
11601
            #if AXIS_IS_TMC(E0)
11602
              case 0: TMC_SET_CURRENT(E0); break;
11603
            #endif
11604
            #if ENABLED(HANGPRINTER)
11605
              // Avoid setting the D-current
11606
              #if AXIS_IS_TMC(E1) && EXTRUDERS > 1
11607
                case 1: TMC_SET_CURRENT(E1); break;
11608
              #endif
11609
              #if AXIS_IS_TMC(E2) && EXTRUDERS > 2
11610
                case 2: TMC_SET_CURRENT(E2); break;
11611
              #endif
11612
              #if AXIS_IS_TMC(E3) && EXTRUDERS > 3
11613
                case 3: TMC_SET_CURRENT(E3); break;
11614
              #endif
11615
              #if AXIS_IS_TMC(E4) && EXTRUDERS > 4
11616
                case 4: TMC_SET_CURRENT(E4); break;
11617
              #endif
11618
            #else
11619
              #if AXIS_IS_TMC(E1)
11620
                case 1: TMC_SET_CURRENT(E1); break;
11621
              #endif
11622
              #if AXIS_IS_TMC(E2)
11623
                case 2: TMC_SET_CURRENT(E2); break;
11624
              #endif
11625
              #if AXIS_IS_TMC(E3)
11626
                case 3: TMC_SET_CURRENT(E3); break;
11627
              #endif
11628
              #if AXIS_IS_TMC(E4)
11629
                case 4: TMC_SET_CURRENT(E4); break;
11630
              #endif
11631
            #endif
11632
          }
11633
        } break;
11634
        #if ENABLED(HANGPRINTER)
11635
          case D_AXIS:
11636
            // D is connected on the first of E1, E2, E3, E4 output that is not an extruder
11637
            #if AXIS_IS_TMC(E1) && EXTRUDERS == 1
11638
              TMC_SET_CURRENT(E1); break;
11639
            #endif
11640
            #if AXIS_IS_TMC(E2) && EXTRUDERS == 2
11641
              TMC_SET_CURRENT(E2); break;
11642
            #endif
11643
            #if AXIS_IS_TMC(E3) && EXTRUDERS == 3
11644
              TMC_SET_CURRENT(E3); break;
11645
            #endif
11646
            #if AXIS_IS_TMC(E4) && EXTRUDERS == 4
11647
              TMC_SET_CURRENT(E4); break;
11648
            #endif
11649
        #endif
11650
      }
11651
    }
11652
 
11653
    if (report) {
11654
      #if AXIS_IS_TMC(X)
11655
        TMC_SAY_CURRENT(X);
11656
      #endif
11657
      #if AXIS_IS_TMC(X2)
11658
        TMC_SAY_CURRENT(X2);
11659
      #endif
11660
      #if AXIS_IS_TMC(Y)
11661
        TMC_SAY_CURRENT(Y);
11662
      #endif
11663
      #if AXIS_IS_TMC(Y2)
11664
        TMC_SAY_CURRENT(Y2);
11665
      #endif
11666
      #if AXIS_IS_TMC(Z)
11667
        TMC_SAY_CURRENT(Z);
11668
      #endif
11669
      #if AXIS_IS_TMC(Z2)
11670
        TMC_SAY_CURRENT(Z2);
11671
      #endif
11672
      #if AXIS_IS_TMC(E0)
11673
        TMC_SAY_CURRENT(E0);
11674
      #endif
11675
      #if ENABLED(HANGPRINTER)
11676
        // D is connected on the first of E1, E2, E3, E4 output that is not an extruder
11677
        #if AXIS_IS_TMC(E1) && EXTRUDERS == 1
11678
          TMC_SAY_CURRENT(E1);
11679
        #endif
11680
        #if AXIS_IS_TMC(E2) && EXTRUDERS == 2
11681
          TMC_SAY_CURRENT(E2);
11682
        #endif
11683
        #if AXIS_IS_TMC(E3) && EXTRUDERS == 3
11684
          TMC_SAY_CURRENT(E3);
11685
        #endif
11686
        #if AXIS_IS_TMC(E4) && EXTRUDERS == 4
11687
          TMC_SAY_CURRENT(E4);
11688
        #endif
11689
      #else
11690
        #if AXIS_IS_TMC(E1)
11691
          TMC_SAY_CURRENT(E1);
11692
        #endif
11693
        #if AXIS_IS_TMC(E2)
11694
          TMC_SAY_CURRENT(E2);
11695
        #endif
11696
        #if AXIS_IS_TMC(E3)
11697
          TMC_SAY_CURRENT(E3);
11698
        #endif
11699
        #if AXIS_IS_TMC(E4)
11700
          TMC_SAY_CURRENT(E4);
11701
        #endif
11702
      #endif
11703
    }
11704
  }
11705
 
11706
  #define M91x_USE(ST) (AXIS_DRIVER_TYPE(ST, TMC2130) || (AXIS_DRIVER_TYPE(ST, TMC2208) && PIN_EXISTS(ST##_SERIAL_RX)))
11707
  #define M91x_USE_E(N) (E_STEPPERS > N && M91x_USE(E##N))
11708
 
11709
  /**
11710
   * M911: Report TMC stepper driver overtemperature pre-warn flag
11711
   *       This flag is held by the library, persisting until cleared by M912
11712
   */
11713
  inline void gcode_M911() {
11714
    #if M91x_USE(X)
11715
      tmc_report_otpw(stepperX, TMC_X);
11716
    #endif
11717
    #if M91x_USE(X2)
11718
      tmc_report_otpw(stepperX2, TMC_X2);
11719
    #endif
11720
    #if M91x_USE(Y)
11721
      tmc_report_otpw(stepperY, TMC_Y);
11722
    #endif
11723
    #if M91x_USE(Y2)
11724
      tmc_report_otpw(stepperY2, TMC_Y2);
11725
    #endif
11726
    #if M91x_USE(Z)
11727
      tmc_report_otpw(stepperZ, TMC_Z);
11728
    #endif
11729
    #if M91x_USE(Z2)
11730
      tmc_report_otpw(stepperZ2, TMC_Z2);
11731
    #endif
11732
    #if M91x_USE_E(0)
11733
      tmc_report_otpw(stepperE0, TMC_E0);
11734
    #endif
11735
    #if M91x_USE_E(1)
11736
      tmc_report_otpw(stepperE1, TMC_E1);
11737
    #endif
11738
    #if M91x_USE_E(2)
11739
      tmc_report_otpw(stepperE2, TMC_E2);
11740
    #endif
11741
    #if M91x_USE_E(3)
11742
      tmc_report_otpw(stepperE3, TMC_E3);
11743
    #endif
11744
    #if M91x_USE_E(4)
11745
      tmc_report_otpw(stepperE4, TMC_E4);
11746
    #endif
11747
  }
11748
 
11749
  /**
11750
   * M912: Clear TMC stepper driver overtemperature pre-warn flag held by the library
11751
   *       Specify one or more axes with X, Y, Z, X1, Y1, Z1, X2, Y2, Z2, and E[index].
11752
   *       If no axes are given, clear all.
11753
   *
11754
   * Examples:
11755
   *       M912 X   ; clear X and X2
11756
   *       M912 X1  ; clear X1 only
11757
   *       M912 X2  ; clear X2 only
11758
   *       M912 X E ; clear X, X2, and all E
11759
   *       M912 E1  ; clear E1 only
11760
   */
11761
  inline void gcode_M912() {
11762
    const bool hasX = parser.seen(axis_codes[X_AXIS]),
11763
               hasY = parser.seen(axis_codes[Y_AXIS]),
11764
               hasZ = parser.seen(axis_codes[Z_AXIS]),
11765
               hasE = parser.seen(axis_codes[E_CART]),
11766
               hasNone = !hasX && !hasY && !hasZ && !hasE;
11767
 
11768
    #if M91x_USE(X) || M91x_USE(X2)
11769
      const uint8_t xval = parser.byteval(axis_codes[X_AXIS], 10);
11770
      #if M91x_USE(X)
11771
        if (hasNone || xval == 1 || (hasX && xval == 10)) tmc_clear_otpw(stepperX, TMC_X);
11772
      #endif
11773
      #if M91x_USE(X2)
11774
        if (hasNone || xval == 2 || (hasX && xval == 10)) tmc_clear_otpw(stepperX2, TMC_X2);
11775
      #endif
11776
    #endif
11777
 
11778
    #if M91x_USE(Y) || M91x_USE(Y2)
11779
      const uint8_t yval = parser.byteval(axis_codes[Y_AXIS], 10);
11780
      #if M91x_USE(Y)
11781
        if (hasNone || yval == 1 || (hasY && yval == 10)) tmc_clear_otpw(stepperY, TMC_Y);
11782
      #endif
11783
      #if M91x_USE(Y2)
11784
        if (hasNone || yval == 2 || (hasY && yval == 10)) tmc_clear_otpw(stepperY2, TMC_Y2);
11785
      #endif
11786
    #endif
11787
 
11788
    #if M91x_USE(Z) || M91x_USE(Z2)
11789
      const uint8_t zval = parser.byteval(axis_codes[Z_AXIS], 10);
11790
      #if M91x_USE(Z)
11791
        if (hasNone || zval == 1 || (hasZ && zval == 10)) tmc_clear_otpw(stepperZ, TMC_Z);
11792
      #endif
11793
      #if M91x_USE(Z2)
11794
        if (hasNone || zval == 2 || (hasZ && zval == 10)) tmc_clear_otpw(stepperZ2, TMC_Z2);
11795
      #endif
11796
    #endif
11797
 
11798
    // TODO: If this is a Hangprinter, E_AXIS will not correspond to E0, E1, etc in this way
11799
    #if M91x_USE_E(0) || M91x_USE_E(1) || M91x_USE_E(2) || M91x_USE_E(3) || M91x_USE_E(4)
11800
      const uint8_t eval = parser.byteval(axis_codes[E_AXIS], 10);
11801
      #if M91x_USE_E(0)
11802
        if (hasNone || eval == 0 || (hasE && eval == 10)) tmc_clear_otpw(stepperE0, TMC_E0);
11803
      #endif
11804
      #if M91x_USE_E(1)
11805
        if (hasNone || eval == 1 || (hasE && eval == 10)) tmc_clear_otpw(stepperE1, TMC_E1);
11806
      #endif
11807
      #if M91x_USE_E(2)
11808
        if (hasNone || eval == 2 || (hasE && eval == 10)) tmc_clear_otpw(stepperE2, TMC_E2);
11809
      #endif
11810
      #if M91x_USE_E(3)
11811
        if (hasNone || eval == 3 || (hasE && eval == 10)) tmc_clear_otpw(stepperE3, TMC_E3);
11812
      #endif
11813
      #if M91x_USE_E(4)
11814
        if (hasNone || eval == 4 || (hasE && eval == 10)) tmc_clear_otpw(stepperE4, TMC_E4);
11815
      #endif
11816
    #endif
11817
  }
11818
 
11819
  /**
11820
   * M913: Set HYBRID_THRESHOLD speed.
11821
   */
11822
  #if ENABLED(HYBRID_THRESHOLD)
11823
    inline void gcode_M913() {
11824
      #define TMC_SAY_PWMTHRS(A,Q) tmc_get_pwmthrs(stepper##Q, TMC_##Q, planner.axis_steps_per_mm[_AXIS(A)])
11825
      #define TMC_SET_PWMTHRS(A,Q) tmc_set_pwmthrs(stepper##Q, value, planner.axis_steps_per_mm[_AXIS(A)])
11826
      #define TMC_SAY_PWMTHRS_E(E) do{ const uint8_t extruder = E; tmc_get_pwmthrs(stepperE##E, TMC_E##E, planner.axis_steps_per_mm[E_AXIS_N]); }while(0)
11827
      #define TMC_SET_PWMTHRS_E(E) do{ const uint8_t extruder = E; tmc_set_pwmthrs(stepperE##E, value, planner.axis_steps_per_mm[E_AXIS_N]); }while(0)
11828
 
11829
      bool report = true;
11830
      const uint8_t index = parser.byteval('I');
11831
      LOOP_XYZE(i) if (int32_t value = parser.longval(axis_codes[i])) {
11832
        report = false;
11833
        switch (i) {
11834
          case X_AXIS:
11835
            #if AXIS_HAS_STEALTHCHOP(X)
11836
              if (index < 2) TMC_SET_PWMTHRS(X,X);
11837
            #endif
11838
            #if AXIS_HAS_STEALTHCHOP(X2)
11839
              if (!(index & 1)) TMC_SET_PWMTHRS(X,X2);
11840
            #endif
11841
            break;
11842
          case Y_AXIS:
11843
            #if AXIS_HAS_STEALTHCHOP(Y)
11844
              if (index < 2) TMC_SET_PWMTHRS(Y,Y);
11845
            #endif
11846
            #if AXIS_HAS_STEALTHCHOP(Y2)
11847
              if (!(index & 1)) TMC_SET_PWMTHRS(Y,Y2);
11848
            #endif
11849
            break;
11850
          case Z_AXIS:
11851
            #if AXIS_HAS_STEALTHCHOP(Z)
11852
              if (index < 2) TMC_SET_PWMTHRS(Z,Z);
11853
            #endif
11854
            #if AXIS_HAS_STEALTHCHOP(Z2)
11855
              if (!(index & 1)) TMC_SET_PWMTHRS(Z,Z2);
11856
            #endif
11857
            break;
11858
          case E_CART: {
11859
            if (get_target_extruder_from_command(913)) return;
11860
            switch (target_extruder) {
11861
              #if AXIS_HAS_STEALTHCHOP(E0)
11862
                case 0: TMC_SET_PWMTHRS_E(0); break;
11863
              #endif
11864
              #if E_STEPPERS > 1 && AXIS_HAS_STEALTHCHOP(E1)
11865
                case 1: TMC_SET_PWMTHRS_E(1); break;
11866
              #endif
11867
              #if E_STEPPERS > 2 && AXIS_HAS_STEALTHCHOP(E2)
11868
                case 2: TMC_SET_PWMTHRS_E(2); break;
11869
              #endif
11870
              #if E_STEPPERS > 3 && AXIS_HAS_STEALTHCHOP(E3)
11871
                case 3: TMC_SET_PWMTHRS_E(3); break;
11872
              #endif
11873
              #if E_STEPPERS > 4 && AXIS_HAS_STEALTHCHOP(E4)
11874
                case 4: TMC_SET_PWMTHRS_E(4); break;
11875
              #endif
11876
            }
11877
          } break;
11878
        }
11879
      }
11880
 
11881
      if (report) {
11882
        #if AXIS_HAS_STEALTHCHOP(X)
11883
          TMC_SAY_PWMTHRS(X,X);
11884
        #endif
11885
        #if AXIS_HAS_STEALTHCHOP(X2)
11886
          TMC_SAY_PWMTHRS(X,X2);
11887
        #endif
11888
        #if AXIS_HAS_STEALTHCHOP(Y)
11889
          TMC_SAY_PWMTHRS(Y,Y);
11890
        #endif
11891
        #if AXIS_HAS_STEALTHCHOP(Y2)
11892
          TMC_SAY_PWMTHRS(Y,Y2);
11893
        #endif
11894
        #if AXIS_HAS_STEALTHCHOP(Z)
11895
          TMC_SAY_PWMTHRS(Z,Z);
11896
        #endif
11897
        #if AXIS_HAS_STEALTHCHOP(Z2)
11898
          TMC_SAY_PWMTHRS(Z,Z2);
11899
        #endif
11900
        #if AXIS_HAS_STEALTHCHOP(E0)
11901
          TMC_SAY_PWMTHRS_E(0);
11902
        #endif
11903
        #if E_STEPPERS > 1 && AXIS_HAS_STEALTHCHOP(E1)
11904
          TMC_SAY_PWMTHRS_E(1);
11905
        #endif
11906
        #if E_STEPPERS > 2 && AXIS_HAS_STEALTHCHOP(E2)
11907
          TMC_SAY_PWMTHRS_E(2);
11908
        #endif
11909
        #if E_STEPPERS > 3 && AXIS_HAS_STEALTHCHOP(E3)
11910
          TMC_SAY_PWMTHRS_E(3);
11911
        #endif
11912
        #if E_STEPPERS > 4 && AXIS_HAS_STEALTHCHOP(E4)
11913
          TMC_SAY_PWMTHRS_E(4);
11914
        #endif
11915
      }
11916
    }
11917
  #endif // HYBRID_THRESHOLD
11918
 
11919
  /**
11920
   * M914: Set SENSORLESS_HOMING sensitivity.
11921
   */
11922
  #if ENABLED(SENSORLESS_HOMING)
11923
    inline void gcode_M914() {
11924
      #define TMC_SAY_SGT(Q) tmc_get_sgt(stepper##Q, TMC_##Q)
11925
      #define TMC_SET_SGT(Q) tmc_set_sgt(stepper##Q, value)
11926
 
11927
      bool report = true;
11928
      const uint8_t index = parser.byteval('I');
11929
      LOOP_XYZ(i) if (parser.seen(axis_codes[i])) {
11930
        const int8_t value = (int8_t)constrain(parser.value_int(), -64, 63);
11931
        report = false;
11932
        switch (i) {
11933
          #if X_SENSORLESS
11934
            case X_AXIS:
11935
              #if AXIS_HAS_STALLGUARD(X)
11936
                if (index < 2) TMC_SET_SGT(X);
11937
              #endif
11938
              #if AXIS_HAS_STALLGUARD(X2)
11939
                if (!(index & 1)) TMC_SET_SGT(X2);
11940
              #endif
11941
              break;
11942
          #endif
11943
          #if Y_SENSORLESS
11944
            case Y_AXIS:
11945
              #if AXIS_HAS_STALLGUARD(Y)
11946
                if (index < 2) TMC_SET_SGT(Y);
11947
              #endif
11948
              #if AXIS_HAS_STALLGUARD(Y2)
11949
                if (!(index & 1)) TMC_SET_SGT(Y2);
11950
              #endif
11951
              break;
11952
          #endif
11953
          #if Z_SENSORLESS
11954
            case Z_AXIS:
11955
              #if AXIS_HAS_STALLGUARD(Z)
11956
                if (index < 2) TMC_SET_SGT(Z);
11957
              #endif
11958
              #if AXIS_HAS_STALLGUARD(Z2)
11959
                if (!(index & 1)) TMC_SET_SGT(Z2);
11960
              #endif
11961
              break;
11962
          #endif
11963
        }
11964
      }
11965
 
11966
      if (report) {
11967
        #if X_SENSORLESS
11968
          #if AXIS_HAS_STALLGUARD(X)
11969
            TMC_SAY_SGT(X);
11970
          #endif
11971
          #if AXIS_HAS_STALLGUARD(X2)
11972
            TMC_SAY_SGT(X2);
11973
          #endif
11974
        #endif
11975
        #if Y_SENSORLESS
11976
          #if AXIS_HAS_STALLGUARD(Y)
11977
            TMC_SAY_SGT(Y);
11978
          #endif
11979
          #if AXIS_HAS_STALLGUARD(Y2)
11980
            TMC_SAY_SGT(Y2);
11981
          #endif
11982
        #endif
11983
        #if Z_SENSORLESS
11984
          #if AXIS_HAS_STALLGUARD(Z)
11985
            TMC_SAY_SGT(Z);
11986
          #endif
11987
          #if AXIS_HAS_STALLGUARD(Z2)
11988
            TMC_SAY_SGT(Z2);
11989
          #endif
11990
        #endif
11991
      }
11992
    }
11993
  #endif // SENSORLESS_HOMING
11994
 
11995
  /**
11996
   * TMC Z axis calibration routine
11997
   */
11998
  #if ENABLED(TMC_Z_CALIBRATION)
11999
    inline void gcode_M915() {
12000
      const uint16_t _rms = parser.seenval('S') ? parser.value_int() : CALIBRATION_CURRENT,
12001
                     _z = parser.seenval('Z') ? parser.value_linear_units() : CALIBRATION_EXTRA_HEIGHT;
12002
 
12003
      if (!TEST(axis_known_position, Z_AXIS)) {
12004
        SERIAL_ECHOLNPGM("\nPlease home Z axis first");
12005
        return;
12006
      }
12007
 
12008
      #if AXIS_IS_TMC(Z)
12009
        const uint16_t Z_current_1 = stepperZ.getCurrent();
12010
        stepperZ.setCurrent(_rms, R_SENSE, HOLD_MULTIPLIER);
12011
      #endif
12012
      #if AXIS_IS_TMC(Z2)
12013
        const uint16_t Z2_current_1 = stepperZ2.getCurrent();
12014
        stepperZ2.setCurrent(_rms, R_SENSE, HOLD_MULTIPLIER);
12015
      #endif
12016
 
12017
      SERIAL_ECHOPAIR("\nCalibration current: Z", _rms);
12018
 
12019
      soft_endstops_enabled = false;
12020
 
12021
      do_blocking_move_to_z(Z_MAX_POS+_z);
12022
 
12023
      #if AXIS_IS_TMC(Z)
12024
        stepperZ.setCurrent(Z_current_1, R_SENSE, HOLD_MULTIPLIER);
12025
      #endif
12026
      #if AXIS_IS_TMC(Z2)
12027
        stepperZ2.setCurrent(Z2_current_1, R_SENSE, HOLD_MULTIPLIER);
12028
      #endif
12029
 
12030
      do_blocking_move_to_z(Z_MAX_POS);
12031
      soft_endstops_enabled = true;
12032
 
12033
      SERIAL_ECHOLNPGM("\nHoming Z due to lost steps");
12034
      enqueue_and_echo_commands_P(PSTR("G28 Z"));
12035
    }
12036
  #endif
12037
 
12038
#endif // HAS_TRINAMIC
12039
 
12040
/**
12041
 * M907: Set digital trimpot motor current using axis codes X, Y, Z, E, B, S
12042
 */
12043
inline void gcode_M907() {
12044
  #if HAS_DIGIPOTSS
12045
 
12046
    LOOP_XYZE(i) if (parser.seen(axis_codes[i])) stepper.digipot_current(i, parser.value_int());
12047
    if (parser.seen('B')) stepper.digipot_current(4, parser.value_int());
12048
    if (parser.seen('S')) for (uint8_t i = 0; i <= 4; i++) stepper.digipot_current(i, parser.value_int());
12049
 
12050
  #elif HAS_MOTOR_CURRENT_PWM
12051
 
12052
    #if PIN_EXISTS(MOTOR_CURRENT_PWM_XY)
12053
      if (parser.seen('X')) stepper.digipot_current(0, parser.value_int());
12054
    #endif
12055
    #if PIN_EXISTS(MOTOR_CURRENT_PWM_Z)
12056
      if (parser.seen('Z')) stepper.digipot_current(1, parser.value_int());
12057
    #endif
12058
    #if PIN_EXISTS(MOTOR_CURRENT_PWM_E)
12059
      if (parser.seen('E')) stepper.digipot_current(2, parser.value_int());
12060
    #endif
12061
 
12062
  #endif
12063
 
12064
  #if ENABLED(DIGIPOT_I2C)
12065
    // this one uses actual amps in floating point
12066
    LOOP_XYZE(i) if (parser.seen(axis_codes[i])) digipot_i2c_set_current(i, parser.value_float());
12067
    // for each additional extruder (named B,C,D,E..., channels 4,5,6,7...)
12068
    for (uint8_t i = NUM_AXIS; i < DIGIPOT_I2C_NUM_CHANNELS; i++) if (parser.seen('B' + i - (NUM_AXIS))) digipot_i2c_set_current(i, parser.value_float());
12069
  #endif
12070
 
12071
  #if ENABLED(DAC_STEPPER_CURRENT)
12072
    if (parser.seen('S')) {
12073
      const float dac_percent = parser.value_float();
12074
      for (uint8_t i = 0; i <= 4; i++) dac_current_percent(i, dac_percent);
12075
    }
12076
    LOOP_XYZE(i) if (parser.seen(axis_codes[i])) dac_current_percent(i, parser.value_float());
12077
  #endif
12078
}
12079
 
12080
#if HAS_DIGIPOTSS || ENABLED(DAC_STEPPER_CURRENT)
12081
 
12082
  /**
12083
   * M908: Control digital trimpot directly (M908 P<pin> S<current>)
12084
   */
12085
  inline void gcode_M908() {
12086
    #if HAS_DIGIPOTSS
12087
      stepper.digitalPotWrite(
12088
        parser.intval('P'),
12089
        parser.intval('S')
12090
      );
12091
    #endif
12092
    #ifdef DAC_STEPPER_CURRENT
12093
      dac_current_raw(
12094
        parser.byteval('P', -1),
12095
        parser.ushortval('S', 0)
12096
      );
12097
    #endif
12098
  }
12099
 
12100
  #if ENABLED(DAC_STEPPER_CURRENT) // As with Printrbot RevF
12101
 
12102
    inline void gcode_M909() { dac_print_values(); }
12103
 
12104
    inline void gcode_M910() { dac_commit_eeprom(); }
12105
 
12106
  #endif
12107
 
12108
#endif // HAS_DIGIPOTSS || DAC_STEPPER_CURRENT
12109
 
12110
#if HAS_MICROSTEPS
12111
 
12112
  // M350 Set microstepping mode. Warning: Steps per unit remains unchanged. S code sets stepping mode for all drivers.
12113
  inline void gcode_M350() {
12114
    if (parser.seen('S')) for (int i = 0; i <= 4; i++) stepper.microstep_mode(i, parser.value_byte());
12115
    LOOP_XYZE(i) if (parser.seen(axis_codes[i])) stepper.microstep_mode(i, parser.value_byte());
12116
    if (parser.seen('B')) stepper.microstep_mode(4, parser.value_byte());
12117
    stepper.microstep_readings();
12118
  }
12119
 
12120
  /**
12121
   * M351: Toggle MS1 MS2 pins directly with axis codes X Y Z E B
12122
   *       S# determines MS1 or MS2, X# sets the pin high/low.
12123
   */
12124
  inline void gcode_M351() {
12125
    if (parser.seenval('S')) switch (parser.value_byte()) {
12126
      case 1:
12127
        LOOP_XYZE(i) if (parser.seenval(axis_codes[i])) stepper.microstep_ms(i, parser.value_byte(), -1);
12128
        if (parser.seenval('B')) stepper.microstep_ms(4, parser.value_byte(), -1);
12129
        break;
12130
      case 2:
12131
        LOOP_XYZE(i) if (parser.seenval(axis_codes[i])) stepper.microstep_ms(i, -1, parser.value_byte());
12132
        if (parser.seenval('B')) stepper.microstep_ms(4, -1, parser.value_byte());
12133
        break;
12134
    }
12135
    stepper.microstep_readings();
12136
  }
12137
 
12138
#endif // HAS_MICROSTEPS
12139
 
12140
#if HAS_CASE_LIGHT
12141
 
12142
  #ifndef INVERT_CASE_LIGHT
12143
    #define INVERT_CASE_LIGHT false
12144
  #endif
12145
  uint8_t case_light_brightness;  // LCD routine wants INT
12146
  bool case_light_on;
12147
 
12148
  #if ENABLED(CASE_LIGHT_USE_NEOPIXEL)
12149
    LEDColor case_light_color =
12150
      #ifdef CASE_LIGHT_NEOPIXEL_COLOR
12151
        CASE_LIGHT_NEOPIXEL_COLOR
12152
      #else
12153
        { 255, 255, 255, 255 }
12154
      #endif
12155
    ;
12156
  #endif
12157
 
12158
  void update_case_light() {
12159
    const uint8_t i = case_light_on ? case_light_brightness : 0, n10ct = INVERT_CASE_LIGHT ? 255 - i : i;
12160
 
12161
    #if ENABLED(CASE_LIGHT_USE_NEOPIXEL)
12162
 
12163
      leds.set_color(
12164
        MakeLEDColor(case_light_color.r, case_light_color.g, case_light_color.b, case_light_color.w, n10ct),
12165
        false
12166
      );
12167
 
12168
    #else // !CASE_LIGHT_USE_NEOPIXEL
12169
 
12170
      SET_OUTPUT(CASE_LIGHT_PIN);
12171
      if (USEABLE_HARDWARE_PWM(CASE_LIGHT_PIN))
12172
        analogWrite(CASE_LIGHT_PIN, n10ct);
12173
      else {
12174
        const bool s = case_light_on ? !INVERT_CASE_LIGHT : INVERT_CASE_LIGHT;
12175
        WRITE(CASE_LIGHT_PIN, s ? HIGH : LOW);
12176
      }
12177
 
12178
    #endif // !CASE_LIGHT_USE_NEOPIXEL
12179
  }
12180
#endif // HAS_CASE_LIGHT
12181
 
12182
/**
12183
 * M355: Turn case light on/off and set brightness
12184
 *
12185
 *   P<byte>  Set case light brightness (PWM pin required - ignored otherwise)
12186
 *
12187
 *   S<bool>  Set case light on/off
12188
 *
12189
 *   When S turns on the light on a PWM pin then the current brightness level is used/restored
12190
 *
12191
 *   M355 P200 S0 turns off the light & sets the brightness level
12192
 *   M355 S1 turns on the light with a brightness of 200 (assuming a PWM pin)
12193
 */
12194
inline void gcode_M355() {
12195
  #if HAS_CASE_LIGHT
12196
    uint8_t args = 0;
12197
    if (parser.seenval('P')) ++args, case_light_brightness = parser.value_byte();
12198
    if (parser.seenval('S')) ++args, case_light_on = parser.value_bool();
12199
    if (args) update_case_light();
12200
 
12201
    // always report case light status
12202
    SERIAL_ECHO_START();
12203
    if (!case_light_on) {
12204
      SERIAL_ECHOLNPGM("Case light: off");
12205
    }
12206
    else {
12207
      if (!USEABLE_HARDWARE_PWM(CASE_LIGHT_PIN)) SERIAL_ECHOLNPGM("Case light: on");
12208
      else SERIAL_ECHOLNPAIR("Case light: ", int(case_light_brightness));
12209
    }
12210
 
12211
  #else
12212
    SERIAL_ERROR_START();
12213
    SERIAL_ERRORLNPGM(MSG_ERR_M355_NONE);
12214
  #endif // HAS_CASE_LIGHT
12215
}
12216
 
12217
#if ENABLED(MIXING_EXTRUDER)
12218
 
12219
  /**
12220
   * M163: Set a single mix factor for a mixing extruder
12221
   *       This is called "weight" by some systems.
12222
   *       The 'P' values must sum to 1.0 or must be followed by M164 to normalize them.
12223
   *
12224
   *   S[index]   The channel index to set
12225
   *   P[float]   The mix value
12226
   */
12227
  inline void gcode_M163() {
12228
    const int mix_index = parser.intval('S');
12229
    if (mix_index < MIXING_STEPPERS)
12230
      mixing_factor[mix_index] = MAX(parser.floatval('P'), 0.0);
12231
  }
12232
 
12233
  /**
12234
   * M164: Normalize and commit the mix.
12235
   *       If 'S' is given store as a virtual tool. (Requires MIXING_VIRTUAL_TOOLS > 1)
12236
   *
12237
   *   S[index]   The virtual tool to store
12238
   */
12239
  inline void gcode_M164() {
12240
    normalize_mix();
12241
    #if MIXING_VIRTUAL_TOOLS > 1
12242
      const int tool_index = parser.intval('S', -1);
12243
      if (WITHIN(tool_index, 0, MIXING_VIRTUAL_TOOLS - 1)) {
12244
        for (uint8_t i = 0; i < MIXING_STEPPERS; i++)
12245
          mixing_virtual_tool_mix[tool_index][i] = mixing_factor[i];
12246
      }
12247
    #endif
12248
  }
12249
 
12250
  #if ENABLED(DIRECT_MIXING_IN_G1)
12251
    /**
12252
     * M165: Set multiple mix factors for a mixing extruder.
12253
     *       Factors that are left out will be set to 0.
12254
     *       All factors should sum to 1.0, but they will be normalized regardless.
12255
     *
12256
     *   A[factor] Mix factor for extruder stepper 1
12257
     *   B[factor] Mix factor for extruder stepper 2
12258
     *   C[factor] Mix factor for extruder stepper 3
12259
     *   D[factor] Mix factor for extruder stepper 4
12260
     *   H[factor] Mix factor for extruder stepper 5
12261
     *   I[factor] Mix factor for extruder stepper 6
12262
     */
12263
    inline void gcode_M165() { gcode_get_mix(); }
12264
  #endif
12265
 
12266
#endif // MIXING_EXTRUDER
12267
 
12268
/**
12269
 * M999: Restart after being stopped
12270
 *
12271
 * Default behaviour is to flush the serial buffer and request
12272
 * a resend to the host starting on the last N line received.
12273
 *
12274
 * Sending "M999 S1" will resume printing without flushing the
12275
 * existing command buffer.
12276
 *
12277
 */
12278
inline void gcode_M999() {
12279
  Running = true;
12280
  lcd_reset_alert_level();
12281
 
12282
  if (parser.boolval('S')) return;
12283
 
12284
  // gcode_LastN = Stopped_gcode_LastN;
12285
  flush_and_request_resend();
12286
}
12287
 
12288
#if DO_SWITCH_EXTRUDER
12289
  #if EXTRUDERS > 3
12290
    #define REQ_ANGLES 4
12291
    #define _SERVO_NR (e < 2 ? SWITCHING_EXTRUDER_SERVO_NR : SWITCHING_EXTRUDER_E23_SERVO_NR)
12292
  #else
12293
    #define REQ_ANGLES 2
12294
    #define _SERVO_NR SWITCHING_EXTRUDER_SERVO_NR
12295
  #endif
12296
  inline void move_extruder_servo(const uint8_t e) {
12297
    constexpr int16_t angles[] = SWITCHING_EXTRUDER_SERVO_ANGLES;
12298
    static_assert(COUNT(angles) == REQ_ANGLES, "SWITCHING_EXTRUDER_SERVO_ANGLES needs " STRINGIFY(REQ_ANGLES) " angles.");
12299
    planner.synchronize();
12300
    #if EXTRUDERS & 1
12301
      if (e < EXTRUDERS - 1)
12302
    #endif
12303
    {
12304
      MOVE_SERVO(_SERVO_NR, angles[e]);
12305
      safe_delay(500);
12306
    }
12307
  }
12308
#endif // DO_SWITCH_EXTRUDER
12309
 
12310
#if ENABLED(SWITCHING_NOZZLE)
12311
  inline void move_nozzle_servo(const uint8_t e) {
12312
    const int16_t angles[2] = SWITCHING_NOZZLE_SERVO_ANGLES;
12313
    planner.synchronize();
12314
    MOVE_SERVO(SWITCHING_NOZZLE_SERVO_NR, angles[e]);
12315
    safe_delay(500);
12316
  }
12317
#endif
12318
 
12319
inline void invalid_extruder_error(const uint8_t e) {
12320
  SERIAL_ECHO_START();
12321
  SERIAL_CHAR('T');
12322
  SERIAL_ECHO_F(e, DEC);
12323
  SERIAL_CHAR(' ');
12324
  SERIAL_ECHOLNPGM(MSG_INVALID_EXTRUDER);
12325
}
12326
 
12327
#if ENABLED(PARKING_EXTRUDER)
12328
 
12329
  #if ENABLED(PARKING_EXTRUDER_SOLENOIDS_INVERT)
12330
    #define PE_MAGNET_ON_STATE !PARKING_EXTRUDER_SOLENOIDS_PINS_ACTIVE
12331
  #else
12332
    #define PE_MAGNET_ON_STATE PARKING_EXTRUDER_SOLENOIDS_PINS_ACTIVE
12333
  #endif
12334
 
12335
  void pe_set_magnet(const uint8_t extruder_num, const uint8_t state) {
12336
    switch (extruder_num) {
12337
      case 1: OUT_WRITE(SOL1_PIN, state); break;
12338
      default: OUT_WRITE(SOL0_PIN, state); break;
12339
    }
12340
    #if PARKING_EXTRUDER_SOLENOIDS_DELAY > 0
12341
      dwell(PARKING_EXTRUDER_SOLENOIDS_DELAY);
12342
    #endif
12343
  }
12344
 
12345
  inline void pe_activate_magnet(const uint8_t extruder_num) { pe_set_magnet(extruder_num, PE_MAGNET_ON_STATE); }
12346
  inline void pe_deactivate_magnet(const uint8_t extruder_num) { pe_set_magnet(extruder_num, !PE_MAGNET_ON_STATE); }
12347
 
12348
#endif // PARKING_EXTRUDER
12349
 
12350
#if HAS_FANMUX
12351
 
12352
  void fanmux_switch(const uint8_t e) {
12353
    WRITE(FANMUX0_PIN, TEST(e, 0) ? HIGH : LOW);
12354
    #if PIN_EXISTS(FANMUX1)
12355
      WRITE(FANMUX1_PIN, TEST(e, 1) ? HIGH : LOW);
12356
      #if PIN_EXISTS(FANMUX2)
12357
        WRITE(FANMUX2, TEST(e, 2) ? HIGH : LOW);
12358
      #endif
12359
    #endif
12360
  }
12361
 
12362
  FORCE_INLINE void fanmux_init(void) {
12363
    SET_OUTPUT(FANMUX0_PIN);
12364
    #if PIN_EXISTS(FANMUX1)
12365
      SET_OUTPUT(FANMUX1_PIN);
12366
      #if PIN_EXISTS(FANMUX2)
12367
        SET_OUTPUT(FANMUX2_PIN);
12368
      #endif
12369
    #endif
12370
    fanmux_switch(0);
12371
  }
12372
 
12373
#endif // HAS_FANMUX
12374
 
12375
/**
12376
 * Tool Change functions
12377
 */
12378
 
12379
#if ENABLED(MIXING_EXTRUDER) && MIXING_VIRTUAL_TOOLS > 1
12380
 
12381
  inline void mixing_tool_change(const uint8_t tmp_extruder) {
12382
    if (tmp_extruder >= MIXING_VIRTUAL_TOOLS)
12383
      return invalid_extruder_error(tmp_extruder);
12384
 
12385
    // T0-Tnnn: Switch virtual tool by changing the mix
12386
    for (uint8_t j = 0; j < MIXING_STEPPERS; j++)
12387
      mixing_factor[j] = mixing_virtual_tool_mix[tmp_extruder][j];
12388
  }
12389
 
12390
#endif // MIXING_EXTRUDER && MIXING_VIRTUAL_TOOLS > 1
12391
 
12392
#if ENABLED(DUAL_X_CARRIAGE)
12393
 
12394
  inline void dualx_tool_change(const uint8_t tmp_extruder, bool &no_move) {
12395
    #if ENABLED(DEBUG_LEVELING_FEATURE)
12396
      if (DEBUGGING(LEVELING)) {
12397
        SERIAL_ECHOPGM("Dual X Carriage Mode ");
12398
        switch (dual_x_carriage_mode) {
12399
          case DXC_FULL_CONTROL_MODE: SERIAL_ECHOLNPGM("DXC_FULL_CONTROL_MODE"); break;
12400
          case DXC_AUTO_PARK_MODE: SERIAL_ECHOLNPGM("DXC_AUTO_PARK_MODE"); break;
12401
          case DXC_DUPLICATION_MODE: SERIAL_ECHOLNPGM("DXC_DUPLICATION_MODE"); break;
12402
        }
12403
      }
12404
    #endif
12405
 
12406
    const float xhome = x_home_pos(active_extruder);
12407
    if (dual_x_carriage_mode == DXC_AUTO_PARK_MODE
12408
        && IsRunning()
12409
        && (delayed_move_time || current_position[X_AXIS] != xhome)
12410
    ) {
12411
      float raised_z = current_position[Z_AXIS] + TOOLCHANGE_PARK_ZLIFT;
12412
      #if ENABLED(MAX_SOFTWARE_ENDSTOPS)
12413
        NOMORE(raised_z, soft_endstop_max[Z_AXIS]);
12414
      #endif
12415
      #if ENABLED(DEBUG_LEVELING_FEATURE)
12416
        if (DEBUGGING(LEVELING)) {
12417
          SERIAL_ECHOLNPAIR("Raise to ", raised_z);
12418
          SERIAL_ECHOLNPAIR("MoveX to ", xhome);
12419
          SERIAL_ECHOLNPAIR("Lower to ", current_position[Z_AXIS]);
12420
        }
12421
      #endif
12422
      // Park old head: 1) raise 2) move to park position 3) lower
12423
      for (uint8_t i = 0; i < 3; i++)
12424
        planner.buffer_line(
12425
          i == 0 ? current_position[X_AXIS] : xhome,
12426
          current_position[Y_AXIS],
12427
          i == 2 ? current_position[Z_AXIS] : raised_z,
12428
          current_position[E_CART],
12429
          planner.max_feedrate_mm_s[i == 1 ? X_AXIS : Z_AXIS],
12430
          active_extruder
12431
        );
12432
      planner.synchronize();
12433
    }
12434
 
12435
    // Apply Y & Z extruder offset (X offset is used as home pos with Dual X)
12436
    current_position[Y_AXIS] -= hotend_offset[Y_AXIS][active_extruder] - hotend_offset[Y_AXIS][tmp_extruder];
12437
    current_position[Z_AXIS] -= hotend_offset[Z_AXIS][active_extruder] - hotend_offset[Z_AXIS][tmp_extruder];
12438
 
12439
    // Activate the new extruder ahead of calling set_axis_is_at_home!
12440
    active_extruder = tmp_extruder;
12441
 
12442
    // This function resets the max/min values - the current position may be overwritten below.
12443
    set_axis_is_at_home(X_AXIS);
12444
 
12445
    #if ENABLED(DEBUG_LEVELING_FEATURE)
12446
      if (DEBUGGING(LEVELING)) DEBUG_POS("New Extruder", current_position);
12447
    #endif
12448
 
12449
    // Only when auto-parking are carriages safe to move
12450
    if (dual_x_carriage_mode != DXC_AUTO_PARK_MODE) no_move = true;
12451
 
12452
    switch (dual_x_carriage_mode) {
12453
      case DXC_FULL_CONTROL_MODE:
12454
        // New current position is the position of the activated extruder
12455
        current_position[X_AXIS] = inactive_extruder_x_pos;
12456
        // Save the inactive extruder's position (from the old current_position)
12457
        inactive_extruder_x_pos = destination[X_AXIS];
12458
        break;
12459
      case DXC_AUTO_PARK_MODE:
12460
        // record raised toolhead position for use by unpark
12461
        COPY(raised_parked_position, current_position);
12462
        raised_parked_position[Z_AXIS] += TOOLCHANGE_UNPARK_ZLIFT;
12463
        #if ENABLED(MAX_SOFTWARE_ENDSTOPS)
12464
          NOMORE(raised_parked_position[Z_AXIS], soft_endstop_max[Z_AXIS]);
12465
        #endif
12466
        active_extruder_parked = true;
12467
        delayed_move_time = 0;
12468
        break;
12469
      case DXC_DUPLICATION_MODE:
12470
        // If the new extruder is the left one, set it "parked"
12471
        // This triggers the second extruder to move into the duplication position
12472
        active_extruder_parked = (active_extruder == 0);
12473
        current_position[X_AXIS] = active_extruder_parked ? inactive_extruder_x_pos : destination[X_AXIS] + duplicate_extruder_x_offset;
12474
        inactive_extruder_x_pos = destination[X_AXIS];
12475
        extruder_duplication_enabled = false;
12476
        #if ENABLED(DEBUG_LEVELING_FEATURE)
12477
          if (DEBUGGING(LEVELING)) {
12478
            SERIAL_ECHOLNPAIR("Set inactive_extruder_x_pos=", inactive_extruder_x_pos);
12479
            SERIAL_ECHOLNPGM("Clear extruder_duplication_enabled");
12480
          }
12481
        #endif
12482
        break;
12483
    }
12484
 
12485
    #if ENABLED(DEBUG_LEVELING_FEATURE)
12486
      if (DEBUGGING(LEVELING)) {
12487
        SERIAL_ECHOLNPAIR("Active extruder parked: ", active_extruder_parked ? "yes" : "no");
12488
        DEBUG_POS("New extruder (parked)", current_position);
12489
      }
12490
    #endif
12491
 
12492
    // No extra case for HAS_ABL in DUAL_X_CARRIAGE. Does that mean they don't work together?
12493
  }
12494
 
12495
#endif // DUAL_X_CARRIAGE
12496
 
12497
#if ENABLED(PARKING_EXTRUDER)
12498
 
12499
  inline void parking_extruder_tool_change(const uint8_t tmp_extruder, bool no_move) {
12500
    constexpr float z_raise = PARKING_EXTRUDER_SECURITY_RAISE;
12501
 
12502
    if (!no_move) {
12503
 
12504
      const float parkingposx[] = PARKING_EXTRUDER_PARKING_X,
12505
                  midpos = (parkingposx[0] + parkingposx[1]) * 0.5 + hotend_offset[X_AXIS][active_extruder],
12506
                  grabpos = parkingposx[tmp_extruder] + hotend_offset[X_AXIS][active_extruder]
12507
                            + (tmp_extruder == 0 ? -(PARKING_EXTRUDER_GRAB_DISTANCE) : PARKING_EXTRUDER_GRAB_DISTANCE);
12508
      /**
12509
       *  Steps:
12510
       *    1. Raise Z-Axis to give enough clearance
12511
       *    2. Move to park position of old extruder
12512
       *    3. Disengage magnetic field, wait for delay
12513
       *    4. Move near new extruder
12514
       *    5. Engage magnetic field for new extruder
12515
       *    6. Move to parking incl. offset of new extruder
12516
       *    7. Lower Z-Axis
12517
       */
12518
 
12519
      // STEP 1
12520
      #if ENABLED(DEBUG_LEVELING_FEATURE)
12521
        SERIAL_ECHOLNPGM("Starting Autopark");
12522
        if (DEBUGGING(LEVELING)) DEBUG_POS("current position:", current_position);
12523
      #endif
12524
      current_position[Z_AXIS] += z_raise;
12525
      #if ENABLED(DEBUG_LEVELING_FEATURE)
12526
        SERIAL_ECHOLNPGM("(1) Raise Z-Axis ");
12527
        if (DEBUGGING(LEVELING)) DEBUG_POS("Moving to Raised Z-Position", current_position);
12528
      #endif
12529
      planner.buffer_line_kinematic(current_position, planner.max_feedrate_mm_s[Z_AXIS], active_extruder);
12530
      planner.synchronize();
12531
 
12532
      // STEP 2
12533
      current_position[X_AXIS] = parkingposx[active_extruder] + hotend_offset[X_AXIS][active_extruder];
12534
      #if ENABLED(DEBUG_LEVELING_FEATURE)
12535
        SERIAL_ECHOLNPAIR("(2) Park extruder ", active_extruder);
12536
        if (DEBUGGING(LEVELING)) DEBUG_POS("Moving ParkPos", current_position);
12537
      #endif
12538
      planner.buffer_line_kinematic(current_position, planner.max_feedrate_mm_s[X_AXIS], active_extruder);
12539
      planner.synchronize();
12540
 
12541
      // STEP 3
12542
      #if ENABLED(DEBUG_LEVELING_FEATURE)
12543
        SERIAL_ECHOLNPGM("(3) Disengage magnet ");
12544
      #endif
12545
      pe_deactivate_magnet(active_extruder);
12546
 
12547
      // STEP 4
12548
      #if ENABLED(DEBUG_LEVELING_FEATURE)
12549
        SERIAL_ECHOLNPGM("(4) Move to position near new extruder");
12550
      #endif
12551
      current_position[X_AXIS] += (active_extruder == 0 ? 10 : -10); // move 10mm away from parked extruder
12552
 
12553
      #if ENABLED(DEBUG_LEVELING_FEATURE)
12554
        if (DEBUGGING(LEVELING)) DEBUG_POS("Moving away from parked extruder", current_position);
12555
      #endif
12556
      planner.buffer_line_kinematic(current_position, planner.max_feedrate_mm_s[X_AXIS], active_extruder);
12557
      planner.synchronize();
12558
 
12559
      // STEP 5
12560
      #if ENABLED(DEBUG_LEVELING_FEATURE)
12561
        SERIAL_ECHOLNPGM("(5) Engage magnetic field");
12562
      #endif
12563
 
12564
      #if ENABLED(PARKING_EXTRUDER_SOLENOIDS_INVERT)
12565
        pe_activate_magnet(active_extruder); //just save power for inverted magnets
12566
      #endif
12567
      pe_activate_magnet(tmp_extruder);
12568
 
12569
      // STEP 6
12570
      current_position[X_AXIS] = grabpos + (tmp_extruder == 0 ? (+10) : (-10));
12571
      planner.buffer_line_kinematic(current_position, planner.max_feedrate_mm_s[X_AXIS], active_extruder);
12572
      current_position[X_AXIS] = grabpos;
12573
      #if ENABLED(DEBUG_LEVELING_FEATURE)
12574
        SERIAL_ECHOLNPAIR("(6) Unpark extruder ", tmp_extruder);
12575
        if (DEBUGGING(LEVELING)) DEBUG_POS("Move UnparkPos", current_position);
12576
      #endif
12577
      planner.buffer_line_kinematic(current_position, planner.max_feedrate_mm_s[X_AXIS]/2, active_extruder);
12578
      planner.synchronize();
12579
 
12580
      // Step 7
12581
      current_position[X_AXIS] = midpos - hotend_offset[X_AXIS][tmp_extruder];
12582
      #if ENABLED(DEBUG_LEVELING_FEATURE)
12583
        SERIAL_ECHOLNPGM("(7) Move midway between hotends");
12584
        if (DEBUGGING(LEVELING)) DEBUG_POS("Move midway to new extruder", current_position);
12585
      #endif
12586
      planner.buffer_line_kinematic(current_position, planner.max_feedrate_mm_s[X_AXIS], active_extruder);
12587
      planner.synchronize();
12588
      #if ENABLED(DEBUG_LEVELING_FEATURE)
12589
        SERIAL_ECHOLNPGM("Autopark done.");
12590
      #endif
12591
    }
12592
    else { // nomove == true
12593
      // Only engage magnetic field for new extruder
12594
      pe_activate_magnet(tmp_extruder);
12595
      #if ENABLED(PARKING_EXTRUDER_SOLENOIDS_INVERT)
12596
        pe_activate_magnet(active_extruder); // Just save power for inverted magnets
12597
      #endif
12598
    }
12599
    current_position[Z_AXIS] += hotend_offset[Z_AXIS][active_extruder] - hotend_offset[Z_AXIS][tmp_extruder];
12600
 
12601
    #if ENABLED(DEBUG_LEVELING_FEATURE)
12602
      if (DEBUGGING(LEVELING)) DEBUG_POS("Applying Z-offset", current_position);
12603
    #endif
12604
  }
12605
 
12606
#endif // PARKING_EXTRUDER
12607
 
12608
/**
12609
 * Perform a tool-change, which may result in moving the
12610
 * previous tool out of the way and the new tool into place.
12611
 */
12612
void tool_change(const uint8_t tmp_extruder, const float fr_mm_s/*=0.0*/, bool no_move/*=false*/) {
12613
  planner.synchronize();
12614
 
12615
  #if HAS_LEVELING
12616
    // Set current position to the physical position
12617
    const bool leveling_was_active = planner.leveling_active;
12618
    set_bed_leveling_enabled(false);
12619
  #endif
12620
 
12621
  #if ENABLED(MIXING_EXTRUDER) && MIXING_VIRTUAL_TOOLS > 1
12622
 
12623
    mixing_tool_change(tmp_extruder);
12624
 
12625
  #else // !MIXING_EXTRUDER || MIXING_VIRTUAL_TOOLS <= 1
12626
 
12627
    if (tmp_extruder >= EXTRUDERS)
12628
      return invalid_extruder_error(tmp_extruder);
12629
 
12630
    #if HOTENDS > 1
12631
 
12632
      const float old_feedrate_mm_s = fr_mm_s > 0.0 ? fr_mm_s : feedrate_mm_s;
12633
 
12634
      feedrate_mm_s = fr_mm_s > 0.0 ? fr_mm_s : XY_PROBE_FEEDRATE_MM_S;
12635
 
12636
      if (tmp_extruder != active_extruder) {
12637
        if (!no_move && axis_unhomed_error()) {
12638
          no_move = true;
12639
          #if ENABLED(DEBUG_LEVELING_FEATURE)
12640
            if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("No move on toolchange");
12641
          #endif
12642
        }
12643
 
12644
        #if ENABLED(DUAL_X_CARRIAGE)
12645
 
12646
          #if HAS_SOFTWARE_ENDSTOPS
12647
            // Update the X software endstops early
12648
            active_extruder = tmp_extruder;
12649
            update_software_endstops(X_AXIS);
12650
            active_extruder = !tmp_extruder;
12651
          #endif
12652
 
12653
          // Don't move the new extruder out of bounds
12654
          if (!WITHIN(current_position[X_AXIS], soft_endstop_min[X_AXIS], soft_endstop_max[X_AXIS]))
12655
            no_move = true;
12656
 
12657
          if (!no_move) set_destination_from_current();
12658
          dualx_tool_change(tmp_extruder, no_move); // Can modify no_move
12659
 
12660
        #else // !DUAL_X_CARRIAGE
12661
 
12662
          set_destination_from_current();
12663
 
12664
          #if ENABLED(PARKING_EXTRUDER)
12665
            parking_extruder_tool_change(tmp_extruder, no_move);
12666
          #endif
12667
 
12668
          #if ENABLED(SWITCHING_NOZZLE)
12669
            // Always raise by at least 1 to avoid workpiece
12670
            const float zdiff = hotend_offset[Z_AXIS][active_extruder] - hotend_offset[Z_AXIS][tmp_extruder];
12671
            current_position[Z_AXIS] += (zdiff > 0.0 ? zdiff : 0.0) + 1;
12672
            planner.buffer_line_kinematic(current_position, planner.max_feedrate_mm_s[Z_AXIS], active_extruder);
12673
            move_nozzle_servo(tmp_extruder);
12674
          #endif
12675
 
12676
          const float xdiff = hotend_offset[X_AXIS][tmp_extruder] - hotend_offset[X_AXIS][active_extruder],
12677
                      ydiff = hotend_offset[Y_AXIS][tmp_extruder] - hotend_offset[Y_AXIS][active_extruder];
12678
 
12679
          #if ENABLED(DEBUG_LEVELING_FEATURE)
12680
            if (DEBUGGING(LEVELING)) {
12681
              SERIAL_ECHOPAIR("Offset Tool XY by { ", xdiff);
12682
              SERIAL_ECHOPAIR(", ", ydiff);
12683
              SERIAL_ECHOLNPGM(" }");
12684
            }
12685
          #endif
12686
 
12687
          // The newly-selected extruder XY is actually at...
12688
          current_position[X_AXIS] += xdiff;
12689
          current_position[Y_AXIS] += ydiff;
12690
 
12691
          // Set the new active extruder
12692
          active_extruder = tmp_extruder;
12693
 
12694
        #endif // !DUAL_X_CARRIAGE
12695
 
12696
        #if ENABLED(SWITCHING_NOZZLE)
12697
          // The newly-selected extruder Z is actually at...
12698
          current_position[Z_AXIS] -= zdiff;
12699
        #endif
12700
 
12701
        // Tell the planner the new "current position"
12702
        SYNC_PLAN_POSITION_KINEMATIC();
12703
 
12704
        #if ENABLED(DELTA)
12705
          //LOOP_XYZ(i) update_software_endstops(i); // or modify the constrain function
12706
          const bool safe_to_move = current_position[Z_AXIS] < delta_clip_start_height - 1;
12707
        #else
12708
          constexpr bool safe_to_move = true;
12709
        #endif
12710
 
12711
        // Raise, move, and lower again
12712
        if (safe_to_move && !no_move && IsRunning()) {
12713
          #if DISABLED(SWITCHING_NOZZLE)
12714
            // Do a small lift to avoid the workpiece in the move back (below)
12715
            current_position[Z_AXIS] += 1.0;
12716
            planner.buffer_line_kinematic(current_position, planner.max_feedrate_mm_s[Z_AXIS], active_extruder);
12717
          #endif
12718
          #if ENABLED(DEBUG_LEVELING_FEATURE)
12719
            if (DEBUGGING(LEVELING)) DEBUG_POS("Move back", destination);
12720
          #endif
12721
          // Move back to the original (or tweaked) position
12722
          do_blocking_move_to(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS]);
12723
          #if ENABLED(DUAL_X_CARRIAGE)
12724
            active_extruder_parked = false;
12725
          #endif
12726
        }
12727
        #if ENABLED(SWITCHING_NOZZLE)
12728
          else {
12729
            // Move back down. (Including when the new tool is higher.)
12730
            do_blocking_move_to_z(destination[Z_AXIS], planner.max_feedrate_mm_s[Z_AXIS]);
12731
          }
12732
        #endif
12733
      } // (tmp_extruder != active_extruder)
12734
 
12735
      planner.synchronize();
12736
 
12737
      #if ENABLED(EXT_SOLENOID) && !ENABLED(PARKING_EXTRUDER)
12738
        disable_all_solenoids();
12739
        enable_solenoid_on_active_extruder();
12740
      #endif
12741
 
12742
      feedrate_mm_s = old_feedrate_mm_s;
12743
 
12744
      #if HAS_SOFTWARE_ENDSTOPS && ENABLED(DUAL_X_CARRIAGE)
12745
        update_software_endstops(X_AXIS);
12746
      #endif
12747
 
12748
    #else // HOTENDS <= 1
12749
 
12750
      UNUSED(fr_mm_s);
12751
      UNUSED(no_move);
12752
 
12753
      #if ENABLED(MK2_MULTIPLEXER)
12754
        if (tmp_extruder >= E_STEPPERS)
12755
          return invalid_extruder_error(tmp_extruder);
12756
 
12757
        select_multiplexed_stepper(tmp_extruder);
12758
      #endif
12759
 
12760
      // Set the new active extruder
12761
      active_extruder = tmp_extruder;
12762
 
12763
    #endif // HOTENDS <= 1
12764
 
12765
    #if DO_SWITCH_EXTRUDER
12766
      planner.synchronize();
12767
      move_extruder_servo(active_extruder);
12768
    #endif
12769
 
12770
    #if HAS_FANMUX
12771
      fanmux_switch(active_extruder);
12772
    #endif
12773
 
12774
    #if HAS_LEVELING
12775
      // Restore leveling to re-establish the logical position
12776
      set_bed_leveling_enabled(leveling_was_active);
12777
    #endif
12778
 
12779
    SERIAL_ECHO_START();
12780
    SERIAL_ECHOLNPAIR(MSG_ACTIVE_EXTRUDER, int(active_extruder));
12781
 
12782
  #endif // !MIXING_EXTRUDER || MIXING_VIRTUAL_TOOLS <= 1
12783
}
12784
 
12785
/**
12786
 * T0-T3: Switch tool, usually switching extruders
12787
 *
12788
 *   F[units/min] Set the movement feedrate
12789
 *   S1           Don't move the tool in XY after change
12790
 */
12791
inline void gcode_T(const uint8_t tmp_extruder) {
12792
 
12793
  #if ENABLED(DEBUG_LEVELING_FEATURE)
12794
    if (DEBUGGING(LEVELING)) {
12795
      SERIAL_ECHOPAIR(">>> gcode_T(", tmp_extruder);
12796
      SERIAL_CHAR(')');
12797
      SERIAL_EOL();
12798
      DEBUG_POS("BEFORE", current_position);
12799
    }
12800
  #endif
12801
 
12802
  #if HOTENDS == 1 || (ENABLED(MIXING_EXTRUDER) && MIXING_VIRTUAL_TOOLS > 1)
12803
 
12804
    tool_change(tmp_extruder);
12805
 
12806
  #elif HOTENDS > 1
12807
 
12808
    tool_change(
12809
      tmp_extruder,
12810
      MMM_TO_MMS(parser.linearval('F')),
12811
      (tmp_extruder == active_extruder) || parser.boolval('S')
12812
    );
12813
 
12814
  #endif
12815
 
12816
  #if ENABLED(DEBUG_LEVELING_FEATURE)
12817
    if (DEBUGGING(LEVELING)) {
12818
      DEBUG_POS("AFTER", current_position);
12819
      SERIAL_ECHOLNPGM("<<< gcode_T");
12820
    }
12821
  #endif
12822
}
12823
 
12824
/**
12825
 * Process the parsed command and dispatch it to its handler
12826
 */
12827
void process_parsed_command() {
12828
  KEEPALIVE_STATE(IN_HANDLER);
12829
 
12830
  // Handle a known G, M, or T
12831
  switch (parser.command_letter) {
12832
    case 'G': switch (parser.codenum) {
12833
 
12834
      case 0: case 1: gcode_G0_G1(                                // G0: Fast Move, G1: Linear Move
12835
                        #if IS_SCARA
12836
                          parser.codenum == 0
12837
                        #endif
12838
                      ); break;
12839
 
12840
      #if ENABLED(ARC_SUPPORT) && DISABLED(SCARA)
12841
        case 2: case 3: gcode_G2_G3(parser.codenum == 2); break;  // G2: CW ARC, G3: CCW ARC
12842
      #endif
12843
 
12844
      case 4: gcode_G4(); break;                                  // G4: Dwell
12845
 
12846
      #if ENABLED(BEZIER_CURVE_SUPPORT)
12847
        case 5: gcode_G5(); break;                                // G5: Cubic B_spline
12848
      #endif
12849
 
12850
      #if ENABLED(UNREGISTERED_MOVE_SUPPORT)
12851
        case 6: gcode_G6(); break;                                // G6: Direct stepper move
12852
      #endif
12853
 
12854
      #if ENABLED(FWRETRACT)
12855
        case 10: gcode_G10(); break;                              // G10: Retract
12856
        case 11: gcode_G11(); break;                              // G11: Prime
12857
      #endif
12858
 
12859
      #if ENABLED(NOZZLE_CLEAN_FEATURE)
12860
        case 12: gcode_G12(); break;                              // G12: Clean Nozzle
12861
      #endif
12862
 
12863
      #if ENABLED(CNC_WORKSPACE_PLANES)
12864
        case 17: gcode_G17(); break;                              // G17: Select Plane XY
12865
        case 18: gcode_G18(); break;                              // G18: Select Plane ZX
12866
        case 19: gcode_G19(); break;                              // G19: Select Plane YZ
12867
      #endif
12868
 
12869
      #if ENABLED(INCH_MODE_SUPPORT)
12870
        case 20: gcode_G20(); break;                              // G20: Inch Units
12871
        case 21: gcode_G21(); break;                              // G21: Millimeter Units
12872
      #endif
12873
 
12874
      #if ENABLED(G26_MESH_VALIDATION)
12875
        case 26: gcode_G26(); break;                              // G26: Mesh Validation Pattern
12876
      #endif
12877
 
12878
      #if ENABLED(NOZZLE_PARK_FEATURE)
12879
        case 27: gcode_G27(); break;                              // G27: Park Nozzle
12880
      #endif
12881
 
12882
      case 28: gcode_G28(false); break;                           // G28: Home one or more axes
12883
 
12884
      #if HAS_LEVELING
12885
        case 29: gcode_G29(); break;                              // G29: Detailed Z probe
12886
      #endif
12887
 
12888
      #if HAS_BED_PROBE
12889
        case 30: gcode_G30(); break;                              // G30: Single Z probe
12890
      #endif
12891
 
12892
      #if ENABLED(Z_PROBE_SLED)
12893
        case 31: gcode_G31(); break;                              // G31: Dock sled
12894
        case 32: gcode_G32(); break;                              // G32: Undock sled
12895
      #endif
12896
 
12897
      #if ENABLED(DELTA_AUTO_CALIBRATION)
12898
        case 33: gcode_G33(); break;                              // G33: Delta Auto-Calibration
12899
      #endif
12900
 
12901
      #if ENABLED(G38_PROBE_TARGET)
12902
        case 38:
12903
          if (parser.subcode == 2 || parser.subcode == 3)
12904
            gcode_G38(parser.subcode == 2);                       // G38.2, G38.3: Probe towards object
12905
          break;
12906
      #endif
12907
 
12908
      #if HAS_MESH
12909
        case 42: gcode_G42(); break;                              // G42: Move to mesh point
12910
      #endif
12911
 
12912
      case 90: relative_mode = false; break;                      // G90: Absolute coordinates
12913
      case 91: relative_mode = true; break;                       // G91: Relative coordinates
12914
 
12915
      case 92: gcode_G92(); break;                                // G92: Set Position
12916
      #if ENABLED(MECHADUINO_I2C_COMMANDS)
12917
        case 95: gcode_G95(); break;                                // G95: Set torque mode
12918
        case 96: gcode_G96(); break;                                // G96: Mark encoder reference point
12919
      #endif
12920
 
12921
      #if ENABLED(DEBUG_GCODE_PARSER)
12922
        case 800: parser.debug(); break;                          // G800: GCode Parser Test for G
12923
      #endif
12924
 
12925
      default: parser.unknown_command_error();
12926
    }
12927
    break;
12928
 
12929
    case 'M': switch (parser.codenum) {
12930
      #if HAS_RESUME_CONTINUE
12931
        case 0: case 1: gcode_M0_M1(); break;                     // M0: Unconditional stop, M1: Conditional stop
12932
      #endif
12933
 
12934
      #if ENABLED(SPINDLE_LASER_ENABLE)
12935
        case 3: gcode_M3_M4(true); break;                         // M3: Laser/CW-Spindle Power
12936
        case 4: gcode_M3_M4(false); break;                        // M4: Laser/CCW-Spindle Power
12937
        case 5: gcode_M5(); break;                                // M5: Laser/Spindle OFF
12938
      #endif
12939
 
12940
      case 17: gcode_M17(); break;                                // M17: Enable all steppers
12941
 
12942
      #if ENABLED(SDSUPPORT)
12943
        case 20: gcode_M20(); break;                              // M20: List SD Card
12944
        case 21: gcode_M21(); break;                              // M21: Init SD Card
12945
        case 22: gcode_M22(); break;                              // M22: Release SD Card
12946
        case 23: gcode_M23(); break;                              // M23: Select File
12947
        case 24: gcode_M24(); break;                              // M24: Start SD Print
12948
        case 25: gcode_M25(); break;                              // M25: Pause SD Print
12949
        case 26: gcode_M26(); break;                              // M26: Set SD Index
12950
        case 27: gcode_M27(); break;                              // M27: Get SD Status
12951
        case 28: gcode_M28(); break;                              // M28: Start SD Write
12952
        case 29: gcode_M29(); break;                              // M29: Stop SD Write
12953
        case 30: gcode_M30(); break;                              // M30: Delete File
12954
        case 32: gcode_M32(); break;                              // M32: Select file, Start SD Print
12955
        #if ENABLED(LONG_FILENAME_HOST_SUPPORT)
12956
          case 33: gcode_M33(); break;                            // M33: Report longname path
12957
        #endif
12958
        #if ENABLED(SDCARD_SORT_ALPHA) && ENABLED(SDSORT_GCODE)
12959
          case 34: gcode_M34(); break;                            // M34: Set SD card sorting options
12960
        #endif
12961
        case 928: gcode_M928(); break;                            // M928: Start SD write
12962
      #endif // SDSUPPORT
12963
 
12964
      case 31: gcode_M31(); break;                                // M31: Report print job elapsed time
12965
 
12966
      case 42: gcode_M42(); break;                                // M42: Change pin state
12967
      #if ENABLED(PINS_DEBUGGING)
12968
        case 43: gcode_M43(); break;                              // M43: Read/monitor pin and endstop states
12969
      #endif
12970
 
12971
      #if ENABLED(Z_MIN_PROBE_REPEATABILITY_TEST)
12972
        case 48: gcode_M48(); break;                              // M48: Z probe repeatability test
12973
      #endif
12974
      #if ENABLED(G26_MESH_VALIDATION)
12975
        case 49: gcode_M49(); break;                              // M49: Toggle the G26 Debug Flag
12976
      #endif
12977
 
12978
      #if ENABLED(ULTRA_LCD) && ENABLED(LCD_SET_PROGRESS_MANUALLY)
12979
        case 73: gcode_M73(); break;                              // M73: Set Print Progress %
12980
      #endif
12981
      case 75: gcode_M75(); break;                                // M75: Start Print Job Timer
12982
      case 76: gcode_M76(); break;                                // M76: Pause Print Job Timer
12983
      case 77: gcode_M77(); break;                                // M77: Stop Print Job Timer
12984
      #if ENABLED(PRINTCOUNTER)
12985
        case 78: gcode_M78(); break;                              // M78: Report Print Statistics
12986
      #endif
12987
 
12988
      #if ENABLED(M100_FREE_MEMORY_WATCHER)
12989
        case 100: gcode_M100(); break;                            // M100: Free Memory Report
12990
      #endif
12991
 
12992
      case 104: gcode_M104(); break;                              // M104: Set Hotend Temperature
12993
      case 110: gcode_M110(); break;                              // M110: Set Current Line Number
12994
      case 111: gcode_M111(); break;                              // M111: Set Debug Flags
12995
 
12996
      #if DISABLED(EMERGENCY_PARSER)
12997
        case 108: gcode_M108(); break;                            // M108: Cancel Waiting
12998
        case 112: gcode_M112(); break;                            // M112: Emergency Stop
12999
        case 410: gcode_M410(); break;                            // M410: Quickstop. Abort all planned moves
13000
      #else
13001
        case 108: case 112: case 410: break;                      // Silently drop as handled by emergency parser
13002
      #endif
13003
 
13004
      #if ENABLED(HOST_KEEPALIVE_FEATURE)
13005
        case 113: gcode_M113(); break;                            // M113: Set Host Keepalive Interval
13006
      #endif
13007
 
13008
      case 105: gcode_M105(); KEEPALIVE_STATE(NOT_BUSY); return;  // M105: Report Temperatures (and say "ok")
13009
 
13010
      #if ENABLED(AUTO_REPORT_TEMPERATURES)
13011
        case 155: gcode_M155(); break;                            // M155: Set Temperature Auto-report Interval
13012
      #endif
13013
 
13014
      case 109: gcode_M109(); break;                              // M109: Set Hotend Temperature. Wait for target.
13015
 
13016
      #if HAS_HEATED_BED
13017
        case 140: gcode_M140(); break;                            // M140: Set Bed Temperature
13018
        case 190: gcode_M190(); break;                            // M190: Set Bed Temperature. Wait for target.
13019
      #endif
13020
 
13021
      #if FAN_COUNT > 0
13022
        case 106: gcode_M106(); break;                            // M106: Set Fan Speed
13023
        case 107: gcode_M107(); break;                            // M107: Fan Off
13024
      #endif
13025
 
13026
      #if ENABLED(PARK_HEAD_ON_PAUSE)
13027
        case 125: gcode_M125(); break;                            // M125: Park (for Filament Change)
13028
      #endif
13029
 
13030
      #if ENABLED(BARICUDA)
13031
        #if HAS_HEATER_1
13032
          case 126: gcode_M126(); break;                          // M126: Valve 1 Open
13033
          case 127: gcode_M127(); break;                          // M127: Valve 1 Closed
13034
        #endif
13035
        #if HAS_HEATER_2
13036
          case 128: gcode_M128(); break;                          // M128: Valve 2 Open
13037
          case 129: gcode_M129(); break;                          // M129: Valve 2 Closed
13038
        #endif
13039
      #endif
13040
 
13041
      #if HAS_POWER_SWITCH
13042
        case 80: gcode_M80(); break;                              // M80: Turn on Power Supply
13043
      #endif
13044
      case 81: gcode_M81(); break;                                // M81: Turn off Power and Power Supply
13045
 
13046
      case 82: gcode_M82(); break;                                // M82: Disable Relative E-Axis
13047
      case 83: gcode_M83(); break;                                // M83: Set Relative E-Axis
13048
      case 18: case 84: gcode_M18_M84(); break;                   // M18/M84: Disable Steppers / Set Timeout
13049
      case 85: gcode_M85(); break;                                // M85: Set inactivity stepper shutdown timeout
13050
      case 92: gcode_M92(); break;                                // M92: Set steps-per-unit
13051
      case 114: gcode_M114(); break;                              // M114: Report Current Position
13052
      case 115: gcode_M115(); break;                              // M115: Capabilities Report
13053
      case 117: gcode_M117(); break;                              // M117: Set LCD message text
13054
      case 118: gcode_M118(); break;                              // M118: Print a message in the host console
13055
      case 119: gcode_M119(); break;                              // M119: Report Endstop states
13056
      case 120: gcode_M120(); break;                              // M120: Enable Endstops
13057
      case 121: gcode_M121(); break;                              // M121: Disable Endstops
13058
 
13059
      #if ENABLED(ULTIPANEL)
13060
        case 145: gcode_M145(); break;                            // M145: Set material heatup parameters
13061
      #endif
13062
 
13063
      #if ENABLED(TEMPERATURE_UNITS_SUPPORT)
13064
        case 149: gcode_M149(); break;                            // M149: Set Temperature Units, C F K
13065
      #endif
13066
 
13067
      #if HAS_COLOR_LEDS
13068
        case 150: gcode_M150(); break;                            // M150: Set Status LED Color
13069
      #endif
13070
 
13071
      #if ENABLED(MIXING_EXTRUDER)
13072
        case 163: gcode_M163(); break;                            // M163: Set Mixing Component
13073
        #if MIXING_VIRTUAL_TOOLS > 1
13074
          case 164: gcode_M164(); break;                          // M164: Save Current Mix
13075
        #endif
13076
        #if ENABLED(DIRECT_MIXING_IN_G1)
13077
          case 165: gcode_M165(); break;                          // M165: Set Multiple Mixing Components
13078
        #endif
13079
      #endif
13080
 
13081
      #if DISABLED(NO_VOLUMETRICS)
13082
        case 200: gcode_M200(); break;                            // M200: Set Filament Diameter, Volumetric Extrusion
13083
      #endif
13084
 
13085
      case 201: gcode_M201(); break;                              // M201: Set Max Printing Acceleration (units/sec^2)
13086
      #if 0
13087
        case 202: gcode_M202(); break;                            // M202: Not used for Sprinter/grbl gen6
13088
      #endif
13089
      case 203: gcode_M203(); break;                              // M203: Set Max Feedrate (units/sec)
13090
      case 204: gcode_M204(); break;                              // M204: Set Acceleration
13091
      case 205: gcode_M205(); break;                              // M205: Set Advanced settings
13092
 
13093
      #if HAS_M206_COMMAND
13094
        case 206: gcode_M206(); break;                            // M206: Set Home Offsets
13095
        case 428: gcode_M428(); break;                            // M428: Set Home Offsets based on current position
13096
      #endif
13097
 
13098
      #if ENABLED(FWRETRACT)
13099
        case 207: gcode_M207(); break;                            // M207: Set Retract Length, Feedrate, Z lift
13100
        case 208: gcode_M208(); break;                            // M208: Set Additional Prime Length and Feedrate
13101
        case 209:
13102
          if (MIN_AUTORETRACT <= MAX_AUTORETRACT) gcode_M209();   // M209: Turn Auto-Retract on/off
13103
          break;
13104
      #endif
13105
 
13106
      case 211: gcode_M211(); break;                              // M211: Enable/Disable/Report Software Endstops
13107
 
13108
      #if HOTENDS > 1
13109
        case 218: gcode_M218(); break;                            // M218: Set Tool Offset
13110
      #endif
13111
 
13112
      case 220: gcode_M220(); break;                              // M220: Set Feedrate Percentage
13113
      case 221: gcode_M221(); break;                              // M221: Set Flow Percentage
13114
      case 226: gcode_M226(); break;                              // M226: Wait for Pin State
13115
 
13116
      #if defined(CHDK) || HAS_PHOTOGRAPH
13117
        case 240: gcode_M240(); break;                            // M240: Trigger Camera
13118
      #endif
13119
 
13120
      #if HAS_LCD_CONTRAST
13121
        case 250: gcode_M250(); break;                            // M250: Set LCD Contrast
13122
      #endif
13123
 
13124
      #if ENABLED(EXPERIMENTAL_I2CBUS)
13125
        case 260: gcode_M260(); break;                            // M260: Send Data to i2c slave
13126
        case 261: gcode_M261(); break;                            // M261: Request Data from i2c slave
13127
      #endif
13128
 
13129
      #if HAS_SERVOS
13130
        case 280: gcode_M280(); break;                            // M280: Set Servo Position
13131
      #endif
13132
 
13133
      #if ENABLED(BABYSTEPPING)
13134
        case 290: gcode_M290(); break;                            // M290: Babystepping
13135
      #endif
13136
 
13137
      #if HAS_BUZZER
13138
        case 300: gcode_M300(); break;                            // M300: Add Tone/Buzz to Queue
13139
      #endif
13140
 
13141
      #if ENABLED(PIDTEMP)
13142
        case 301: gcode_M301(); break;                            // M301: Set Hotend PID parameters
13143
      #endif
13144
 
13145
      #if ENABLED(PREVENT_COLD_EXTRUSION)
13146
        case 302: gcode_M302(); break;                            // M302: Set Minimum Extrusion Temp
13147
      #endif
13148
 
13149
      case 303: gcode_M303(); break;                              // M303: PID Autotune
13150
 
13151
      #if ENABLED(PIDTEMPBED)
13152
        case 304: gcode_M304(); break;                            // M304: Set Bed PID parameters
13153
      #endif
13154
 
13155
      #if HAS_MICROSTEPS
13156
        case 350: gcode_M350(); break;                            // M350: Set microstepping mode. Warning: Steps per unit remains unchanged. S code sets stepping mode for all drivers.
13157
        case 351: gcode_M351(); break;                            // M351: Toggle MS1 MS2 pins directly, S# determines MS1 or MS2, X# sets the pin high/low.
13158
      #endif
13159
 
13160
      case 355: gcode_M355(); break;                              // M355: Set Case Light brightness
13161
 
13162
      #if ENABLED(MORGAN_SCARA)
13163
        case 360: if (gcode_M360()) return; break;                // M360: SCARA Theta pos1
13164
        case 361: if (gcode_M361()) return; break;                // M361: SCARA Theta pos2
13165
        case 362: if (gcode_M362()) return; break;                // M362: SCARA Psi pos1
13166
        case 363: if (gcode_M363()) return; break;                // M363: SCARA Psi pos2
13167
        case 364: if (gcode_M364()) return; break;                // M364: SCARA Psi pos3 (90 deg to Theta)
13168
      #endif
13169
 
13170
      case 400: gcode_M400(); break;                              // M400: Synchronize. Wait for moves to finish.
13171
 
13172
      #if HAS_BED_PROBE
13173
        case 401: gcode_M401(); break;                            // M401: Deploy Probe
13174
        case 402: gcode_M402(); break;                            // M402: Stow Probe
13175
      #endif
13176
 
13177
      #if ENABLED(FILAMENT_WIDTH_SENSOR)
13178
        case 404: gcode_M404(); break;                            // M404: Set/Report Nominal Filament Width
13179
        case 405: gcode_M405(); break;                            // M405: Enable Filament Width Sensor
13180
        case 406: gcode_M406(); break;                            // M406: Disable Filament Width Sensor
13181
        case 407: gcode_M407(); break;                            // M407: Report Measured Filament Width
13182
      #endif
13183
 
13184
      #if HAS_LEVELING
13185
        case 420: gcode_M420(); break;                            // M420: Set Bed Leveling Enabled / Fade
13186
      #endif
13187
 
13188
      #if HAS_MESH
13189
        case 421: gcode_M421(); break;                            // M421: Set a Mesh Z value
13190
      #endif
13191
 
13192
      case 500: gcode_M500(); break;                              // M500: Store Settings in EEPROM
13193
      case 501: gcode_M501(); break;                              // M501: Read Settings from EEPROM
13194
      case 502: gcode_M502(); break;                              // M502: Revert Settings to defaults
13195
      #if DISABLED(DISABLE_M503)
13196
        case 503: gcode_M503(); break;                            // M503: Report Settings (in SRAM)
13197
      #endif
13198
      #if ENABLED(EEPROM_SETTINGS)
13199
        case 504: gcode_M504(); break;                            // M504: Validate EEPROM
13200
      #endif
13201
 
13202
      #if ENABLED(SDSUPPORT)
13203
        case 524: gcode_M524(); break;                            // M524: Abort SD print job
13204
      #endif
13205
 
13206
      #if ENABLED(ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED)
13207
        case 540: gcode_M540(); break;                            // M540: Set Abort on Endstop Hit for SD Printing
13208
      #endif
13209
 
13210
      #if ENABLED(ADVANCED_PAUSE_FEATURE)
13211
        case 600: gcode_M600(); break;                            // M600: Pause for Filament Change
13212
        case 603: gcode_M603(); break;                            // M603: Configure Filament Change
13213
      #endif
13214
 
13215
      #if ENABLED(DUAL_X_CARRIAGE) || ENABLED(DUAL_NOZZLE_DUPLICATION_MODE)
13216
        case 605: gcode_M605(); break;                            // M605: Set Dual X Carriage movement mode
13217
      #endif
13218
 
13219
      #if ENABLED(DELTA) || ENABLED(HANGPRINTER)
13220
        case 665: gcode_M665(); break;                            // M665: Delta / Hangprinter Configuration
13221
      #endif
13222
      #if ENABLED(DELTA) || ENABLED(X_DUAL_ENDSTOPS) || ENABLED(Y_DUAL_ENDSTOPS) || ENABLED(Z_DUAL_ENDSTOPS)
13223
        case 666: gcode_M666(); break;                            // M666: DELTA/Dual Endstop Adjustment
13224
      #endif
13225
 
13226
      #if ENABLED(FILAMENT_LOAD_UNLOAD_GCODES)
13227
        case 701: gcode_M701(); break;                            // M701: Load Filament
13228
        case 702: gcode_M702(); break;                            // M702: Unload Filament
13229
      #endif
13230
 
13231
      #if ENABLED(MAX7219_GCODE)
13232
        case 7219: gcode_M7219(); break;                          // M7219: Set LEDs, columns, and rows
13233
      #endif
13234
 
13235
      #if ENABLED(DEBUG_GCODE_PARSER)
13236
        case 800: parser.debug(); break;                          // M800: GCode Parser Test for M
13237
      #endif
13238
 
13239
      #if HAS_BED_PROBE
13240
        case 851: gcode_M851(); break;                            // M851: Set Z Probe Z Offset
13241
      #endif
13242
 
13243
      #if ENABLED(SKEW_CORRECTION_GCODE)
13244
        case 852: gcode_M852(); break;                            // M852: Set Skew factors
13245
      #endif
13246
 
13247
      #if ENABLED(I2C_POSITION_ENCODERS)
13248
        case 860: gcode_M860(); break;                            // M860: Report encoder module position
13249
        case 861: gcode_M861(); break;                            // M861: Report encoder module status
13250
        case 862: gcode_M862(); break;                            // M862: Perform axis test
13251
        case 863: gcode_M863(); break;                            // M863: Calibrate steps/mm
13252
        case 864: gcode_M864(); break;                            // M864: Change module address
13253
        case 865: gcode_M865(); break;                            // M865: Check module firmware version
13254
        case 866: gcode_M866(); break;                            // M866: Report axis error count
13255
        case 867: gcode_M867(); break;                            // M867: Toggle error correction
13256
        case 868: gcode_M868(); break;                            // M868: Set error correction threshold
13257
        case 869: gcode_M869(); break;                            // M869: Report axis error
13258
      #endif
13259
 
13260
      #if ENABLED(LIN_ADVANCE)
13261
        case 900: gcode_M900(); break;                            // M900: Set Linear Advance K factor
13262
      #endif
13263
 
13264
      case 907: gcode_M907(); break;                              // M907: Set Digital Trimpot Motor Current using axis codes.
13265
 
13266
      #if HAS_DIGIPOTSS || ENABLED(DAC_STEPPER_CURRENT)
13267
        case 908: gcode_M908(); break;                            // M908: Direct Control Digital Trimpot
13268
        #if ENABLED(DAC_STEPPER_CURRENT)
13269
          case 909: gcode_M909(); break;                          // M909: Print Digipot/DAC current value (As with Printrbot RevF)
13270
          case 910: gcode_M910(); break;                          // M910: Commit Digipot/DAC value to External EEPROM (As with Printrbot RevF)
13271
        #endif
13272
      #endif
13273
 
13274
      #if HAS_DRIVER(TMC2130) || HAS_DRIVER(TMC2208)
13275
        #if ENABLED(TMC_DEBUG)
13276
          case 122: gcode_M122(); break;                          // M122: Debug TMC steppers
13277
        #endif
13278
        case 906: gcode_M906(); break;                            // M906: Set motor current in milliamps using axis codes X, Y, Z, E
13279
        case 911: gcode_M911(); break;                            // M911: Report TMC prewarn triggered flags
13280
        case 912: gcode_M912(); break;                            // M911: Clear TMC prewarn triggered flags
13281
        #if ENABLED(HYBRID_THRESHOLD)
13282
          case 913: gcode_M913(); break;                          // M913: Set HYBRID_THRESHOLD speed.
13283
        #endif
13284
        #if ENABLED(SENSORLESS_HOMING)
13285
          case 914: gcode_M914(); break;                          // M914: Set SENSORLESS_HOMING sensitivity.
13286
        #endif
13287
        #if ENABLED(TMC_Z_CALIBRATION)
13288
          case 915: gcode_M915(); break;                          // M915: TMC Z axis calibration routine
13289
        #endif
13290
      #endif
13291
 
13292
      case 999: gcode_M999(); break;                              // M999: Restart after being Stopped
13293
 
13294
      default: parser.unknown_command_error();
13295
    }
13296
    break;
13297
 
13298
    case 'T': gcode_T(parser.codenum); break;                     // T: Tool Select
13299
 
13300
    default: parser.unknown_command_error();
13301
  }
13302
 
13303
  KEEPALIVE_STATE(NOT_BUSY);
13304
  ok_to_send();
13305
}
13306
 
13307
void process_next_command() {
13308
  char * const current_command = command_queue[cmd_queue_index_r];
13309
 
13310
  if (DEBUGGING(ECHO)) {
13311
    SERIAL_ECHO_START();
13312
    SERIAL_ECHOLN(current_command);
13313
    #if ENABLED(M100_FREE_MEMORY_WATCHER)
13314
      SERIAL_ECHOPAIR("slot:", cmd_queue_index_r);
13315
      M100_dump_routine("   Command Queue:", (const char*)command_queue, (const char*)(command_queue + sizeof(command_queue)));
13316
    #endif
13317
  }
13318
 
13319
  // Parse the next command in the queue
13320
  parser.parse(current_command);
13321
  process_parsed_command();
13322
}
13323
 
13324
/**
13325
 * Send a "Resend: nnn" message to the host to
13326
 * indicate that a command needs to be re-sent.
13327
 */
13328
void flush_and_request_resend() {
13329
  //char command_queue[cmd_queue_index_r][100]="Resend:";
13330
  SERIAL_FLUSH();
13331
  SERIAL_PROTOCOLPGM(MSG_RESEND);
13332
  SERIAL_PROTOCOLLN(gcode_LastN + 1);
13333
  ok_to_send();
13334
}
13335
 
13336
/**
13337
 * Send an "ok" message to the host, indicating
13338
 * that a command was successfully processed.
13339
 *
13340
 * If ADVANCED_OK is enabled also include:
13341
 *   N<int>  Line number of the command, if any
13342
 *   P<int>  Planner space remaining
13343
 *   B<int>  Block queue space remaining
13344
 */
13345
void ok_to_send() {
13346
  if (!send_ok[cmd_queue_index_r]) return;
13347
  SERIAL_PROTOCOLPGM(MSG_OK);
13348
  #if ENABLED(ADVANCED_OK)
13349
    char* p = command_queue[cmd_queue_index_r];
13350
    if (*p == 'N') {
13351
      SERIAL_PROTOCOL(' ');
13352
      SERIAL_ECHO(*p++);
13353
      while (NUMERIC_SIGNED(*p))
13354
        SERIAL_ECHO(*p++);
13355
    }
13356
    SERIAL_PROTOCOLPGM(" P"); SERIAL_PROTOCOL(int(BLOCK_BUFFER_SIZE - planner.movesplanned() - 1));
13357
    SERIAL_PROTOCOLPGM(" B"); SERIAL_PROTOCOL(BUFSIZE - commands_in_queue);
13358
  #endif
13359
  SERIAL_EOL();
13360
}
13361
 
13362
#if HAS_SOFTWARE_ENDSTOPS
13363
 
13364
  /**
13365
   * Constrain the given coordinates to the software endstops.
13366
   *
13367
   * For DELTA/SCARA the XY constraint is based on the smallest
13368
   * radius within the set software endstops.
13369
   */
13370
  void clamp_to_software_endstops(float target[XYZ]) {
13371
    if (!soft_endstops_enabled) return;
13372
    #if IS_KINEMATIC
13373
      const float dist_2 = HYPOT2(target[X_AXIS], target[Y_AXIS]);
13374
      if (dist_2 > soft_endstop_radius_2) {
13375
        const float ratio = soft_endstop_radius / SQRT(dist_2); // 200 / 300 = 0.66
13376
        target[X_AXIS] *= ratio;
13377
        target[Y_AXIS] *= ratio;
13378
      }
13379
    #else
13380
      #if ENABLED(MIN_SOFTWARE_ENDSTOP_X)
13381
        NOLESS(target[X_AXIS], soft_endstop_min[X_AXIS]);
13382
      #endif
13383
      #if ENABLED(MIN_SOFTWARE_ENDSTOP_Y)
13384
        NOLESS(target[Y_AXIS], soft_endstop_min[Y_AXIS]);
13385
      #endif
13386
      #if ENABLED(MAX_SOFTWARE_ENDSTOP_X)
13387
        NOMORE(target[X_AXIS], soft_endstop_max[X_AXIS]);
13388
      #endif
13389
      #if ENABLED(MAX_SOFTWARE_ENDSTOP_Y)
13390
        NOMORE(target[Y_AXIS], soft_endstop_max[Y_AXIS]);
13391
      #endif
13392
    #endif
13393
    #if ENABLED(MIN_SOFTWARE_ENDSTOP_Z)
13394
      NOLESS(target[Z_AXIS], soft_endstop_min[Z_AXIS]);
13395
    #endif
13396
    #if ENABLED(MAX_SOFTWARE_ENDSTOP_Z)
13397
      NOMORE(target[Z_AXIS], soft_endstop_max[Z_AXIS]);
13398
    #endif
13399
  }
13400
 
13401
#endif
13402
 
13403
#if ENABLED(AUTO_BED_LEVELING_BILINEAR)
13404
 
13405
  // Get the Z adjustment for non-linear bed leveling
13406
  float bilinear_z_offset(const float raw[XYZ]) {
13407
 
13408
    static float z1, d2, z3, d4, L, D, ratio_x, ratio_y,
13409
                 last_x = -999.999, last_y = -999.999;
13410
 
13411
    // Whole units for the grid line indices. Constrained within bounds.
13412
    static int8_t gridx, gridy, nextx, nexty,
13413
                  last_gridx = -99, last_gridy = -99;
13414
 
13415
    // XY relative to the probed area
13416
    const float rx = raw[X_AXIS] - bilinear_start[X_AXIS],
13417
                ry = raw[Y_AXIS] - bilinear_start[Y_AXIS];
13418
 
13419
    #if ENABLED(EXTRAPOLATE_BEYOND_GRID)
13420
      // Keep using the last grid box
13421
      #define FAR_EDGE_OR_BOX 2
13422
    #else
13423
      // Just use the grid far edge
13424
      #define FAR_EDGE_OR_BOX 1
13425
    #endif
13426
 
13427
    if (last_x != rx) {
13428
      last_x = rx;
13429
      ratio_x = rx * ABL_BG_FACTOR(X_AXIS);
13430
      const float gx = constrain(FLOOR(ratio_x), 0, ABL_BG_POINTS_X - FAR_EDGE_OR_BOX);
13431
      ratio_x -= gx;      // Subtract whole to get the ratio within the grid box
13432
 
13433
      #if DISABLED(EXTRAPOLATE_BEYOND_GRID)
13434
        // Beyond the grid maintain height at grid edges
13435
        NOLESS(ratio_x, 0); // Never < 0.0. (> 1.0 is ok when nextx==gridx.)
13436
      #endif
13437
 
13438
      gridx = gx;
13439
      nextx = MIN(gridx + 1, ABL_BG_POINTS_X - 1);
13440
    }
13441
 
13442
    if (last_y != ry || last_gridx != gridx) {
13443
 
13444
      if (last_y != ry) {
13445
        last_y = ry;
13446
        ratio_y = ry * ABL_BG_FACTOR(Y_AXIS);
13447
        const float gy = constrain(FLOOR(ratio_y), 0, ABL_BG_POINTS_Y - FAR_EDGE_OR_BOX);
13448
        ratio_y -= gy;
13449
 
13450
        #if DISABLED(EXTRAPOLATE_BEYOND_GRID)
13451
          // Beyond the grid maintain height at grid edges
13452
          NOLESS(ratio_y, 0); // Never < 0.0. (> 1.0 is ok when nexty==gridy.)
13453
        #endif
13454
 
13455
        gridy = gy;
13456
        nexty = MIN(gridy + 1, ABL_BG_POINTS_Y - 1);
13457
      }
13458
 
13459
      if (last_gridx != gridx || last_gridy != gridy) {
13460
        last_gridx = gridx;
13461
        last_gridy = gridy;
13462
        // Z at the box corners
13463
        z1 = ABL_BG_GRID(gridx, gridy);       // left-front
13464
        d2 = ABL_BG_GRID(gridx, nexty) - z1;  // left-back (delta)
13465
        z3 = ABL_BG_GRID(nextx, gridy);       // right-front
13466
        d4 = ABL_BG_GRID(nextx, nexty) - z3;  // right-back (delta)
13467
      }
13468
 
13469
      // Bilinear interpolate. Needed since ry or gridx has changed.
13470
                  L = z1 + d2 * ratio_y;   // Linear interp. LF -> LB
13471
      const float R = z3 + d4 * ratio_y;   // Linear interp. RF -> RB
13472
 
13473
      D = R - L;
13474
    }
13475
 
13476
    const float offset = L + ratio_x * D;   // the offset almost always changes
13477
 
13478
    /*
13479
    static float last_offset = 0;
13480
    if (ABS(last_offset - offset) > 0.2) {
13481
      SERIAL_ECHOPGM("Sudden Shift at ");
13482
      SERIAL_ECHOPAIR("x=", rx);
13483
      SERIAL_ECHOPAIR(" / ", bilinear_grid_spacing[X_AXIS]);
13484
      SERIAL_ECHOLNPAIR(" -> gridx=", gridx);
13485
      SERIAL_ECHOPAIR(" y=", ry);
13486
      SERIAL_ECHOPAIR(" / ", bilinear_grid_spacing[Y_AXIS]);
13487
      SERIAL_ECHOLNPAIR(" -> gridy=", gridy);
13488
      SERIAL_ECHOPAIR(" ratio_x=", ratio_x);
13489
      SERIAL_ECHOLNPAIR(" ratio_y=", ratio_y);
13490
      SERIAL_ECHOPAIR(" z1=", z1);
13491
      SERIAL_ECHOPAIR(" z2=", z2);
13492
      SERIAL_ECHOPAIR(" z3=", z3);
13493
      SERIAL_ECHOLNPAIR(" z4=", z4);
13494
      SERIAL_ECHOPAIR(" L=", L);
13495
      SERIAL_ECHOPAIR(" R=", R);
13496
      SERIAL_ECHOLNPAIR(" offset=", offset);
13497
    }
13498
    last_offset = offset;
13499
    //*/
13500
 
13501
    return offset;
13502
  }
13503
 
13504
#endif // AUTO_BED_LEVELING_BILINEAR
13505
 
13506
#if ENABLED(DELTA)
13507
 
13508
  /**
13509
   * Recalculate factors used for delta kinematics whenever
13510
   * settings have been changed (e.g., by M665).
13511
   */
13512
  void recalc_delta_settings() {
13513
    const float trt[ABC] = DELTA_RADIUS_TRIM_TOWER,
13514
                drt[ABC] = DELTA_DIAGONAL_ROD_TRIM_TOWER;
13515
    delta_tower[A_AXIS][X_AXIS] = cos(RADIANS(210 + delta_tower_angle_trim[A_AXIS])) * (delta_radius + trt[A_AXIS]); // front left tower
13516
    delta_tower[A_AXIS][Y_AXIS] = sin(RADIANS(210 + delta_tower_angle_trim[A_AXIS])) * (delta_radius + trt[A_AXIS]);
13517
    delta_tower[B_AXIS][X_AXIS] = cos(RADIANS(330 + delta_tower_angle_trim[B_AXIS])) * (delta_radius + trt[B_AXIS]); // front right tower
13518
    delta_tower[B_AXIS][Y_AXIS] = sin(RADIANS(330 + delta_tower_angle_trim[B_AXIS])) * (delta_radius + trt[B_AXIS]);
13519
    delta_tower[C_AXIS][X_AXIS] = cos(RADIANS( 90 + delta_tower_angle_trim[C_AXIS])) * (delta_radius + trt[C_AXIS]); // back middle tower
13520
    delta_tower[C_AXIS][Y_AXIS] = sin(RADIANS( 90 + delta_tower_angle_trim[C_AXIS])) * (delta_radius + trt[C_AXIS]);
13521
    delta_diagonal_rod_2_tower[A_AXIS] = sq(delta_diagonal_rod + drt[A_AXIS]);
13522
    delta_diagonal_rod_2_tower[B_AXIS] = sq(delta_diagonal_rod + drt[B_AXIS]);
13523
    delta_diagonal_rod_2_tower[C_AXIS] = sq(delta_diagonal_rod + drt[C_AXIS]);
13524
    update_software_endstops(Z_AXIS);
13525
    axis_homed = 0;
13526
  }
13527
 
13528
  /**
13529
   * Delta Inverse Kinematics
13530
   *
13531
   * Calculate the tower positions for a given machine
13532
   * position, storing the result in the delta[] array.
13533
   *
13534
   * This is an expensive calculation, requiring 3 square
13535
   * roots per segmented linear move, and strains the limits
13536
   * of a Mega2560 with a Graphical Display.
13537
   *
13538
   * Suggested optimizations include:
13539
   *
13540
   * - Disable the home_offset (M206) and/or position_shift (G92)
13541
   *   features to remove up to 12 float additions.
13542
   */
13543
 
13544
  #define DELTA_DEBUG(VAR) do { \
13545
      SERIAL_ECHOPAIR("cartesian X:", VAR[X_AXIS]); \
13546
      SERIAL_ECHOPAIR(" Y:", VAR[Y_AXIS]);          \
13547
      SERIAL_ECHOLNPAIR(" Z:", VAR[Z_AXIS]);        \
13548
      SERIAL_ECHOPAIR("delta A:", delta[A_AXIS]);   \
13549
      SERIAL_ECHOPAIR(" B:", delta[B_AXIS]);        \
13550
      SERIAL_ECHOLNPAIR(" C:", delta[C_AXIS]);      \
13551
    }while(0)
13552
 
13553
  void inverse_kinematics(const float raw[XYZ]) {
13554
    #if HOTENDS > 1
13555
      // Delta hotend offsets must be applied in Cartesian space with no "spoofing"
13556
      const float pos[XYZ] = {
13557
        raw[X_AXIS] - hotend_offset[X_AXIS][active_extruder],
13558
        raw[Y_AXIS] - hotend_offset[Y_AXIS][active_extruder],
13559
        raw[Z_AXIS]
13560
      };
13561
      DELTA_IK(pos);
13562
      //DELTA_DEBUG(pos);
13563
    #else
13564
      DELTA_IK(raw);
13565
      //DELTA_DEBUG(raw);
13566
    #endif
13567
  }
13568
 
13569
  /**
13570
   * Calculate the highest Z position where the
13571
   * effector has the full range of XY motion.
13572
   */
13573
  float delta_safe_distance_from_top() {
13574
    float cartesian[XYZ] = { 0, 0, 0 };
13575
    inverse_kinematics(cartesian);
13576
    const float centered_extent = delta[A_AXIS];
13577
    cartesian[Y_AXIS] = DELTA_PRINTABLE_RADIUS;
13578
    inverse_kinematics(cartesian);
13579
    return ABS(centered_extent - delta[A_AXIS]);
13580
  }
13581
 
13582
  /**
13583
   * Delta Forward Kinematics
13584
   *
13585
   * See the Wikipedia article "Trilateration"
13586
   * https://en.wikipedia.org/wiki/Trilateration
13587
   *
13588
   * Establish a new coordinate system in the plane of the
13589
   * three carriage points. This system has its origin at
13590
   * tower1, with tower2 on the X axis. Tower3 is in the X-Y
13591
   * plane with a Z component of zero.
13592
   * We will define unit vectors in this coordinate system
13593
   * in our original coordinate system. Then when we calculate
13594
   * the Xnew, Ynew and Znew values, we can translate back into
13595
   * the original system by moving along those unit vectors
13596
   * by the corresponding values.
13597
   *
13598
   * Variable names matched to Marlin, c-version, and avoid the
13599
   * use of any vector library.
13600
   *
13601
   * by Andreas Hardtung 2016-06-07
13602
   * based on a Java function from "Delta Robot Kinematics V3"
13603
   * by Steve Graves
13604
   *
13605
   * The result is stored in the cartes[] array.
13606
   */
13607
  void forward_kinematics_DELTA(const float &z1, const float &z2, const float &z3) {
13608
    // Create a vector in old coordinates along x axis of new coordinate
13609
    const float p12[] = {
13610
      delta_tower[B_AXIS][X_AXIS] - delta_tower[A_AXIS][X_AXIS],
13611
      delta_tower[B_AXIS][Y_AXIS] - delta_tower[A_AXIS][Y_AXIS],
13612
      z2 - z1
13613
    },
13614
 
13615
    // Get the reciprocal of Magnitude of vector.
13616
    d2 = sq(p12[0]) + sq(p12[1]) + sq(p12[2]), inv_d = RSQRT(d2),
13617
 
13618
    // Create unit vector by multiplying by the inverse of the magnitude.
13619
    ex[3] = { p12[0] * inv_d, p12[1] * inv_d, p12[2] * inv_d },
13620
 
13621
    // Get the vector from the origin of the new system to the third point.
13622
    p13[3] = {
13623
      delta_tower[C_AXIS][X_AXIS] - delta_tower[A_AXIS][X_AXIS],
13624
      delta_tower[C_AXIS][Y_AXIS] - delta_tower[A_AXIS][Y_AXIS],
13625
      z3 - z1
13626
    },
13627
 
13628
    // Use the dot product to find the component of this vector on the X axis.
13629
    i = ex[0] * p13[0] + ex[1] * p13[1] + ex[2] * p13[2],
13630
 
13631
    // Create a vector along the x axis that represents the x component of p13.
13632
    iex[] = { ex[0] * i, ex[1] * i, ex[2] * i };
13633
 
13634
    // Subtract the X component from the original vector leaving only Y. We use the
13635
    // variable that will be the unit vector after we scale it.
13636
    float ey[3] = { p13[0] - iex[0], p13[1] - iex[1], p13[2] - iex[2] };
13637
 
13638
    // The magnitude and the inverse of the magnitude of Y component
13639
    const float j2 = sq(ey[0]) + sq(ey[1]) + sq(ey[2]), inv_j = RSQRT(j2);
13640
 
13641
    // Convert to a unit vector
13642
    ey[0] *= inv_j; ey[1] *= inv_j;  ey[2] *= inv_j;
13643
 
13644
    // The cross product of the unit x and y is the unit z
13645
    // float[] ez = vectorCrossProd(ex, ey);
13646
    const float ez[3] = {
13647
      ex[1] * ey[2] - ex[2] * ey[1],
13648
      ex[2] * ey[0] - ex[0] * ey[2],
13649
      ex[0] * ey[1] - ex[1] * ey[0]
13650
    },
13651
    // We now have the d, i and j values defined in Wikipedia.
13652
    // Plug them into the equations defined in Wikipedia for Xnew, Ynew and Znew
13653
    Xnew = (delta_diagonal_rod_2_tower[A_AXIS] - delta_diagonal_rod_2_tower[B_AXIS] + d2) * inv_d * 0.5,
13654
    Ynew = ((delta_diagonal_rod_2_tower[A_AXIS] - delta_diagonal_rod_2_tower[C_AXIS] + sq(i) + j2) * 0.5 - i * Xnew) * inv_j,
13655
    Znew = SQRT(delta_diagonal_rod_2_tower[A_AXIS] - HYPOT2(Xnew, Ynew));
13656
 
13657
    // Start from the origin of the old coordinates and add vectors in the
13658
    // old coords that represent the Xnew, Ynew and Znew to find the point
13659
    // in the old system.
13660
    cartes[X_AXIS] = delta_tower[A_AXIS][X_AXIS] + ex[0] * Xnew + ey[0] * Ynew - ez[0] * Znew;
13661
    cartes[Y_AXIS] = delta_tower[A_AXIS][Y_AXIS] + ex[1] * Xnew + ey[1] * Ynew - ez[1] * Znew;
13662
    cartes[Z_AXIS] =                          z1 + ex[2] * Xnew + ey[2] * Ynew - ez[2] * Znew;
13663
  }
13664
 
13665
  void forward_kinematics_DELTA(const float (&point)[ABC]) {
13666
    forward_kinematics_DELTA(point[A_AXIS], point[B_AXIS], point[C_AXIS]);
13667
  }
13668
 
13669
#endif // DELTA
13670
 
13671
#if ENABLED(HANGPRINTER)
13672
 
13673
  /**
13674
   * Recalculate factors used for hangprinter kinematics whenever
13675
   * settings have been changed (e.g., by M665).
13676
   */
13677
  void recalc_hangprinter_settings(){
13678
    HANGPRINTER_IK_ORIGIN(line_lengths_origin);
13679
 
13680
    #if ENABLED(LINE_BUILDUP_COMPENSATION_FEATURE)
13681
 
13682
      const uint8_t mech_adv_tmp[MOV_AXIS] = MECHANICAL_ADVANTAGE,
13683
                    actn_pts_tmp[MOV_AXIS] = ACTION_POINTS;
13684
      const uint16_t m_g_t_tmp[MOV_AXIS]   = MOTOR_GEAR_TEETH,
13685
                     s_g_t_tmp[MOV_AXIS]   = SPOOL_GEAR_TEETH;
13686
      const float mnt_l_tmp[MOV_AXIS]      = MOUNTED_LINE;
13687
      float s_r2_tmp[MOV_AXIS]             = SPOOL_RADII,
13688
            steps_per_unit_times_r_tmp[MOV_AXIS];
13689
      uint8_t nr_lines_dir_tmp[MOV_AXIS];
13690
 
13691
      LOOP_MOV_AXIS(i){
13692
        steps_per_unit_times_r_tmp[i] = (float(mech_adv_tmp[i])*STEPS_PER_MOTOR_REVOLUTION*s_g_t_tmp[i])/(2*M_PI*m_g_t_tmp[i]);
13693
        nr_lines_dir_tmp[i] = mech_adv_tmp[i]*actn_pts_tmp[i];
13694
        s_r2_tmp[i] *= s_r2_tmp[i];
13695
        planner.k2[i] = -(float)nr_lines_dir_tmp[i]*SPOOL_BUILDUP_FACTOR;
13696
        planner.k0[i] = 2.0*steps_per_unit_times_r_tmp[i]/planner.k2[i];
13697
      }
13698
 
13699
      // Assumes spools are mounted near D-anchor in ceiling
13700
      #define HYP3D(x,y,z) SQRT(sq(x) + sq(y) + sq(z))
13701
      float line_on_spool_origin_tmp[MOV_AXIS];
13702
      line_on_spool_origin_tmp[A_AXIS] = actn_pts_tmp[A_AXIS] * mnt_l_tmp[A_AXIS]
13703
                                         - actn_pts_tmp[A_AXIS] * HYPOT(anchor_A_y, anchor_D_z - anchor_A_z)
13704
                                         - nr_lines_dir_tmp[A_AXIS] * line_lengths_origin[A_AXIS];
13705
      line_on_spool_origin_tmp[B_AXIS] = actn_pts_tmp[B_AXIS] * mnt_l_tmp[B_AXIS]
13706
                                         - actn_pts_tmp[B_AXIS] * HYP3D(anchor_B_x, anchor_B_y, anchor_D_z - anchor_B_z)
13707
                                         - nr_lines_dir_tmp[B_AXIS] * line_lengths_origin[B_AXIS];
13708
      line_on_spool_origin_tmp[C_AXIS] = actn_pts_tmp[C_AXIS] * mnt_l_tmp[C_AXIS]
13709
                                         - actn_pts_tmp[C_AXIS] * HYP3D(anchor_C_x, anchor_C_y, anchor_D_z - anchor_C_z)
13710
                                         - nr_lines_dir_tmp[C_AXIS] * line_lengths_origin[C_AXIS];
13711
      line_on_spool_origin_tmp[D_AXIS] = actn_pts_tmp[D_AXIS] * mnt_l_tmp[D_AXIS]
13712
                                         - nr_lines_dir_tmp[D_AXIS] * line_lengths_origin[D_AXIS];
13713
 
13714
      LOOP_MOV_AXIS(i) {
13715
        planner.axis_steps_per_mm[i] = steps_per_unit_times_r_tmp[i] /
13716
            SQRT((SPOOL_BUILDUP_FACTOR) * line_on_spool_origin_tmp[i] + s_r2_tmp[i]);
13717
        planner.k1[i] = (SPOOL_BUILDUP_FACTOR) *
13718
          (line_on_spool_origin_tmp[i] + nr_lines_dir_tmp[i] * line_lengths_origin[i]) + s_r2_tmp[i];
13719
 
13720
        planner.sqrtk1[i] = SQRT(planner.k1[i]);
13721
      }
13722
      planner.axis_steps_per_mm[E_AXIS] = DEFAULT_E_AXIS_STEPS_PER_UNIT;
13723
 
13724
    #endif // LINE_BUILDUP_COMPENSATION_FEATURE
13725
 
13726
    SYNC_PLAN_POSITION_KINEMATIC(); // recalcs line lengths in case anchor was moved
13727
  }
13728
 
13729
  /**
13730
   * Hangprinter inverse kinematics
13731
   */
13732
  void inverse_kinematics(const float raw[XYZ]) {
13733
    HANGPRINTER_IK(raw);
13734
  }
13735
 
13736
  /**
13737
   * Hangprinter forward kinematics
13738
   * Basic idea is to subtract squared line lengths to get linear equations.
13739
   * Subtracting d*d from a*a, b*b, and c*c gives the cleanest derivation:
13740
   *
13741
   *  a*a - d*d = k1        +  k2*y +  k3*z     <---- a line  (I)
13742
   *  b*b - d*d = k4 + k5*x +  k6*y +  k7*z     <---- a plane (II)
13743
   *  c*c - d*d = k8 + k9*x + k10*y + k11*z     <---- a plane (III)
13744
   *
13745
   * Use (I) to reduce (II) and (III) into lines. Eliminate y, keep z.
13746
   *
13747
   *  (II):  b*b - d*d = k12 + k13*x + k14*z
13748
   *  <=>            x = k0b + k1b*z,           <---- a line  (IV)
13749
   *
13750
   *  (III): c*c - d*d = k15 + k16*x + k17*z
13751
   *  <=>            x = k0c + k1c*z,           <---- a line  (V)
13752
   *
13753
   * where k1, k2, ..., k17, k0b, k0c, k1b, and k1c are known constants.
13754
   *
13755
   * These two straight lines are not parallel, so they will cross in exactly one point.
13756
   * Find z by setting (IV) = (V)
13757
   * Find x by inserting z into (V)
13758
   * Find y by inserting z into (I)
13759
   *
13760
   * Warning: truncation errors will typically be in the order of a few tens of microns.
13761
   */
13762
  void forward_kinematics_HANGPRINTER(float a, float b, float c, float d){
13763
    const float Asq =                  sq(anchor_A_y) + sq(anchor_A_z),
13764
                Bsq = sq(anchor_B_x) + sq(anchor_B_y) + sq(anchor_B_z),
13765
                Csq = sq(anchor_C_x) + sq(anchor_C_y) + sq(anchor_C_z),
13766
                Dsq =                                   sq(anchor_D_z),
13767
                aa = sq(a),
13768
                dd = sq(d),
13769
                k0b = (-sq(b) + Bsq - Dsq + dd) / (2.0 * anchor_B_x) + (anchor_B_y / (2.0 * anchor_A_y * anchor_B_x)) * (Dsq - Asq + aa - dd),
13770
                k0c = (-sq(c) + Csq - Dsq + dd) / (2.0 * anchor_C_x) + (anchor_C_y / (2.0 * anchor_A_y * anchor_C_x)) * (Dsq - Asq + aa - dd),
13771
                k1b = (anchor_B_y * (anchor_A_z - anchor_D_z)) / (anchor_A_y * anchor_B_x) + (anchor_D_z - anchor_B_z) / anchor_B_x,
13772
                k1c = (anchor_C_y * (anchor_A_z - anchor_D_z)) / (anchor_A_y * anchor_C_x) + (anchor_D_z - anchor_C_z) / anchor_C_x;
13773
 
13774
    cartes[Z_AXIS] = (k0b - k0c) / (k1c - k1b);
13775
    cartes[X_AXIS] = k0c + k1c * cartes[Z_AXIS];
13776
    cartes[Y_AXIS] = (Asq - Dsq - aa + dd) / (2.0 * anchor_A_y) + ((anchor_D_z - anchor_A_z) / anchor_A_y) * cartes[Z_AXIS];
13777
  }
13778
#endif // HANGPRINTER
13779
 
13780
/**
13781
 * Get the stepper positions in the cartes[] array.
13782
 * Forward kinematics are applied for DELTA and SCARA.
13783
 *
13784
 * The result is in the current coordinate space with
13785
 * leveling applied. The coordinates need to be run through
13786
 * unapply_leveling to obtain machine coordinates suitable
13787
 * for current_position, etc.
13788
 */
13789
void get_cartesian_from_steppers() {
13790
  #if ENABLED(DELTA)
13791
    forward_kinematics_DELTA(
13792
      planner.get_axis_position_mm(A_AXIS),
13793
      planner.get_axis_position_mm(B_AXIS),
13794
      planner.get_axis_position_mm(C_AXIS)
13795
    );
13796
  #elif ENABLED(HANGPRINTER)
13797
    forward_kinematics_HANGPRINTER(
13798
      planner.get_axis_position_mm(A_AXIS),
13799
      planner.get_axis_position_mm(B_AXIS),
13800
      planner.get_axis_position_mm(C_AXIS),
13801
      planner.get_axis_position_mm(D_AXIS)
13802
    );
13803
  #else
13804
    #if IS_SCARA
13805
      forward_kinematics_SCARA(
13806
        planner.get_axis_position_degrees(A_AXIS),
13807
        planner.get_axis_position_degrees(B_AXIS)
13808
      );
13809
    #else
13810
      cartes[X_AXIS] = planner.get_axis_position_mm(X_AXIS);
13811
      cartes[Y_AXIS] = planner.get_axis_position_mm(Y_AXIS);
13812
    #endif
13813
    cartes[Z_AXIS] = planner.get_axis_position_mm(Z_AXIS);
13814
  #endif
13815
}
13816
 
13817
/**
13818
 * Set the current_position for an axis based on
13819
 * the stepper positions, removing any leveling that
13820
 * may have been applied.
13821
 *
13822
 * To prevent small shifts in axis position always call
13823
 * SYNC_PLAN_POSITION_KINEMATIC after updating axes with this.
13824
 *
13825
 * To keep hosts in sync, always call report_current_position
13826
 * after updating the current_position.
13827
 */
13828
void set_current_from_steppers_for_axis(const AxisEnum axis) {
13829
  get_cartesian_from_steppers();
13830
  #if PLANNER_LEVELING
13831
    planner.unapply_leveling(cartes);
13832
  #endif
13833
  if (axis == ALL_AXES)
13834
    COPY(current_position, cartes);
13835
  else
13836
    current_position[axis] = cartes[axis];
13837
}
13838
 
13839
#if IS_CARTESIAN
13840
#if ENABLED(SEGMENT_LEVELED_MOVES)
13841
 
13842
  /**
13843
   * Prepare a segmented move on a CARTESIAN setup.
13844
   *
13845
   * This calls planner.buffer_line several times, adding
13846
   * small incremental moves. This allows the planner to
13847
   * apply more detailed bed leveling to the full move.
13848
   */
13849
  inline void segmented_line_to_destination(const float &fr_mm_s, const float segment_size=LEVELED_SEGMENT_LENGTH) {
13850
 
13851
    const float xdiff = destination[X_AXIS] - current_position[X_AXIS],
13852
                ydiff = destination[Y_AXIS] - current_position[Y_AXIS];
13853
 
13854
    // If the move is only in Z/E don't split up the move
13855
    if (!xdiff && !ydiff) {
13856
      planner.buffer_line_kinematic(destination, fr_mm_s, active_extruder);
13857
      return;
13858
    }
13859
 
13860
    // Remaining cartesian distances
13861
    const float zdiff = destination[Z_AXIS] - current_position[Z_AXIS],
13862
                ediff = destination[E_CART] - current_position[E_CART];
13863
 
13864
    // Get the linear distance in XYZ
13865
    // If the move is very short, check the E move distance
13866
    // No E move either? Game over.
13867
    float cartesian_mm = SQRT(sq(xdiff) + sq(ydiff) + sq(zdiff));
13868
    if (UNEAR_ZERO(cartesian_mm)) cartesian_mm = ABS(ediff);
13869
    if (UNEAR_ZERO(cartesian_mm)) return;
13870
 
13871
    // The length divided by the segment size
13872
    // At least one segment is required
13873
    uint16_t segments = cartesian_mm / segment_size;
13874
    NOLESS(segments, 1);
13875
 
13876
    // The approximate length of each segment
13877
    const float inv_segments = 1.0f / float(segments),
13878
                cartesian_segment_mm = cartesian_mm * inv_segments,
13879
                segment_distance[XYZE] = {
13880
                  xdiff * inv_segments,
13881
                  ydiff * inv_segments,
13882
                  zdiff * inv_segments,
13883
                  ediff * inv_segments
13884
                };
13885
 
13886
    // SERIAL_ECHOPAIR("mm=", cartesian_mm);
13887
    // SERIAL_ECHOLNPAIR(" segments=", segments);
13888
    // SERIAL_ECHOLNPAIR(" segment_mm=", cartesian_segment_mm);
13889
 
13890
    // Get the raw current position as starting point
13891
    float raw[XYZE];
13892
    COPY(raw, current_position);
13893
 
13894
    // Calculate and execute the segments
13895
    while (--segments) {
13896
      static millis_t next_idle_ms = millis() + 200UL;
13897
      thermalManager.manage_heater();  // This returns immediately if not really needed.
13898
      if (ELAPSED(millis(), next_idle_ms)) {
13899
        next_idle_ms = millis() + 200UL;
13900
        idle();
13901
      }
13902
      LOOP_XYZE(i) raw[i] += segment_distance[i];
13903
      if (!planner.buffer_line_kinematic(raw, fr_mm_s, active_extruder, cartesian_segment_mm))
13904
        break;
13905
    }
13906
 
13907
    // Since segment_distance is only approximate,
13908
    // the final move must be to the exact destination.
13909
    planner.buffer_line_kinematic(destination, fr_mm_s, active_extruder, cartesian_segment_mm);
13910
  }
13911
 
13912
#elif ENABLED(MESH_BED_LEVELING)
13913
 
13914
  /**
13915
   * Prepare a mesh-leveled linear move in a Cartesian setup,
13916
   * splitting the move where it crosses mesh borders.
13917
   */
13918
  void mesh_line_to_destination(const float fr_mm_s, uint8_t x_splits=0xFF, uint8_t y_splits=0xFF) {
13919
    // Get current and destination cells for this line
13920
    int cx1 = mbl.cell_index_x(current_position[X_AXIS]),
13921
        cy1 = mbl.cell_index_y(current_position[Y_AXIS]),
13922
        cx2 = mbl.cell_index_x(destination[X_AXIS]),
13923
        cy2 = mbl.cell_index_y(destination[Y_AXIS]);
13924
    NOMORE(cx1, GRID_MAX_POINTS_X - 2);
13925
    NOMORE(cy1, GRID_MAX_POINTS_Y - 2);
13926
    NOMORE(cx2, GRID_MAX_POINTS_X - 2);
13927
    NOMORE(cy2, GRID_MAX_POINTS_Y - 2);
13928
 
13929
    // Start and end in the same cell? No split needed.
13930
    if (cx1 == cx2 && cy1 == cy2) {
13931
      buffer_line_to_destination(fr_mm_s);
13932
      set_current_from_destination();
13933
      return;
13934
    }
13935
 
13936
    #define MBL_SEGMENT_END(A) (current_position[_AXIS(A)] + (destination[_AXIS(A)] - current_position[_AXIS(A)]) * normalized_dist)
13937
    #define MBL_SEGMENT_END_E (current_position[E_CART] + (destination[E_CART] - current_position[E_CART]) * normalized_dist)
13938
 
13939
    float normalized_dist, end[XYZE];
13940
    const int8_t gcx = MAX(cx1, cx2), gcy = MAX(cy1, cy2);
13941
 
13942
    // Crosses on the X and not already split on this X?
13943
    // The x_splits flags are insurance against rounding errors.
13944
    if (cx2 != cx1 && TEST(x_splits, gcx)) {
13945
      // Split on the X grid line
13946
      CBI(x_splits, gcx);
13947
      COPY(end, destination);
13948
      destination[X_AXIS] = mbl.index_to_xpos[gcx];
13949
      normalized_dist = (destination[X_AXIS] - current_position[X_AXIS]) / (end[X_AXIS] - current_position[X_AXIS]);
13950
      destination[Y_AXIS] = MBL_SEGMENT_END(Y);
13951
    }
13952
    // Crosses on the Y and not already split on this Y?
13953
    else if (cy2 != cy1 && TEST(y_splits, gcy)) {
13954
      // Split on the Y grid line
13955
      CBI(y_splits, gcy);
13956
      COPY(end, destination);
13957
      destination[Y_AXIS] = mbl.index_to_ypos[gcy];
13958
      normalized_dist = (destination[Y_AXIS] - current_position[Y_AXIS]) / (end[Y_AXIS] - current_position[Y_AXIS]);
13959
      destination[X_AXIS] = MBL_SEGMENT_END(X);
13960
    }
13961
    else {
13962
      // Must already have been split on these border(s)
13963
      buffer_line_to_destination(fr_mm_s);
13964
      set_current_from_destination();
13965
      return;
13966
    }
13967
 
13968
    destination[Z_AXIS] = MBL_SEGMENT_END(Z);
13969
    destination[E_CART] = MBL_SEGMENT_END_E;
13970
 
13971
    // Do the split and look for more borders
13972
    mesh_line_to_destination(fr_mm_s, x_splits, y_splits);
13973
 
13974
    // Restore destination from stack
13975
    COPY(destination, end);
13976
    mesh_line_to_destination(fr_mm_s, x_splits, y_splits);
13977
  }
13978
 
13979
#elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
13980
 
13981
  #define CELL_INDEX(A,V) ((V - bilinear_start[_AXIS(A)]) * ABL_BG_FACTOR(_AXIS(A)))
13982
 
13983
  /**
13984
   * Prepare a bilinear-leveled linear move on Cartesian,
13985
   * splitting the move where it crosses grid borders.
13986
   */
13987
  void bilinear_line_to_destination(const float fr_mm_s, uint16_t x_splits=0xFFFF, uint16_t y_splits=0xFFFF) {
13988
    // Get current and destination cells for this line
13989
    int cx1 = CELL_INDEX(X, current_position[X_AXIS]),
13990
        cy1 = CELL_INDEX(Y, current_position[Y_AXIS]),
13991
        cx2 = CELL_INDEX(X, destination[X_AXIS]),
13992
        cy2 = CELL_INDEX(Y, destination[Y_AXIS]);
13993
    cx1 = constrain(cx1, 0, ABL_BG_POINTS_X - 2);
13994
    cy1 = constrain(cy1, 0, ABL_BG_POINTS_Y - 2);
13995
    cx2 = constrain(cx2, 0, ABL_BG_POINTS_X - 2);
13996
    cy2 = constrain(cy2, 0, ABL_BG_POINTS_Y - 2);
13997
 
13998
    // Start and end in the same cell? No split needed.
13999
    if (cx1 == cx2 && cy1 == cy2) {
14000
      buffer_line_to_destination(fr_mm_s);
14001
      set_current_from_destination();
14002
      return;
14003
    }
14004
 
14005
    #define LINE_SEGMENT_END(A) (current_position[_AXIS(A)] + (destination[_AXIS(A)] - current_position[_AXIS(A)]) * normalized_dist)
14006
    #define LINE_SEGMENT_END_E (current_position[E_CART] + (destination[E_CART] - current_position[E_CART]) * normalized_dist)
14007
 
14008
    float normalized_dist, end[XYZE];
14009
    const int8_t gcx = MAX(cx1, cx2), gcy = MAX(cy1, cy2);
14010
 
14011
    // Crosses on the X and not already split on this X?
14012
    // The x_splits flags are insurance against rounding errors.
14013
    if (cx2 != cx1 && TEST(x_splits, gcx)) {
14014
      // Split on the X grid line
14015
      CBI(x_splits, gcx);
14016
      COPY(end, destination);
14017
      destination[X_AXIS] = bilinear_start[X_AXIS] + ABL_BG_SPACING(X_AXIS) * gcx;
14018
      normalized_dist = (destination[X_AXIS] - current_position[X_AXIS]) / (end[X_AXIS] - current_position[X_AXIS]);
14019
      destination[Y_AXIS] = LINE_SEGMENT_END(Y);
14020
    }
14021
    // Crosses on the Y and not already split on this Y?
14022
    else if (cy2 != cy1 && TEST(y_splits, gcy)) {
14023
      // Split on the Y grid line
14024
      CBI(y_splits, gcy);
14025
      COPY(end, destination);
14026
      destination[Y_AXIS] = bilinear_start[Y_AXIS] + ABL_BG_SPACING(Y_AXIS) * gcy;
14027
      normalized_dist = (destination[Y_AXIS] - current_position[Y_AXIS]) / (end[Y_AXIS] - current_position[Y_AXIS]);
14028
      destination[X_AXIS] = LINE_SEGMENT_END(X);
14029
    }
14030
    else {
14031
      // Must already have been split on these border(s)
14032
      buffer_line_to_destination(fr_mm_s);
14033
      set_current_from_destination();
14034
      return;
14035
    }
14036
 
14037
    destination[Z_AXIS] = LINE_SEGMENT_END(Z);
14038
    destination[E_CART] = LINE_SEGMENT_END_E;
14039
 
14040
    // Do the split and look for more borders
14041
    bilinear_line_to_destination(fr_mm_s, x_splits, y_splits);
14042
 
14043
    // Restore destination from stack
14044
    COPY(destination, end);
14045
    bilinear_line_to_destination(fr_mm_s, x_splits, y_splits);
14046
  }
14047
 
14048
#endif // AUTO_BED_LEVELING_BILINEAR
14049
#endif // IS_CARTESIAN
14050
 
14051
#if !UBL_SEGMENTED
14052
#if IS_KINEMATIC
14053
 
14054
  #if IS_SCARA
14055
    /**
14056
     * Before raising this value, use M665 S[seg_per_sec] to decrease
14057
     * the number of segments-per-second. Default is 200. Some deltas
14058
     * do better with 160 or lower. It would be good to know how many
14059
     * segments-per-second are actually possible for SCARA on AVR.
14060
     *
14061
     * Longer segments result in less kinematic overhead
14062
     * but may produce jagged lines. Try 0.5mm, 1.0mm, and 2.0mm
14063
     * and compare the difference.
14064
     */
14065
    #define SCARA_MIN_SEGMENT_LENGTH 0.5f
14066
  #endif
14067
 
14068
  /**
14069
   * Prepare a linear move in a DELTA, SCARA or HANGPRINTER setup.
14070
   *
14071
   * This calls planner.buffer_line several times, adding
14072
   * small incremental moves for DELTA, SCARA or HANGPRINTER.
14073
   *
14074
   * For Unified Bed Leveling (Delta or Segmented Cartesian)
14075
   * the ubl.prepare_segmented_line_to method replaces this.
14076
   */
14077
  inline bool prepare_kinematic_move_to(const float (&rtarget)[XYZE]) {
14078
 
14079
    // Get the top feedrate of the move in the XY plane
14080
    const float _feedrate_mm_s = MMS_SCALED(feedrate_mm_s);
14081
 
14082
    const float xdiff = rtarget[X_AXIS] - current_position[X_AXIS],
14083
                ydiff = rtarget[Y_AXIS] - current_position[Y_AXIS]
14084
                #if ENABLED(HANGPRINTER)
14085
                  , zdiff = rtarget[Z_AXIS] - current_position[Z_AXIS]
14086
                #endif
14087
                ;
14088
 
14089
    // If the move is only in Z/E (for Hangprinter only in E) don't split up the move
14090
    if (!xdiff && !ydiff
14091
      #if ENABLED(HANGPRINTER)
14092
        && !zdiff
14093
      #endif
14094
    ) {
14095
      planner.buffer_line_kinematic(rtarget, _feedrate_mm_s, active_extruder);
14096
      return false; // caller will update current_position
14097
    }
14098
 
14099
    // Fail if attempting move outside printable radius
14100
    if (!position_is_reachable(rtarget[X_AXIS], rtarget[Y_AXIS])) return true;
14101
 
14102
    // Remaining cartesian distances
14103
    const float
14104
                #if DISABLED(HANGPRINTER)
14105
                  zdiff = rtarget[Z_AXIS] - current_position[Z_AXIS],
14106
                #endif
14107
                ediff = rtarget[E_CART] - current_position[E_CART];
14108
 
14109
    // Get the linear distance in XYZ
14110
    // If the move is very short, check the E move distance
14111
    // No E move either? Game over.
14112
    float cartesian_mm = SQRT(sq(xdiff) + sq(ydiff) + sq(zdiff));
14113
    if (UNEAR_ZERO(cartesian_mm)) cartesian_mm = ABS(ediff);
14114
    if (UNEAR_ZERO(cartesian_mm)) return true;
14115
 
14116
    // Minimum number of seconds to move the given distance
14117
    const float seconds = cartesian_mm / _feedrate_mm_s;
14118
 
14119
    // The number of segments-per-second times the duration
14120
    // gives the number of segments
14121
    uint16_t segments = delta_segments_per_second * seconds;
14122
 
14123
    // For SCARA enforce a minimum segment size
14124
    #if IS_SCARA
14125
      NOMORE(segments, cartesian_mm * (1.0f / float(SCARA_MIN_SEGMENT_LENGTH)));
14126
    #endif
14127
 
14128
    // At least one segment is required
14129
    NOLESS(segments, 1);
14130
 
14131
    // The approximate length of each segment
14132
    const float inv_segments = 1.0f / float(segments),
14133
                segment_distance[XYZE] = {
14134
                  xdiff * inv_segments,
14135
                  ydiff * inv_segments,
14136
                  zdiff * inv_segments,
14137
                  ediff * inv_segments
14138
                };
14139
 
14140
    #if !HAS_FEEDRATE_SCALING
14141
      const float cartesian_segment_mm = cartesian_mm * inv_segments;
14142
    #endif
14143
 
14144
    /*
14145
    SERIAL_ECHOPAIR("mm=", cartesian_mm);
14146
    SERIAL_ECHOPAIR(" seconds=", seconds);
14147
    SERIAL_ECHOPAIR(" segments=", segments);
14148
    #if !HAS_FEEDRATE_SCALING
14149
      SERIAL_ECHOPAIR(" segment_mm=", cartesian_segment_mm);
14150
    #endif
14151
    SERIAL_EOL();
14152
    //*/
14153
 
14154
    #if HAS_FEEDRATE_SCALING
14155
      // SCARA needs to scale the feed rate from mm/s to degrees/s
14156
      // i.e., Complete the angular vector in the given time.
14157
      const float segment_length = cartesian_mm * inv_segments,
14158
                  inv_segment_length = 1.0f / segment_length, // 1/mm/segs
14159
                  inverse_secs = inv_segment_length * _feedrate_mm_s;
14160
 
14161
      float oldA = planner.position_float[A_AXIS],
14162
            oldB = planner.position_float[B_AXIS]
14163
            #if ENABLED(DELTA_FEEDRATE_SCALING)
14164
              , oldC = planner.position_float[C_AXIS]
14165
            #endif
14166
            ;
14167
 
14168
      /*
14169
      SERIAL_ECHOPGM("Scaled kinematic move: ");
14170
      SERIAL_ECHOPAIR(" segment_length (inv)=", segment_length);
14171
      SERIAL_ECHOPAIR(" (", inv_segment_length);
14172
      SERIAL_ECHOPAIR(") _feedrate_mm_s=", _feedrate_mm_s);
14173
      SERIAL_ECHOPAIR(" inverse_secs=", inverse_secs);
14174
      SERIAL_ECHOPAIR(" oldA=", oldA);
14175
      SERIAL_ECHOPAIR(" oldB=", oldB);
14176
      #if ENABLED(DELTA_FEEDRATE_SCALING)
14177
        SERIAL_ECHOPAIR(" oldC=", oldC);
14178
      #endif
14179
      SERIAL_EOL();
14180
      safe_delay(5);
14181
      //*/
14182
    #endif
14183
 
14184
    // Get the current position as starting point
14185
    float raw[XYZE];
14186
    COPY(raw, current_position);
14187
 
14188
    // Calculate and execute the segments
14189
    while (--segments) {
14190
 
14191
      static millis_t next_idle_ms = millis() + 200UL;
14192
      thermalManager.manage_heater();  // This returns immediately if not really needed.
14193
      if (ELAPSED(millis(), next_idle_ms)) {
14194
        next_idle_ms = millis() + 200UL;
14195
        idle();
14196
      }
14197
 
14198
      LOOP_XYZE(i) raw[i] += segment_distance[i];
14199
      #if ENABLED(DELTA) && HOTENDS < 2
14200
        DELTA_IK(raw); // Delta can inline its kinematics
14201
      #elif ENABLED(HANGPRINTER)
14202
        HANGPRINTER_IK(raw); // Modifies line_lengths[ABCD]
14203
      #else
14204
        inverse_kinematics(raw);
14205
      #endif
14206
 
14207
      ADJUST_DELTA(raw); // Adjust Z if bed leveling is enabled
14208
 
14209
      #if ENABLED(SCARA_FEEDRATE_SCALING)
14210
        // For SCARA scale the feed rate from mm/s to degrees/s
14211
        // i.e., Complete the angular vector in the given time.
14212
        if (!planner.buffer_segment(delta[A_AXIS], delta[B_AXIS], raw[Z_AXIS], raw[E_CART], HYPOT(delta[A_AXIS] - oldA, delta[B_AXIS] - oldB) * inverse_secs, active_extruder, segment_length))
14213
          break;
14214
        /*
14215
        SERIAL_ECHO(segments);
14216
        SERIAL_ECHOPAIR(": X=", raw[X_AXIS]); SERIAL_ECHOPAIR(" Y=", raw[Y_AXIS]);
14217
        SERIAL_ECHOPAIR(" A=", delta[A_AXIS]); SERIAL_ECHOPAIR(" B=", delta[B_AXIS]);
14218
        SERIAL_ECHOLNPAIR(" F", HYPOT(delta[A_AXIS] - oldA, delta[B_AXIS] - oldB) * inverse_secs * 60);
14219
        safe_delay(5);
14220
        //*/
14221
        oldA = delta[A_AXIS]; oldB = delta[B_AXIS];
14222
      #elif ENABLED(DELTA_FEEDRATE_SCALING)
14223
        // For DELTA scale the feed rate from Effector mm/s to Carriage mm/s
14224
        // i.e., Complete the linear vector in the given time.
14225
        if (!planner.buffer_segment(delta[A_AXIS], delta[B_AXIS], delta[C_AXIS], raw[E_AXIS], SQRT(sq(delta[A_AXIS] - oldA) + sq(delta[B_AXIS] - oldB) + sq(delta[C_AXIS] - oldC)) * inverse_secs, active_extruder, segment_length))
14226
          break;
14227
        /*
14228
        SERIAL_ECHO(segments);
14229
        SERIAL_ECHOPAIR(": X=", raw[X_AXIS]); SERIAL_ECHOPAIR(" Y=", raw[Y_AXIS]);
14230
        SERIAL_ECHOPAIR(" A=", delta[A_AXIS]); SERIAL_ECHOPAIR(" B=", delta[B_AXIS]); SERIAL_ECHOPAIR(" C=", delta[C_AXIS]);
14231
        SERIAL_ECHOLNPAIR(" F", SQRT(sq(delta[A_AXIS] - oldA) + sq(delta[B_AXIS] - oldB) + sq(delta[C_AXIS] - oldC)) * inverse_secs * 60);
14232
        safe_delay(5);
14233
        //*/
14234
        oldA = delta[A_AXIS]; oldB = delta[B_AXIS]; oldC = delta[C_AXIS];
14235
      #elif ENABLED(HANGPRINTER)
14236
        if (!planner.buffer_line(line_lengths[A_AXIS], line_lengths[B_AXIS], line_lengths[C_AXIS], line_lengths[D_AXIS], raw[E_CART], _feedrate_mm_s, active_extruder, cartesian_segment_mm))
14237
          break;
14238
      #else
14239
        if (!planner.buffer_line(delta[A_AXIS], delta[B_AXIS], delta[C_AXIS], raw[E_CART], _feedrate_mm_s, active_extruder, cartesian_segment_mm))
14240
          break;
14241
      #endif
14242
    }
14243
 
14244
    // Ensure last segment arrives at target location.
14245
    #if HAS_FEEDRATE_SCALING
14246
      inverse_kinematics(rtarget);
14247
      ADJUST_DELTA(rtarget);
14248
    #endif
14249
 
14250
    #if ENABLED(SCARA_FEEDRATE_SCALING)
14251
      const float diff2 = HYPOT2(delta[A_AXIS] - oldA, delta[B_AXIS] - oldB);
14252
      if (diff2) {
14253
        planner.buffer_segment(delta[A_AXIS], delta[B_AXIS], rtarget[Z_AXIS], rtarget[E_CART], SQRT(diff2) * inverse_secs, active_extruder, segment_length);
14254
        /*
14255
        SERIAL_ECHOPAIR("final: A=", delta[A_AXIS]); SERIAL_ECHOPAIR(" B=", delta[B_AXIS]);
14256
        SERIAL_ECHOPAIR(" adiff=", delta[A_AXIS] - oldA); SERIAL_ECHOPAIR(" bdiff=", delta[B_AXIS] - oldB);
14257
        SERIAL_ECHOLNPAIR(" F", SQRT(diff2) * inverse_secs * 60);
14258
        SERIAL_EOL();
14259
        safe_delay(5);
14260
        //*/
14261
      }
14262
    #elif ENABLED(DELTA_FEEDRATE_SCALING)
14263
      const float diff2 = sq(delta[A_AXIS] - oldA) + sq(delta[B_AXIS] - oldB) + sq(delta[C_AXIS] - oldC);
14264
      if (diff2) {
14265
        planner.buffer_segment(delta[A_AXIS], delta[B_AXIS], delta[C_AXIS], rtarget[E_AXIS], SQRT(diff2) * inverse_secs, active_extruder, segment_length);
14266
        /*
14267
        SERIAL_ECHOPAIR("final: A=", delta[A_AXIS]); SERIAL_ECHOPAIR(" B=", delta[B_AXIS]); SERIAL_ECHOPAIR(" C=", delta[C_AXIS]);
14268
        SERIAL_ECHOPAIR(" adiff=", delta[A_AXIS] - oldA); SERIAL_ECHOPAIR(" bdiff=", delta[B_AXIS] - oldB); SERIAL_ECHOPAIR(" cdiff=", delta[C_AXIS] - oldC);
14269
        SERIAL_ECHOLNPAIR(" F", SQRT(diff2) * inverse_secs * 60);
14270
        SERIAL_EOL();
14271
        safe_delay(5);
14272
        //*/
14273
      }
14274
    #else
14275
      planner.buffer_line_kinematic(rtarget, _feedrate_mm_s, active_extruder, cartesian_segment_mm);
14276
    #endif
14277
 
14278
    return false; // caller will update current_position
14279
  }
14280
 
14281
#else // !IS_KINEMATIC
14282
 
14283
  /**
14284
   * Prepare a linear move in a Cartesian setup.
14285
   *
14286
   * When a mesh-based leveling system is active, moves are segmented
14287
   * according to the configuration of the leveling system.
14288
   *
14289
   * Returns true if current_position[] was set to destination[]
14290
   */
14291
  inline bool prepare_move_to_destination_cartesian() {
14292
    #if HAS_MESH
14293
      if (planner.leveling_active && planner.leveling_active_at_z(destination[Z_AXIS])) {
14294
        #if ENABLED(AUTO_BED_LEVELING_UBL)
14295
          ubl.line_to_destination_cartesian(MMS_SCALED(feedrate_mm_s), active_extruder);  // UBL's motion routine needs to know about
14296
          return true;                                                                    // all moves, including Z-only moves.
14297
        #elif ENABLED(SEGMENT_LEVELED_MOVES)
14298
          segmented_line_to_destination(MMS_SCALED(feedrate_mm_s));
14299
          return false; // caller will update current_position
14300
        #else
14301
          /**
14302
           * For MBL and ABL-BILINEAR only segment moves when X or Y are involved.
14303
           * Otherwise fall through to do a direct single move.
14304
           */
14305
          if (current_position[X_AXIS] != destination[X_AXIS] || current_position[Y_AXIS] != destination[Y_AXIS]) {
14306
            #if ENABLED(MESH_BED_LEVELING)
14307
              mesh_line_to_destination(MMS_SCALED(feedrate_mm_s));
14308
            #elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
14309
              bilinear_line_to_destination(MMS_SCALED(feedrate_mm_s));
14310
            #endif
14311
            return true;
14312
          }
14313
        #endif
14314
      }
14315
    #endif // HAS_MESH
14316
 
14317
    buffer_line_to_destination(MMS_SCALED(feedrate_mm_s));
14318
    return false; // caller will update current_position
14319
  }
14320
 
14321
#endif // !IS_KINEMATIC
14322
#endif // !UBL_SEGMENTED
14323
 
14324
#if ENABLED(DUAL_X_CARRIAGE)
14325
 
14326
  /**
14327
   * Unpark the carriage, if needed
14328
   */
14329
  inline bool dual_x_carriage_unpark() {
14330
    if (active_extruder_parked)
14331
      switch (dual_x_carriage_mode) {
14332
 
14333
        case DXC_FULL_CONTROL_MODE: break;
14334
 
14335
        case DXC_AUTO_PARK_MODE:
14336
          if (current_position[E_CART] == destination[E_CART]) {
14337
            // This is a travel move (with no extrusion)
14338
            // Skip it, but keep track of the current position
14339
            // (so it can be used as the start of the next non-travel move)
14340
            if (delayed_move_time != 0xFFFFFFFFUL) {
14341
              set_current_from_destination();
14342
              NOLESS(raised_parked_position[Z_AXIS], destination[Z_AXIS]);
14343
              delayed_move_time = millis();
14344
              return true;
14345
            }
14346
          }
14347
          // unpark extruder: 1) raise, 2) move into starting XY position, 3) lower
14348
          for (uint8_t i = 0; i < 3; i++)
14349
            if (!planner.buffer_line(
14350
              i == 0 ? raised_parked_position[X_AXIS] : current_position[X_AXIS],
14351
              i == 0 ? raised_parked_position[Y_AXIS] : current_position[Y_AXIS],
14352
              i == 2 ? current_position[Z_AXIS] : raised_parked_position[Z_AXIS],
14353
              current_position[E_CART],
14354
              i == 1 ? PLANNER_XY_FEEDRATE() : planner.max_feedrate_mm_s[Z_AXIS],
14355
              active_extruder)
14356
            ) break;
14357
          delayed_move_time = 0;
14358
          active_extruder_parked = false;
14359
          #if ENABLED(DEBUG_LEVELING_FEATURE)
14360
            if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("Clear active_extruder_parked");
14361
          #endif
14362
          break;
14363
 
14364
        case DXC_DUPLICATION_MODE:
14365
          if (active_extruder == 0) {
14366
            #if ENABLED(DEBUG_LEVELING_FEATURE)
14367
              if (DEBUGGING(LEVELING)) {
14368
                SERIAL_ECHOPAIR("Set planner X", inactive_extruder_x_pos);
14369
                SERIAL_ECHOLNPAIR(" ... Line to X", current_position[X_AXIS] + duplicate_extruder_x_offset);
14370
              }
14371
            #endif
14372
            // move duplicate extruder into correct duplication position.
14373
            planner.set_position_mm(inactive_extruder_x_pos, current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_CART]);
14374
            if (!planner.buffer_line(
14375
              current_position[X_AXIS] + duplicate_extruder_x_offset,
14376
              current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_CART],
14377
              planner.max_feedrate_mm_s[X_AXIS], 1)
14378
            ) break;
14379
            planner.synchronize();
14380
            SYNC_PLAN_POSITION_KINEMATIC();
14381
            extruder_duplication_enabled = true;
14382
            active_extruder_parked = false;
14383
            #if ENABLED(DEBUG_LEVELING_FEATURE)
14384
              if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("Set extruder_duplication_enabled\nClear active_extruder_parked");
14385
            #endif
14386
          }
14387
          else {
14388
            #if ENABLED(DEBUG_LEVELING_FEATURE)
14389
              if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("Active extruder not 0");
14390
            #endif
14391
          }
14392
          break;
14393
      }
14394
    return false;
14395
  }
14396
 
14397
#endif // DUAL_X_CARRIAGE
14398
 
14399
/**
14400
 * Prepare a single move and get ready for the next one
14401
 *
14402
 * This may result in several calls to planner.buffer_line to
14403
 * do smaller moves for DELTA, SCARA, HANGPRINTER, mesh moves, etc.
14404
 *
14405
 * Make sure current_position[E] and destination[E] are good
14406
 * before calling or cold/lengthy extrusion may get missed.
14407
 */
14408
void prepare_move_to_destination() {
14409
  clamp_to_software_endstops(destination);
14410
 
14411
  #if ENABLED(PREVENT_COLD_EXTRUSION) || ENABLED(PREVENT_LENGTHY_EXTRUDE)
14412
 
14413
    if (!DEBUGGING(DRYRUN)) {
14414
      if (destination[E_CART] != current_position[E_CART]) {
14415
        #if ENABLED(PREVENT_COLD_EXTRUSION)
14416
          if (thermalManager.tooColdToExtrude(active_extruder)) {
14417
            current_position[E_CART] = destination[E_CART]; // Behave as if the move really took place, but ignore E part
14418
            SERIAL_ECHO_START();
14419
            SERIAL_ECHOLNPGM(MSG_ERR_COLD_EXTRUDE_STOP);
14420
          }
14421
        #endif // PREVENT_COLD_EXTRUSION
14422
        #if ENABLED(PREVENT_LENGTHY_EXTRUDE)
14423
          if (ABS(destination[E_CART] - current_position[E_CART]) * planner.e_factor[active_extruder] > (EXTRUDE_MAXLENGTH)) {
14424
            current_position[E_CART] = destination[E_CART]; // Behave as if the move really took place, but ignore E part
14425
            SERIAL_ECHO_START();
14426
            SERIAL_ECHOLNPGM(MSG_ERR_LONG_EXTRUDE_STOP);
14427
          }
14428
        #endif // PREVENT_LENGTHY_EXTRUDE
14429
      }
14430
    }
14431
 
14432
  #endif
14433
 
14434
  #if ENABLED(DUAL_X_CARRIAGE)
14435
    if (dual_x_carriage_unpark()) return;
14436
  #endif
14437
 
14438
  if (
14439
    #if UBL_SEGMENTED
14440
      ubl.prepare_segmented_line_to(destination, MMS_SCALED(feedrate_mm_s))
14441
    #elif IS_KINEMATIC
14442
      prepare_kinematic_move_to(destination)
14443
    #else
14444
      prepare_move_to_destination_cartesian()
14445
    #endif
14446
  ) return;
14447
 
14448
  set_current_from_destination();
14449
}
14450
 
14451
#if ENABLED(ARC_SUPPORT)
14452
 
14453
  #if N_ARC_CORRECTION < 1
14454
    #undef N_ARC_CORRECTION
14455
    #define N_ARC_CORRECTION 1
14456
  #endif
14457
 
14458
  /**
14459
   * Plan an arc in 2 dimensions
14460
   *
14461
   * The arc is approximated by generating many small linear segments.
14462
   * The length of each segment is configured in MM_PER_ARC_SEGMENT (Default 1mm)
14463
   * Arcs should only be made relatively large (over 5mm), as larger arcs with
14464
   * larger segments will tend to be more efficient. Your slicer should have
14465
   * options for G2/G3 arc generation. In future these options may be GCode tunable.
14466
   */
14467
  void plan_arc(
14468
    const float (&cart)[XYZE], // Destination position
14469
    const float (&offset)[2], // Center of rotation relative to current_position
14470
    const bool clockwise      // Clockwise?
14471
  ) {
14472
    #if ENABLED(CNC_WORKSPACE_PLANES)
14473
      AxisEnum p_axis, q_axis, l_axis;
14474
      switch (workspace_plane) {
14475
        default:
14476
        case PLANE_XY: p_axis = X_AXIS; q_axis = Y_AXIS; l_axis = Z_AXIS; break;
14477
        case PLANE_ZX: p_axis = Z_AXIS; q_axis = X_AXIS; l_axis = Y_AXIS; break;
14478
        case PLANE_YZ: p_axis = Y_AXIS; q_axis = Z_AXIS; l_axis = X_AXIS; break;
14479
      }
14480
    #else
14481
      constexpr AxisEnum p_axis = X_AXIS, q_axis = Y_AXIS, l_axis = Z_AXIS;
14482
    #endif
14483
 
14484
    // Radius vector from center to current location
14485
    float r_P = -offset[0], r_Q = -offset[1];
14486
 
14487
    const float radius = HYPOT(r_P, r_Q),
14488
                center_P = current_position[p_axis] - r_P,
14489
                center_Q = current_position[q_axis] - r_Q,
14490
                rt_X = cart[p_axis] - center_P,
14491
                rt_Y = cart[q_axis] - center_Q,
14492
                linear_travel = cart[l_axis] - current_position[l_axis],
14493
                extruder_travel = cart[E_CART] - current_position[E_CART];
14494
 
14495
    // CCW angle of rotation between position and target from the circle center. Only one atan2() trig computation required.
14496
    float angular_travel = ATAN2(r_P * rt_Y - r_Q * rt_X, r_P * rt_X + r_Q * rt_Y);
14497
    if (angular_travel < 0) angular_travel += RADIANS(360);
14498
    if (clockwise) angular_travel -= RADIANS(360);
14499
 
14500
    // Make a circle if the angular rotation is 0 and the target is current position
14501
    if (angular_travel == 0 && current_position[p_axis] == cart[p_axis] && current_position[q_axis] == cart[q_axis])
14502
      angular_travel = RADIANS(360);
14503
 
14504
    const float flat_mm = radius * angular_travel,
14505
                mm_of_travel = linear_travel ? HYPOT(flat_mm, linear_travel) : ABS(flat_mm);
14506
    if (mm_of_travel < 0.001f) return;
14507
 
14508
    uint16_t segments = FLOOR(mm_of_travel / (MM_PER_ARC_SEGMENT));
14509
    NOLESS(segments, 1);
14510
 
14511
    /**
14512
     * Vector rotation by transformation matrix: r is the original vector, r_T is the rotated vector,
14513
     * and phi is the angle of rotation. Based on the solution approach by Jens Geisler.
14514
     *     r_T = [cos(phi) -sin(phi);
14515
     *            sin(phi)  cos(phi)] * r ;
14516
     *
14517
     * For arc generation, the center of the circle is the axis of rotation and the radius vector is
14518
     * defined from the circle center to the initial position. Each line segment is formed by successive
14519
     * vector rotations. This requires only two cos() and sin() computations to form the rotation
14520
     * matrix for the duration of the entire arc. Error may accumulate from numerical round-off, since
14521
     * all double numbers are single precision on the Arduino. (True double precision will not have
14522
     * round off issues for CNC applications.) Single precision error can accumulate to be greater than
14523
     * tool precision in some cases. Therefore, arc path correction is implemented.
14524
     *
14525
     * Small angle approximation may be used to reduce computation overhead further. This approximation
14526
     * holds for everything, but very small circles and large MM_PER_ARC_SEGMENT values. In other words,
14527
     * theta_per_segment would need to be greater than 0.1 rad and N_ARC_CORRECTION would need to be large
14528
     * to cause an appreciable drift error. N_ARC_CORRECTION~=25 is more than small enough to correct for
14529
     * numerical drift error. N_ARC_CORRECTION may be on the order a hundred(s) before error becomes an
14530
     * issue for CNC machines with the single precision Arduino calculations.
14531
     *
14532
     * This approximation also allows plan_arc to immediately insert a line segment into the planner
14533
     * without the initial overhead of computing cos() or sin(). By the time the arc needs to be applied
14534
     * a correction, the planner should have caught up to the lag caused by the initial plan_arc overhead.
14535
     * This is important when there are successive arc motions.
14536
     */
14537
    // Vector rotation matrix values
14538
    float raw[XYZE];
14539
    const float theta_per_segment = angular_travel / segments,
14540
                linear_per_segment = linear_travel / segments,
14541
                extruder_per_segment = extruder_travel / segments,
14542
                sin_T = theta_per_segment,
14543
                cos_T = 1 - 0.5f * sq(theta_per_segment); // Small angle approximation
14544
 
14545
    // Initialize the linear axis
14546
    raw[l_axis] = current_position[l_axis];
14547
 
14548
    // Initialize the extruder axis
14549
    raw[E_CART] = current_position[E_CART];
14550
 
14551
    const float fr_mm_s = MMS_SCALED(feedrate_mm_s);
14552
 
14553
    millis_t next_idle_ms = millis() + 200UL;
14554
 
14555
    #if HAS_FEEDRATE_SCALING
14556
      // SCARA needs to scale the feed rate from mm/s to degrees/s
14557
      const float inv_segment_length = 1.0f / (MM_PER_ARC_SEGMENT),
14558
                  inverse_secs = inv_segment_length * fr_mm_s;
14559
      float oldA = planner.position_float[A_AXIS],
14560
            oldB = planner.position_float[B_AXIS]
14561
            #if ENABLED(DELTA_FEEDRATE_SCALING)
14562
              , oldC = planner.position_float[C_AXIS]
14563
            #endif
14564
            ;
14565
    #endif
14566
 
14567
    #if N_ARC_CORRECTION > 1
14568
      int8_t arc_recalc_count = N_ARC_CORRECTION;
14569
    #endif
14570
 
14571
    for (uint16_t i = 1; i < segments; i++) { // Iterate (segments-1) times
14572
 
14573
      thermalManager.manage_heater();
14574
      if (ELAPSED(millis(), next_idle_ms)) {
14575
        next_idle_ms = millis() + 200UL;
14576
        idle();
14577
      }
14578
 
14579
      #if N_ARC_CORRECTION > 1
14580
        if (--arc_recalc_count) {
14581
          // Apply vector rotation matrix to previous r_P / 1
14582
          const float r_new_Y = r_P * sin_T + r_Q * cos_T;
14583
          r_P = r_P * cos_T - r_Q * sin_T;
14584
          r_Q = r_new_Y;
14585
        }
14586
        else
14587
      #endif
14588
      {
14589
        #if N_ARC_CORRECTION > 1
14590
          arc_recalc_count = N_ARC_CORRECTION;
14591
        #endif
14592
 
14593
        // Arc correction to radius vector. Computed only every N_ARC_CORRECTION increments.
14594
        // Compute exact location by applying transformation matrix from initial radius vector(=-offset).
14595
        // To reduce stuttering, the sin and cos could be computed at different times.
14596
        // For now, compute both at the same time.
14597
        const float cos_Ti = cos(i * theta_per_segment), sin_Ti = sin(i * theta_per_segment);
14598
        r_P = -offset[0] * cos_Ti + offset[1] * sin_Ti;
14599
        r_Q = -offset[0] * sin_Ti - offset[1] * cos_Ti;
14600
      }
14601
 
14602
      // Update raw location
14603
      raw[p_axis] = center_P + r_P;
14604
      raw[q_axis] = center_Q + r_Q;
14605
      raw[l_axis] += linear_per_segment;
14606
      raw[E_CART] += extruder_per_segment;
14607
 
14608
      clamp_to_software_endstops(raw);
14609
 
14610
      #if HAS_FEEDRATE_SCALING
14611
        inverse_kinematics(raw);
14612
        ADJUST_DELTA(raw);
14613
      #endif
14614
 
14615
      #if ENABLED(SCARA_FEEDRATE_SCALING)
14616
        // For SCARA scale the feed rate from mm/s to degrees/s
14617
        // i.e., Complete the angular vector in the given time.
14618
        if (!planner.buffer_segment(delta[A_AXIS], delta[B_AXIS], raw[Z_AXIS], raw[E_CART], HYPOT(delta[A_AXIS] - oldA, delta[B_AXIS] - oldB) * inverse_secs, active_extruder, MM_PER_ARC_SEGMENT))
14619
          break;
14620
        oldA = delta[A_AXIS]; oldB = delta[B_AXIS];
14621
      #elif ENABLED(DELTA_FEEDRATE_SCALING)
14622
        // For DELTA scale the feed rate from Effector mm/s to Carriage mm/s
14623
        // i.e., Complete the linear vector in the given time.
14624
        if (!planner.buffer_segment(delta[A_AXIS], delta[B_AXIS], delta[C_AXIS], raw[E_AXIS], SQRT(sq(delta[A_AXIS] - oldA) + sq(delta[B_AXIS] - oldB) + sq(delta[C_AXIS] - oldC)) * inverse_secs, active_extruder, MM_PER_ARC_SEGMENT))
14625
          break;
14626
        oldA = delta[A_AXIS]; oldB = delta[B_AXIS]; oldC = delta[C_AXIS];
14627
      #elif HAS_UBL_AND_CURVES
14628
        float pos[XYZ] = { raw[X_AXIS], raw[Y_AXIS], raw[Z_AXIS] };
14629
        planner.apply_leveling(pos);
14630
        if (!planner.buffer_segment(pos[X_AXIS], pos[Y_AXIS], pos[Z_AXIS], raw[E_CART], fr_mm_s, active_extruder, MM_PER_ARC_SEGMENT))
14631
          break;
14632
      #else
14633
        if (!planner.buffer_line_kinematic(raw, fr_mm_s, active_extruder))
14634
          break;
14635
      #endif
14636
    }
14637
 
14638
    // Ensure last segment arrives at target location.
14639
    #if HAS_FEEDRATE_SCALING
14640
      inverse_kinematics(cart);
14641
      ADJUST_DELTA(cart);
14642
    #endif
14643
 
14644
    #if ENABLED(SCARA_FEEDRATE_SCALING)
14645
      const float diff2 = HYPOT2(delta[A_AXIS] - oldA, delta[B_AXIS] - oldB);
14646
      if (diff2)
14647
        planner.buffer_segment(delta[A_AXIS], delta[B_AXIS], cart[Z_AXIS], cart[E_CART], SQRT(diff2) * inverse_secs, active_extruder, MM_PER_ARC_SEGMENT);
14648
    #elif ENABLED(DELTA_FEEDRATE_SCALING)
14649
      const float diff2 = sq(delta[A_AXIS] - oldA) + sq(delta[B_AXIS] - oldB) + sq(delta[C_AXIS] - oldC);
14650
      if (diff2)
14651
        planner.buffer_segment(delta[A_AXIS], delta[B_AXIS], delta[C_AXIS], cart[E_CART], SQRT(diff2) * inverse_secs, active_extruder, MM_PER_ARC_SEGMENT);
14652
    #elif HAS_UBL_AND_CURVES
14653
      float pos[XYZ] = { cart[X_AXIS], cart[Y_AXIS], cart[Z_AXIS] };
14654
      planner.apply_leveling(pos);
14655
      planner.buffer_segment(pos[X_AXIS], pos[Y_AXIS], pos[Z_AXIS], cart[E_CART], fr_mm_s, active_extruder, MM_PER_ARC_SEGMENT);
14656
    #else
14657
      planner.buffer_line_kinematic(cart, fr_mm_s, active_extruder);
14658
    #endif
14659
 
14660
    COPY(current_position, cart);
14661
  } // plan_arc
14662
 
14663
#endif // ARC_SUPPORT
14664
 
14665
#if ENABLED(BEZIER_CURVE_SUPPORT)
14666
 
14667
  void plan_cubic_move(const float (&cart)[XYZE], const float (&offset)[4]) {
14668
    cubic_b_spline(current_position, cart, offset, MMS_SCALED(feedrate_mm_s), active_extruder);
14669
    COPY(current_position, cart);
14670
  }
14671
 
14672
#endif // BEZIER_CURVE_SUPPORT
14673
 
14674
#if ENABLED(USE_CONTROLLER_FAN)
14675
 
14676
  void controllerFan() {
14677
    static millis_t lastMotorOn = 0, // Last time a motor was turned on
14678
                    nextMotorCheck = 0; // Last time the state was checked
14679
    const millis_t ms = millis();
14680
    if (ELAPSED(ms, nextMotorCheck)) {
14681
      nextMotorCheck = ms + 2500UL; // Not a time critical function, so only check every 2.5s
14682
 
14683
      // If any of the drivers or the bed are enabled...
14684
      if (X_ENABLE_READ == X_ENABLE_ON || Y_ENABLE_READ == Y_ENABLE_ON || Z_ENABLE_READ == Z_ENABLE_ON
14685
        #if HAS_HEATED_BED
14686
          || thermalManager.soft_pwm_amount_bed > 0
14687
        #endif
14688
          #if HAS_X2_ENABLE
14689
            || X2_ENABLE_READ == X_ENABLE_ON
14690
          #endif
14691
          #if HAS_Y2_ENABLE
14692
            || Y2_ENABLE_READ == Y_ENABLE_ON
14693
          #endif
14694
          #if HAS_Z2_ENABLE
14695
            || Z2_ENABLE_READ == Z_ENABLE_ON
14696
          #endif
14697
          || E0_ENABLE_READ == E_ENABLE_ON
14698
          #if E_STEPPERS > 1
14699
            || E1_ENABLE_READ == E_ENABLE_ON
14700
            #if E_STEPPERS > 2
14701
                || E2_ENABLE_READ == E_ENABLE_ON
14702
              #if E_STEPPERS > 3
14703
                  || E3_ENABLE_READ == E_ENABLE_ON
14704
                #if E_STEPPERS > 4
14705
                    || E4_ENABLE_READ == E_ENABLE_ON
14706
                #endif
14707
              #endif
14708
            #endif
14709
          #endif
14710
      ) {
14711
        lastMotorOn = ms; //... set time to NOW so the fan will turn on
14712
      }
14713
 
14714
      // Fan off if no steppers have been enabled for CONTROLLERFAN_SECS seconds
14715
      const uint8_t speed = (lastMotorOn && PENDING(ms, lastMotorOn + (CONTROLLERFAN_SECS) * 1000UL)) ? CONTROLLERFAN_SPEED : 0;
14716
      controllerFanSpeed = speed;
14717
 
14718
      // allows digital or PWM fan output to be used (see M42 handling)
14719
      WRITE(CONTROLLER_FAN_PIN, speed);
14720
      analogWrite(CONTROLLER_FAN_PIN, speed);
14721
    }
14722
  }
14723
 
14724
#endif // USE_CONTROLLER_FAN
14725
 
14726
#if ENABLED(MORGAN_SCARA)
14727
 
14728
  /**
14729
   * Morgan SCARA Forward Kinematics. Results in cartes[].
14730
   * Maths and first version by QHARLEY.
14731
   * Integrated into Marlin and slightly restructured by Joachim Cerny.
14732
   */
14733
  void forward_kinematics_SCARA(const float &a, const float &b) {
14734
 
14735
    float a_sin = sin(RADIANS(a)) * L1,
14736
          a_cos = cos(RADIANS(a)) * L1,
14737
          b_sin = sin(RADIANS(b)) * L2,
14738
          b_cos = cos(RADIANS(b)) * L2;
14739
 
14740
    cartes[X_AXIS] = a_cos + b_cos + SCARA_OFFSET_X;  //theta
14741
    cartes[Y_AXIS] = a_sin + b_sin + SCARA_OFFSET_Y;  //theta+phi
14742
 
14743
    /*
14744
      SERIAL_ECHOPAIR("SCARA FK Angle a=", a);
14745
      SERIAL_ECHOPAIR(" b=", b);
14746
      SERIAL_ECHOPAIR(" a_sin=", a_sin);
14747
      SERIAL_ECHOPAIR(" a_cos=", a_cos);
14748
      SERIAL_ECHOPAIR(" b_sin=", b_sin);
14749
      SERIAL_ECHOLNPAIR(" b_cos=", b_cos);
14750
      SERIAL_ECHOPAIR(" cartes[X_AXIS]=", cartes[X_AXIS]);
14751
      SERIAL_ECHOLNPAIR(" cartes[Y_AXIS]=", cartes[Y_AXIS]);
14752
    //*/
14753
  }
14754
 
14755
  /**
14756
   * Morgan SCARA Inverse Kinematics. Results in delta[].
14757
   *
14758
   * See http://forums.reprap.org/read.php?185,283327
14759
   *
14760
   * Maths and first version by QHARLEY.
14761
   * Integrated into Marlin and slightly restructured by Joachim Cerny.
14762
   */
14763
  void inverse_kinematics(const float raw[XYZ]) {
14764
 
14765
    static float C2, S2, SK1, SK2, THETA, PSI;
14766
 
14767
    float sx = raw[X_AXIS] - SCARA_OFFSET_X,  // Translate SCARA to standard X Y
14768
          sy = raw[Y_AXIS] - SCARA_OFFSET_Y;  // With scaling factor.
14769
 
14770
    if (L1 == L2)
14771
      C2 = HYPOT2(sx, sy) / L1_2_2 - 1;
14772
    else
14773
      C2 = (HYPOT2(sx, sy) - (L1_2 + L2_2)) / (2.0 * L1 * L2);
14774
 
14775
    S2 = SQRT(1 - sq(C2));
14776
 
14777
    // Unrotated Arm1 plus rotated Arm2 gives the distance from Center to End
14778
    SK1 = L1 + L2 * C2;
14779
 
14780
    // Rotated Arm2 gives the distance from Arm1 to Arm2
14781
    SK2 = L2 * S2;
14782
 
14783
    // Angle of Arm1 is the difference between Center-to-End angle and the Center-to-Elbow
14784
    THETA = ATAN2(SK1, SK2) - ATAN2(sx, sy);
14785
 
14786
    // Angle of Arm2
14787
    PSI = ATAN2(S2, C2);
14788
 
14789
    delta[A_AXIS] = DEGREES(THETA);        // theta is support arm angle
14790
    delta[B_AXIS] = DEGREES(THETA + PSI);  // equal to sub arm angle (inverted motor)
14791
    delta[C_AXIS] = raw[Z_AXIS];
14792
 
14793
    /*
14794
      DEBUG_POS("SCARA IK", raw);
14795
      DEBUG_POS("SCARA IK", delta);
14796
      SERIAL_ECHOPAIR("  SCARA (x,y) ", sx);
14797
      SERIAL_ECHOPAIR(",", sy);
14798
      SERIAL_ECHOPAIR(" C2=", C2);
14799
      SERIAL_ECHOPAIR(" S2=", S2);
14800
      SERIAL_ECHOPAIR(" Theta=", THETA);
14801
      SERIAL_ECHOLNPAIR(" Phi=", PHI);
14802
    //*/
14803
  }
14804
 
14805
#endif // MORGAN_SCARA
14806
 
14807
#if ENABLED(TEMP_STAT_LEDS)
14808
 
14809
  static uint8_t red_led = -1;  // Invalid value to force leds initializzation on startup
14810
  static millis_t next_status_led_update_ms = 0;
14811
 
14812
  void handle_status_leds(void) {
14813
    if (ELAPSED(millis(), next_status_led_update_ms)) {
14814
      next_status_led_update_ms += 500; // Update every 0.5s
14815
      float max_temp = 0.0;
14816
      #if HAS_HEATED_BED
14817
        max_temp = MAX(thermalManager.degTargetBed(), thermalManager.degBed());
14818
      #endif
14819
      HOTEND_LOOP()
14820
        max_temp = MAX3(max_temp, thermalManager.degHotend(e), thermalManager.degTargetHotend(e));
14821
      const uint8_t new_led = (max_temp > 55.0) ? HIGH : (max_temp < 54.0 || red_led == -1) ? LOW : red_led;
14822
      if (new_led != red_led) {
14823
        red_led = new_led;
14824
        #if PIN_EXISTS(STAT_LED_RED)
14825
          WRITE(STAT_LED_RED_PIN, new_led);
14826
        #endif
14827
        #if PIN_EXISTS(STAT_LED_BLUE)
14828
          WRITE(STAT_LED_BLUE_PIN, !new_led);
14829
        #endif
14830
      }
14831
    }
14832
  }
14833
 
14834
#endif
14835
 
14836
void enable_all_steppers() {
14837
  #if ENABLED(AUTO_POWER_CONTROL)
14838
    powerManager.power_on();
14839
  #endif
14840
  #if ENABLED(HANGPRINTER)
14841
    enable_A();
14842
    enable_B();
14843
    enable_C();
14844
    enable_D();
14845
  #else
14846
    enable_X();
14847
    enable_Y();
14848
    enable_Z();
14849
    enable_E4();
14850
  #endif
14851
  enable_E0();
14852
  enable_E1();
14853
  enable_E2();
14854
  enable_E3();
14855
}
14856
 
14857
void disable_e_stepper(const uint8_t e) {
14858
  switch (e) {
14859
    case 0: disable_E0(); break;
14860
    case 1: disable_E1(); break;
14861
    case 2: disable_E2(); break;
14862
    case 3: disable_E3(); break;
14863
    case 4: disable_E4(); break;
14864
  }
14865
}
14866
 
14867
void disable_e_steppers() {
14868
  disable_E0();
14869
  disable_E1();
14870
  disable_E2();
14871
  disable_E3();
14872
  disable_E4();
14873
}
14874
 
14875
void disable_all_steppers() {
14876
  disable_X();
14877
  disable_Y();
14878
  disable_Z();
14879
  disable_e_steppers();
14880
}
14881
 
14882
/**
14883
 * Manage several activities:
14884
 *  - Check for Filament Runout
14885
 *  - Keep the command buffer full
14886
 *  - Check for maximum inactive time between commands
14887
 *  - Check for maximum inactive time between stepper commands
14888
 *  - Check if pin CHDK needs to go LOW
14889
 *  - Check for KILL button held down
14890
 *  - Check for HOME button held down
14891
 *  - Check if cooling fan needs to be switched on
14892
 *  - Check if an idle but hot extruder needs filament extruded (EXTRUDER_RUNOUT_PREVENT)
14893
 */
14894
void manage_inactivity(const bool ignore_stepper_queue/*=false*/) {
14895
 
14896
  #if ENABLED(FILAMENT_RUNOUT_SENSOR)
14897
    runout.run();
14898
  #endif
14899
 
14900
  if (commands_in_queue < BUFSIZE) get_available_commands();
14901
 
14902
  const millis_t ms = millis();
14903
 
14904
  if (max_inactive_time && ELAPSED(ms, previous_move_ms + max_inactive_time)) {
14905
    SERIAL_ERROR_START();
14906
    SERIAL_ECHOLNPAIR(MSG_KILL_INACTIVE_TIME, parser.command_ptr);
14907
    kill(PSTR(MSG_KILLED));
14908
  }
14909
 
14910
  // Prevent steppers timing-out in the middle of M600
14911
  #if ENABLED(ADVANCED_PAUSE_FEATURE) && ENABLED(PAUSE_PARK_NO_STEPPER_TIMEOUT)
14912
    #define MOVE_AWAY_TEST !did_pause_print
14913
  #else
14914
    #define MOVE_AWAY_TEST true
14915
  #endif
14916
 
14917
  if (stepper_inactive_time) {
14918
    if (planner.has_blocks_queued())
14919
      previous_move_ms = ms; // reset_stepper_timeout to keep steppers powered
14920
    else if (MOVE_AWAY_TEST && !ignore_stepper_queue && ELAPSED(ms, previous_move_ms + stepper_inactive_time)) {
14921
      #if ENABLED(DISABLE_INACTIVE_X)
14922
        disable_X();
14923
      #endif
14924
      #if ENABLED(DISABLE_INACTIVE_Y)
14925
        disable_Y();
14926
      #endif
14927
      #if ENABLED(DISABLE_INACTIVE_Z)
14928
        disable_Z();
14929
      #endif
14930
      #if ENABLED(DISABLE_INACTIVE_E)
14931
        disable_e_steppers();
14932
      #endif
14933
      #if ENABLED(AUTO_BED_LEVELING_UBL) && ENABLED(ULTIPANEL)  // Only needed with an LCD
14934
        if (ubl.lcd_map_control) ubl.lcd_map_control = defer_return_to_status = false;
14935
      #endif
14936
    }
14937
  }
14938
 
14939
  #ifdef CHDK // Check if pin should be set to LOW after M240 set it to HIGH
14940
    if (chdkActive && ELAPSED(ms, chdkHigh + CHDK_DELAY)) {
14941
      chdkActive = false;
14942
      WRITE(CHDK, LOW);
14943
    }
14944
  #endif
14945
 
14946
  #if HAS_KILL
14947
 
14948
    // Check if the kill button was pressed and wait just in case it was an accidental
14949
    // key kill key press
14950
    // -------------------------------------------------------------------------------
14951
    static int killCount = 0;   // make the inactivity button a bit less responsive
14952
    const int KILL_DELAY = 750;
14953
    if (!READ(KILL_PIN))
14954
      killCount++;
14955
    else if (killCount > 0)
14956
      killCount--;
14957
 
14958
    // Exceeded threshold and we can confirm that it was not accidental
14959
    // KILL the machine
14960
    // ----------------------------------------------------------------
14961
    if (killCount >= KILL_DELAY) {
14962
      SERIAL_ERROR_START();
14963
      SERIAL_ERRORLNPGM(MSG_KILL_BUTTON);
14964
      kill(PSTR(MSG_KILLED));
14965
    }
14966
  #endif
14967
 
14968
  #if HAS_HOME
14969
    // Check to see if we have to home, use poor man's debouncer
14970
    // ---------------------------------------------------------
14971
    static int homeDebounceCount = 0;   // poor man's debouncing count
14972
    const int HOME_DEBOUNCE_DELAY = 2500;
14973
    if (!IS_SD_PRINTING() && !READ(HOME_PIN)) {
14974
      if (!homeDebounceCount) {
14975
        enqueue_and_echo_commands_P(PSTR("G28"));
14976
        LCD_MESSAGEPGM(MSG_AUTO_HOME);
14977
      }
14978
      if (homeDebounceCount < HOME_DEBOUNCE_DELAY)
14979
        homeDebounceCount++;
14980
      else
14981
        homeDebounceCount = 0;
14982
    }
14983
  #endif
14984
 
14985
  #if ENABLED(USE_CONTROLLER_FAN)
14986
    controllerFan(); // Check if fan should be turned on to cool stepper drivers down
14987
  #endif
14988
 
14989
  #if ENABLED(AUTO_POWER_CONTROL)
14990
    powerManager.check();
14991
  #endif
14992
 
14993
  #if ENABLED(EXTRUDER_RUNOUT_PREVENT)
14994
    if (thermalManager.degHotend(active_extruder) > EXTRUDER_RUNOUT_MINTEMP
14995
      && ELAPSED(ms, previous_move_ms + (EXTRUDER_RUNOUT_SECONDS) * 1000UL)
14996
      && !planner.has_blocks_queued()
14997
    ) {
14998
      #if ENABLED(SWITCHING_EXTRUDER)
14999
        bool oldstatus;
15000
        switch (active_extruder) {
15001
          default: oldstatus = E0_ENABLE_READ; enable_E0(); break;
15002
          #if E_STEPPERS > 1
15003
            case 2: case 3: oldstatus = E1_ENABLE_READ; enable_E1(); break;
15004
            #if E_STEPPERS > 2
15005
              case 4: oldstatus = E2_ENABLE_READ; enable_E2(); break;
15006
            #endif // E_STEPPERS > 2
15007
          #endif // E_STEPPERS > 1
15008
        }
15009
      #else // !SWITCHING_EXTRUDER
15010
        bool oldstatus;
15011
        switch (active_extruder) {
15012
          default: oldstatus = E0_ENABLE_READ; enable_E0(); break;
15013
          #if E_STEPPERS > 1
15014
            case 1: oldstatus = E1_ENABLE_READ; enable_E1(); break;
15015
            #if E_STEPPERS > 2
15016
              case 2: oldstatus = E2_ENABLE_READ; enable_E2(); break;
15017
              #if E_STEPPERS > 3
15018
                case 3: oldstatus = E3_ENABLE_READ; enable_E3(); break;
15019
                #if E_STEPPERS > 4
15020
                  case 4: oldstatus = E4_ENABLE_READ; enable_E4(); break;
15021
                #endif // E_STEPPERS > 4
15022
              #endif // E_STEPPERS > 3
15023
            #endif // E_STEPPERS > 2
15024
          #endif // E_STEPPERS > 1
15025
        }
15026
      #endif // !SWITCHING_EXTRUDER
15027
 
15028
      const float olde = current_position[E_CART];
15029
      current_position[E_CART] += EXTRUDER_RUNOUT_EXTRUDE;
15030
      planner.buffer_line_kinematic(current_position, MMM_TO_MMS(EXTRUDER_RUNOUT_SPEED), active_extruder);
15031
      current_position[E_CART] = olde;
15032
      planner.set_e_position_mm(olde);
15033
      planner.synchronize();
15034
 
15035
      #if ENABLED(SWITCHING_EXTRUDER)
15036
        switch (active_extruder) {
15037
          default: oldstatus = E0_ENABLE_WRITE(oldstatus); break;
15038
          #if E_STEPPERS > 1
15039
            case 2: case 3: oldstatus = E1_ENABLE_WRITE(oldstatus); break;
15040
            #if E_STEPPERS > 2
15041
              case 4: oldstatus = E2_ENABLE_WRITE(oldstatus); break;
15042
            #endif // E_STEPPERS > 2
15043
          #endif // E_STEPPERS > 1
15044
        }
15045
      #else // !SWITCHING_EXTRUDER
15046
        switch (active_extruder) {
15047
          case 0: E0_ENABLE_WRITE(oldstatus); break;
15048
          #if E_STEPPERS > 1
15049
            case 1: E1_ENABLE_WRITE(oldstatus); break;
15050
            #if E_STEPPERS > 2
15051
              case 2: E2_ENABLE_WRITE(oldstatus); break;
15052
              #if E_STEPPERS > 3
15053
                case 3: E3_ENABLE_WRITE(oldstatus); break;
15054
                #if E_STEPPERS > 4
15055
                  case 4: E4_ENABLE_WRITE(oldstatus); break;
15056
                #endif // E_STEPPERS > 4
15057
              #endif // E_STEPPERS > 3
15058
            #endif // E_STEPPERS > 2
15059
          #endif // E_STEPPERS > 1
15060
        }
15061
      #endif // !SWITCHING_EXTRUDER
15062
 
15063
      previous_move_ms = ms; // reset_stepper_timeout to keep steppers powered
15064
    }
15065
  #endif // EXTRUDER_RUNOUT_PREVENT
15066
 
15067
  #if ENABLED(DUAL_X_CARRIAGE)
15068
    // handle delayed move timeout
15069
    if (delayed_move_time && ELAPSED(ms, delayed_move_time + 1000UL) && IsRunning()) {
15070
      // travel moves have been received so enact them
15071
      delayed_move_time = 0xFFFFFFFFUL; // force moves to be done
15072
      set_destination_from_current();
15073
      prepare_move_to_destination();
15074
    }
15075
  #endif
15076
 
15077
  #if ENABLED(TEMP_STAT_LEDS)
15078
    handle_status_leds();
15079
  #endif
15080
 
15081
  #if ENABLED(MONITOR_DRIVER_STATUS)
15082
    monitor_tmc_driver();
15083
  #endif
15084
 
15085
  planner.check_axes_activity();
15086
}
15087
 
15088
/**
15089
 * Standard idle routine keeps the machine alive
15090
 */
15091
void idle(
15092
  #if ENABLED(ADVANCED_PAUSE_FEATURE)
15093
    bool no_stepper_sleep/*=false*/
15094
  #endif
15095
) {
15096
  #if ENABLED(MAX7219_DEBUG)
15097
    max7219.idle_tasks();
15098
  #endif
15099
 
15100
  lcd_update();
15101
 
15102
  host_keepalive();
15103
 
15104
  manage_inactivity(
15105
    #if ENABLED(ADVANCED_PAUSE_FEATURE)
15106
      no_stepper_sleep
15107
    #endif
15108
  );
15109
 
15110
  thermalManager.manage_heater();
15111
 
15112
  #if ENABLED(PRINTCOUNTER)
15113
    print_job_timer.tick();
15114
  #endif
15115
 
15116
  #if HAS_BUZZER && DISABLED(LCD_USE_I2C_BUZZER)
15117
    buzzer.tick();
15118
  #endif
15119
 
15120
  #if ENABLED(I2C_POSITION_ENCODERS)
15121
    static millis_t i2cpem_next_update_ms;
15122
    if (planner.has_blocks_queued() && ELAPSED(millis(), i2cpem_next_update_ms)) {
15123
      I2CPEM.update();
15124
      i2cpem_next_update_ms = millis() + I2CPE_MIN_UPD_TIME_MS;
15125
    }
15126
  #endif
15127
 
15128
  #if HAS_AUTO_REPORTING
15129
    if (!suspend_auto_report) {
15130
      #if ENABLED(AUTO_REPORT_TEMPERATURES)
15131
        thermalManager.auto_report_temperatures();
15132
      #endif
15133
      #if ENABLED(AUTO_REPORT_SD_STATUS)
15134
        card.auto_report_sd_status();
15135
      #endif
15136
    }
15137
  #endif
15138
}
15139
 
15140
/**
15141
 * Kill all activity and lock the machine.
15142
 * After this the machine will need to be reset.
15143
 */
15144
void kill(const char* lcd_msg) {
15145
  SERIAL_ERROR_START();
15146
  SERIAL_ERRORLNPGM(MSG_ERR_KILLED);
15147
 
15148
  thermalManager.disable_all_heaters();
15149
  disable_all_steppers();
15150
 
15151
  #if ENABLED(ULTRA_LCD)
15152
    kill_screen(lcd_msg);
15153
  #else
15154
    UNUSED(lcd_msg);
15155
  #endif
15156
 
15157
  _delay_ms(600); // Wait a short time (allows messages to get out before shutting down.
15158
  cli(); // Stop interrupts
15159
 
15160
  _delay_ms(250); //Wait to ensure all interrupts routines stopped
15161
  thermalManager.disable_all_heaters(); //turn off heaters again
15162
 
15163
  #ifdef ACTION_ON_KILL
15164
    SERIAL_ECHOLNPGM("//action:" ACTION_ON_KILL);
15165
  #endif
15166
 
15167
  #if HAS_POWER_SWITCH
15168
    PSU_OFF();
15169
  #endif
15170
 
15171
  suicide();
15172
  while (1) {
15173
    #if ENABLED(USE_WATCHDOG)
15174
      watchdog_reset();
15175
    #endif
15176
  } // Wait for reset
15177
}
15178
 
15179
/**
15180
 * Turn off heaters and stop the print in progress
15181
 * After a stop the machine may be resumed with M999
15182
 */
15183
void stop() {
15184
  thermalManager.disable_all_heaters(); // 'unpause' taken care of in here
15185
 
15186
  #if ENABLED(PROBING_FANS_OFF)
15187
    if (fans_paused) fans_pause(false); // put things back the way they were
15188
  #endif
15189
 
15190
  if (IsRunning()) {
15191
    Stopped_gcode_LastN = gcode_LastN; // Save last g_code for restart
15192
    SERIAL_ERROR_START();
15193
    SERIAL_ERRORLNPGM(MSG_ERR_STOPPED);
15194
    LCD_MESSAGEPGM(MSG_STOPPED);
15195
    safe_delay(350);       // allow enough time for messages to get out before stopping
15196
    Running = false;
15197
  }
15198
}
15199
 
15200
/**
15201
 * Marlin entry-point: Set up before the program loop
15202
 *  - Set up the kill pin, filament runout, power hold
15203
 *  - Start the serial port
15204
 *  - Print startup messages and diagnostics
15205
 *  - Get EEPROM or default settings
15206
 *  - Initialize managers for:
15207
 *    • temperature
15208
 *    • planner
15209
 *    • watchdog
15210
 *    • stepper
15211
 *    • photo pin
15212
 *    • servos
15213
 *    • LCD controller
15214
 *    • Digipot I2C
15215
 *    • Z probe sled
15216
 *    • status LEDs
15217
 */
15218
void setup() {
15219
 
15220
  #if ENABLED(MAX7219_DEBUG)
15221
    max7219.init();
15222
  #endif
15223
 
15224
  #if ENABLED(DISABLE_JTAG)
15225
    // Disable JTAG on AT90USB chips to free up pins for IO
15226
    MCUCR = 0x80;
15227
    MCUCR = 0x80;
15228
  #endif
15229
 
15230
  #if ENABLED(FILAMENT_RUNOUT_SENSOR)
15231
    runout.setup();
15232
  #endif
15233
 
15234
  setup_killpin();
15235
 
15236
  setup_powerhold();
15237
 
15238
  #if HAS_STEPPER_RESET
15239
    disableStepperDrivers();
15240
  #endif
15241
 
15242
  MYSERIAL0.begin(BAUDRATE);
15243
  SERIAL_PROTOCOLLNPGM("start");
15244
  SERIAL_ECHO_START();
15245
 
15246
  // Prepare communication for TMC drivers
15247
  #if HAS_DRIVER(TMC2130)
15248
    tmc_init_cs_pins();
15249
  #endif
15250
  #if HAS_DRIVER(TMC2208)
15251
    tmc2208_serial_begin();
15252
  #endif
15253
 
15254
  // Check startup - does nothing if bootloader sets MCUSR to 0
15255
  byte mcu = MCUSR;
15256
  if (mcu &  1) SERIAL_ECHOLNPGM(MSG_POWERUP);
15257
  if (mcu &  2) SERIAL_ECHOLNPGM(MSG_EXTERNAL_RESET);
15258
  if (mcu &  4) SERIAL_ECHOLNPGM(MSG_BROWNOUT_RESET);
15259
  if (mcu &  8) SERIAL_ECHOLNPGM(MSG_WATCHDOG_RESET);
15260
  if (mcu & 32) SERIAL_ECHOLNPGM(MSG_SOFTWARE_RESET);
15261
  MCUSR = 0;
15262
 
15263
  SERIAL_ECHOPGM(MSG_MARLIN);
15264
  SERIAL_CHAR(' ');
15265
  SERIAL_ECHOLNPGM(SHORT_BUILD_VERSION);
15266
  SERIAL_EOL();
15267
 
15268
  #if defined(STRING_DISTRIBUTION_DATE) && defined(STRING_CONFIG_H_AUTHOR)
15269
    SERIAL_ECHO_START();
15270
    SERIAL_ECHOPGM(MSG_CONFIGURATION_VER);
15271
    SERIAL_ECHOPGM(STRING_DISTRIBUTION_DATE);
15272
    SERIAL_ECHOLNPGM(MSG_AUTHOR STRING_CONFIG_H_AUTHOR);
15273
    SERIAL_ECHO_START();
15274
    SERIAL_ECHOLNPGM("Compiled: " __DATE__);
15275
  #endif
15276
 
15277
  SERIAL_ECHO_START();
15278
  SERIAL_ECHOPAIR(MSG_FREE_MEMORY, freeMemory());
15279
  SERIAL_ECHOLNPAIR(MSG_PLANNER_BUFFER_BYTES, int(sizeof(block_t))*(BLOCK_BUFFER_SIZE));
15280
 
15281
  // Send "ok" after commands by default
15282
  for (int8_t i = 0; i < BUFSIZE; i++) send_ok[i] = true;
15283
 
15284
  // Load data from EEPROM if available (or use defaults)
15285
  // This also updates variables in the planner, elsewhere
15286
  (void)settings.load();
15287
 
15288
  #if HAS_M206_COMMAND
15289
    // Initialize current position based on home_offset
15290
    COPY(current_position, home_offset);
15291
  #else
15292
    ZERO(current_position);
15293
  #endif
15294
 
15295
  // Vital to init stepper/planner equivalent for current_position
15296
  SYNC_PLAN_POSITION_KINEMATIC();
15297
 
15298
  thermalManager.init();    // Initialize temperature loop
15299
 
15300
  print_job_timer.init();   // Initial setup of print job timer
15301
 
15302
  endstops.init();          // Init endstops and pullups
15303
 
15304
  stepper.init();           // Init stepper. This enables interrupts!
15305
 
15306
  servo_init();             // Initialize all servos, stow servo probe
15307
 
15308
  #if HAS_PHOTOGRAPH
15309
    OUT_WRITE(PHOTOGRAPH_PIN, LOW);
15310
  #endif
15311
 
15312
  #if HAS_CASE_LIGHT
15313
    case_light_on = CASE_LIGHT_DEFAULT_ON;
15314
    case_light_brightness = CASE_LIGHT_DEFAULT_BRIGHTNESS;
15315
    update_case_light();
15316
  #endif
15317
 
15318
  #if ENABLED(SPINDLE_LASER_ENABLE)
15319
    OUT_WRITE(SPINDLE_LASER_ENABLE_PIN, !SPINDLE_LASER_ENABLE_INVERT);  // init spindle to off
15320
    #if SPINDLE_DIR_CHANGE
15321
      OUT_WRITE(SPINDLE_DIR_PIN, SPINDLE_INVERT_DIR ? 255 : 0);  // init rotation to clockwise (M3)
15322
    #endif
15323
    #if ENABLED(SPINDLE_LASER_PWM)
15324
      SET_OUTPUT(SPINDLE_LASER_PWM_PIN);
15325
      analogWrite(SPINDLE_LASER_PWM_PIN, SPINDLE_LASER_PWM_INVERT ? 255 : 0);  // set to lowest speed
15326
    #endif
15327
  #endif
15328
 
15329
  #if HAS_BED_PROBE
15330
    endstops.enable_z_probe(false);
15331
  #endif
15332
 
15333
  #if ENABLED(USE_CONTROLLER_FAN)
15334
    SET_OUTPUT(CONTROLLER_FAN_PIN); //Set pin used for driver cooling fan
15335
  #endif
15336
 
15337
  #if HAS_STEPPER_RESET
15338
    enableStepperDrivers();
15339
  #endif
15340
 
15341
  #if ENABLED(DIGIPOT_I2C)
15342
    digipot_i2c_init();
15343
  #endif
15344
 
15345
  #if ENABLED(DAC_STEPPER_CURRENT)
15346
    dac_init();
15347
  #endif
15348
 
15349
  #if (ENABLED(Z_PROBE_SLED) || ENABLED(SOLENOID_PROBE)) && HAS_SOLENOID_1
15350
    OUT_WRITE(SOL1_PIN, LOW); // turn it off
15351
  #endif
15352
 
15353
  #if HAS_HOME
15354
    SET_INPUT_PULLUP(HOME_PIN);
15355
  #endif
15356
 
15357
  #if PIN_EXISTS(STAT_LED_RED)
15358
    OUT_WRITE(STAT_LED_RED_PIN, LOW); // turn it off
15359
  #endif
15360
 
15361
  #if PIN_EXISTS(STAT_LED_BLUE)
15362
    OUT_WRITE(STAT_LED_BLUE_PIN, LOW); // turn it off
15363
  #endif
15364
 
15365
  #if HAS_COLOR_LEDS
15366
    leds.setup();
15367
  #endif
15368
 
15369
  #if ENABLED(RGB_LED) || ENABLED(RGBW_LED)
15370
    SET_OUTPUT(RGB_LED_R_PIN);
15371
    SET_OUTPUT(RGB_LED_G_PIN);
15372
    SET_OUTPUT(RGB_LED_B_PIN);
15373
    #if ENABLED(RGBW_LED)
15374
      SET_OUTPUT(RGB_LED_W_PIN);
15375
    #endif
15376
  #endif
15377
 
15378
  #if ENABLED(MK2_MULTIPLEXER)
15379
    SET_OUTPUT(E_MUX0_PIN);
15380
    SET_OUTPUT(E_MUX1_PIN);
15381
    SET_OUTPUT(E_MUX2_PIN);
15382
  #endif
15383
 
15384
  #if HAS_FANMUX
15385
    fanmux_init();
15386
  #endif
15387
 
15388
  lcd_init();
15389
  lcd_reset_status();
15390
 
15391
  #if ENABLED(SHOW_BOOTSCREEN)
15392
    lcd_bootscreen();
15393
  #endif
15394
 
15395
  #if ENABLED(MIXING_EXTRUDER) && MIXING_VIRTUAL_TOOLS > 1
15396
    // Virtual Tools 0, 1, 2, 3 = Filament 1, 2, 3, 4, etc.
15397
    for (uint8_t t = 0; t < MIXING_VIRTUAL_TOOLS && t < MIXING_STEPPERS; t++)
15398
      for (uint8_t i = 0; i < MIXING_STEPPERS; i++)
15399
        mixing_virtual_tool_mix[t][i] = (t == i) ? 1.0 : 0.0;
15400
 
15401
    // Remaining virtual tools are 100% filament 1
15402
    #if MIXING_STEPPERS < MIXING_VIRTUAL_TOOLS
15403
      for (uint8_t t = MIXING_STEPPERS; t < MIXING_VIRTUAL_TOOLS; t++)
15404
        for (uint8_t i = 0; i < MIXING_STEPPERS; i++)
15405
          mixing_virtual_tool_mix[t][i] = (i == 0) ? 1.0 : 0.0;
15406
    #endif
15407
 
15408
    // Initialize mixing to tool 0 color
15409
    for (uint8_t i = 0; i < MIXING_STEPPERS; i++)
15410
      mixing_factor[i] = mixing_virtual_tool_mix[0][i];
15411
  #endif
15412
 
15413
  #if ENABLED(BLTOUCH)
15414
    // Make sure any BLTouch error condition is cleared
15415
    bltouch_command(BLTOUCH_RESET, BLTOUCH_RESET_DELAY);
15416
    set_bltouch_deployed(false);
15417
  #endif
15418
 
15419
  #if ENABLED(I2C_POSITION_ENCODERS)
15420
    I2CPEM.init();
15421
  #endif
15422
 
15423
  #if ENABLED(EXPERIMENTAL_I2CBUS) && I2C_SLAVE_ADDRESS > 0
15424
    i2c.onReceive(i2c_on_receive);
15425
    i2c.onRequest(i2c_on_request);
15426
  #endif
15427
 
15428
  #if DO_SWITCH_EXTRUDER
15429
    move_extruder_servo(0);  // Initialize extruder servo
15430
  #endif
15431
 
15432
  #if ENABLED(SWITCHING_NOZZLE)
15433
    move_nozzle_servo(0);  // Initialize nozzle servo
15434
  #endif
15435
 
15436
  #if ENABLED(PARKING_EXTRUDER)
15437
    #if ENABLED(PARKING_EXTRUDER_SOLENOIDS_INVERT)
15438
      pe_activate_magnet(0);
15439
      pe_activate_magnet(1);
15440
    #else
15441
      pe_deactivate_magnet(0);
15442
      pe_deactivate_magnet(1);
15443
    #endif
15444
  #endif
15445
 
15446
  #if ENABLED(POWER_LOSS_RECOVERY)
15447
    check_print_job_recovery();
15448
  #endif
15449
 
15450
  #if ENABLED(USE_WATCHDOG)
15451
    watchdog_init();
15452
  #endif
15453
 
15454
  #if ENABLED(HANGPRINTER)
15455
    enable_A();
15456
    enable_B();
15457
    enable_C();
15458
    enable_D();
15459
  #endif
15460
 
15461
  #if ENABLED(SDSUPPORT) && !(ENABLED(ULTRA_LCD) && PIN_EXISTS(SD_DETECT))
15462
    card.beginautostart();
15463
  #endif
15464
}
15465
 
15466
/**
15467
 * The main Marlin program loop
15468
 *
15469
 *  - Abort SD printing if flagged
15470
 *  - Save or log commands to SD
15471
 *  - Process available commands (if not saving)
15472
 *  - Call heater manager
15473
 *  - Call inactivity manager
15474
 *  - Call endstop manager
15475
 *  - Call LCD update
15476
 */
15477
void loop() {
15478
 
15479
  #if ENABLED(SDSUPPORT)
15480
 
15481
    card.checkautostart();
15482
 
15483
    if (card.abort_sd_printing) {
15484
      card.stopSDPrint(
15485
        #if SD_RESORT
15486
          true
15487
        #endif
15488
      );
15489
      clear_command_queue();
15490
      quickstop_stepper();
15491
      print_job_timer.stop();
15492
      thermalManager.disable_all_heaters();
15493
      #if FAN_COUNT > 0
15494
        for (uint8_t i = 0; i < FAN_COUNT; i++) fanSpeeds[i] = 0;
15495
      #endif
15496
      wait_for_heatup = false;
15497
      #if ENABLED(POWER_LOSS_RECOVERY)
15498
        card.removeJobRecoveryFile();
15499
      #endif
15500
    }
15501
 
15502
  #endif // SDSUPPORT
15503
 
15504
  if (commands_in_queue < BUFSIZE) get_available_commands();
15505
 
15506
  if (commands_in_queue) {
15507
 
15508
    #if ENABLED(SDSUPPORT)
15509
 
15510
      if (card.saving) {
15511
        char* command = command_queue[cmd_queue_index_r];
15512
        if (strstr_P(command, PSTR("M29"))) {
15513
          // M29 closes the file
15514
          card.closefile();
15515
          SERIAL_PROTOCOLLNPGM(MSG_FILE_SAVED);
15516
 
15517
          #if USE_MARLINSERIAL
15518
            #if ENABLED(SERIAL_STATS_DROPPED_RX)
15519
              SERIAL_ECHOLNPAIR("Dropped bytes: ", customizedSerial.dropped());
15520
            #endif
15521
            #if ENABLED(SERIAL_STATS_MAX_RX_QUEUED)
15522
              SERIAL_ECHOLNPAIR("Max RX Queue Size: ", customizedSerial.rxMaxEnqueued());
15523
            #endif
15524
          #endif
15525
 
15526
          ok_to_send();
15527
        }
15528
        else {
15529
          // Write the string from the read buffer to SD
15530
          card.write_command(command);
15531
          if (card.logging)
15532
            process_next_command(); // The card is saving because it's logging
15533
          else
15534
            ok_to_send();
15535
        }
15536
      }
15537
      else {
15538
        process_next_command();
15539
        #if ENABLED(POWER_LOSS_RECOVERY)
15540
          if (card.cardOK && card.sdprinting) save_job_recovery_info();
15541
        #endif
15542
      }
15543
 
15544
    #else
15545
 
15546
      process_next_command();
15547
 
15548
    #endif // SDSUPPORT
15549
 
15550
    // The queue may be reset by a command handler or by code invoked by idle() within a handler
15551
    if (commands_in_queue) {
15552
      --commands_in_queue;
15553
      if (++cmd_queue_index_r >= BUFSIZE) cmd_queue_index_r = 0;
15554
    }
15555
  }
15556
  endstops.event_handler();
15557
  idle();
15558
}