Clean up LCD Manual Move / UBL Mesh Edit (#18373)
This commit is contained in:
		| @@ -498,12 +498,7 @@ inline void manage_inactivity(const bool ignore_stepper_queue=false) { | ||||
|         if (ENABLED(DISABLE_INACTIVE_Z)) DISABLE_AXIS_Z(); | ||||
|         if (ENABLED(DISABLE_INACTIVE_E)) disable_e_steppers(); | ||||
|  | ||||
|         #if BOTH(HAS_LCD_MENU, AUTO_BED_LEVELING_UBL) | ||||
|           if (ubl.lcd_map_control) { | ||||
|             ubl.lcd_map_control = false; | ||||
|             ui.defer_status_screen(false); | ||||
|           } | ||||
|         #endif | ||||
|         TERN_(AUTO_BED_LEVELING_UBL, ubl.steppers_were_disabled()); | ||||
|       } | ||||
|     } | ||||
|     else | ||||
|   | ||||
| @@ -84,11 +84,7 @@ | ||||
|     _GRIDPOS(Y, 12), _GRIDPOS(Y, 13), _GRIDPOS(Y, 14), _GRIDPOS(Y, 15) | ||||
|   ); | ||||
|  | ||||
|   #if HAS_LCD_MENU | ||||
|     bool unified_bed_leveling::lcd_map_control = false; | ||||
|   #endif | ||||
|  | ||||
|   volatile int unified_bed_leveling::encoder_diff; | ||||
|   volatile int16_t unified_bed_leveling::encoder_diff; | ||||
|  | ||||
|   unified_bed_leveling::unified_bed_leveling() { | ||||
|     reset(); | ||||
|   | ||||
| @@ -111,9 +111,12 @@ class unified_bed_leveling { | ||||
|  | ||||
|     #if HAS_LCD_MENU | ||||
|       static bool lcd_map_control; | ||||
|       static void steppers_were_disabled(); | ||||
|     #else | ||||
|       static inline void steppers_were_disabled() {} | ||||
|     #endif | ||||
|  | ||||
|     static volatile int encoder_diff; // Volatile because it's changed at interrupt time. | ||||
|     static volatile int16_t encoder_diff; // Volatile because buttons may changed it at interrupt time | ||||
|  | ||||
|     unified_bed_leveling(); | ||||
|  | ||||
|   | ||||
| @@ -54,7 +54,18 @@ | ||||
|   #define UBL_G29_P31 | ||||
|  | ||||
|   #if HAS_LCD_MENU | ||||
|     void _lcd_ubl_output_map_lcd(); | ||||
|  | ||||
|     bool unified_bed_leveling::lcd_map_control = false; | ||||
|  | ||||
|     void unified_bed_leveling::steppers_were_disabled() { | ||||
|       if (lcd_map_control) { | ||||
|         lcd_map_control = false; | ||||
|         ui.defer_status_screen(false); | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     void ubl_map_screen(); | ||||
|  | ||||
|   #endif | ||||
|  | ||||
|   #define SIZE_OF_LITTLE_RAISE 1 | ||||
| @@ -789,11 +800,11 @@ | ||||
|  | ||||
|     bool click_and_hold(const clickFunc_t func=nullptr) { | ||||
|       if (ui.button_pressed()) { | ||||
|         ui.quick_feedback(false);                // Preserve button state for click-and-hold | ||||
|         ui.quick_feedback(false);         // Preserve button state for click-and-hold | ||||
|         const millis_t nxt = millis() + 1500UL; | ||||
|         while (ui.button_pressed()) {                // Loop while the encoder is pressed. Uses hardware flag! | ||||
|           idle();                                 // idle, of course | ||||
|           if (ELAPSED(millis(), nxt)) {           // After 1.5 seconds | ||||
|         while (ui.button_pressed()) {     // Loop while the encoder is pressed. Uses hardware flag! | ||||
|           idle();                         // idle, of course | ||||
|           if (ELAPSED(millis(), nxt)) {   // After 1.5 seconds | ||||
|             ui.quick_feedback(); | ||||
|             if (func) (*func)(); | ||||
|             ui.wait_for_release(); | ||||
| @@ -995,9 +1006,9 @@ | ||||
|         lcd_mesh_edit_setup(new_z); | ||||
|  | ||||
|         do { | ||||
|           idle(); | ||||
|           new_z = lcd_mesh_edit(); | ||||
|           TERN_(UBL_MESH_EDIT_MOVES_Z, do_blocking_move_to_z(h_offset + new_z)); // Move the nozzle as the point is edited | ||||
|           idle(); | ||||
|           SERIAL_FLUSH();                                   // Prevent host M105 buffer overrun. | ||||
|         } while (!ui.button_pressed()); | ||||
|  | ||||
| @@ -1022,7 +1033,7 @@ | ||||
|       SERIAL_ECHOLNPGM("Done Editing Mesh"); | ||||
|  | ||||
|       if (lcd_map_control) | ||||
|         ui.goto_screen(_lcd_ubl_output_map_lcd); | ||||
|         ui.goto_screen(ubl_map_screen); | ||||
|       else | ||||
|         ui.return_to_status(); | ||||
|     } | ||||
|   | ||||
| @@ -81,7 +81,6 @@ | ||||
| #endif | ||||
|  | ||||
| XPT2046 touch; | ||||
| extern int8_t encoderDiff; | ||||
|  | ||||
| void XPT2046::init() { | ||||
|   SET_INPUT(TOUCH_MISO_PIN); | ||||
|   | ||||
| @@ -64,11 +64,6 @@ void GcodeSuite::M18_M84() { | ||||
|     else | ||||
|       planner.finish_and_disable(); | ||||
|  | ||||
|     #if BOTH(HAS_LCD_MENU, AUTO_BED_LEVELING_UBL) | ||||
|       if (ubl.lcd_map_control) { | ||||
|         ubl.lcd_map_control = false; | ||||
|         ui.defer_status_screen(false); | ||||
|       } | ||||
|     #endif | ||||
|     TERN_(AUTO_BED_LEVELING_UBL, ubl.steppers_were_disabled()); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -230,7 +230,7 @@ void MarlinUI::goto_screen(screenFunc_t screen, const uint16_t encoder/*=0*/, co | ||||
|           screen = TERN(BABYSTEP_ZPROBE_OFFSET, lcd_babystep_zoffset, lcd_babystep_z); | ||||
|         else { | ||||
|           #if ENABLED(MOVE_Z_WHEN_IDLE) | ||||
|             move_menu_scale = MOVE_Z_IDLE_MULTIPLICATOR; | ||||
|             ui.manual_move.menu_scale = MOVE_Z_IDLE_MULTIPLICATOR; | ||||
|             screen = lcd_move_z; | ||||
|           #endif | ||||
|         } | ||||
|   | ||||
| @@ -46,7 +46,7 @@ void _man_probe_pt(const xy_pos_t &xy) { | ||||
|     do_blocking_move_to_xy_z(xy, Z_CLEARANCE_BETWEEN_PROBES); | ||||
|     ui.wait_for_move = false; | ||||
|     ui.synchronize(); | ||||
|     move_menu_scale = _MAX(PROBE_MANUALLY_STEP, MIN_STEPS_PER_SEGMENT / float(DEFAULT_XYZ_STEPS_PER_UNIT)); | ||||
|     ui.manual_move.menu_scale = _MAX(PROBE_MANUALLY_STEP, MIN_STEPS_PER_SEGMENT / float(DEFAULT_XYZ_STEPS_PER_UNIT)); | ||||
|     ui.goto_screen(lcd_move_z); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -50,28 +50,13 @@ | ||||
|   float manual_move_e_origin = 0; | ||||
| #endif | ||||
|  | ||||
| // | ||||
| // Tell ui.update() to start a move to current_position" after a short delay. | ||||
| // | ||||
| inline void manual_move_to_current(AxisEnum axis | ||||
|   #if MULTI_MANUAL | ||||
|     , const int8_t eindex=-1 | ||||
|   #endif | ||||
| ) { | ||||
|   #if MULTI_MANUAL | ||||
|     if (axis == E_AXIS) ui.manual_move_e_index = eindex >= 0 ? eindex : active_extruder; | ||||
|   #endif | ||||
|   ui.manual_move_start_time = millis() + (move_menu_scale < 0.99f ? 0UL : 250UL); // delay for bigger moves | ||||
|   ui.manual_move_axis = (int8_t)axis; | ||||
| } | ||||
|  | ||||
| // | ||||
| // "Motion" > "Move Axis" submenu | ||||
| // | ||||
|  | ||||
| static void _lcd_move_xyz(PGM_P const name, const AxisEnum axis) { | ||||
|   if (ui.use_click()) return ui.goto_previous_screen_no_defer(); | ||||
|   if (ui.encoderPosition && !ui.processing_manual_move) { | ||||
|   if (ui.encoderPosition && !ui.manual_move.processing) { | ||||
|  | ||||
|     // Start with no limits to movement | ||||
|     float min = current_position[axis] - 1000, | ||||
| @@ -105,13 +90,13 @@ static void _lcd_move_xyz(PGM_P const name, const AxisEnum axis) { | ||||
|     #endif | ||||
|  | ||||
|     // Get the new position | ||||
|     const float diff = float(int32_t(ui.encoderPosition)) * move_menu_scale; | ||||
|     const float diff = float(int32_t(ui.encoderPosition)) * ui.manual_move.menu_scale; | ||||
|     #if IS_KINEMATIC | ||||
|       ui.manual_move_offset += diff; | ||||
|       ui.manual_move.offset += diff; | ||||
|       if (int32_t(ui.encoderPosition) < 0) | ||||
|         NOLESS(ui.manual_move_offset, min - current_position[axis]); | ||||
|         NOLESS(ui.manual_move.offset, min - current_position[axis]); | ||||
|       else | ||||
|         NOMORE(ui.manual_move_offset, max - current_position[axis]); | ||||
|         NOMORE(ui.manual_move.offset, max - current_position[axis]); | ||||
|     #else | ||||
|       current_position[axis] += diff; | ||||
|       if (int32_t(ui.encoderPosition) < 0) | ||||
| @@ -120,16 +105,16 @@ static void _lcd_move_xyz(PGM_P const name, const AxisEnum axis) { | ||||
|         NOMORE(current_position[axis], max); | ||||
|     #endif | ||||
|  | ||||
|     manual_move_to_current(axis); | ||||
|     ui.manual_move.soon(axis); | ||||
|     ui.refresh(LCDVIEW_REDRAW_NOW); | ||||
|   } | ||||
|   ui.encoderPosition = 0; | ||||
|   if (ui.should_draw()) { | ||||
|     const float pos = NATIVE_TO_LOGICAL( | ||||
|       ui.processing_manual_move ? destination[axis] : current_position[axis] + TERN0(IS_KINEMATIC, ui.manual_move_offset), | ||||
|       ui.manual_move.processing ? destination[axis] : current_position[axis] + TERN0(IS_KINEMATIC, ui.manual_move.offset), | ||||
|       axis | ||||
|     ); | ||||
|     MenuEditItemBase::draw_edit_screen(name, move_menu_scale >= 0.1f ? ftostr41sign(pos) : ftostr43sign(pos)); | ||||
|     MenuEditItemBase::draw_edit_screen(name, ui.manual_move.menu_scale >= 0.1f ? ftostr41sign(pos) : ftostr43sign(pos)); | ||||
|   } | ||||
| } | ||||
| void lcd_move_x() { _lcd_move_xyz(GET_TEXT(MSG_MOVE_X), X_AXIS); } | ||||
| @@ -141,10 +126,10 @@ void lcd_move_z() { _lcd_move_xyz(GET_TEXT(MSG_MOVE_Z), Z_AXIS); } | ||||
|   static void lcd_move_e(TERN_(MULTI_MANUAL, const int8_t eindex=-1)) { | ||||
|     if (ui.use_click()) return ui.goto_previous_screen_no_defer(); | ||||
|     if (ui.encoderPosition) { | ||||
|       if (!ui.processing_manual_move) { | ||||
|         const float diff = float(int32_t(ui.encoderPosition)) * move_menu_scale; | ||||
|         TERN(IS_KINEMATIC, ui.manual_move_offset, current_position.e) += diff; | ||||
|         manual_move_to_current(E_AXIS | ||||
|       if (!ui.manual_move.processing) { | ||||
|         const float diff = float(int32_t(ui.encoderPosition)) * ui.manual_move.menu_scale; | ||||
|         TERN(IS_KINEMATIC, ui.manual_move.offset, current_position.e) += diff; | ||||
|         ui.manual_move.soon(E_AXIS | ||||
|           #if MULTI_MANUAL | ||||
|             , eindex | ||||
|           #endif | ||||
| @@ -160,7 +145,7 @@ void lcd_move_z() { _lcd_move_xyz(GET_TEXT(MSG_MOVE_Z), Z_AXIS); } | ||||
|       MenuEditItemBase::draw_edit_screen( | ||||
|         GET_TEXT(TERN(MULTI_MANUAL, MSG_MOVE_EN, MSG_MOVE_E)), | ||||
|         ftostr41sign(current_position.e | ||||
|           + TERN0(IS_KINEMATIC, ui.manual_move_offset) | ||||
|           + TERN0(IS_KINEMATIC, ui.manual_move.offset) | ||||
|           - TERN0(MANUAL_E_MOVES_RELATIVE, manual_move_e_origin) | ||||
|         ) | ||||
|       ); | ||||
| @@ -181,7 +166,7 @@ screenFunc_t _manual_move_func_ptr; | ||||
|  | ||||
| void _goto_manual_move(const float scale) { | ||||
|   ui.defer_status_screen(); | ||||
|   move_menu_scale = scale; | ||||
|   ui.manual_move.menu_scale = scale; | ||||
|   ui.goto_screen(_manual_move_func_ptr); | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -49,46 +49,36 @@ static int8_t x_plot = 0, y_plot = 0; // May be negative during move | ||||
|   static int16_t custom_bed_temp = 50; | ||||
| #endif | ||||
|  | ||||
| float mesh_edit_value, mesh_edit_accumulator; // We round mesh_edit_value to 2.5 decimal places. So we keep a | ||||
|                                               // separate value that doesn't lose precision. | ||||
| static int16_t ubl_encoderPosition = 0; | ||||
| float mesh_edit_accumulator;  // Rounded to 2.5 decimal places on use | ||||
|  | ||||
| inline float rounded_mesh_value() { | ||||
|   const int32_t rounded = int32_t(mesh_edit_accumulator * 1000); | ||||
|   return float(rounded - (rounded % 5L)) / 1000; | ||||
| } | ||||
|  | ||||
| static void _lcd_mesh_fine_tune(PGM_P const msg) { | ||||
|   ui.defer_status_screen(); | ||||
|   if (ubl.encoder_diff) { | ||||
|     ubl_encoderPosition = (ubl.encoder_diff > 0) ? 1 : -1; | ||||
|     mesh_edit_accumulator += ubl.encoder_diff > 0 ? 0.005f : -0.005f; | ||||
|     ubl.encoder_diff = 0; | ||||
|  | ||||
|     mesh_edit_accumulator += float(ubl_encoderPosition) * 0.005f * 0.5f; | ||||
|     mesh_edit_value = mesh_edit_accumulator; | ||||
|     ui.encoderPosition = 0; | ||||
|     ui.refresh(LCDVIEW_CALL_REDRAW_NEXT); | ||||
|  | ||||
|     const int32_t rounded = (int32_t)(mesh_edit_value * 1000); | ||||
|     mesh_edit_value = float(rounded - (rounded % 5L)) / 1000; | ||||
|   } | ||||
|  | ||||
|   if (ui.should_draw()) { | ||||
|     MenuEditItemBase::draw_edit_screen(msg, ftostr43sign(mesh_edit_value)); | ||||
|     TERN_(MESH_EDIT_GFX_OVERLAY, _lcd_zoffset_overlay_gfx(mesh_edit_value)); | ||||
|     const float rounded_f = rounded_mesh_value(); | ||||
|     MenuEditItemBase::draw_edit_screen(msg, ftostr43sign(rounded_f)); | ||||
|     TERN_(MESH_EDIT_GFX_OVERLAY, _lcd_zoffset_overlay_gfx(rounded_f)); | ||||
|   } | ||||
| } | ||||
|  | ||||
| void lcd_limbo() { | ||||
|   ui.currentScreen = []{}; | ||||
|   ui.defer_status_screen(); | ||||
| } | ||||
|  | ||||
| float lcd_mesh_edit() { | ||||
|   lcd_limbo(); | ||||
|   ui.refresh(LCDVIEW_CALL_REDRAW_NEXT); | ||||
|   _lcd_mesh_fine_tune(GET_TEXT(MSG_MESH_EDITOR)); | ||||
|   return mesh_edit_value; | ||||
| } | ||||
| // | ||||
| // Called external to the menu system to acquire the result of an edit. | ||||
| // | ||||
| float lcd_mesh_edit() { return rounded_mesh_value(); } | ||||
|  | ||||
| void lcd_mesh_edit_setup(const float &initial) { | ||||
|   mesh_edit_value = mesh_edit_accumulator = initial; | ||||
|   lcd_limbo(); | ||||
|   mesh_edit_accumulator = initial; | ||||
|   ui.goto_screen([]{ _lcd_mesh_fine_tune(GET_TEXT(MSG_MESH_EDIT_Z)); }); | ||||
| } | ||||
|  | ||||
| void _lcd_z_offset_edit() { | ||||
| @@ -97,11 +87,11 @@ void _lcd_z_offset_edit() { | ||||
|  | ||||
| float lcd_z_offset_edit() { | ||||
|   ui.goto_screen(_lcd_z_offset_edit); | ||||
|   return mesh_edit_value; | ||||
|   return rounded_mesh_value(); | ||||
| } | ||||
|  | ||||
| void lcd_z_offset_edit_setup(const float &initial) { | ||||
|   mesh_edit_value = mesh_edit_accumulator = initial; | ||||
|   mesh_edit_accumulator = initial; | ||||
|   ui.goto_screen(_lcd_z_offset_edit); | ||||
| } | ||||
|  | ||||
| @@ -390,24 +380,10 @@ void _lcd_ubl_storage_mesh() { | ||||
|   END_MENU(); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * UBL LCD "radar" map homing | ||||
|  */ | ||||
| void _lcd_ubl_output_map_lcd(); | ||||
|  | ||||
| void _lcd_ubl_map_homing() { | ||||
|   ui.defer_status_screen(); | ||||
|   _lcd_draw_homing(); | ||||
|   if (all_axes_homed()) { | ||||
|     ubl.lcd_map_control = true; // Return to the map screen | ||||
|     ui.goto_screen(_lcd_ubl_output_map_lcd); | ||||
|   } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * UBL LCD "radar" map point editing | ||||
|  */ | ||||
| void _lcd_ubl_map_lcd_edit_cmd() { | ||||
| void _lcd_ubl_map_edit_cmd() { | ||||
|   char ubl_lcd_gcode[50], str[10], str2[10]; | ||||
|   dtostrf(ubl.mesh_index_to_xpos(x_plot), 0, 2, str); | ||||
|   dtostrf(ubl.mesh_index_to_ypos(y_plot), 0, 2, str2); | ||||
| @@ -419,85 +395,122 @@ void _lcd_ubl_map_lcd_edit_cmd() { | ||||
|  * UBL LCD Map Movement | ||||
|  */ | ||||
| void ubl_map_move_to_xy() { | ||||
|   const feedRate_t fr_mm_s = MMM_TO_MMS(XY_PROBE_SPEED); | ||||
|  | ||||
|   destination = current_position;          // sync destination at the start | ||||
|  | ||||
|   #if ENABLED(DELTA) | ||||
|     if (current_position.z > delta_clip_start_height) { | ||||
|     if (current_position.z > delta_clip_start_height) { // Make sure the delta has fully free motion | ||||
|       destination = current_position; | ||||
|       destination.z = delta_clip_start_height; | ||||
|       prepare_internal_move_to_destination(fr_mm_s); | ||||
|       prepare_internal_fast_move_to_destination(homing_feedrate(Z_AXIS)); // Set current_position from destination | ||||
|     } | ||||
|   #endif | ||||
|  | ||||
|   destination.set(ubl.mesh_index_to_xpos(x_plot), ubl.mesh_index_to_ypos(y_plot)); | ||||
|   prepare_internal_move_to_destination(fr_mm_s); | ||||
|   // Set the nozzle position to the mesh point | ||||
|   current_position.set(ubl.mesh_index_to_xpos(x_plot), ubl.mesh_index_to_ypos(y_plot)); | ||||
|  | ||||
|   // Use the built-in manual move handler | ||||
|   ui.manual_move.soon(ALL_AXES); | ||||
| } | ||||
|  | ||||
| inline int32_t grid_index(const uint8_t x, const uint8_t y) { | ||||
|   return (GRID_MAX_POINTS_X) * y + x; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * UBL LCD "radar" map | ||||
|  */ | ||||
| void _lcd_ubl_output_map_lcd() { | ||||
| void ubl_map_screen() { | ||||
|   // static millis_t next_move = 0; | ||||
|   // const millis_t ms = millis(); | ||||
|  | ||||
|   static int16_t step_scaler = 0; | ||||
|   uint8_t x, y; | ||||
|  | ||||
|   if (ui.use_click()) return _lcd_ubl_map_lcd_edit_cmd(); | ||||
|   if (ui.first_page) { | ||||
|  | ||||
|   if (ui.encoderPosition) { | ||||
|     step_scaler += int32_t(ui.encoderPosition); | ||||
|     x_plot += step_scaler / (ENCODER_STEPS_PER_MENU_ITEM); | ||||
|     ui.encoderPosition = 0; | ||||
|     ui.refresh(LCDVIEW_REDRAW_NOW); | ||||
|   } | ||||
|     // On click send "G29 P4 ..." to edit the Z value | ||||
|     if (ui.use_click()) { | ||||
|       _lcd_ubl_map_edit_cmd(); | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|   #define KEEP_LOOPING ENABLED(IS_KINEMATIC) // Loop until a valid point is found | ||||
|  | ||||
|   do { | ||||
|     // Encoder to the right (++) | ||||
|     if (x_plot >= GRID_MAX_POINTS_X) { x_plot = 0; y_plot++; } | ||||
|     if (y_plot >= GRID_MAX_POINTS_Y) y_plot = 0; | ||||
|  | ||||
|     // Encoder to the left (--) | ||||
|     if (x_plot < 0) { x_plot = GRID_MAX_POINTS_X - 1; y_plot--; } | ||||
|     if (y_plot < 0) y_plot = GRID_MAX_POINTS_Y - 1; | ||||
|     ui.defer_status_screen(); | ||||
|  | ||||
|     #if IS_KINEMATIC | ||||
|       const xy_pos_t xy = { ubl.mesh_index_to_xpos(x_plot), ubl.mesh_index_to_ypos(y_plot) }; | ||||
|       if (position_is_reachable(xy)) break; // Found a valid point | ||||
|       x_plot += (step_scaler < 0) ? -1 : 1; | ||||
|       // Index of the mesh point upon entry | ||||
|       const uint32_t old_pos_index = grid_index(x_plot, y_plot); | ||||
|       // Direction from new (unconstrained) encoder value | ||||
|       const int8_t step_dir = int32_t(ui.encoderPosition) < old_pos_index ? -1 : 1; | ||||
|     #endif | ||||
|  | ||||
|   } while(KEEP_LOOPING); | ||||
|     do { | ||||
|       // Now, keep the encoder position within range | ||||
|       if (int32_t(ui.encoderPosition) < 0) ui.encoderPosition = GRID_MAX_POINTS - 1; | ||||
|       if (int32_t(ui.encoderPosition) > GRID_MAX_POINTS - 1) ui.encoderPosition = 0; | ||||
|  | ||||
|   // Determine number of points to edit | ||||
|   #if IS_KINEMATIC | ||||
|     n_edit_pts = 9; //TODO: Delta accessible edit points | ||||
|   #else | ||||
|     const bool xc = WITHIN(x_plot, 1, GRID_MAX_POINTS_X - 2), | ||||
|                yc = WITHIN(y_plot, 1, GRID_MAX_POINTS_Y - 2); | ||||
|     n_edit_pts = yc ? (xc ? 9 : 6) : (xc ? 6 : 4); // Corners | ||||
|   #endif | ||||
|       // Draw the grid point based on the encoder | ||||
|       x = ui.encoderPosition % (GRID_MAX_POINTS_X); | ||||
|       y = ui.encoderPosition / (GRID_MAX_POINTS_X); | ||||
|  | ||||
|   // Cleanup | ||||
|   if (ABS(step_scaler) >= ENCODER_STEPS_PER_MENU_ITEM) step_scaler = 0; | ||||
|       // Validate if needed | ||||
|       #if IS_KINEMATIC | ||||
|         const xy_pos_t xy = { ubl.mesh_index_to_xpos(x), ubl.mesh_index_to_ypos(y) }; | ||||
|         if (position_is_reachable(xy)) break; // Found a valid point | ||||
|         ui.encoderPosition += step_dir;       // Test the next point | ||||
|       #endif | ||||
|     } while(ENABLED(IS_KINEMATIC)); | ||||
|  | ||||
|   if (ui.should_draw()) { | ||||
|     ui.ubl_plot(x_plot, y_plot); | ||||
|     if (!planner.movesplanned()) | ||||
|       ubl_map_move_to_xy();       // Move to new location | ||||
|     // Determine number of points to edit | ||||
|     #if IS_KINEMATIC | ||||
|       n_edit_pts = 9; // TODO: Delta accessible edit points | ||||
|     #else | ||||
|       const bool xc = WITHIN(x, 1, GRID_MAX_POINTS_X - 2), | ||||
|                  yc = WITHIN(y, 1, GRID_MAX_POINTS_Y - 2); | ||||
|       n_edit_pts = yc ? (xc ? 9 : 6) : (xc ? 6 : 4); // Corners | ||||
|     #endif | ||||
|  | ||||
|     // Refresh is also set by encoder movement | ||||
|     //if (int32_t(ui.encoderPosition) != grid_index(x, y)) | ||||
|     //  ui.refresh(LCDVIEW_CALL_REDRAW_NEXT); | ||||
|   } | ||||
|  | ||||
|   // Draw the grid point based on the encoder | ||||
|   x = ui.encoderPosition % (GRID_MAX_POINTS_X); | ||||
|   y = ui.encoderPosition / (GRID_MAX_POINTS_X); | ||||
|  | ||||
|   if (ui.should_draw()) ui.ubl_plot(x, y); | ||||
|  | ||||
|   // Add a move if needed to match the grid point | ||||
|   if (x != x_plot || y != y_plot) { | ||||
|     x_plot = x; y_plot = y;   // The move is always posted, so update the grid point now | ||||
|     ubl_map_move_to_xy();     // Sets up a "manual move" | ||||
|     ui.refresh(LCDVIEW_CALL_REDRAW_NEXT); // Clean up a half drawn box | ||||
|   } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * UBL LCD "radar" map homing | ||||
|  */ | ||||
| void _ubl_map_screen_homing() { | ||||
|   ui.defer_status_screen(); | ||||
|   _lcd_draw_homing(); | ||||
|   if (all_axes_homed()) { | ||||
|     ubl.lcd_map_control = true;     // Return to the map screen after editing Z | ||||
|     ui.goto_screen(ubl_map_screen, grid_index(x_plot, y_plot)); // Pre-set the encoder value | ||||
|     ui.manual_move.menu_scale = 0;  // Immediate move | ||||
|     ubl_map_move_to_xy();           // Move to current mesh point | ||||
|     ui.manual_move.menu_scale = 1;  // Delayed moves | ||||
|   } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * UBL Homing before LCD map | ||||
|  */ | ||||
| void _lcd_ubl_output_map_lcd_cmd() { | ||||
| void _ubl_goto_map_screen() { | ||||
|   if (planner.movesplanned()) return;     // The ACTION_ITEM will do nothing | ||||
|   if (!all_axes_known()) { | ||||
|     set_all_unhomed(); | ||||
|     queue.inject_P(G28_STR); | ||||
|   } | ||||
|   if (planner.movesplanned()) return; | ||||
|   ui.goto_screen(_lcd_ubl_map_homing); | ||||
|   ui.goto_screen(_ubl_map_screen_homing); // Go to the "Homing" screen | ||||
| } | ||||
|  | ||||
| /** | ||||
| @@ -591,7 +604,7 @@ void _lcd_ubl_level_bed() { | ||||
|   #if ENABLED(G26_MESH_VALIDATION) | ||||
|     SUBMENU(MSG_UBL_STEP_BY_STEP_MENU, _lcd_ubl_step_by_step); | ||||
|   #endif | ||||
|   ACTION_ITEM(MSG_UBL_MESH_EDIT, _lcd_ubl_output_map_lcd_cmd); | ||||
|   ACTION_ITEM(MSG_UBL_MESH_EDIT, _ubl_goto_map_screen); | ||||
|   SUBMENU(MSG_UBL_STORAGE_MESH_MENU, _lcd_ubl_storage_mesh); | ||||
|   SUBMENU(MSG_UBL_OUTPUT_MAP, _lcd_ubl_output_map); | ||||
|   SUBMENU(MSG_UBL_TOOLS, _menu_ubl_tools); | ||||
|   | ||||
| @@ -211,7 +211,6 @@ millis_t MarlinUI::next_button_update_ms; // = 0 | ||||
|   #endif | ||||
|  | ||||
|   bool MarlinUI::lcd_clicked; | ||||
|   float move_menu_scale; | ||||
|  | ||||
|   bool MarlinUI::use_click() { | ||||
|     const bool click = lcd_clicked; | ||||
| @@ -388,7 +387,7 @@ bool MarlinUI::get_blink() { | ||||
|     void lcd_move_z(); | ||||
|  | ||||
|     void _reprapworld_keypad_move(const AxisEnum axis, const int16_t dir) { | ||||
|       move_menu_scale = REPRAPWORLD_KEYPAD_MOVE_STEP; | ||||
|       ui.manual_move.menu_scale = REPRAPWORLD_KEYPAD_MOVE_STEP; | ||||
|       ui.encoderPosition = dir; | ||||
|       switch (axis) { | ||||
|         case X_AXIS: lcd_move_x(); break; | ||||
| @@ -637,51 +636,65 @@ void MarlinUI::quick_feedback(const bool clear_buttons/*=true*/) { | ||||
|  | ||||
| #if HAS_LCD_MENU | ||||
|  | ||||
|   int8_t MarlinUI::manual_move_axis = (int8_t)NO_AXIS; | ||||
|   millis_t MarlinUI::manual_move_start_time = 0; | ||||
|   ManualMove MarlinUI::manual_move{}; | ||||
|  | ||||
|   #if IS_KINEMATIC | ||||
|     bool MarlinUI::processing_manual_move = false; | ||||
|     float MarlinUI::manual_move_offset = 0; | ||||
|   #endif | ||||
|  | ||||
|   #if MULTI_MANUAL | ||||
|     int8_t MarlinUI::manual_move_e_index = 0; | ||||
|   #endif | ||||
|   millis_t ManualMove::start_time = 0; | ||||
|   float ManualMove::menu_scale = 1; | ||||
|   TERN_(IS_KINEMATIC, float ManualMove::offset = 0); | ||||
|   TERN_(IS_KINEMATIC, bool ManualMove::processing = false); | ||||
|   TERN_(MULTI_MANUAL, int8_t ManualMove::e_index = 0); | ||||
|   uint8_t ManualMove::axis = (uint8_t)NO_AXIS; | ||||
|  | ||||
|   /** | ||||
|    * If the most recent manual move hasn't been fed to the planner yet, | ||||
|    * and the planner can accept one, send a move immediately. | ||||
|    * If a manual move has been posted and its time has arrived, and if the planner | ||||
|    * has a space for it, then add a linear move to current_position the planner. | ||||
|    * | ||||
|    * If any manual move needs to be interrupted, make sure to force a manual move | ||||
|    * by setting manual_move.start_time to millis() after updating current_position. | ||||
|    * | ||||
|    * To post a manual move: | ||||
|    *   - Update current_position to the new place you want to go. | ||||
|    *   - Set manual_move.axis to an axis like X_AXIS. Use ALL_AXES for diagonal moves. | ||||
|    *   - Set manual_move.start_time to a point in the future (in ms) when the move should be done. | ||||
|    * | ||||
|    * For kinematic machines: | ||||
|    *   - Set manual_move.offset to modify one axis and post the move. | ||||
|    *     This is used to achieve more rapid stepping on kinematic machines. | ||||
|    * | ||||
|    * Currently used by the _lcd_move_xyz function in menu_motion.cpp | ||||
|    * and the ubl_map_move_to_xy funtion in menu_ubl.cpp. | ||||
|    */ | ||||
|   void MarlinUI::manage_manual_move() { | ||||
|   void ManualMove::task() { | ||||
|  | ||||
|     if (processing_manual_move) return; | ||||
|     if (processing) return;   // Prevent re-entry from idle() calls | ||||
|  | ||||
|     if (manual_move_axis != (int8_t)NO_AXIS && ELAPSED(millis(), manual_move_start_time) && !planner.is_full()) { | ||||
|     // Add a manual move to the queue? | ||||
|     if (axis != (uint8_t)NO_AXIS && ELAPSED(millis(), start_time) && !planner.is_full()) { | ||||
|  | ||||
|       const feedRate_t fr_mm_s = (uint8_t(axis) <= E_AXIS) ? manual_feedrate_mm_s[axis] : XY_PROBE_FEEDRATE_MM_S; | ||||
|  | ||||
|       const feedRate_t fr_mm_s = manual_feedrate_mm_s[manual_move_axis]; | ||||
|       #if IS_KINEMATIC | ||||
|  | ||||
|         #if EXTRUDERS > 1 | ||||
|           const int8_t old_extruder = active_extruder; | ||||
|           if (manual_move_axis == E_AXIS) active_extruder = manual_move_e_index; | ||||
|           if (axis == E_AXIS) active_extruder = e_index; | ||||
|         #endif | ||||
|  | ||||
|         // Set movement on a single axis | ||||
|         // Apply a linear offset to a single axis | ||||
|         destination = current_position; | ||||
|         destination[manual_move_axis] += manual_move_offset; | ||||
|         if (axis <= XYZE) destination[axis] += offset; | ||||
|  | ||||
|         // Reset for the next move | ||||
|         manual_move_offset = 0; | ||||
|         manual_move_axis = (int8_t)NO_AXIS; | ||||
|         offset = 0; | ||||
|         axis = (uint8_t)NO_AXIS; | ||||
|  | ||||
|         // DELTA and SCARA machines use segmented moves, which could fill the planner during the call to | ||||
|         // move_to_destination. This will cause idle() to be called, which can then call this function while the | ||||
|         // previous invocation is being blocked. Modifications to manual_move_offset shouldn't be made while | ||||
|         // processing_manual_move is true or the planner will get out of sync. | ||||
|         processing_manual_move = true; | ||||
|         // previous invocation is being blocked. Modifications to offset shouldn't be made while | ||||
|         // processing is true or the planner will get out of sync. | ||||
|         processing = true; | ||||
|         prepare_internal_move_to_destination(fr_mm_s);  // will set current_position from destination | ||||
|         processing_manual_move = false; | ||||
|         processing = false; | ||||
|  | ||||
|         #if EXTRUDERS > 1 | ||||
|           active_extruder = old_extruder; | ||||
| @@ -689,15 +702,47 @@ void MarlinUI::quick_feedback(const bool clear_buttons/*=true*/) { | ||||
|  | ||||
|       #else | ||||
|  | ||||
|         planner.buffer_line(current_position, fr_mm_s, manual_move_axis == E_AXIS ? manual_move_e_index : active_extruder); | ||||
|         manual_move_axis = (int8_t)NO_AXIS; | ||||
|         // For Cartesian / Core motion simply move to the current_position | ||||
|         planner.buffer_line(current_position, fr_mm_s, axis == E_AXIS ? e_index : active_extruder); | ||||
|  | ||||
|         //SERIAL_ECHOLNPAIR("Add planner.move with Axis ", int(axis), " at FR ", fr_mm_s); | ||||
|  | ||||
|         axis = (uint8_t)NO_AXIS; | ||||
|  | ||||
|       #endif | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   // | ||||
|   // Tell ui.update() to start a move to current_position after a short delay. | ||||
|   // | ||||
|   void ManualMove::soon(AxisEnum move_axis | ||||
|     #if MULTI_MANUAL | ||||
|       , const int8_t eindex/*=-1*/ | ||||
|     #endif | ||||
|   ) { | ||||
|     #if MULTI_MANUAL | ||||
|       if (move_axis == E_AXIS) e_index = eindex >= 0 ? eindex : active_extruder; | ||||
|     #endif | ||||
|     start_time = millis() + (menu_scale < 0.99f ? 0UL : 250UL); // delay for bigger moves | ||||
|     axis = (uint8_t)move_axis; | ||||
|     //SERIAL_ECHOLNPAIR("Post Move with Axis ", int(axis), " soon."); | ||||
|   } | ||||
|  | ||||
| #endif // HAS_LCD_MENU | ||||
|  | ||||
| #if ENABLED(AUTO_BED_LEVELING_UBL) | ||||
|  | ||||
|   void MarlinUI::external_encoder() { | ||||
|     if (external_control && encoderDiff) { | ||||
|       ubl.encoder_diff += encoderDiff;  // Encoder for UBL G29 mesh editing | ||||
|       encoderDiff = 0;                  // Hide encoder events from the screen handler | ||||
|       refresh(LCDVIEW_REDRAW_NOW);      // ...but keep the refresh. | ||||
|     } | ||||
|   } | ||||
|  | ||||
| #endif | ||||
|  | ||||
| /** | ||||
|  * Update the LCD, read encoder buttons, etc. | ||||
|  *   - Read button states | ||||
| @@ -753,7 +798,7 @@ void MarlinUI::update() { | ||||
|   #if HAS_LCD_MENU | ||||
|  | ||||
|     // Handle any queued Move Axis motion | ||||
|     manage_manual_move(); | ||||
|     manual_move.task(); | ||||
|  | ||||
|     // Update button states for button_pressed(), etc. | ||||
|     // If the state changes the next update may be delayed 300-500ms. | ||||
| @@ -776,7 +821,7 @@ void MarlinUI::update() { | ||||
|           if (ELAPSED(ms, next_button_update_ms)) { | ||||
|             encoderDiff = (ENCODER_STEPS_PER_MENU_ITEM) * (ENCODER_PULSES_PER_STEP) * encoderDirection; | ||||
|             if (touch_buttons & EN_A) encoderDiff *= -1; | ||||
|             TERN_(AUTO_BED_LEVELING_UBL, if (external_control) ubl.encoder_diff = encoderDiff); | ||||
|             TERN_(AUTO_BED_LEVELING_UBL, external_encoder()); | ||||
|             next_button_update_ms = ms + repeat_delay;    // Assume the repeat delay | ||||
|             if (!wait_for_unclick) { | ||||
|               next_button_update_ms += 250;               // Longer delay on first press | ||||
| @@ -1196,10 +1241,7 @@ void MarlinUI::update() { | ||||
|           case encrot2: ENCODER_SPIN(encrot1, encrot3); break; | ||||
|           case encrot3: ENCODER_SPIN(encrot2, encrot0); break; | ||||
|         } | ||||
|         if (external_control) { | ||||
|           TERN_(AUTO_BED_LEVELING_UBL, ubl.encoder_diff = encoderDiff); // Make encoder rotation available to UBL G29 mesh editing. | ||||
|           encoderDiff = 0;                    // Hide the encoder event from the current screen handler. | ||||
|         } | ||||
|         TERN_(AUTO_BED_LEVELING_UBL, external_encoder()); | ||||
|         lastEncoderBits = enc; | ||||
|       } | ||||
|  | ||||
|   | ||||
| @@ -99,9 +99,6 @@ | ||||
|     typedef void (*screenFunc_t)(); | ||||
|     typedef void (*menuAction_t)(); | ||||
|  | ||||
|     // Manual Movement | ||||
|     extern float move_menu_scale; | ||||
|  | ||||
|     #if ENABLED(ADVANCED_PAUSE_FEATURE) | ||||
|       void lcd_pause_show_message(const PauseMessage message, | ||||
|                                   const PauseMode mode=PAUSE_MODE_SAME, | ||||
| @@ -264,6 +261,35 @@ | ||||
|   } preheat_t; | ||||
| #endif | ||||
|  | ||||
| #if HAS_LCD_MENU | ||||
|  | ||||
|   // Manual Movement class | ||||
|   class ManualMove { | ||||
|   public: | ||||
|     static millis_t start_time; | ||||
|     static float menu_scale; | ||||
|     TERN_(IS_KINEMATIC, static float offset); | ||||
|     #if IS_KINEMATIC | ||||
|       static bool processing; | ||||
|     #else | ||||
|       static bool constexpr processing = false; | ||||
|     #endif | ||||
|     #if MULTI_MANUAL | ||||
|       static int8_t e_index; | ||||
|     #else | ||||
|       static int8_t constexpr e_index = 0; | ||||
|     #endif | ||||
|     static uint8_t axis; | ||||
|     static void task(); | ||||
|     static void soon(AxisEnum axis | ||||
|       #if MULTI_MANUAL | ||||
|         , const int8_t eindex=-1 | ||||
|       #endif | ||||
|     ); | ||||
|   }; | ||||
|  | ||||
| #endif | ||||
|  | ||||
| //////////////////////////////////////////// | ||||
| //////////// MarlinUI Singleton //////////// | ||||
| //////////////////////////////////////////// | ||||
| @@ -494,29 +520,14 @@ public: | ||||
|       static void enable_encoder_multiplier(const bool onoff); | ||||
|     #endif | ||||
|  | ||||
|     static int8_t manual_move_axis; | ||||
|     static millis_t manual_move_start_time; | ||||
|  | ||||
|     #if IS_KINEMATIC | ||||
|       static float manual_move_offset; | ||||
|       static bool processing_manual_move; | ||||
|     #else | ||||
|       static constexpr bool processing_manual_move = false; | ||||
|     #endif | ||||
|  | ||||
|     #if E_MANUAL > 1 | ||||
|       static int8_t manual_move_e_index; | ||||
|     #else | ||||
|       static constexpr int8_t manual_move_e_index = 0; | ||||
|     #endif | ||||
|     // Manual Movement | ||||
|     static ManualMove manual_move; | ||||
|  | ||||
|     // Select Screen (modal NO/YES style dialog) | ||||
|     static bool selection; | ||||
|     static void set_selection(const bool sel) { selection = sel; } | ||||
|     static bool update_selection(); | ||||
|  | ||||
|     static void manage_manual_move(); | ||||
|  | ||||
|     static bool lcd_clicked; | ||||
|     static bool use_click(); | ||||
|  | ||||
| @@ -609,6 +620,9 @@ public: | ||||
|     static bool external_control; | ||||
|     FORCE_INLINE static void capture() { external_control = true; } | ||||
|     FORCE_INLINE static void release() { external_control = false; } | ||||
|     #if ENABLED(AUTO_BED_LEVELING_UBL) | ||||
|       static void external_encoder(); | ||||
|     #endif | ||||
|   #else | ||||
|     static constexpr bool external_control = false; | ||||
|   #endif | ||||
|   | ||||
| @@ -1316,16 +1316,18 @@ void do_homing_move(const AxisEnum axis, const float distance, const feedRate_t | ||||
|     current_position[axis] = distance; | ||||
|     line_to_current_position(real_fr_mm_s); | ||||
|   #else | ||||
|     // Get the ABC or XYZ positions in mm | ||||
|     abce_pos_t target = planner.get_axis_positions_mm(); | ||||
|     target[axis] = 0; | ||||
|     planner.set_machine_position_mm(target); | ||||
|     target[axis] = distance; | ||||
|  | ||||
|     target[axis] = 0;                         // Set the single homing axis to 0 | ||||
|     planner.set_machine_position_mm(target);  // Update the machine position | ||||
|  | ||||
|     #if HAS_DIST_MM_ARG | ||||
|       const xyze_float_t cart_dist_mm{0}; | ||||
|     #endif | ||||
|  | ||||
|     // Set delta/cartesian axes directly | ||||
|     target[axis] = distance;                  // The move will be towards the endstop | ||||
|     planner.buffer_segment(target | ||||
|       #if HAS_DIST_MM_ARG | ||||
|         , cart_dist_mm | ||||
|   | ||||
| @@ -1654,7 +1654,7 @@ void Planner::synchronize() { | ||||
|  *  extruder      - target extruder | ||||
|  *  millimeters   - the length of the movement, if known | ||||
|  * | ||||
|  * Returns true if movement was properly queued, false otherwise | ||||
|  * Returns true if movement was properly queued, false otherwise (if cleaning) | ||||
|  */ | ||||
| bool Planner::_buffer_steps(const xyze_long_t &target | ||||
|   #if HAS_POSITION_FLOAT | ||||
| @@ -2637,6 +2637,8 @@ void Planner::buffer_sync_block() { | ||||
|  *  fr_mm_s     - (target) speed of the move | ||||
|  *  extruder    - target extruder | ||||
|  *  millimeters - the length of the movement, if known | ||||
|  * | ||||
|  * Return 'false' if no segment was queued due to cleaning, cold extrusion, full queue, etc. | ||||
|  */ | ||||
| bool Planner::buffer_segment(const float &a, const float &b, const float &c, const float &e | ||||
|   #if HAS_DIST_MM_ARG | ||||
| @@ -2706,7 +2708,7 @@ bool Planner::buffer_segment(const float &a, const float &b, const float &c, con | ||||
|     SERIAL_ECHOLNPGM(")"); | ||||
|   //*/ | ||||
|  | ||||
|   // Queue the movement | ||||
|   // Queue the movement. Return 'false' if the move was not queued. | ||||
|   if (!_buffer_steps(target | ||||
|       #if HAS_POSITION_FLOAT | ||||
|         , target_float | ||||
|   | ||||
		Reference in New Issue
	
	Block a user