Browse Source

Group UBL parameters, add comments

Scott Lahteine 4 years ago
parent
commit
da4b6896f7

+ 19
- 16
Marlin/src/feature/bedlevel/ubl/ubl.h View File

45
   typedef int16_t mesh_store_t[GRID_MAX_POINTS_X][GRID_MAX_POINTS_Y];
45
   typedef int16_t mesh_store_t[GRID_MAX_POINTS_X][GRID_MAX_POINTS_Y];
46
 #endif
46
 #endif
47
 
47
 
48
+typedef struct {
49
+  bool      C_seen;
50
+  int8_t    V_verbosity,
51
+            P_phase,
52
+            R_repetition,
53
+            KLS_storage_slot,
54
+            T_map_type;
55
+  float     B_shim_thickness,
56
+            C_constant;
57
+  xy_pos_t  XY_pos;
58
+  xy_bool_t XY_seen;
59
+  #if HAS_BED_PROBE
60
+    int     grid_size;
61
+  #endif
62
+} G29_parameters_t;
63
+
48
 class unified_bed_leveling {
64
 class unified_bed_leveling {
49
 private:
65
 private:
50
 
66
 
51
-  static int    g29_verbose_level,
52
-                g29_phase_value,
53
-                g29_repetition_cnt,
54
-                g29_storage_slot,
55
-                g29_map_type;
56
-  static bool   g29_c_flag;
57
-  static float  g29_card_thickness,
58
-                g29_constant;
59
-  static xy_pos_t g29_pos;
60
-  static xy_bool_t xy_seen;
61
-
62
-  #if HAS_BED_PROBE
63
-    static int  g29_grid_size;
64
-  #endif
67
+  static G29_parameters_t param;
65
 
68
 
66
   #if IS_NEWPANEL
69
   #if IS_NEWPANEL
67
     static void move_z_with_encoder(const float &multiplier);
70
     static void move_z_with_encoder(const float &multiplier);
71
     static void fine_tune_mesh(const xy_pos_t &pos, const bool do_ubl_mesh_map) _O0;
74
     static void fine_tune_mesh(const xy_pos_t &pos, const bool do_ubl_mesh_map) _O0;
72
   #endif
75
   #endif
73
 
76
 
74
-  static bool g29_parameter_parsing() _O0;
77
+  static bool G29_parse_parameters() _O0;
75
   static void shift_mesh_height();
78
   static void shift_mesh_height();
76
   static void probe_entire_mesh(const xy_pos_t &near, const bool do_ubl_mesh_map, const bool stow_probe, const bool do_furthest) _O0;
79
   static void probe_entire_mesh(const xy_pos_t &near, const bool do_ubl_mesh_map, const bool stow_probe, const bool do_furthest) _O0;
77
   static void tilt_mesh_based_on_3pts(const float &z1, const float &z2, const float &z3);
80
   static void tilt_mesh_based_on_3pts(const float &z1, const float &z2, const float &z3);
129
     static inline void steppers_were_disabled() {}
132
     static inline void steppers_were_disabled() {}
130
   #endif
133
   #endif
131
 
134
 
132
-  static volatile int16_t encoder_diff; // Volatile because buttons may changed it at interrupt time
135
+  static volatile int16_t encoder_diff; // Volatile because buttons may change it at interrupt time
133
 
136
 
134
   unified_bed_leveling();
137
   unified_bed_leveling();
135
 
138
 

+ 172
- 163
Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp View File

71
 #define SIZE_OF_LITTLE_RAISE 1
71
 #define SIZE_OF_LITTLE_RAISE 1
72
 #define BIG_RAISE_NOT_NEEDED 0
72
 #define BIG_RAISE_NOT_NEEDED 0
73
 
73
 
74
-int    unified_bed_leveling::g29_verbose_level,
75
-       unified_bed_leveling::g29_phase_value,
76
-       unified_bed_leveling::g29_repetition_cnt,
77
-       unified_bed_leveling::g29_storage_slot = 0,
78
-       unified_bed_leveling::g29_map_type;
79
-bool   unified_bed_leveling::g29_c_flag;
80
-float  unified_bed_leveling::g29_card_thickness = 0,
81
-       unified_bed_leveling::g29_constant = 0;
82
-xy_bool_t unified_bed_leveling::xy_seen;
83
-xy_pos_t unified_bed_leveling::g29_pos;
84
-
85
-#if HAS_BED_PROBE
86
-  int  unified_bed_leveling::g29_grid_size;
87
-#endif
88
-
89
 /**
74
 /**
90
  *   G29: Unified Bed Leveling by Roxy
75
  *   G29: Unified Bed Leveling by Roxy
91
  *
76
  *
309
  *   features of all three systems combined.
294
  *   features of all three systems combined.
310
  */
295
  */
311
 
296
 
297
+G29_parameters_t unified_bed_leveling::param;
298
+
312
 void unified_bed_leveling::G29() {
299
 void unified_bed_leveling::G29() {
313
 
300
 
314
   bool probe_deployed = false;
301
   bool probe_deployed = false;
315
-  if (g29_parameter_parsing()) return; // Abort on parameter error
302
+  if (G29_parse_parameters()) return; // Abort on parameter error
316
 
303
 
317
   const int8_t p_val = parser.intval('P', -1);
304
   const int8_t p_val = parser.intval('P', -1);
318
   const bool may_move = p_val == 1 || p_val == 2 || p_val == 4 || parser.seen('J');
305
   const bool may_move = p_val == 1 || p_val == 2 || p_val == 4 || parser.seen('J');
326
     TERN_(HAS_MULTI_HOTEND, if (active_extruder) tool_change(0));
313
     TERN_(HAS_MULTI_HOTEND, if (active_extruder) tool_change(0));
327
   }
314
   }
328
 
315
 
329
-  // Invalidate Mesh Points. This command is a little bit asymmetrical because
330
-  // it directly specifies the repetition count and does not use the 'R' parameter.
316
+  // Invalidate one or more nearby mesh points, possibly all.
331
   if (parser.seen('I')) {
317
   if (parser.seen('I')) {
332
-    uint8_t cnt = 0;
333
-    g29_repetition_cnt = parser.has_value() ? parser.value_int() : 1;
334
-    if (g29_repetition_cnt >= GRID_MAX_POINTS) {
335
-      set_all_mesh_points_to_value(NAN);
336
-    }
337
-    else {
338
-      while (g29_repetition_cnt--) {
339
-        if (cnt > 20) { cnt = 0; idle(); }
340
-        const mesh_index_pair closest = find_closest_mesh_point_of_type(REAL, g29_pos);
341
-        const xy_int8_t &cpos = closest.pos;
342
-        if (cpos.x < 0) {
343
-          // No more REAL mesh points to invalidate, so we ASSUME the user
344
-          // meant to invalidate the ENTIRE mesh, which cannot be done with
345
-          // find_closest_mesh_point loop which only returns REAL points.
346
-          set_all_mesh_points_to_value(NAN);
347
-          SERIAL_ECHOLNPGM("Entire Mesh invalidated.\n");
348
-          break;            // No more invalid Mesh Points to populate
349
-        }
350
-        z_values[cpos.x][cpos.y] = NAN;
351
-        TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(cpos, 0.0f));
352
-        cnt++;
318
+    int16_t count = parser.has_value() ? parser.value_int() : 1;
319
+    bool invalidate_all = count >= GRID_MAX_POINTS;
320
+    if (!invalidate_all) {
321
+      while (count--) {
322
+        if ((count & 0x0F) == 0x0F) idle();
323
+        const mesh_index_pair closest = find_closest_mesh_point_of_type(REAL, param.XY_pos);
324
+        // No more REAL mesh points to invalidate? Assume the user meant
325
+        // to invalidate the ENTIRE mesh, which can't be done with
326
+        // find_closest_mesh_point (which only returns REAL points).
327
+        if (closest.pos.x < 0) { invalidate_all = true; break; }
328
+        z_values[closest.pos.x][closest.pos.y] = NAN;
329
+        TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(closest.pos, 0.0f));
353
       }
330
       }
354
     }
331
     }
355
-    SERIAL_ECHOLNPGM("Locations invalidated.\n");
332
+    if (invalidate_all) {
333
+      invalidate();
334
+      SERIAL_ECHOPGM("Entire Mesh");
335
+    }
336
+    else
337
+      SERIAL_ECHOPGM("Locations");
338
+    SERIAL_ECHOLNPGM(" invalidated.\n");
356
   }
339
   }
357
 
340
 
358
   if (parser.seen('Q')) {
341
   if (parser.seen('Q')) {
364
     SERIAL_ECHOLNPGM("Loading test_pattern values.\n");
347
     SERIAL_ECHOLNPGM("Loading test_pattern values.\n");
365
     switch (test_pattern) {
348
     switch (test_pattern) {
366
 
349
 
367
-      #if ENABLED(UBL_DEVEL_DEBUGGING)
368
-        case -1:
369
-          g29_eeprom_dump();
370
-          break;
371
-      #endif
350
+      case -1: TERN_(UBL_DEVEL_DEBUGGING, g29_eeprom_dump()); break;
372
 
351
 
373
       case 0:
352
       case 0:
374
         GRID_LOOP(x, y) {                                     // Create a bowl shape similar to a poorly-calibrated Delta
353
         GRID_LOOP(x, y) {                                     // Create a bowl shape similar to a poorly-calibrated Delta
395
         // Allow the user to specify the height because 10mm is a little extreme in some cases.
374
         // Allow the user to specify the height because 10mm is a little extreme in some cases.
396
         for (uint8_t x = (GRID_MAX_POINTS_X) / 3; x < 2 * (GRID_MAX_POINTS_X) / 3; x++)     // Create a rectangular raised area in
375
         for (uint8_t x = (GRID_MAX_POINTS_X) / 3; x < 2 * (GRID_MAX_POINTS_X) / 3; x++)     // Create a rectangular raised area in
397
           for (uint8_t y = (GRID_MAX_POINTS_Y) / 3; y < 2 * (GRID_MAX_POINTS_Y) / 3; y++) { // the center of the bed
376
           for (uint8_t y = (GRID_MAX_POINTS_Y) / 3; y < 2 * (GRID_MAX_POINTS_Y) / 3; y++) { // the center of the bed
398
-            z_values[x][y] += parser.seen('C') ? g29_constant : 9.99f;
377
+            z_values[x][y] += parser.seen('C') ? param.C_constant : 9.99f;
399
             TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(x, y, z_values[x][y]));
378
             TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(x, y, z_values[x][y]));
400
           }
379
           }
401
         break;
380
         break;
406
 
385
 
407
     if (parser.seen('J')) {
386
     if (parser.seen('J')) {
408
       save_ubl_active_state_and_disable();
387
       save_ubl_active_state_and_disable();
409
-      tilt_mesh_based_on_probed_grid(g29_grid_size == 0); // Zero size does 3-Point
388
+      tilt_mesh_based_on_probed_grid(param.grid_size == 0); // Zero size does 3-Point
410
       restore_ubl_active_state_and_leave();
389
       restore_ubl_active_state_and_leave();
411
       #if ENABLED(UBL_G29_J_RECENTER)
390
       #if ENABLED(UBL_G29_J_RECENTER)
412
         do_blocking_move_to_xy(0.5f * ((MESH_MIN_X) + (MESH_MAX_X)), 0.5f * ((MESH_MIN_Y) + (MESH_MAX_Y)));
391
         do_blocking_move_to_xy(0.5f * ((MESH_MIN_X) + (MESH_MAX_X)), 0.5f * ((MESH_MIN_Y) + (MESH_MAX_Y)));
418
   #endif // HAS_BED_PROBE
397
   #endif // HAS_BED_PROBE
419
 
398
 
420
   if (parser.seen('P')) {
399
   if (parser.seen('P')) {
421
-    if (WITHIN(g29_phase_value, 0, 1) && storage_slot == -1) {
400
+    if (WITHIN(param.P_phase, 0, 1) && storage_slot == -1) {
422
       storage_slot = 0;
401
       storage_slot = 0;
423
       SERIAL_ECHOLNPGM("Default storage slot 0 selected.");
402
       SERIAL_ECHOLNPGM("Default storage slot 0 selected.");
424
     }
403
     }
425
 
404
 
426
-    switch (g29_phase_value) {
405
+    switch (param.P_phase) {
427
       case 0:
406
       case 0:
428
         //
407
         //
429
         // Zero Mesh Data
408
         // Zero Mesh Data
442
             invalidate();
421
             invalidate();
443
             SERIAL_ECHOLNPGM("Mesh invalidated. Probing mesh.");
422
             SERIAL_ECHOLNPGM("Mesh invalidated. Probing mesh.");
444
           }
423
           }
445
-          if (g29_verbose_level > 1) {
446
-            SERIAL_ECHOPAIR("Probing around (", g29_pos.x);
424
+          if (param.V_verbosity > 1) {
425
+            SERIAL_ECHOPAIR("Probing around (", param.XY_pos.x);
447
             SERIAL_CHAR(',');
426
             SERIAL_CHAR(',');
448
-            SERIAL_DECIMAL(g29_pos.y);
427
+            SERIAL_DECIMAL(param.XY_pos.y);
449
             SERIAL_ECHOLNPGM(").\n");
428
             SERIAL_ECHOLNPGM(").\n");
450
           }
429
           }
451
-          const xy_pos_t near_probe_xy = g29_pos + probe.offset_xy;
430
+          const xy_pos_t near_probe_xy = param.XY_pos + probe.offset_xy;
452
           probe_entire_mesh(near_probe_xy, parser.seen('T'), parser.seen('E'), parser.seen('U'));
431
           probe_entire_mesh(near_probe_xy, parser.seen('T'), parser.seen('E'), parser.seen('U'));
453
 
432
 
454
           report_current_position();
433
           report_current_position();
465
           SERIAL_ECHOLNPGM("Manually probing unreachable points.");
444
           SERIAL_ECHOLNPGM("Manually probing unreachable points.");
466
           do_z_clearance(Z_CLEARANCE_BETWEEN_PROBES);
445
           do_z_clearance(Z_CLEARANCE_BETWEEN_PROBES);
467
 
446
 
468
-          if (parser.seen('C') && !xy_seen) {
447
+          if (parser.seen('C') && !param.XY_seen) {
469
 
448
 
470
             /**
449
             /**
471
              * Use a good default location for the path.
450
              * Use a good default location for the path.
474
              * It may make sense to have Delta printers default to the center of the bed.
453
              * It may make sense to have Delta printers default to the center of the bed.
475
              * Until that is decided, this can be forced with the X and Y parameters.
454
              * Until that is decided, this can be forced with the X and Y parameters.
476
              */
455
              */
477
-            g29_pos.set(
456
+            param.XY_pos.set(
478
               #if IS_KINEMATIC
457
               #if IS_KINEMATIC
479
                 X_HOME_POS, Y_HOME_POS
458
                 X_HOME_POS, Y_HOME_POS
480
               #else
459
               #else
485
           }
464
           }
486
 
465
 
487
           if (parser.seen('B')) {
466
           if (parser.seen('B')) {
488
-            g29_card_thickness = parser.has_value() ? parser.value_float() : measure_business_card_thickness();
489
-            if (ABS(g29_card_thickness) > 1.5f) {
467
+            param.B_shim_thickness = parser.has_value() ? parser.value_float() : measure_business_card_thickness();
468
+            if (ABS(param.B_shim_thickness) > 1.5f) {
490
               SERIAL_ECHOLNPGM("?Error in Business Card measurement.");
469
               SERIAL_ECHOLNPGM("?Error in Business Card measurement.");
491
               return;
470
               return;
492
             }
471
             }
493
             probe_deployed = true;
472
             probe_deployed = true;
494
           }
473
           }
495
 
474
 
496
-          if (!position_is_reachable(g29_pos)) {
475
+          if (!position_is_reachable(param.XY_pos)) {
497
             SERIAL_ECHOLNPGM("XY outside printable radius.");
476
             SERIAL_ECHOLNPGM("XY outside printable radius.");
498
             return;
477
             return;
499
           }
478
           }
500
 
479
 
501
           const float height = parser.floatval('H', Z_CLEARANCE_BETWEEN_PROBES);
480
           const float height = parser.floatval('H', Z_CLEARANCE_BETWEEN_PROBES);
502
-          manually_probe_remaining_mesh(g29_pos, height, g29_card_thickness, parser.seen('T'));
481
+          manually_probe_remaining_mesh(param.XY_pos, height, param.B_shim_thickness, parser.seen('T'));
503
 
482
 
504
           SERIAL_ECHOLNPGM("G29 P2 finished.");
483
           SERIAL_ECHOLNPGM("G29 P2 finished.");
505
 
484
 
521
          *   - Allow 'G29 P3' to choose a 'reasonable' constant.
500
          *   - Allow 'G29 P3' to choose a 'reasonable' constant.
522
          */
501
          */
523
 
502
 
524
-        if (g29_c_flag) {
525
-          if (g29_repetition_cnt >= GRID_MAX_POINTS) {
526
-            set_all_mesh_points_to_value(g29_constant);
503
+        if (param.C_seen) {
504
+          if (param.R_repetition >= GRID_MAX_POINTS) {
505
+            set_all_mesh_points_to_value(param.C_constant);
527
           }
506
           }
528
           else {
507
           else {
529
-            while (g29_repetition_cnt--) {  // this only populates reachable mesh points near
530
-              const mesh_index_pair closest = find_closest_mesh_point_of_type(INVALID, g29_pos);
508
+            while (param.R_repetition--) {  // this only populates reachable mesh points near
509
+              const mesh_index_pair closest = find_closest_mesh_point_of_type(INVALID, param.XY_pos);
531
               const xy_int8_t &cpos = closest.pos;
510
               const xy_int8_t &cpos = closest.pos;
532
               if (cpos.x < 0) {
511
               if (cpos.x < 0) {
533
                 // No more REAL INVALID mesh points to populate, so we ASSUME
512
                 // No more REAL INVALID mesh points to populate, so we ASSUME
534
                 // user meant to populate ALL INVALID mesh points to value
513
                 // user meant to populate ALL INVALID mesh points to value
535
-                GRID_LOOP(x, y) if (isnan(z_values[x][y])) z_values[x][y] = g29_constant;
514
+                GRID_LOOP(x, y) if (isnan(z_values[x][y])) z_values[x][y] = param.C_constant;
536
                 break; // No more invalid Mesh Points to populate
515
                 break; // No more invalid Mesh Points to populate
537
               }
516
               }
538
               else {
517
               else {
539
-                z_values[cpos.x][cpos.y] = g29_constant;
540
-                TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(cpos, g29_constant));
518
+                z_values[cpos.x][cpos.y] = param.C_constant;
519
+                TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(cpos, param.C_constant));
541
               }
520
               }
542
             }
521
             }
543
           }
522
           }
571
 
550
 
572
       case 4: // Fine Tune (i.e., Edit) the Mesh
551
       case 4: // Fine Tune (i.e., Edit) the Mesh
573
         #if HAS_LCD_MENU
552
         #if HAS_LCD_MENU
574
-          fine_tune_mesh(g29_pos, parser.seen('T'));
553
+          fine_tune_mesh(param.XY_pos, parser.seen('T'));
575
         #else
554
         #else
576
           SERIAL_ECHOLNPGM("?P4 is only available when an LCD is present.");
555
           SERIAL_ECHOLNPGM("?P4 is only available when an LCD is present.");
577
           return;
556
           return;
578
         #endif
557
         #endif
579
         break;
558
         break;
580
 
559
 
581
-      case 5: adjust_mesh_to_mean(g29_c_flag, g29_constant); break;
560
+      case 5: adjust_mesh_to_mean(param.C_seen, param.C_constant); break;
582
 
561
 
583
       case 6: shift_mesh_height(); break;
562
       case 6: shift_mesh_height(); break;
584
     }
563
     }
608
   //
587
   //
609
 
588
 
610
   if (parser.seen('L')) {     // Load Current Mesh Data
589
   if (parser.seen('L')) {     // Load Current Mesh Data
611
-    g29_storage_slot = parser.has_value() ? parser.value_int() : storage_slot;
590
+    param.KLS_storage_slot = parser.has_value() ? parser.value_int() : storage_slot;
612
 
591
 
613
     int16_t a = settings.calc_num_meshes();
592
     int16_t a = settings.calc_num_meshes();
614
 
593
 
617
       return;
596
       return;
618
     }
597
     }
619
 
598
 
620
-    if (!WITHIN(g29_storage_slot, 0, a - 1)) {
599
+    if (!WITHIN(param.KLS_storage_slot, 0, a - 1)) {
621
       SERIAL_ECHOLNPAIR("?Invalid storage slot.\n?Use 0 to ", a - 1);
600
       SERIAL_ECHOLNPAIR("?Invalid storage slot.\n?Use 0 to ", a - 1);
622
       return;
601
       return;
623
     }
602
     }
624
 
603
 
625
-    settings.load_mesh(g29_storage_slot);
626
-    storage_slot = g29_storage_slot;
604
+    settings.load_mesh(param.KLS_storage_slot);
605
+    storage_slot = param.KLS_storage_slot;
627
 
606
 
628
     SERIAL_ECHOLNPGM("Done.");
607
     SERIAL_ECHOLNPGM("Done.");
629
   }
608
   }
633
   //
612
   //
634
 
613
 
635
   if (parser.seen('S')) {     // Store (or Save) Current Mesh Data
614
   if (parser.seen('S')) {     // Store (or Save) Current Mesh Data
636
-    g29_storage_slot = parser.has_value() ? parser.value_int() : storage_slot;
615
+    param.KLS_storage_slot = parser.has_value() ? parser.value_int() : storage_slot;
637
 
616
 
638
-    if (g29_storage_slot == -1)                     // Special case, the user wants to 'Export' the mesh to the
617
+    if (param.KLS_storage_slot == -1)                     // Special case, the user wants to 'Export' the mesh to the
639
       return report_current_mesh();                 // host program to be saved on the user's computer
618
       return report_current_mesh();                 // host program to be saved on the user's computer
640
 
619
 
641
     int16_t a = settings.calc_num_meshes();
620
     int16_t a = settings.calc_num_meshes();
645
       goto LEAVE;
624
       goto LEAVE;
646
     }
625
     }
647
 
626
 
648
-    if (!WITHIN(g29_storage_slot, 0, a - 1)) {
627
+    if (!WITHIN(param.KLS_storage_slot, 0, a - 1)) {
649
       SERIAL_ECHOLNPAIR("?Invalid storage slot.\n?Use 0 to ", a - 1);
628
       SERIAL_ECHOLNPAIR("?Invalid storage slot.\n?Use 0 to ", a - 1);
650
       goto LEAVE;
629
       goto LEAVE;
651
     }
630
     }
652
 
631
 
653
-    settings.store_mesh(g29_storage_slot);
654
-    storage_slot = g29_storage_slot;
632
+    settings.store_mesh(param.KLS_storage_slot);
633
+    storage_slot = param.KLS_storage_slot;
655
 
634
 
656
     SERIAL_ECHOLNPGM("Done.");
635
     SERIAL_ECHOLNPGM("Done.");
657
   }
636
   }
658
 
637
 
659
   if (parser.seen('T'))
638
   if (parser.seen('T'))
660
-    display_map(g29_map_type);
639
+    display_map(param.T_map_type);
661
 
640
 
662
   LEAVE:
641
   LEAVE:
663
 
642
 
682
   return;
661
   return;
683
 }
662
 }
684
 
663
 
685
-void unified_bed_leveling::adjust_mesh_to_mean(const bool cflag, const float value) {
664
+/**
665
+ * M420 C<value>
666
+ * G29 P5 C<value> : Adjust Mesh To Mean (and subtract the given offset).
667
+ *                   Find the mean average and shift the mesh to center on that value.
668
+ */
669
+void unified_bed_leveling::adjust_mesh_to_mean(const bool cflag, const float offset) {
686
   float sum = 0;
670
   float sum = 0;
687
   int n = 0;
671
   int n = 0;
688
   GRID_LOOP(x, y)
672
   GRID_LOOP(x, y)
710
   if (cflag)
694
   if (cflag)
711
     GRID_LOOP(x, y)
695
     GRID_LOOP(x, y)
712
       if (!isnan(z_values[x][y])) {
696
       if (!isnan(z_values[x][y])) {
713
-        z_values[x][y] -= mean + value;
697
+        z_values[x][y] -= mean + offset;
714
         TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(x, y, z_values[x][y]));
698
         TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(x, y, z_values[x][y]));
715
       }
699
       }
716
 }
700
 }
717
 
701
 
702
+/**
703
+ * G29 P6 C<offset> : Shift Mesh Height by a uniform constant.
704
+ */
718
 void unified_bed_leveling::shift_mesh_height() {
705
 void unified_bed_leveling::shift_mesh_height() {
719
   GRID_LOOP(x, y)
706
   GRID_LOOP(x, y)
720
     if (!isnan(z_values[x][y])) {
707
     if (!isnan(z_values[x][y])) {
721
-      z_values[x][y] += g29_constant;
708
+      z_values[x][y] += param.C_constant;
722
       TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(x, y, z_values[x][y]));
709
       TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(x, y, z_values[x][y]));
723
     }
710
     }
724
 }
711
 }
725
 
712
 
726
 #if HAS_BED_PROBE
713
 #if HAS_BED_PROBE
727
   /**
714
   /**
728
-   * Probe all invalidated locations of the mesh that can be reached by the probe.
729
-   * This attempts to fill in locations closest to the nozzle's start location first.
715
+   * G29 P1 T<maptype> V<verbosity> : Probe Entire Mesh
716
+   *   Probe all invalidated locations of the mesh that can be reached by the probe.
717
+   *   This attempts to fill in locations closest to the nozzle's start location first.
730
    */
718
    */
731
   void unified_bed_leveling::probe_entire_mesh(const xy_pos_t &nearby, const bool do_ubl_mesh_map, const bool stow_probe, const bool do_furthest) {
719
   void unified_bed_leveling::probe_entire_mesh(const xy_pos_t &nearby, const bool do_ubl_mesh_map, const bool stow_probe, const bool do_furthest) {
732
     probe.deploy(); // Deploy before ui.capture() to allow for PAUSE_BEFORE_DEPLOY_STOW
720
     probe.deploy(); // Deploy before ui.capture() to allow for PAUSE_BEFORE_DEPLOY_STOW
739
     mesh_index_pair best;
727
     mesh_index_pair best;
740
     TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(best.pos, ExtUI::MESH_START));
728
     TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(best.pos, ExtUI::MESH_START));
741
     do {
729
     do {
742
-      if (do_ubl_mesh_map) display_map(g29_map_type);
730
+      if (do_ubl_mesh_map) display_map(param.T_map_type);
743
 
731
 
744
       const int point_num = (GRID_MAX_POINTS) - count + 1;
732
       const int point_num = (GRID_MAX_POINTS) - count + 1;
745
       SERIAL_ECHOLNPAIR("Probing mesh point ", point_num, "/", GRID_MAX_POINTS, ".");
733
       SERIAL_ECHOLNPAIR("Probing mesh point ", point_num, "/", GRID_MAX_POINTS, ".");
767
         TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(best.pos, ExtUI::PROBE_START));
755
         TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(best.pos, ExtUI::PROBE_START));
768
         const float measured_z = probe.probe_at_point(
756
         const float measured_z = probe.probe_at_point(
769
                       best.meshpos(),
757
                       best.meshpos(),
770
-                      stow_probe ? PROBE_PT_STOW : PROBE_PT_RAISE, g29_verbose_level
758
+                      stow_probe ? PROBE_PT_STOW : PROBE_PT_RAISE, param.V_verbosity
771
                     );
759
                     );
772
         z_values[best.pos.x][best.pos.y] = measured_z;
760
         z_values[best.pos.x][best.pos.y] = measured_z;
773
         #if ENABLED(EXTENSIBLE_UI)
761
         #if ENABLED(EXTENSIBLE_UI)
798
 
786
 
799
 #endif // HAS_BED_PROBE
787
 #endif // HAS_BED_PROBE
800
 
788
 
789
+void set_message_with_feedback(PGM_P const msg_P) {
790
+  #if HAS_LCD_MENU
791
+    ui.set_status_P(msg_P);
792
+    ui.quick_feedback();
793
+  #else
794
+    UNUSED(msg_P);
795
+  #endif
796
+}
797
+
801
 #if HAS_LCD_MENU
798
 #if HAS_LCD_MENU
802
 
799
 
803
   typedef void (*clickFunc_t)();
800
   typedef void (*clickFunc_t)();
804
 
801
 
805
-  bool click_and_hold(const clickFunc_t func=nullptr) {
802
+  bool _click_and_hold(const clickFunc_t func=nullptr) {
806
     if (ui.button_pressed()) {
803
     if (ui.button_pressed()) {
807
       ui.quick_feedback(false);         // Preserve button state for click-and-hold
804
       ui.quick_feedback(false);         // Preserve button state for click-and-hold
808
       const millis_t nxt = millis() + 1500UL;
805
       const millis_t nxt = millis() + 1500UL;
834
 
831
 
835
   float unified_bed_leveling::measure_point_with_encoder() {
832
   float unified_bed_leveling::measure_point_with_encoder() {
836
     KEEPALIVE_STATE(PAUSED_FOR_USER);
833
     KEEPALIVE_STATE(PAUSED_FOR_USER);
837
-    move_z_with_encoder(0.01f);
834
+    const float z_step = 0.01f;
835
+    move_z_with_encoder(z_step);
838
     return current_position.z;
836
     return current_position.z;
839
   }
837
   }
840
 
838
 
866
 
864
 
867
     const float thickness = ABS(z1 - z2);
865
     const float thickness = ABS(z1 - z2);
868
 
866
 
869
-    if (g29_verbose_level > 1) {
867
+    if (param.V_verbosity > 1) {
870
       SERIAL_ECHOPAIR_F("Business Card is ", thickness, 4);
868
       SERIAL_ECHOPAIR_F("Business Card is ", thickness, 4);
871
       SERIAL_ECHOLNPGM("mm thick.");
869
       SERIAL_ECHOLNPGM("mm thick.");
872
     }
870
     }
876
     return thickness;
874
     return thickness;
877
   }
875
   }
878
 
876
 
877
+  /**
878
+   * G29 P2 : Manually Probe Remaining Mesh Points.
879
+   *          Move to INVALID points and
880
+   *          NOTE: Blocks the G-code queue and captures Marlin UI during use.
881
+   */
879
   void unified_bed_leveling::manually_probe_remaining_mesh(const xy_pos_t &pos, const float &z_clearance, const float &thick, const bool do_ubl_mesh_map) {
882
   void unified_bed_leveling::manually_probe_remaining_mesh(const xy_pos_t &pos, const float &z_clearance, const float &thick, const bool do_ubl_mesh_map) {
880
     ui.capture();
883
     ui.capture();
881
 
884
 
907
       KEEPALIVE_STATE(PAUSED_FOR_USER);
910
       KEEPALIVE_STATE(PAUSED_FOR_USER);
908
       ui.capture();
911
       ui.capture();
909
 
912
 
910
-      if (do_ubl_mesh_map) display_map(g29_map_type);  // show user where we're probing
913
+      if (do_ubl_mesh_map) display_map(param.T_map_type);   // Show user where we're probing
911
 
914
 
912
       if (parser.seen('B')) {
915
       if (parser.seen('B')) {
913
         SERIAL_ECHOPGM_P(GET_TEXT(MSG_UBL_BC_INSERT));
916
         SERIAL_ECHOPGM_P(GET_TEXT(MSG_UBL_BC_INSERT));
918
         LCD_MESSAGEPGM(MSG_UBL_BC_INSERT2);
921
         LCD_MESSAGEPGM(MSG_UBL_BC_INSERT2);
919
       }
922
       }
920
 
923
 
921
-      const float z_step = 0.01f;                         // existing behavior: 0.01mm per click, occasionally step
922
-      //const float z_step = planner.steps_to_mm[Z_AXIS]; // approx one step each click
923
-
924
+      const float z_step = 0.01f;                         // 0.01mm per encoder tick, occasionally step
924
       move_z_with_encoder(z_step);
925
       move_z_with_encoder(z_step);
925
 
926
 
926
-      if (click_and_hold()) {
927
+      if (_click_and_hold([]{
927
         SERIAL_ECHOLNPGM("\nMesh only partially populated.");
928
         SERIAL_ECHOLNPGM("\nMesh only partially populated.");
928
         do_z_clearance(Z_CLEARANCE_DEPLOY_PROBE);
929
         do_z_clearance(Z_CLEARANCE_DEPLOY_PROBE);
929
-        return restore_ubl_active_state_and_leave();
930
-      }
930
+      })) return restore_ubl_active_state_and_leave();
931
 
931
 
932
+      // Store the Z position minus the shim height
932
       z_values[lpos.x][lpos.y] = current_position.z - thick;
933
       z_values[lpos.x][lpos.y] = current_position.z - thick;
934
+
935
+      // Tell the external UI to update
933
       TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(location, z_values[lpos.x][lpos.y]));
936
       TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(location, z_values[lpos.x][lpos.y]));
934
 
937
 
935
-      if (g29_verbose_level > 2)
938
+      if (param.V_verbosity > 2)
936
         SERIAL_ECHOLNPAIR_F("Mesh Point Measured at: ", z_values[lpos.x][lpos.y], 6);
939
         SERIAL_ECHOLNPAIR_F("Mesh Point Measured at: ", z_values[lpos.x][lpos.y], 6);
937
       SERIAL_FLUSH(); // Prevent host M105 buffer overrun.
940
       SERIAL_FLUSH(); // Prevent host M105 buffer overrun.
938
     } while (location.valid());
941
     } while (location.valid());
939
 
942
 
940
-    if (do_ubl_mesh_map) display_map(g29_map_type);  // show user where we're probing
943
+    if (do_ubl_mesh_map) display_map(param.T_map_type);  // show user where we're probing
941
 
944
 
942
     restore_ubl_active_state_and_leave();
945
     restore_ubl_active_state_and_leave();
943
     do_blocking_move_to_xy_z(pos, Z_CLEARANCE_DEPLOY_PROBE);
946
     do_blocking_move_to_xy_z(pos, Z_CLEARANCE_DEPLOY_PROBE);
944
   }
947
   }
945
 
948
 
946
-  inline void set_message_with_feedback(PGM_P const msg_P) {
947
-    ui.set_status_P(msg_P);
948
-    ui.quick_feedback();
949
-  }
950
-
951
-  void abort_fine_tune() {
952
-    ui.return_to_status();
953
-    do_z_clearance(Z_CLEARANCE_BETWEEN_PROBES);
954
-    set_message_with_feedback(GET_TEXT(MSG_EDITING_STOPPED));
955
-  }
956
-
949
+  /**
950
+   * G29 P4 : Mesh Fine-Tuning. Go to point(s) and adjust values with the LCD.
951
+   *          NOTE: Blocks the G-code queue and captures Marlin UI during use.
952
+   */
957
   void unified_bed_leveling::fine_tune_mesh(const xy_pos_t &pos, const bool do_ubl_mesh_map) {
953
   void unified_bed_leveling::fine_tune_mesh(const xy_pos_t &pos, const bool do_ubl_mesh_map) {
958
-    if (!parser.seen('R'))      // fine_tune_mesh() is special. If no repetition count flag is specified
959
-      g29_repetition_cnt = 1;   // do exactly one mesh location. Otherwise use what the parser decided.
954
+    if (!parser.seen('R'))        // fine_tune_mesh() is special. If no repetition count flag is specified
955
+      param.R_repetition = 1;   // do exactly one mesh location. Otherwise use what the parser decided.
960
 
956
 
961
     #if ENABLED(UBL_MESH_EDIT_MOVES_Z)
957
     #if ENABLED(UBL_MESH_EDIT_MOVES_Z)
962
       const float h_offset = parser.seenval('H') ? parser.value_linear_units() : MANUAL_PROBE_START_Z;
958
       const float h_offset = parser.seenval('H') ? parser.value_linear_units() : MANUAL_PROBE_START_Z;
984
     const xy_int8_t &lpos = location.pos;
980
     const xy_int8_t &lpos = location.pos;
985
 
981
 
986
     #if IS_TFTGLCD_PANEL
982
     #if IS_TFTGLCD_PANEL
987
-      lcd_mesh_edit_setup(0);                             // Change current screen before calling ui.ubl_plot
983
+      ui.ubl_mesh_edit_start(0);                          // Change current screen before calling ui.ubl_plot
988
       safe_delay(50);
984
       safe_delay(50);
989
     #endif
985
     #endif
990
 
986
 
1009
 
1005
 
1010
       KEEPALIVE_STATE(PAUSED_FOR_USER);
1006
       KEEPALIVE_STATE(PAUSED_FOR_USER);
1011
 
1007
 
1012
-      if (do_ubl_mesh_map) display_map(g29_map_type);     // Display the current point
1008
+      if (do_ubl_mesh_map) display_map(param.T_map_type);     // Display the current point
1013
 
1009
 
1014
       #if IS_TFTGLCD_PANEL
1010
       #if IS_TFTGLCD_PANEL
1015
         ui.ubl_plot(lpos.x, lpos.y);   // update plot screen
1011
         ui.ubl_plot(lpos.x, lpos.y);   // update plot screen
1021
       if (isnan(new_z)) new_z = 0;                        // Invalid points begin at 0
1017
       if (isnan(new_z)) new_z = 0;                        // Invalid points begin at 0
1022
       new_z = FLOOR(new_z * 1000) * 0.001f;               // Chop off digits after the 1000ths place
1018
       new_z = FLOOR(new_z * 1000) * 0.001f;               // Chop off digits after the 1000ths place
1023
 
1019
 
1024
-      lcd_mesh_edit_setup(new_z);
1020
+      ui.ubl_mesh_edit_start(new_z);
1025
 
1021
 
1026
       SET_SOFT_ENDSTOP_LOOSE(true);
1022
       SET_SOFT_ENDSTOP_LOOSE(true);
1027
 
1023
 
1028
       do {
1024
       do {
1029
         idle();
1025
         idle();
1030
-        new_z = lcd_mesh_edit();
1026
+        new_z = ui.ubl_mesh_value();
1031
         TERN_(UBL_MESH_EDIT_MOVES_Z, do_blocking_move_to_z(h_offset + new_z)); // Move the nozzle as the point is edited
1027
         TERN_(UBL_MESH_EDIT_MOVES_Z, do_blocking_move_to_z(h_offset + new_z)); // Move the nozzle as the point is edited
1032
         SERIAL_FLUSH();                                   // Prevent host M105 buffer overrun.
1028
         SERIAL_FLUSH();                                   // Prevent host M105 buffer overrun.
1033
       } while (!ui.button_pressed());
1029
       } while (!ui.button_pressed());
1036
 
1032
 
1037
       if (!lcd_map_control) ui.return_to_status();        // Just editing a single point? Return to status
1033
       if (!lcd_map_control) ui.return_to_status();        // Just editing a single point? Return to status
1038
 
1034
 
1039
-      if (click_and_hold(abort_fine_tune)) break;         // Button held down? Abort editing
1035
+      // Button held down? Abort editing
1036
+      if (_click_and_hold([]{
1037
+        ui.return_to_status();
1038
+        do_z_clearance(Z_CLEARANCE_BETWEEN_PROBES);
1039
+        set_message_with_feedback(GET_TEXT(MSG_EDITING_STOPPED));
1040
+      })) break;
1041
+
1042
+      // TODO: Disable leveling here so the Z value becomes the 'native' Z value.
1040
 
1043
 
1041
       z_values[lpos.x][lpos.y] = new_z;                   // Save the updated Z value
1044
       z_values[lpos.x][lpos.y] = new_z;                   // Save the updated Z value
1045
+
1046
+      // TODO: Re-enable leveling here so Z is correctly based on the updated mesh.
1047
+
1042
       TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(location, new_z));
1048
       TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(location, new_z));
1043
 
1049
 
1044
       serial_delay(20);                                   // No switch noise
1050
       serial_delay(20);                                   // No switch noise
1045
       ui.refresh();
1051
       ui.refresh();
1046
 
1052
 
1047
-    } while (lpos.x >= 0 && --g29_repetition_cnt > 0);
1053
+    } while (lpos.x >= 0 && --param.R_repetition > 0);
1048
 
1054
 
1049
-    if (do_ubl_mesh_map) display_map(g29_map_type);
1055
+    if (do_ubl_mesh_map) display_map(param.T_map_type);
1050
     restore_ubl_active_state_and_leave();
1056
     restore_ubl_active_state_and_leave();
1051
 
1057
 
1052
     do_blocking_move_to_xy_z(pos, Z_CLEARANCE_BETWEEN_PROBES);
1058
     do_blocking_move_to_xy_z(pos, Z_CLEARANCE_BETWEEN_PROBES);
1062
 
1068
 
1063
 #endif // HAS_LCD_MENU
1069
 #endif // HAS_LCD_MENU
1064
 
1070
 
1065
-bool unified_bed_leveling::g29_parameter_parsing() {
1071
+/**
1072
+ * Parse and validate most G29 parameters, store for use by G29 functions.
1073
+ */
1074
+bool unified_bed_leveling::G29_parse_parameters() {
1066
   bool err_flag = false;
1075
   bool err_flag = false;
1067
 
1076
 
1068
-  TERN_(HAS_LCD_MENU, set_message_with_feedback(GET_TEXT(MSG_UBL_DOING_G29)));
1077
+  set_message_with_feedback(GET_TEXT(MSG_UBL_DOING_G29));
1069
 
1078
 
1070
-  g29_constant = 0;
1071
-  g29_repetition_cnt = 0;
1079
+  param.C_constant = 0;
1080
+  param.R_repetition = 0;
1072
 
1081
 
1073
   if (parser.seen('R')) {
1082
   if (parser.seen('R')) {
1074
-    g29_repetition_cnt = parser.has_value() ? parser.value_int() : GRID_MAX_POINTS;
1075
-    NOMORE(g29_repetition_cnt, GRID_MAX_POINTS);
1076
-    if (g29_repetition_cnt < 1) {
1083
+    param.R_repetition = parser.has_value() ? parser.value_int() : GRID_MAX_POINTS;
1084
+    NOMORE(param.R_repetition, GRID_MAX_POINTS);
1085
+    if (param.R_repetition < 1) {
1077
       SERIAL_ECHOLNPGM("?(R)epetition count invalid (1+).\n");
1086
       SERIAL_ECHOLNPGM("?(R)epetition count invalid (1+).\n");
1078
       return UBL_ERR;
1087
       return UBL_ERR;
1079
     }
1088
     }
1080
   }
1089
   }
1081
 
1090
 
1082
-  g29_verbose_level = parser.seen('V') ? parser.value_int() : 0;
1083
-  if (!WITHIN(g29_verbose_level, 0, 4)) {
1091
+  param.V_verbosity = parser.seen('V') ? parser.value_int() : 0;
1092
+  if (!WITHIN(param.V_verbosity, 0, 4)) {
1084
     SERIAL_ECHOLNPGM("?(V)erbose level implausible (0-4).\n");
1093
     SERIAL_ECHOLNPGM("?(V)erbose level implausible (0-4).\n");
1085
     err_flag = true;
1094
     err_flag = true;
1086
   }
1095
   }
1095
       else
1104
       else
1096
     #endif
1105
     #endif
1097
       {
1106
       {
1098
-        g29_phase_value = pv;
1099
-        if (!WITHIN(g29_phase_value, 0, 6)) {
1107
+        param.P_phase = pv;
1108
+        if (!WITHIN(param.P_phase, 0, 6)) {
1100
           SERIAL_ECHOLNPGM("?(P)hase value invalid (0-6).\n");
1109
           SERIAL_ECHOLNPGM("?(P)hase value invalid (0-6).\n");
1101
           err_flag = true;
1110
           err_flag = true;
1102
         }
1111
         }
1105
 
1114
 
1106
   if (parser.seen('J')) {
1115
   if (parser.seen('J')) {
1107
     #if HAS_BED_PROBE
1116
     #if HAS_BED_PROBE
1108
-      g29_grid_size = parser.has_value() ? parser.value_int() : 0;
1109
-      if (g29_grid_size && !WITHIN(g29_grid_size, 2, 9)) {
1117
+      param.grid_size = parser.has_value() ? parser.value_int() : 0;
1118
+      if (param.grid_size && !WITHIN(param.grid_size, 2, 9)) {
1110
         SERIAL_ECHOLNPGM("?Invalid grid size (J) specified (2-9).\n");
1119
         SERIAL_ECHOLNPGM("?Invalid grid size (J) specified (2-9).\n");
1111
         err_flag = true;
1120
         err_flag = true;
1112
       }
1121
       }
1116
     #endif
1125
     #endif
1117
   }
1126
   }
1118
 
1127
 
1119
-  xy_seen.x = parser.seenval('X');
1120
-  float sx = xy_seen.x ? parser.value_float() : current_position.x;
1121
-  xy_seen.y = parser.seenval('Y');
1122
-  float sy = xy_seen.y ? parser.value_float() : current_position.y;
1128
+  param.XY_seen.x = parser.seenval('X');
1129
+  float sx = param.XY_seen.x ? parser.value_float() : current_position.x;
1130
+  param.XY_seen.y = parser.seenval('Y');
1131
+  float sy = param.XY_seen.y ? parser.value_float() : current_position.y;
1123
 
1132
 
1124
-  if (xy_seen.x != xy_seen.y) {
1133
+  if (param.XY_seen.x != param.XY_seen.y) {
1125
     SERIAL_ECHOLNPGM("Both X & Y locations must be specified.\n");
1134
     SERIAL_ECHOLNPGM("Both X & Y locations must be specified.\n");
1126
     err_flag = true;
1135
     err_flag = true;
1127
   }
1136
   }
1132
 
1141
 
1133
   if (err_flag) return UBL_ERR;
1142
   if (err_flag) return UBL_ERR;
1134
 
1143
 
1135
-  g29_pos.set(sx, sy);
1144
+  param.XY_pos.set(sx, sy);
1136
 
1145
 
1137
   /**
1146
   /**
1138
    * Activate or deactivate UBL
1147
    * Activate or deactivate UBL
1154
   }
1163
   }
1155
 
1164
 
1156
   // Set global 'C' flag and its value
1165
   // Set global 'C' flag and its value
1157
-  if ((g29_c_flag = parser.seen('C')))
1158
-    g29_constant = parser.value_float();
1166
+  if ((param.C_seen = parser.seen('C')))
1167
+    param.C_constant = parser.value_float();
1159
 
1168
 
1160
   #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
1169
   #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
1161
     if (parser.seenval('F')) {
1170
     if (parser.seenval('F')) {
1168
     }
1177
     }
1169
   #endif
1178
   #endif
1170
 
1179
 
1171
-  g29_map_type = parser.intval('T');
1172
-  if (!WITHIN(g29_map_type, 0, 2)) {
1180
+  param.T_map_type = parser.intval('T');
1181
+  if (!WITHIN(param.T_map_type, 0, 2)) {
1173
     SERIAL_ECHOLNPGM("Invalid map type.\n");
1182
     SERIAL_ECHOLNPGM("Invalid map type.\n");
1174
     return UBL_ERR;
1183
     return UBL_ERR;
1175
   }
1184
   }
1187
     ubl_state_recursion_chk++;
1196
     ubl_state_recursion_chk++;
1188
     if (ubl_state_recursion_chk != 1) {
1197
     if (ubl_state_recursion_chk != 1) {
1189
       SERIAL_ECHOLNPGM("save_ubl_active_state_and_disabled() called multiple times in a row.");
1198
       SERIAL_ECHOLNPGM("save_ubl_active_state_and_disabled() called multiple times in a row.");
1190
-      TERN_(HAS_LCD_MENU, set_message_with_feedback(GET_TEXT(MSG_UBL_SAVE_ERROR)));
1199
+      set_message_with_feedback(GET_TEXT(MSG_UBL_SAVE_ERROR));
1191
       return;
1200
       return;
1192
     }
1201
     }
1193
   #endif
1202
   #endif
1200
   #if ENABLED(UBL_DEVEL_DEBUGGING)
1209
   #if ENABLED(UBL_DEVEL_DEBUGGING)
1201
     if (--ubl_state_recursion_chk) {
1210
     if (--ubl_state_recursion_chk) {
1202
       SERIAL_ECHOLNPGM("restore_ubl_active_state_and_leave() called too many times.");
1211
       SERIAL_ECHOLNPGM("restore_ubl_active_state_and_leave() called too many times.");
1203
-      TERN_(HAS_LCD_MENU, set_message_with_feedback(GET_TEXT(MSG_UBL_RESTORE_ERROR)));
1212
+      set_message_with_feedback(GET_TEXT(MSG_UBL_RESTORE_ERROR));
1204
       return;
1213
       return;
1205
     }
1214
     }
1206
   #endif
1215
   #endif
1411
   void unified_bed_leveling::tilt_mesh_based_on_probed_grid(const bool do_3_pt_leveling) {
1420
   void unified_bed_leveling::tilt_mesh_based_on_probed_grid(const bool do_3_pt_leveling) {
1412
     const float x_min = probe.min_x(), x_max = probe.max_x(),
1421
     const float x_min = probe.min_x(), x_max = probe.max_x(),
1413
                 y_min = probe.min_y(), y_max = probe.max_y(),
1422
                 y_min = probe.min_y(), y_max = probe.max_y(),
1414
-                dx = (x_max - x_min) / (g29_grid_size - 1),
1415
-                dy = (y_max - y_min) / (g29_grid_size - 1);
1423
+                dx = (x_max - x_min) / (param.grid_size - 1),
1424
+                dy = (y_max - y_min) / (param.grid_size - 1);
1416
 
1425
 
1417
     xy_float_t points[3];
1426
     xy_float_t points[3];
1418
     probe.get_three_points(points);
1427
     probe.get_three_points(points);
1431
       SERIAL_ECHOLNPGM("Tilting mesh (1/3)");
1440
       SERIAL_ECHOLNPGM("Tilting mesh (1/3)");
1432
       TERN_(HAS_DISPLAY, ui.status_printf_P(0, PSTR(S_FMT " 1/3"), GET_TEXT(MSG_LCD_TILTING_MESH)));
1441
       TERN_(HAS_DISPLAY, ui.status_printf_P(0, PSTR(S_FMT " 1/3"), GET_TEXT(MSG_LCD_TILTING_MESH)));
1433
 
1442
 
1434
-      measured_z = probe.probe_at_point(points[0], PROBE_PT_RAISE, g29_verbose_level);
1443
+      measured_z = probe.probe_at_point(points[0], PROBE_PT_RAISE, param.V_verbosity);
1435
       if (isnan(measured_z))
1444
       if (isnan(measured_z))
1436
         abort_flag = true;
1445
         abort_flag = true;
1437
       else {
1446
       else {
1439
         #ifdef VALIDATE_MESH_TILT
1448
         #ifdef VALIDATE_MESH_TILT
1440
           z1 = measured_z;
1449
           z1 = measured_z;
1441
         #endif
1450
         #endif
1442
-        if (g29_verbose_level > 3) {
1451
+        if (param.V_verbosity > 3) {
1443
           serial_spaces(16);
1452
           serial_spaces(16);
1444
           SERIAL_ECHOLNPAIR("Corrected_Z=", measured_z);
1453
           SERIAL_ECHOLNPAIR("Corrected_Z=", measured_z);
1445
         }
1454
         }
1450
         SERIAL_ECHOLNPGM("Tilting mesh (2/3)");
1459
         SERIAL_ECHOLNPGM("Tilting mesh (2/3)");
1451
         TERN_(HAS_DISPLAY, ui.status_printf_P(0, PSTR(S_FMT " 2/3"), GET_TEXT(MSG_LCD_TILTING_MESH)));
1460
         TERN_(HAS_DISPLAY, ui.status_printf_P(0, PSTR(S_FMT " 2/3"), GET_TEXT(MSG_LCD_TILTING_MESH)));
1452
 
1461
 
1453
-        measured_z = probe.probe_at_point(points[1], PROBE_PT_RAISE, g29_verbose_level);
1462
+        measured_z = probe.probe_at_point(points[1], PROBE_PT_RAISE, param.V_verbosity);
1454
         #ifdef VALIDATE_MESH_TILT
1463
         #ifdef VALIDATE_MESH_TILT
1455
           z2 = measured_z;
1464
           z2 = measured_z;
1456
         #endif
1465
         #endif
1458
           abort_flag = true;
1467
           abort_flag = true;
1459
         else {
1468
         else {
1460
           measured_z -= get_z_correction(points[1]);
1469
           measured_z -= get_z_correction(points[1]);
1461
-          if (g29_verbose_level > 3) {
1470
+          if (param.V_verbosity > 3) {
1462
             serial_spaces(16);
1471
             serial_spaces(16);
1463
             SERIAL_ECHOLNPAIR("Corrected_Z=", measured_z);
1472
             SERIAL_ECHOLNPAIR("Corrected_Z=", measured_z);
1464
           }
1473
           }
1470
         SERIAL_ECHOLNPGM("Tilting mesh (3/3)");
1479
         SERIAL_ECHOLNPGM("Tilting mesh (3/3)");
1471
         TERN_(HAS_DISPLAY, ui.status_printf_P(0, PSTR(S_FMT " 3/3"), GET_TEXT(MSG_LCD_TILTING_MESH)));
1480
         TERN_(HAS_DISPLAY, ui.status_printf_P(0, PSTR(S_FMT " 3/3"), GET_TEXT(MSG_LCD_TILTING_MESH)));
1472
 
1481
 
1473
-        measured_z = probe.probe_at_point(points[2], PROBE_PT_STOW, g29_verbose_level);
1482
+        measured_z = probe.probe_at_point(points[2], PROBE_PT_STOW, param.V_verbosity);
1474
         #ifdef VALIDATE_MESH_TILT
1483
         #ifdef VALIDATE_MESH_TILT
1475
           z3 = measured_z;
1484
           z3 = measured_z;
1476
         #endif
1485
         #endif
1478
           abort_flag = true;
1487
           abort_flag = true;
1479
         else {
1488
         else {
1480
           measured_z -= get_z_correction(points[2]);
1489
           measured_z -= get_z_correction(points[2]);
1481
-          if (g29_verbose_level > 3) {
1490
+          if (param.V_verbosity > 3) {
1482
             serial_spaces(16);
1491
             serial_spaces(16);
1483
             SERIAL_ECHOLNPAIR("Corrected_Z=", measured_z);
1492
             SERIAL_ECHOLNPAIR("Corrected_Z=", measured_z);
1484
           }
1493
           }
1498
 
1507
 
1499
       bool zig_zag = false;
1508
       bool zig_zag = false;
1500
 
1509
 
1501
-      const uint16_t total_points = sq(g29_grid_size);
1510
+      const uint16_t total_points = sq(param.grid_size);
1502
       uint16_t point_num = 1;
1511
       uint16_t point_num = 1;
1503
 
1512
 
1504
       xy_pos_t rpos;
1513
       xy_pos_t rpos;
1505
-      LOOP_L_N(ix, g29_grid_size) {
1514
+      LOOP_L_N(ix, param.grid_size) {
1506
         rpos.x = x_min + ix * dx;
1515
         rpos.x = x_min + ix * dx;
1507
-        LOOP_L_N(iy, g29_grid_size) {
1508
-          rpos.y = y_min + dy * (zig_zag ? g29_grid_size - 1 - iy : iy);
1516
+        LOOP_L_N(iy, param.grid_size) {
1517
+          rpos.y = y_min + dy * (zig_zag ? param.grid_size - 1 - iy : iy);
1509
 
1518
 
1510
           if (!abort_flag) {
1519
           if (!abort_flag) {
1511
             SERIAL_ECHOLNPAIR("Tilting mesh point ", point_num, "/", total_points, "\n");
1520
             SERIAL_ECHOLNPAIR("Tilting mesh point ", point_num, "/", total_points, "\n");
1512
             TERN_(HAS_DISPLAY, ui.status_printf_P(0, PSTR(S_FMT " %i/%i"), GET_TEXT(MSG_LCD_TILTING_MESH), point_num, total_points));
1521
             TERN_(HAS_DISPLAY, ui.status_printf_P(0, PSTR(S_FMT " %i/%i"), GET_TEXT(MSG_LCD_TILTING_MESH), point_num, total_points));
1513
 
1522
 
1514
-            measured_z = probe.probe_at_point(rpos, parser.seen('E') ? PROBE_PT_STOW : PROBE_PT_RAISE, g29_verbose_level); // TODO: Needs error handling
1523
+            measured_z = probe.probe_at_point(rpos, parser.seen('E') ? PROBE_PT_STOW : PROBE_PT_RAISE, param.V_verbosity); // TODO: Needs error handling
1515
 
1524
 
1516
             abort_flag = isnan(measured_z);
1525
             abort_flag = isnan(measured_z);
1517
 
1526
 
1534
 
1543
 
1535
             if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR_F("   final >>>---> ", measured_z, 7);
1544
             if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPAIR_F("   final >>>---> ", measured_z, 7);
1536
 
1545
 
1537
-            if (g29_verbose_level > 3) {
1546
+            if (param.V_verbosity > 3) {
1538
               serial_spaces(16);
1547
               serial_spaces(16);
1539
               SERIAL_ECHOLNPAIR("Corrected_Z=", measured_z);
1548
               SERIAL_ECHOLNPAIR("Corrected_Z=", measured_z);
1540
             }
1549
             }
1557
 
1566
 
1558
     vector_3 normal = vector_3(lsf_results.A, lsf_results.B, 1).get_normal();
1567
     vector_3 normal = vector_3(lsf_results.A, lsf_results.B, 1).get_normal();
1559
 
1568
 
1560
-    if (g29_verbose_level > 2) {
1569
+    if (param.V_verbosity > 2) {
1561
       SERIAL_ECHOPAIR_F("bed plane normal = [", normal.x, 7);
1570
       SERIAL_ECHOPAIR_F("bed plane normal = [", normal.x, 7);
1562
       SERIAL_CHAR(',');
1571
       SERIAL_CHAR(',');
1563
       SERIAL_ECHO_F(normal.y, 7);
1572
       SERIAL_ECHO_F(normal.y, 7);
1721
       SERIAL_ECHOLNPAIR_F("Fade Height M420 Z", planner.z_fade_height, 4);
1730
       SERIAL_ECHOLNPAIR_F("Fade Height M420 Z", planner.z_fade_height, 4);
1722
     #endif
1731
     #endif
1723
 
1732
 
1724
-    adjust_mesh_to_mean(g29_c_flag, g29_constant);
1733
+    adjust_mesh_to_mean(param.C_seen, param.C_constant);
1725
 
1734
 
1726
     #if HAS_BED_PROBE
1735
     #if HAS_BED_PROBE
1727
       SERIAL_ECHOLNPAIR_F("Probe Offset M851 Z", probe.offset.z, 7);
1736
       SERIAL_ECHOLNPAIR_F("Probe Offset M851 Z", probe.offset.z, 7);
1819
       return;
1828
       return;
1820
     }
1829
     }
1821
 
1830
 
1822
-    if (!parser.has_value() || !WITHIN(g29_storage_slot, 0, a - 1)) {
1831
+    if (!parser.has_value() || !WITHIN(parser.value_int(), 0, a - 1)) {
1823
       SERIAL_ECHOLNPAIR("?Invalid storage slot.\n?Use 0 to ", a - 1);
1832
       SERIAL_ECHOLNPAIR("?Invalid storage slot.\n?Use 0 to ", a - 1);
1824
       return;
1833
       return;
1825
     }
1834
     }
1826
 
1835
 
1827
-    g29_storage_slot = parser.value_int();
1836
+    param.KLS_storage_slot = parser.value_int();
1828
 
1837
 
1829
     float tmp_z_values[GRID_MAX_POINTS_X][GRID_MAX_POINTS_Y];
1838
     float tmp_z_values[GRID_MAX_POINTS_X][GRID_MAX_POINTS_Y];
1830
-    settings.load_mesh(g29_storage_slot, &tmp_z_values);
1839
+    settings.load_mesh(param.KLS_storage_slot, &tmp_z_values);
1831
 
1840
 
1832
-    SERIAL_ECHOLNPAIR("Subtracting mesh in slot ", g29_storage_slot, " from current mesh.");
1841
+    SERIAL_ECHOLNPAIR("Subtracting mesh in slot ", param.KLS_storage_slot, " from current mesh.");
1833
 
1842
 
1834
     GRID_LOOP(x, y) {
1843
     GRID_LOOP(x, y) {
1835
       z_values[x][y] -= tmp_z_values[x][y];
1844
       z_values[x][y] -= tmp_z_values[x][y];

+ 3
- 3
Marlin/src/gcode/bedlevel/M420.cpp View File

156
             GRID_LOOP(x, y) mesh_sum += Z_VALUES(x, y);
156
             GRID_LOOP(x, y) mesh_sum += Z_VALUES(x, y);
157
             const float zmean = mesh_sum / float(GRID_MAX_POINTS);
157
             const float zmean = mesh_sum / float(GRID_MAX_POINTS);
158
 
158
 
159
-          #else
159
+          #else // midrange
160
 
160
 
161
-            // Find the low and high mesh values
161
+            // Find the low and high mesh values.
162
             float lo_val = 100, hi_val = -100;
162
             float lo_val = 100, hi_val = -100;
163
             GRID_LOOP(x, y) {
163
             GRID_LOOP(x, y) {
164
               const float z = Z_VALUES(x, y);
164
               const float z = Z_VALUES(x, y);
165
               NOMORE(lo_val, z);
165
               NOMORE(lo_val, z);
166
               NOLESS(hi_val, z);
166
               NOLESS(hi_val, z);
167
             }
167
             }
168
-            // Take the mean of the lowest and highest
168
+            // Get the midrange plus C value. (The median may be better.)
169
             const float zmean = (lo_val + hi_val) / 2.0 + cval;
169
             const float zmean = (lo_val + hi_val) / 2.0 + cval;
170
 
170
 
171
           #endif
171
           #endif

+ 5
- 5
Marlin/src/lcd/marlinui.h View File

85
     typedef void (*screenFunc_t)();
85
     typedef void (*screenFunc_t)();
86
     typedef void (*menuAction_t)();
86
     typedef void (*menuAction_t)();
87
 
87
 
88
-    #if ENABLED(AUTO_BED_LEVELING_UBL)
89
-      void lcd_mesh_edit_setup(const float &initial);
90
-      float lcd_mesh_edit();
91
-    #endif
92
-
93
   #endif // HAS_LCD_MENU
88
   #endif // HAS_LCD_MENU
94
 
89
 
95
 #endif // HAS_WIRED_LCD
90
 #endif // HAS_WIRED_LCD
488
       static void ubl_plot(const uint8_t x_plot, const uint8_t y_plot);
483
       static void ubl_plot(const uint8_t x_plot, const uint8_t y_plot);
489
     #endif
484
     #endif
490
 
485
 
486
+    #if ENABLED(AUTO_BED_LEVELING_UBL)
487
+      static void ubl_mesh_edit_start(const float &initial);
488
+      static float ubl_mesh_value();
489
+    #endif
490
+
491
     static void draw_select_screen_prompt(PGM_P const pref, const char * const string=nullptr, PGM_P const suff=nullptr);
491
     static void draw_select_screen_prompt(PGM_P const pref, const char * const string=nullptr, PGM_P const suff=nullptr);
492
 
492
 
493
   #elif HAS_WIRED_LCD
493
   #elif HAS_WIRED_LCD

+ 24
- 22
Marlin/src/lcd/menu/menu_ubl.cpp View File

56
   return float(rounded - (rounded % 5L)) / 1000;
56
   return float(rounded - (rounded % 5L)) / 1000;
57
 }
57
 }
58
 
58
 
59
-static void _lcd_mesh_fine_tune(PGM_P const msg) {
59
+/**
60
+ * This screen displays the temporary mesh value and updates it based on encoder
61
+ * movement. While this screen is active ubl.fine_tune_mesh sits in a loop getting
62
+ * the current value via ubl_mesh_value, moves the Z axis, and updates the mesh
63
+ * value until the encoder button is pressed.
64
+ *
65
+ * - Update the 'mesh_edit_accumulator' from encoder rotation
66
+ * - Draw the mesh value (with draw_edit_screen)
67
+ * - Draw the graphical overlay, if enabled.
68
+ * - Update the 'refresh' state according to the display type
69
+ */
70
+void _lcd_mesh_fine_tune(PGM_P const msg) {
71
+  constexpr float mesh_edit_step = 1.0f / 200.0f;
60
   ui.defer_status_screen();
72
   ui.defer_status_screen();
61
   if (ubl.encoder_diff) {
73
   if (ubl.encoder_diff) {
62
     mesh_edit_accumulator += TERN(IS_TFTGLCD_PANEL,
74
     mesh_edit_accumulator += TERN(IS_TFTGLCD_PANEL,
63
-      ubl.encoder_diff * 0.005f / ENCODER_PULSES_PER_STEP,
64
-      ubl.encoder_diff > 0 ? 0.005f : -0.005f
75
+      ubl.encoder_diff * mesh_edit_step / ENCODER_PULSES_PER_STEP,
76
+      ubl.encoder_diff > 0 ? mesh_edit_step : -mesh_edit_step
65
     );
77
     );
66
     ubl.encoder_diff = 0;
78
     ubl.encoder_diff = 0;
67
     IF_DISABLED(IS_TFTGLCD_PANEL, ui.refresh(LCDVIEW_CALL_REDRAW_NEXT));
79
     IF_DISABLED(IS_TFTGLCD_PANEL, ui.refresh(LCDVIEW_CALL_REDRAW_NEXT));
77
 }
89
 }
78
 
90
 
79
 //
91
 //
80
-// Called external to the menu system to acquire the result of an edit.
92
+// Init mesh editing and go to the fine tuning screen (ubl.fine_tune_mesh)
93
+// To capture encoder events UBL will also call ui.capture and ui.release.
81
 //
94
 //
82
-float lcd_mesh_edit() { return rounded_mesh_value(); }
83
-
84
-void lcd_mesh_edit_setup(const float &initial) {
85
-  TERN_(HAS_GRAPHICAL_TFT, ui.clear_lcd());
95
+void MarlinUI::ubl_mesh_edit_start(const float &initial) {
96
+  TERN_(HAS_GRAPHICAL_TFT, clear_lcd());
86
   mesh_edit_accumulator = initial;
97
   mesh_edit_accumulator = initial;
87
-  ui.goto_screen([]{ _lcd_mesh_fine_tune(GET_TEXT(MSG_MESH_EDIT_Z)); });
88
-}
89
-
90
-void _lcd_z_offset_edit() {
91
-  _lcd_mesh_fine_tune(GET_TEXT(MSG_UBL_Z_OFFSET));
98
+  goto_screen([]{ _lcd_mesh_fine_tune(GET_TEXT(MSG_MESH_EDIT_Z)); });
92
 }
99
 }
93
 
100
 
94
-float lcd_z_offset_edit() {
95
-  ui.goto_screen(_lcd_z_offset_edit);
96
-  return rounded_mesh_value();
97
-}
98
-
99
-void lcd_z_offset_edit_setup(const float &initial) {
100
-  mesh_edit_accumulator = initial;
101
-  ui.goto_screen(_lcd_z_offset_edit);
102
-}
101
+//
102
+// Get the mesh value within a Z adjustment loop (ubl.fine_tune_mesh)
103
+//
104
+float MarlinUI::ubl_mesh_value() { return rounded_mesh_value(); }
103
 
105
 
104
 /**
106
 /**
105
  * UBL Build Custom Mesh Command
107
  * UBL Build Custom Mesh Command

Loading…
Cancel
Save