Clean up LCD Manual Move / UBL Mesh Edit (#18373)

This commit is contained in:
Scott Lahteine 2020-07-03 09:53:22 -05:00 committed by GitHub
parent 2c15a787c7
commit f6a2b64091
Signed by: GitHub
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 265 additions and 208 deletions

View file

@ -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_Z)) DISABLE_AXIS_Z();
if (ENABLED(DISABLE_INACTIVE_E)) disable_e_steppers(); if (ENABLED(DISABLE_INACTIVE_E)) disable_e_steppers();
#if BOTH(HAS_LCD_MENU, AUTO_BED_LEVELING_UBL) TERN_(AUTO_BED_LEVELING_UBL, ubl.steppers_were_disabled());
if (ubl.lcd_map_control) {
ubl.lcd_map_control = false;
ui.defer_status_screen(false);
}
#endif
} }
} }
else else

View file

@ -84,11 +84,7 @@
_GRIDPOS(Y, 12), _GRIDPOS(Y, 13), _GRIDPOS(Y, 14), _GRIDPOS(Y, 15) _GRIDPOS(Y, 12), _GRIDPOS(Y, 13), _GRIDPOS(Y, 14), _GRIDPOS(Y, 15)
); );
#if HAS_LCD_MENU volatile int16_t unified_bed_leveling::encoder_diff;
bool unified_bed_leveling::lcd_map_control = false;
#endif
volatile int unified_bed_leveling::encoder_diff;
unified_bed_leveling::unified_bed_leveling() { unified_bed_leveling::unified_bed_leveling() {
reset(); reset();

View file

@ -111,9 +111,12 @@ class unified_bed_leveling {
#if HAS_LCD_MENU #if HAS_LCD_MENU
static bool lcd_map_control; static bool lcd_map_control;
static void steppers_were_disabled();
#else
static inline void steppers_were_disabled() {}
#endif #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(); unified_bed_leveling();

View file

@ -54,7 +54,18 @@
#define UBL_G29_P31 #define UBL_G29_P31
#if HAS_LCD_MENU #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 #endif
#define SIZE_OF_LITTLE_RAISE 1 #define SIZE_OF_LITTLE_RAISE 1
@ -995,9 +1006,9 @@
lcd_mesh_edit_setup(new_z); lcd_mesh_edit_setup(new_z);
do { do {
idle();
new_z = lcd_mesh_edit(); 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 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. SERIAL_FLUSH(); // Prevent host M105 buffer overrun.
} while (!ui.button_pressed()); } while (!ui.button_pressed());
@ -1022,7 +1033,7 @@
SERIAL_ECHOLNPGM("Done Editing Mesh"); SERIAL_ECHOLNPGM("Done Editing Mesh");
if (lcd_map_control) if (lcd_map_control)
ui.goto_screen(_lcd_ubl_output_map_lcd); ui.goto_screen(ubl_map_screen);
else else
ui.return_to_status(); ui.return_to_status();
} }

View file

@ -81,7 +81,6 @@
#endif #endif
XPT2046 touch; XPT2046 touch;
extern int8_t encoderDiff;
void XPT2046::init() { void XPT2046::init() {
SET_INPUT(TOUCH_MISO_PIN); SET_INPUT(TOUCH_MISO_PIN);

View file

@ -64,11 +64,6 @@ void GcodeSuite::M18_M84() {
else else
planner.finish_and_disable(); planner.finish_and_disable();
#if BOTH(HAS_LCD_MENU, AUTO_BED_LEVELING_UBL) TERN_(AUTO_BED_LEVELING_UBL, ubl.steppers_were_disabled());
if (ubl.lcd_map_control) {
ubl.lcd_map_control = false;
ui.defer_status_screen(false);
}
#endif
} }
} }

View file

@ -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); screen = TERN(BABYSTEP_ZPROBE_OFFSET, lcd_babystep_zoffset, lcd_babystep_z);
else { else {
#if ENABLED(MOVE_Z_WHEN_IDLE) #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; screen = lcd_move_z;
#endif #endif
} }

View file

@ -46,7 +46,7 @@ void _man_probe_pt(const xy_pos_t &xy) {
do_blocking_move_to_xy_z(xy, Z_CLEARANCE_BETWEEN_PROBES); do_blocking_move_to_xy_z(xy, Z_CLEARANCE_BETWEEN_PROBES);
ui.wait_for_move = false; ui.wait_for_move = false;
ui.synchronize(); 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); ui.goto_screen(lcd_move_z);
} }
} }

View file

@ -50,28 +50,13 @@
float manual_move_e_origin = 0; float manual_move_e_origin = 0;
#endif #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 // "Motion" > "Move Axis" submenu
// //
static void _lcd_move_xyz(PGM_P const name, const AxisEnum axis) { 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.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 // Start with no limits to movement
float min = current_position[axis] - 1000, float min = current_position[axis] - 1000,
@ -105,13 +90,13 @@ static void _lcd_move_xyz(PGM_P const name, const AxisEnum axis) {
#endif #endif
// Get the new position // 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 #if IS_KINEMATIC
ui.manual_move_offset += diff; ui.manual_move.offset += diff;
if (int32_t(ui.encoderPosition) < 0) 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 else
NOMORE(ui.manual_move_offset, max - current_position[axis]); NOMORE(ui.manual_move.offset, max - current_position[axis]);
#else #else
current_position[axis] += diff; current_position[axis] += diff;
if (int32_t(ui.encoderPosition) < 0) 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); NOMORE(current_position[axis], max);
#endif #endif
manual_move_to_current(axis); ui.manual_move.soon(axis);
ui.refresh(LCDVIEW_REDRAW_NOW); ui.refresh(LCDVIEW_REDRAW_NOW);
} }
ui.encoderPosition = 0; ui.encoderPosition = 0;
if (ui.should_draw()) { if (ui.should_draw()) {
const float pos = NATIVE_TO_LOGICAL( 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 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); } 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)) { 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.use_click()) return ui.goto_previous_screen_no_defer();
if (ui.encoderPosition) { if (ui.encoderPosition) {
if (!ui.processing_manual_move) { if (!ui.manual_move.processing) {
const float diff = float(int32_t(ui.encoderPosition)) * move_menu_scale; const float diff = float(int32_t(ui.encoderPosition)) * ui.manual_move.menu_scale;
TERN(IS_KINEMATIC, ui.manual_move_offset, current_position.e) += diff; TERN(IS_KINEMATIC, ui.manual_move.offset, current_position.e) += diff;
manual_move_to_current(E_AXIS ui.manual_move.soon(E_AXIS
#if MULTI_MANUAL #if MULTI_MANUAL
, eindex , eindex
#endif #endif
@ -160,7 +145,7 @@ void lcd_move_z() { _lcd_move_xyz(GET_TEXT(MSG_MOVE_Z), Z_AXIS); }
MenuEditItemBase::draw_edit_screen( MenuEditItemBase::draw_edit_screen(
GET_TEXT(TERN(MULTI_MANUAL, MSG_MOVE_EN, MSG_MOVE_E)), GET_TEXT(TERN(MULTI_MANUAL, MSG_MOVE_EN, MSG_MOVE_E)),
ftostr41sign(current_position.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) - 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) { void _goto_manual_move(const float scale) {
ui.defer_status_screen(); ui.defer_status_screen();
move_menu_scale = scale; ui.manual_move.menu_scale = scale;
ui.goto_screen(_manual_move_func_ptr); ui.goto_screen(_manual_move_func_ptr);
} }

View file

@ -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; static int16_t custom_bed_temp = 50;
#endif #endif
float mesh_edit_value, mesh_edit_accumulator; // We round mesh_edit_value to 2.5 decimal places. So we keep a float mesh_edit_accumulator; // Rounded to 2.5 decimal places on use
// separate value that doesn't lose precision.
static int16_t ubl_encoderPosition = 0; 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) { static void _lcd_mesh_fine_tune(PGM_P const msg) {
ui.defer_status_screen(); ui.defer_status_screen();
if (ubl.encoder_diff) { 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; 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); 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()) { if (ui.should_draw()) {
MenuEditItemBase::draw_edit_screen(msg, ftostr43sign(mesh_edit_value)); const float rounded_f = rounded_mesh_value();
TERN_(MESH_EDIT_GFX_OVERLAY, _lcd_zoffset_overlay_gfx(mesh_edit_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 = []{}; // Called external to the menu system to acquire the result of an edit.
ui.defer_status_screen(); //
} float lcd_mesh_edit() { return rounded_mesh_value(); }
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;
}
void lcd_mesh_edit_setup(const float &initial) { void lcd_mesh_edit_setup(const float &initial) {
mesh_edit_value = mesh_edit_accumulator = initial; mesh_edit_accumulator = initial;
lcd_limbo(); ui.goto_screen([]{ _lcd_mesh_fine_tune(GET_TEXT(MSG_MESH_EDIT_Z)); });
} }
void _lcd_z_offset_edit() { void _lcd_z_offset_edit() {
@ -97,11 +87,11 @@ void _lcd_z_offset_edit() {
float lcd_z_offset_edit() { float lcd_z_offset_edit() {
ui.goto_screen(_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) { 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); ui.goto_screen(_lcd_z_offset_edit);
} }
@ -390,24 +380,10 @@ void _lcd_ubl_storage_mesh() {
END_MENU(); 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 * 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]; 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_xpos(x_plot), 0, 2, str);
dtostrf(ubl.mesh_index_to_ypos(y_plot), 0, 2, str2); 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 * UBL LCD Map Movement
*/ */
void ubl_map_move_to_xy() { 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 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; 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 #endif
destination.set(ubl.mesh_index_to_xpos(x_plot), ubl.mesh_index_to_ypos(y_plot)); // Set the nozzle position to the mesh point
prepare_internal_move_to_destination(fr_mm_s); 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 * 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) { // On click send "G29 P4 ..." to edit the Z value
step_scaler += int32_t(ui.encoderPosition); if (ui.use_click()) {
x_plot += step_scaler / (ENCODER_STEPS_PER_MENU_ITEM); _lcd_ubl_map_edit_cmd();
ui.encoderPosition = 0; return;
ui.refresh(LCDVIEW_REDRAW_NOW);
} }
#define KEEP_LOOPING ENABLED(IS_KINEMATIC) // Loop until a valid point is found ui.defer_status_screen();
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;
#if IS_KINEMATIC #if IS_KINEMATIC
const xy_pos_t xy = { ubl.mesh_index_to_xpos(x_plot), ubl.mesh_index_to_ypos(y_plot) }; // Index of the mesh point upon entry
if (position_is_reachable(xy)) break; // Found a valid point const uint32_t old_pos_index = grid_index(x_plot, y_plot);
x_plot += (step_scaler < 0) ? -1 : 1; // Direction from new (unconstrained) encoder value
const int8_t step_dir = int32_t(ui.encoderPosition) < old_pos_index ? -1 : 1;
#endif #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;
// Draw the grid point based on the encoder
x = ui.encoderPosition % (GRID_MAX_POINTS_X);
y = ui.encoderPosition / (GRID_MAX_POINTS_X);
// 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));
// Determine number of points to edit // Determine number of points to edit
#if IS_KINEMATIC #if IS_KINEMATIC
n_edit_pts = 9; //TODO: Delta accessible edit points n_edit_pts = 9; // TODO: Delta accessible edit points
#else #else
const bool xc = WITHIN(x_plot, 1, GRID_MAX_POINTS_X - 2), const bool xc = WITHIN(x, 1, GRID_MAX_POINTS_X - 2),
yc = WITHIN(y_plot, 1, GRID_MAX_POINTS_Y - 2); yc = WITHIN(y, 1, GRID_MAX_POINTS_Y - 2);
n_edit_pts = yc ? (xc ? 9 : 6) : (xc ? 6 : 4); // Corners n_edit_pts = yc ? (xc ? 9 : 6) : (xc ? 6 : 4); // Corners
#endif #endif
// Cleanup // Refresh is also set by encoder movement
if (ABS(step_scaler) >= ENCODER_STEPS_PER_MENU_ITEM) step_scaler = 0; //if (int32_t(ui.encoderPosition) != grid_index(x, y))
// ui.refresh(LCDVIEW_CALL_REDRAW_NEXT);
}
if (ui.should_draw()) { // Draw the grid point based on the encoder
ui.ubl_plot(x_plot, y_plot); x = ui.encoderPosition % (GRID_MAX_POINTS_X);
if (!planner.movesplanned()) y = ui.encoderPosition / (GRID_MAX_POINTS_X);
ubl_map_move_to_xy(); // Move to new location
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 * 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()) { if (!all_axes_known()) {
set_all_unhomed(); set_all_unhomed();
queue.inject_P(G28_STR); queue.inject_P(G28_STR);
} }
if (planner.movesplanned()) return; ui.goto_screen(_ubl_map_screen_homing); // Go to the "Homing" screen
ui.goto_screen(_lcd_ubl_map_homing);
} }
/** /**
@ -591,7 +604,7 @@ void _lcd_ubl_level_bed() {
#if ENABLED(G26_MESH_VALIDATION) #if ENABLED(G26_MESH_VALIDATION)
SUBMENU(MSG_UBL_STEP_BY_STEP_MENU, _lcd_ubl_step_by_step); SUBMENU(MSG_UBL_STEP_BY_STEP_MENU, _lcd_ubl_step_by_step);
#endif #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_STORAGE_MESH_MENU, _lcd_ubl_storage_mesh);
SUBMENU(MSG_UBL_OUTPUT_MAP, _lcd_ubl_output_map); SUBMENU(MSG_UBL_OUTPUT_MAP, _lcd_ubl_output_map);
SUBMENU(MSG_UBL_TOOLS, _menu_ubl_tools); SUBMENU(MSG_UBL_TOOLS, _menu_ubl_tools);

View file

@ -211,7 +211,6 @@ millis_t MarlinUI::next_button_update_ms; // = 0
#endif #endif
bool MarlinUI::lcd_clicked; bool MarlinUI::lcd_clicked;
float move_menu_scale;
bool MarlinUI::use_click() { bool MarlinUI::use_click() {
const bool click = lcd_clicked; const bool click = lcd_clicked;
@ -388,7 +387,7 @@ bool MarlinUI::get_blink() {
void lcd_move_z(); void lcd_move_z();
void _reprapworld_keypad_move(const AxisEnum axis, const int16_t dir) { 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; ui.encoderPosition = dir;
switch (axis) { switch (axis) {
case X_AXIS: lcd_move_x(); break; case X_AXIS: lcd_move_x(); break;
@ -637,51 +636,65 @@ void MarlinUI::quick_feedback(const bool clear_buttons/*=true*/) {
#if HAS_LCD_MENU #if HAS_LCD_MENU
int8_t MarlinUI::manual_move_axis = (int8_t)NO_AXIS; ManualMove MarlinUI::manual_move{};
millis_t MarlinUI::manual_move_start_time = 0;
#if IS_KINEMATIC millis_t ManualMove::start_time = 0;
bool MarlinUI::processing_manual_move = false; float ManualMove::menu_scale = 1;
float MarlinUI::manual_move_offset = 0; TERN_(IS_KINEMATIC, float ManualMove::offset = 0);
#endif TERN_(IS_KINEMATIC, bool ManualMove::processing = false);
TERN_(MULTI_MANUAL, int8_t ManualMove::e_index = 0);
#if MULTI_MANUAL uint8_t ManualMove::axis = (uint8_t)NO_AXIS;
int8_t MarlinUI::manual_move_e_index = 0;
#endif
/** /**
* If the most recent manual move hasn't been fed to the planner yet, * If a manual move has been posted and its time has arrived, and if the planner
* and the planner can accept one, send a move immediately. * 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 IS_KINEMATIC
#if EXTRUDERS > 1 #if EXTRUDERS > 1
const int8_t old_extruder = active_extruder; 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 #endif
// Set movement on a single axis // Apply a linear offset to a single axis
destination = current_position; destination = current_position;
destination[manual_move_axis] += manual_move_offset; if (axis <= XYZE) destination[axis] += offset;
// Reset for the next move // Reset for the next move
manual_move_offset = 0; offset = 0;
manual_move_axis = (int8_t)NO_AXIS; axis = (uint8_t)NO_AXIS;
// DELTA and SCARA machines use segmented moves, which could fill the planner during the call to // 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 // 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 // previous invocation is being blocked. Modifications to offset shouldn't be made while
// processing_manual_move is true or the planner will get out of sync. // processing is true or the planner will get out of sync.
processing_manual_move = true; processing = true;
prepare_internal_move_to_destination(fr_mm_s); // will set current_position from destination prepare_internal_move_to_destination(fr_mm_s); // will set current_position from destination
processing_manual_move = false; processing = false;
#if EXTRUDERS > 1 #if EXTRUDERS > 1
active_extruder = old_extruder; active_extruder = old_extruder;
@ -689,15 +702,47 @@ void MarlinUI::quick_feedback(const bool clear_buttons/*=true*/) {
#else #else
planner.buffer_line(current_position, fr_mm_s, manual_move_axis == E_AXIS ? manual_move_e_index : active_extruder); // For Cartesian / Core motion simply move to the current_position
manual_move_axis = (int8_t)NO_AXIS; 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 #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 #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. * Update the LCD, read encoder buttons, etc.
* - Read button states * - Read button states
@ -753,7 +798,7 @@ void MarlinUI::update() {
#if HAS_LCD_MENU #if HAS_LCD_MENU
// Handle any queued Move Axis motion // Handle any queued Move Axis motion
manage_manual_move(); manual_move.task();
// Update button states for button_pressed(), etc. // Update button states for button_pressed(), etc.
// If the state changes the next update may be delayed 300-500ms. // 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)) { if (ELAPSED(ms, next_button_update_ms)) {
encoderDiff = (ENCODER_STEPS_PER_MENU_ITEM) * (ENCODER_PULSES_PER_STEP) * encoderDirection; encoderDiff = (ENCODER_STEPS_PER_MENU_ITEM) * (ENCODER_PULSES_PER_STEP) * encoderDirection;
if (touch_buttons & EN_A) encoderDiff *= -1; 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 next_button_update_ms = ms + repeat_delay; // Assume the repeat delay
if (!wait_for_unclick) { if (!wait_for_unclick) {
next_button_update_ms += 250; // Longer delay on first press 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 encrot2: ENCODER_SPIN(encrot1, encrot3); break;
case encrot3: ENCODER_SPIN(encrot2, encrot0); break; case encrot3: ENCODER_SPIN(encrot2, encrot0); break;
} }
if (external_control) { TERN_(AUTO_BED_LEVELING_UBL, external_encoder());
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.
}
lastEncoderBits = enc; lastEncoderBits = enc;
} }

View file

@ -99,9 +99,6 @@
typedef void (*screenFunc_t)(); typedef void (*screenFunc_t)();
typedef void (*menuAction_t)(); typedef void (*menuAction_t)();
// Manual Movement
extern float move_menu_scale;
#if ENABLED(ADVANCED_PAUSE_FEATURE) #if ENABLED(ADVANCED_PAUSE_FEATURE)
void lcd_pause_show_message(const PauseMessage message, void lcd_pause_show_message(const PauseMessage message,
const PauseMode mode=PAUSE_MODE_SAME, const PauseMode mode=PAUSE_MODE_SAME,
@ -264,6 +261,35 @@
} preheat_t; } preheat_t;
#endif #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 //////////// //////////// MarlinUI Singleton ////////////
//////////////////////////////////////////// ////////////////////////////////////////////
@ -494,29 +520,14 @@ public:
static void enable_encoder_multiplier(const bool onoff); static void enable_encoder_multiplier(const bool onoff);
#endif #endif
static int8_t manual_move_axis; // Manual Movement
static millis_t manual_move_start_time; static ManualMove manual_move;
#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
// Select Screen (modal NO/YES style dialog) // Select Screen (modal NO/YES style dialog)
static bool selection; static bool selection;
static void set_selection(const bool sel) { selection = sel; } static void set_selection(const bool sel) { selection = sel; }
static bool update_selection(); static bool update_selection();
static void manage_manual_move();
static bool lcd_clicked; static bool lcd_clicked;
static bool use_click(); static bool use_click();
@ -609,6 +620,9 @@ public:
static bool external_control; static bool external_control;
FORCE_INLINE static void capture() { external_control = true; } FORCE_INLINE static void capture() { external_control = true; }
FORCE_INLINE static void release() { external_control = false; } FORCE_INLINE static void release() { external_control = false; }
#if ENABLED(AUTO_BED_LEVELING_UBL)
static void external_encoder();
#endif
#else #else
static constexpr bool external_control = false; static constexpr bool external_control = false;
#endif #endif

View file

@ -1316,16 +1316,18 @@ void do_homing_move(const AxisEnum axis, const float distance, const feedRate_t
current_position[axis] = distance; current_position[axis] = distance;
line_to_current_position(real_fr_mm_s); line_to_current_position(real_fr_mm_s);
#else #else
// Get the ABC or XYZ positions in mm
abce_pos_t target = planner.get_axis_positions_mm(); abce_pos_t target = planner.get_axis_positions_mm();
target[axis] = 0;
planner.set_machine_position_mm(target); target[axis] = 0; // Set the single homing axis to 0
target[axis] = distance; planner.set_machine_position_mm(target); // Update the machine position
#if HAS_DIST_MM_ARG #if HAS_DIST_MM_ARG
const xyze_float_t cart_dist_mm{0}; const xyze_float_t cart_dist_mm{0};
#endif #endif
// Set delta/cartesian axes directly // Set delta/cartesian axes directly
target[axis] = distance; // The move will be towards the endstop
planner.buffer_segment(target planner.buffer_segment(target
#if HAS_DIST_MM_ARG #if HAS_DIST_MM_ARG
, cart_dist_mm , cart_dist_mm

View file

@ -1654,7 +1654,7 @@ void Planner::synchronize() {
* extruder - target extruder * extruder - target extruder
* millimeters - the length of the movement, if known * 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 bool Planner::_buffer_steps(const xyze_long_t &target
#if HAS_POSITION_FLOAT #if HAS_POSITION_FLOAT
@ -2637,6 +2637,8 @@ void Planner::buffer_sync_block() {
* fr_mm_s - (target) speed of the move * fr_mm_s - (target) speed of the move
* extruder - target extruder * extruder - target extruder
* millimeters - the length of the movement, if known * 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 bool Planner::buffer_segment(const float &a, const float &b, const float &c, const float &e
#if HAS_DIST_MM_ARG #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(")"); SERIAL_ECHOLNPGM(")");
//*/ //*/
// Queue the movement // Queue the movement. Return 'false' if the move was not queued.
if (!_buffer_steps(target if (!_buffer_steps(target
#if HAS_POSITION_FLOAT #if HAS_POSITION_FLOAT
, target_float , target_float