@@ -200,13 +200,15 @@ class G29_State {
200200 *
201201 * With AUTO_BED_LEVELING_BILINEAR:
202202 * Z<float> Supply additional Z offset to all probe points.
203- * W<bool> Write a mesh point. (If G29 is idle.)
204- * I<index> Index for mesh point
205- * J<index> Index for mesh point
206- * X<float> For mesh point, overrides I
207- * Y<float> For mesh point, overrides J
208- * Z<float> For mesh point. If omitted, uses current position's raw Z
209- * P<float> Populate the mesh with a specified Z value.
203+ * W<bool> Write a mesh point. (If G29 is idle.)
204+ * I<index> Index for mesh point
205+ * J<index> Index for mesh point
206+ * X<float> For mesh point, overrides I
207+ * Y<float> For mesh point, overrides J
208+ * Z<float> For mesh point. If omitted, uses current position's raw Z
209+ *
210+ * With ABL_BILINEAR_G29_P_FILL_MESH
211+ * P<float> Populate the mesh with a specified Z value
210212 *
211213 * With DEBUG_LEVELING_FEATURE:
212214 * C<bool> Make a totally fake grid with no actual probing.
@@ -243,30 +245,89 @@ G29_TYPE GcodeSuite::G29() {
243245 if (DISABLED (PROBE_MANUALLY) && seenQ) G29_RETURN (false , false );
244246 #endif
245247
246- // P = populate grid with specified Z value
247- #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
248- bool do_init = parser.seenval (' P' );
249- float init_val = 0 .0f ;
250- if (do_init) {
251- init_val = RAW_Z_POSITION (parser.value_linear_units ());
252- if (!WITHIN (init_val, -10 , 10 )) {
253- SERIAL_ERROR_MSG (" Bad initialization value" );
248+ // W = Write a mesh point (below)
249+ const bool seenW = TERN0 (AUTO_BED_LEVELING_BILINEAR, parser.seen_test (' W' ));
250+ if (seenW && g29_in_progress) {
251+ SERIAL_WARN_MSG (" (W) ignored." );
252+ G29_RETURN (false , false );
253+ }
254+
255+ // J = Jettison bed leveling data
256+ const bool seenJ = !seenW && parser.seen_test (' J' );
257+ if (seenJ) {
258+ if (g29_in_progress) {
259+ SERIAL_WARN_MSG (" (J) ignored." );
260+ G29_RETURN (false , false );
261+ }
262+ else
263+ reset_bed_level ();
264+ }
265+
266+ // P = Populate the mesh with a specified value
267+ #if ENABLED(ABL_BILINEAR_G29_P_FILL_MESH)
268+ if (parser.seenval (' P' )) {
269+ const float init_val = parser.value_linear_units ();
270+ if (!WITHIN (init_val, -10 .0f , 10 .0f )) {
271+ SERIAL_WARN_MSG (" (P) value out of range (-10-10).\n " );
254272 G29_RETURN (false , false );
255273 }
274+ bedlevel.fill (init_val);
256275 }
257- #else
258- constexpr bool do_init = false ;
259- constexpr float init_val = 0 .0f ;
276+ #endif
277+
278+ #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
279+
280+ if (seenW) {
281+
282+ const float rz = parser.seenval (' Z' ) ? RAW_Z_POSITION (parser.value_linear_units ()) : current_position.z ;
283+ if (!WITHIN (rz, -10 , 10 )) {
284+ SERIAL_ERROR_MSG (" (W) value out of range (-10-10)." );
285+ G29_RETURN (false , false );
286+ }
287+
288+ const float rx = RAW_X_POSITION (parser.linearval (' X' , NAN)),
289+ ry = RAW_Y_POSITION (parser.linearval (' Y' , NAN));
290+ int8_t i = parser.byteval (' I' , -1 ), j = parser.byteval (' J' , -1 );
291+
292+ #pragma GCC diagnostic push
293+ #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
294+
295+ if (!isnan (rx) && !isnan (ry)) {
296+ // Get nearest i / j from rx / ry
297+ i = (rx - bedlevel.grid_start .x ) / bedlevel.grid_spacing .x + 0 .5f ;
298+ j = (ry - bedlevel.grid_start .y ) / bedlevel.grid_spacing .y + 0 .5f ;
299+ LIMIT (i, 0 , (GRID_MAX_POINTS_X) - 1 );
300+ LIMIT (j, 0 , (GRID_MAX_POINTS_Y) - 1 );
301+ }
302+
303+ #pragma GCC diagnostic pop
304+
305+ if (WITHIN (i, 0 , (GRID_MAX_POINTS_X) - 1 ) && WITHIN (j, 0 , (GRID_MAX_POINTS_Y) - 1 )) {
306+ set_bed_leveling_enabled (false );
307+ bedlevel.z_values [i][j] = rz;
308+ bedlevel.refresh_bed_level ();
309+ TERN_ (EXTENSIBLE_UI, ExtUI::onMeshUpdate (i, j, rz));
310+ if (!leveling_is_valid ()) SERIAL_WARN_MSG (" Bilinear grid is invalid." );
311+ if (abl.reenable ) {
312+ set_bed_leveling_enabled (true );
313+ report_current_position ();
314+ }
315+ }
316+
317+ G29_RETURN (false , false );
318+
319+ } // seenW
320+
260321 #endif
261322
262323 // A = Abort manual probing
263324 // C<bool> = Generate fake probe points (DEBUG_LEVELING_FEATURE)
264325 const bool seenA = TERN0 (PROBE_MANUALLY, parser.seen_test (' A' )),
265326 no_action = seenA || seenQ,
266- faux = (ENABLED (DEBUG_LEVELING_FEATURE) && DISABLED (PROBE_MANUALLY) ? parser.boolval (' C' ) : no_action) || do_init ;
327+ faux = (ENABLED (DEBUG_LEVELING_FEATURE) && DISABLED (PROBE_MANUALLY) ? parser.boolval (' C' ) : no_action);
267328
268329 // O = Don't level if leveling is already active
269- if (!no_action && planner. leveling_active && parser. boolval ( ' O ' ) ) {
330+ if (parser. boolval ( ' O ' ) && !no_action && planner. leveling_active ) {
270331 if (DEBUGGING (LEVELING)) DEBUG_ECHOLNPGM (" > Auto-level not needed, skip" );
271332 G29_RETURN (false , false );
272333 }
@@ -275,14 +336,8 @@ G29_TYPE GcodeSuite::G29() {
275336 if (parser.seen_test (' N' ))
276337 process_subcommands_now (TERN (CAN_SET_LEVELING_AFTER_G28, F (" G28L0" ), FPSTR (G28_STR)));
277338
278- #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
279- const bool seen_w = parser.seen_test (' W' );
280- #else
281- constexpr bool seen_w = false ;
282- #endif
283-
284339 // Don't allow auto-leveling without homing first
285- if (!seen_w && ! faux && homing_needed_error ()) G29_RETURN (false , false );
340+ if (!faux && homing_needed_error ()) G29_RETURN (false , false );
286341
287342 // 3-point leveling gets points from the probe class
288343 #if ENABLED(AUTO_BED_LEVELING_3POINT)
@@ -320,58 +375,6 @@ G29_TYPE GcodeSuite::G29() {
320375
321376 abl.reenable = planner.leveling_active ;
322377
323- #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
324-
325- if (seen_w) {
326- if (!leveling_is_valid ()) {
327- SERIAL_ERROR_MSG (" No bilinear grid" );
328- G29_RETURN (false , false );
329- }
330-
331- const float rz = parser.seenval (' Z' ) ? RAW_Z_POSITION (parser.value_linear_units ()) : current_position.z ;
332- if (!WITHIN (rz, -10 , 10 )) {
333- SERIAL_ERROR_MSG (" Bad Z value" );
334- G29_RETURN (false , false );
335- }
336-
337- const float rx = RAW_X_POSITION (parser.linearval (' X' , NAN)),
338- ry = RAW_Y_POSITION (parser.linearval (' Y' , NAN));
339- int8_t i = parser.byteval (' I' , -1 ), j = parser.byteval (' J' , -1 );
340-
341- #pragma GCC diagnostic push
342- #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
343-
344- if (!isnan (rx) && !isnan (ry)) {
345- // Get nearest i / j from rx / ry
346- i = (rx - bedlevel.grid_start .x ) / bedlevel.grid_spacing .x + 0 .5f ;
347- j = (ry - bedlevel.grid_start .y ) / bedlevel.grid_spacing .y + 0 .5f ;
348- LIMIT (i, 0 , (GRID_MAX_POINTS_X) - 1 );
349- LIMIT (j, 0 , (GRID_MAX_POINTS_Y) - 1 );
350- }
351-
352- #pragma GCC diagnostic pop
353-
354- if (WITHIN (i, 0 , (GRID_MAX_POINTS_X) - 1 ) && WITHIN (j, 0 , (GRID_MAX_POINTS_Y) - 1 )) {
355- set_bed_leveling_enabled (false );
356- bedlevel.z_values [i][j] = rz;
357- bedlevel.refresh_bed_level ();
358- TERN_ (EXTENSIBLE_UI, ExtUI::onMeshUpdate (i, j, rz));
359- if (abl.reenable ) {
360- set_bed_leveling_enabled (true );
361- report_current_position ();
362- }
363- }
364- G29_RETURN (false , false );
365- } // parser.seen_test('W')
366-
367- #endif
368-
369- // Jettison bed leveling data
370- if (!seen_w && parser.seen_test (' J' )) {
371- reset_bed_level ();
372- G29_RETURN (false , false );
373- }
374-
375378 abl.verbose_level = parser.intval (' V' );
376379 if (!WITHIN (abl.verbose_level , 0 , 4 )) {
377380 SERIAL_ECHOLNPGM (GCODE_ERR_MSG (" (V)erbose level implausible (0-4)." ));
@@ -732,12 +735,9 @@ G29_TYPE GcodeSuite::G29() {
732735 if (PR_INNER_VAR == inStart) {
733736 char tmp_1[32 ];
734737
735- // move to the start point of new line
736- if (faux)
737- abl.measured_z = do_init ? init_val : 0 .001f * random (-100 , 101 );
738- else
739- abl.measured_z = probe.probe_at_point (abl.probePos , raise_after, abl.verbose_level );
740-
738+ // Move to the start point of new line
739+ abl.measured_z = faux ? 0 .001f * random (-100 , 101 ) : probe.probe_at_point (abl.probePos , raise_after, abl.verbose_level );
740+
741741 // Go to the end of the row/column ... and back up by one
742742 // TODO: Why not just use... PR_INNER_VAR = inStop - inInc
743743 for (PR_INNER_VAR = inStart; PR_INNER_VAR != inStop; PR_INNER_VAR += inInc);
@@ -790,10 +790,7 @@ G29_TYPE GcodeSuite::G29() {
790790
791791 #else // !BD_SENSOR_PROBE_NO_STOP
792792
793- if (faux)
794- abl.measured_z = do_init ? init_val : 0 .001f * random (-100 , 101 );
795- else
796- abl.measured_z = probe.probe_at_point (abl.probePos , raise_after, abl.verbose_level );
793+ abl.measured_z = faux ? 0 .001f * random (-100 , 101 ) : probe.probe_at_point (abl.probePos , raise_after, abl.verbose_level );
797794
798795 #endif
799796
@@ -842,10 +839,7 @@ G29_TYPE GcodeSuite::G29() {
842839
843840 // Retain the last probe position
844841 abl.probePos = xy_pos_t (points[i]);
845- if (faux)
846- abl.measured_z = do_init ? init_val : 0 .001f * random (-100 , 101 );
847- else
848- abl.measured_z = probe.probe_at_point (abl.probePos , raise_after, abl.verbose_level );
842+ abl.measured_z = faux ? 0 .001f * random (-100 , 101 ) : probe.probe_at_point (abl.probePos , raise_after, abl.verbose_level );
849843 if (isnan (abl.measured_z )) {
850844 set_bed_leveling_enabled (abl.reenable );
851845 break ;
@@ -1036,10 +1030,6 @@ G29_TYPE GcodeSuite::G29() {
10361030 // Restore state after probing
10371031 if (!faux) restore_feedrate_and_scaling ();
10381032
1039- // Return here if we merely initialized for a with value (bilinear G29 P<value>)
1040- // No need to do the after G29 gcode or the other stuff
1041- if (do_init) G29_RETURN (false , true );
1042-
10431033 TERN_ (HAS_BED_PROBE, probe.move_z_after_probing ());
10441034
10451035 #ifdef EVENT_GCODE_AFTER_G29
0 commit comments