Encapsulate common display code in a singleton (#12395)

* Encapsulate common LCD code in a singleton
* Depend more UBL code on UBL_DEVEL_DEBUGGING
  - Since most users don't need the debugging on at all times, this helps reduce the default build size for UBL by over 2K, a little closer to fitting on 128K boards.
This commit is contained in:
Scott Lahteine
2018-11-11 12:16:24 -06:00
committed by GitHub
parent 9da6809ac3
commit a0c795b097
65 changed files with 1881 additions and 1997 deletions

View File

@ -233,7 +233,7 @@ void reset_bed_level() {
current_position[Y_AXIS] = ry;
#if ENABLED(LCD_BED_LEVELING)
lcd_wait_for_move = false;
ui.wait_for_bl_move = false;
#endif
}

View File

@ -34,8 +34,6 @@
#include "math.h"
uint8_t ubl_cnt = 0;
void unified_bed_leveling::echo_name(
#if NUM_SERIAL > 1
const int8_t port/*= -1*/
@ -106,30 +104,19 @@
if (xy_dist == 0.0) return;
SERIAL_ECHOPGM(" fpmm=");
const float fpmm = de / xy_dist;
SERIAL_ECHO_F(fpmm, 6);
SERIAL_ECHOPGM(" fpmm="); SERIAL_ECHO_F(fpmm, 6);
SERIAL_ECHOPGM(" current=( ");
SERIAL_ECHO_F(current_position[X_AXIS], 6);
SERIAL_ECHOPGM(", ");
SERIAL_ECHO_F(current_position[Y_AXIS], 6);
SERIAL_ECHOPGM(", ");
SERIAL_ECHO_F(current_position[Z_AXIS], 6);
SERIAL_ECHOPGM(", ");
SERIAL_ECHO_F(current_position[E_AXIS], 6);
SERIAL_ECHOPGM(" ) destination=( ");
debug_echo_axis(X_AXIS);
SERIAL_ECHOPGM(", ");
debug_echo_axis(Y_AXIS);
SERIAL_ECHOPGM(", ");
debug_echo_axis(Z_AXIS);
SERIAL_ECHOPGM(", ");
debug_echo_axis(E_AXIS);
SERIAL_ECHOPGM(" ) ");
SERIAL_ECHO_F(current_position[X_AXIS], 6); SERIAL_ECHOPGM(", ");
SERIAL_ECHO_F(current_position[Y_AXIS], 6); SERIAL_ECHOPGM(", ");
SERIAL_ECHO_F(current_position[Z_AXIS], 6); SERIAL_ECHOPGM(", ");
SERIAL_ECHO_F(current_position[E_AXIS], 6); SERIAL_ECHOPGM(" ) destination=( ");
debug_echo_axis(X_AXIS); SERIAL_ECHOPGM(", ");
debug_echo_axis(Y_AXIS); SERIAL_ECHOPGM(", ");
debug_echo_axis(Z_AXIS); SERIAL_ECHOPGM(", ");
debug_echo_axis(E_AXIS); SERIAL_ECHOPGM(" ) ");
serialprintPGM(title);
SERIAL_EOL();
}
#endif // UBL_DEVEL_DEBUGGING
@ -150,7 +137,6 @@
volatile int unified_bed_leveling::encoder_diff;
unified_bed_leveling::unified_bed_leveling() {
ubl_cnt++; // Debug counter to ensure we only have one UBL object present in memory. We can eliminate this (and all references to ubl_cnt) very soon.
reset();
}

View File

@ -26,6 +26,7 @@
#include "../bedlevel.h"
#include "../../../module/planner.h"
#include "../../../module/motion.h"
#include "../../../lcd/ultralcd.h"
#include "../../../Marlin.h"
#define UBL_VERSION "1.01"
@ -49,12 +50,6 @@ enum MeshPointType : char { INVALID, REAL, SET_IN_BITMAP };
// External references
extern uint8_t ubl_cnt;
#if ENABLED(ULTRA_LCD)
void lcd_quick_feedback(const bool clear_buttons);
#endif
#define MESH_X_DIST (float(MESH_MAX_X - (MESH_MIN_X)) / float(GRID_MAX_POINTS_X - 1))
#define MESH_Y_DIST (float(MESH_MAX_Y - (MESH_MIN_Y)) / float(GRID_MAX_POINTS_Y - 1))
@ -88,12 +83,15 @@ class unified_bed_leveling {
static void probe_entire_mesh(const float &rx, const float &ry, const bool do_ubl_mesh_map, const bool stow_probe, const bool do_furthest) _O0;
static void tilt_mesh_based_on_3pts(const float &z1, const float &z2, const float &z3);
static void tilt_mesh_based_on_probed_grid(const bool do_ubl_mesh_map);
static void g29_what_command();
static void g29_eeprom_dump();
static void g29_compare_current_mesh_to_stored_mesh();
static bool smart_fill_one(const uint8_t x, const uint8_t y, const int8_t xdir, const int8_t ydir);
static void smart_fill_mesh();
#if ENABLED(UBL_DEVEL_DEBUGGING)
static void g29_what_command();
static void g29_eeprom_dump();
static void g29_compare_current_mesh_to_stored_mesh();
#endif
public:
static void echo_name(

View File

@ -53,7 +53,6 @@
extern float destination[XYZE], current_position[XYZE];
#if HAS_LCD_MENU
void lcd_return_to_status();
void _lcd_ubl_output_map_lcd();
#endif
@ -345,9 +344,13 @@
}
SERIAL_PROTOCOLLNPGM("Loading test_pattern values.\n");
switch (test_pattern) {
case -1:
g29_eeprom_dump();
break;
#if ENABLED(UBL_DEVEL_DEBUGGING)
case -1:
g29_eeprom_dump();
break;
#endif
case 0:
for (uint8_t x = 0; x < GRID_MAX_POINTS_X; x++) { // Create a bowl shape - similar to
for (uint8_t y = 0; y < GRID_MAX_POINTS_Y; y++) { // a poorly calibrated Delta.
@ -357,12 +360,14 @@
}
}
break;
case 1:
for (uint8_t x = 0; x < GRID_MAX_POINTS_X; x++) { // Create a diagonal line several Mesh cells thick that is raised
z_values[x][x] += 9.999f;
z_values[x][x + (x < GRID_MAX_POINTS_Y - 1) ? 1 : -1] += 9.999f; // We want the altered line several mesh points thick
}
break;
case 2:
// Allow the user to specify the height because 10mm is a little extreme in some cases.
for (uint8_t x = (GRID_MAX_POINTS_X) / 3; x < 2 * (GRID_MAX_POINTS_X) / 3; x++) // Create a rectangular raised area in
@ -554,19 +559,24 @@
}
}
//
// Much of the 'What?' command can be eliminated. But until we are fully debugged, it is
// good to have the extra information. Soon... we prune this to just a few items
//
if (parser.seen('W')) g29_what_command();
#if ENABLED(UBL_DEVEL_DEBUGGING)
//
// When we are fully debugged, this may go away. But there are some valid
// use cases for the users. So we can wait and see what to do with it.
//
//
// Much of the 'What?' command can be eliminated. But until we are fully debugged, it is
// good to have the extra information. Soon... we prune this to just a few items
//
if (parser.seen('W')) g29_what_command();
//
// When we are fully debugged, this may go away. But there are some valid
// use cases for the users. So we can wait and see what to do with it.
//
if (parser.seen('K')) // Kompare Current Mesh Data to Specified Stored Mesh
g29_compare_current_mesh_to_stored_mesh();
#endif // UBL_DEVEL_DEBUGGING
if (parser.seen('K')) // Kompare Current Mesh Data to Specified Stored Mesh
g29_compare_current_mesh_to_stored_mesh();
//
// Load a Mesh from the EEPROM
@ -629,10 +639,10 @@
LEAVE:
#if HAS_LCD_MENU
lcd_reset_alert_level();
lcd_quick_feedback();
lcd_reset_status();
lcd_external_control = false;
ui.reset_alert_level();
ui.quick_feedback();
ui.reset_status();
ui.release();
#endif
return;
@ -683,30 +693,6 @@
z_values[x][y] += g29_constant;
}
#if HAS_LCD_MENU
typedef void (*clickFunc_t)();
bool click_and_hold(const clickFunc_t func=NULL) {
if (is_lcd_clicked()) {
lcd_quick_feedback(false); // Preserve button state for click-and-hold
const millis_t nxt = millis() + 1500UL;
while (is_lcd_clicked()) { // Loop while the encoder is pressed. Uses hardware flag!
idle(); // idle, of course
if (ELAPSED(millis(), nxt)) { // After 1.5 seconds
lcd_quick_feedback();
if (func) (*func)();
wait_for_release();
return true;
}
}
}
safe_delay(15);
return false;
}
#endif // HAS_LCD_MENU
#if HAS_BED_PROBE
/**
* Probe all invalidated locations of the mesh that can be reached by the probe.
@ -716,10 +702,10 @@
mesh_index_pair location;
#if HAS_LCD_MENU
lcd_external_control = true;
ui.capture();
#endif
save_ubl_active_state_and_disable(); // No bed level correction so only raw data is obtained
save_ubl_active_state_and_disable(); // No bed level correction so only raw data is obtained
DEPLOY_PROBE();
uint16_t count = GRID_MAX_POINTS;
@ -728,13 +714,13 @@
if (do_ubl_mesh_map) display_map(g29_map_type);
#if HAS_LCD_MENU
if (is_lcd_clicked()) {
lcd_quick_feedback(false); // Preserve button state for click-and-hold
if (ui.button_pressed()) {
ui.quick_feedback(false); // Preserve button state for click-and-hold
SERIAL_PROTOCOLLNPGM("\nMesh only partially populated.\n");
STOW_PROBE();
wait_for_release();
lcd_quick_feedback();
lcd_external_control = false;
ui.wait_for_release();
ui.quick_feedback();
ui.release();
restore_ubl_active_state_and_leave();
return;
}
@ -769,14 +755,33 @@
);
}
#endif // HAS_BED_PROBE
#if HAS_LCD_MENU
typedef void (*clickFunc_t)();
bool click_and_hold(const clickFunc_t func=NULL) {
if (ui.button_pressed()) {
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
ui.quick_feedback();
if (func) (*func)();
ui.wait_for_release();
return true;
}
}
}
safe_delay(15);
return false;
}
void unified_bed_leveling::move_z_with_encoder(const float &multiplier) {
wait_for_release();
while (!is_lcd_clicked()) {
ui.wait_for_release();
while (!ui.button_pressed()) {
idle();
gcode.reset_stepper_timeout(); // Keep steppers powered
if (encoder_diff) {
@ -796,7 +801,7 @@
static void echo_and_take_a_measurement() { SERIAL_PROTOCOLLNPGM(" and take a measurement."); }
float unified_bed_leveling::measure_business_card_thickness(float in_height) {
lcd_external_control = true;
ui.capture();
save_ubl_active_state_and_disable(); // Disable bed level correction for probing
do_blocking_move_to(0.5f * (MESH_MAX_X - (MESH_MIN_X)), 0.5f * (MESH_MAX_Y - (MESH_MIN_Y)), in_height);
@ -805,7 +810,7 @@
SERIAL_PROTOCOLPGM("Place shim under nozzle");
LCD_MESSAGEPGM(MSG_UBL_BC_INSERT);
lcd_return_to_status();
ui.return_to_status();
echo_and_take_a_measurement();
const float z1 = measure_point_with_encoder();
@ -828,7 +833,7 @@
SERIAL_PROTOCOLLNPGM("mm thick.");
}
lcd_external_control = false;
ui.release();
restore_ubl_active_state_and_leave();
@ -838,20 +843,20 @@
void abort_manual_probe_remaining_mesh() {
SERIAL_PROTOCOLLNPGM("\nMesh only partially populated.");
do_blocking_move_to_z(Z_CLEARANCE_DEPLOY_PROBE);
lcd_external_control = false;
ui.release();
KEEPALIVE_STATE(IN_HANDLER);
lcd_quick_feedback();
ui.quick_feedback();
ubl.restore_ubl_active_state_and_leave();
}
void unified_bed_leveling::manually_probe_remaining_mesh(const float &rx, const float &ry, const float &z_clearance, const float &thick, const bool do_ubl_mesh_map) {
lcd_external_control = true;
ui.capture();
save_ubl_active_state_and_disable(); // we don't do bed level correction because we want the raw data when we probe
save_ubl_active_state_and_disable(); // No bed level correction so only raw data is obtained
do_blocking_move_to(current_position[X_AXIS], current_position[Y_AXIS], z_clearance);
lcd_return_to_status();
ui.return_to_status();
mesh_index_pair location;
do {
@ -870,7 +875,7 @@
do_blocking_move_to_z(z_clearance);
KEEPALIVE_STATE(PAUSED_FOR_USER);
lcd_external_control = true;
ui.capture();
if (do_ubl_mesh_map) display_map(g29_map_type); // show user where we're probing
@ -884,7 +889,7 @@
if (click_and_hold()) {
SERIAL_PROTOCOLLNPGM("\nMesh only partially populated.");
do_blocking_move_to_z(Z_CLEARANCE_DEPLOY_PROBE);
lcd_external_control = false;
ui.release();
KEEPALIVE_STATE(IN_HANDLER);
restore_ubl_active_state_and_leave();
return;
@ -905,12 +910,121 @@
KEEPALIVE_STATE(IN_HANDLER);
do_blocking_move_to(rx, ry, Z_CLEARANCE_DEPLOY_PROBE);
}
#endif // HAS_LCD_MENU
inline void set_message_with_feedback(PGM_P const msg_P) {
lcd_setstatusPGM(msg_P);
lcd_quick_feedback();
}
inline void set_message_with_feedback(PGM_P const msg_P) {
ui.setstatusPGM(msg_P);
ui.quick_feedback();
}
void abort_fine_tune() {
ui.return_to_status();
do_blocking_move_to_z(Z_CLEARANCE_BETWEEN_PROBES);
set_message_with_feedback(PSTR(MSG_EDITING_STOPPED));
}
void unified_bed_leveling::fine_tune_mesh(const float &rx, const float &ry, const bool do_ubl_mesh_map) {
if (!parser.seen('R')) // fine_tune_mesh() is special. If no repetition count flag is specified
g29_repetition_cnt = 1; // do exactly one mesh location. Otherwise use what the parser decided.
#if ENABLED(UBL_MESH_EDIT_MOVES_Z)
const float h_offset = parser.seenval('H') ? parser.value_linear_units() : 0;
if (!WITHIN(h_offset, 0, 10)) {
SERIAL_PROTOCOLLNPGM("Offset out of bounds. (0 to 10mm)\n");
return;
}
#endif
mesh_index_pair location;
if (!position_is_reachable(rx, ry)) {
SERIAL_PROTOCOLLNPGM("(X,Y) outside printable radius.");
return;
}
save_ubl_active_state_and_disable();
LCD_MESSAGEPGM(MSG_UBL_FINE_TUNE_MESH);
ui.capture(); // Take over control of the LCD encoder
do_blocking_move_to(rx, ry, Z_CLEARANCE_BETWEEN_PROBES); // Move to the given XY with probe clearance
#if ENABLED(UBL_MESH_EDIT_MOVES_Z)
do_blocking_move_to_z(h_offset); // Move Z to the given 'H' offset
#endif
uint16_t not_done[16];
memset(not_done, 0xFF, sizeof(not_done));
do {
location = find_closest_mesh_point_of_type(SET_IN_BITMAP, rx, ry, USE_NOZZLE_AS_REFERENCE, not_done);
if (location.x_index < 0) break; // Stop when there are no more reachable points
bitmap_clear(not_done, location.x_index, location.y_index); // Mark this location as 'adjusted' so a new
// location is used on the next loop
const float rawx = mesh_index_to_xpos(location.x_index),
rawy = mesh_index_to_ypos(location.y_index);
if (!position_is_reachable(rawx, rawy)) break; // SHOULD NOT OCCUR because find_closest_mesh_point_of_type will only return reachable
do_blocking_move_to(rawx, rawy, Z_CLEARANCE_BETWEEN_PROBES); // Move the nozzle to the edit point with probe clearance
#if ENABLED(UBL_MESH_EDIT_MOVES_Z)
do_blocking_move_to_z(h_offset); // Move Z to the given 'H' offset before editing
#endif
KEEPALIVE_STATE(PAUSED_FOR_USER);
if (do_ubl_mesh_map) display_map(g29_map_type); // Display the current point
ui.refresh();
float new_z = z_values[location.x_index][location.y_index];
if (isnan(new_z)) new_z = 0; // Invalid points begin at 0
new_z = FLOOR(new_z * 1000) * 0.001f; // Chop off digits after the 1000ths place
lcd_mesh_edit_setup(new_z);
do {
new_z = lcd_mesh_edit();
#if ENABLED(UBL_MESH_EDIT_MOVES_Z)
do_blocking_move_to_z(h_offset + new_z); // Move the nozzle as the point is edited
#endif
idle();
SERIAL_FLUSH(); // Prevent host M105 buffer overrun.
} while (!ui.button_pressed());
if (!lcd_map_control) ui.return_to_status(); // Just editing a single point? Return to status
if (click_and_hold(abort_fine_tune)) goto FINE_TUNE_EXIT; // If the click is held down, abort editing
z_values[location.x_index][location.y_index] = new_z; // Save the updated Z value
safe_delay(20); // No switch noise
ui.refresh();
} while (location.x_index >= 0 && --g29_repetition_cnt > 0);
FINE_TUNE_EXIT:
ui.release();
KEEPALIVE_STATE(IN_HANDLER);
if (do_ubl_mesh_map) display_map(g29_map_type);
restore_ubl_active_state_and_leave();
do_blocking_move_to(rx, ry, Z_CLEARANCE_BETWEEN_PROBES);
LCD_MESSAGEPGM(MSG_UBL_DONE_EDITING_MESH);
SERIAL_ECHOLNPGM("Done Editing Mesh");
if (lcd_map_control)
ui.goto_screen(_lcd_ubl_output_map_lcd);
else
ui.return_to_status();
}
#endif // HAS_LCD_MENU
bool unified_bed_leveling::g29_parameter_parsing() {
bool err_flag = false;
@ -1060,170 +1174,6 @@
set_bed_leveling_enabled(ubl_state_at_invocation);
}
/**
* Much of the 'What?' command can be eliminated. But until we are fully debugged, it is
* good to have the extra information. Soon... we prune this to just a few items
*/
void unified_bed_leveling::g29_what_command() {
report_state();
if (storage_slot == -1)
SERIAL_PROTOCOLPGM("No Mesh Loaded.");
else {
SERIAL_PROTOCOLPAIR("Mesh ", storage_slot);
SERIAL_PROTOCOLPGM(" Loaded.");
}
SERIAL_EOL();
safe_delay(50);
SERIAL_PROTOCOLLNPAIR("UBL object count: ", (int)ubl_cnt);
#if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
SERIAL_PROTOCOLPGM("planner.z_fade_height : ");
SERIAL_PROTOCOL_F(planner.z_fade_height, 4);
SERIAL_EOL();
#endif
adjust_mesh_to_mean(g29_c_flag, g29_constant);
#if HAS_BED_PROBE
SERIAL_PROTOCOLPGM("zprobe_zoffset: ");
SERIAL_PROTOCOL_F(zprobe_zoffset, 7);
SERIAL_EOL();
#endif
SERIAL_ECHOLNPAIR("MESH_MIN_X " STRINGIFY(MESH_MIN_X) "=", MESH_MIN_X);
safe_delay(50);
SERIAL_ECHOLNPAIR("MESH_MIN_Y " STRINGIFY(MESH_MIN_Y) "=", MESH_MIN_Y);
safe_delay(50);
SERIAL_ECHOLNPAIR("MESH_MAX_X " STRINGIFY(MESH_MAX_X) "=", MESH_MAX_X);
safe_delay(50);
SERIAL_ECHOLNPAIR("MESH_MAX_Y " STRINGIFY(MESH_MAX_Y) "=", MESH_MAX_Y);
safe_delay(50);
SERIAL_ECHOLNPAIR("GRID_MAX_POINTS_X ", GRID_MAX_POINTS_X);
safe_delay(50);
SERIAL_ECHOLNPAIR("GRID_MAX_POINTS_Y ", GRID_MAX_POINTS_Y);
safe_delay(50);
SERIAL_ECHOLNPAIR("MESH_X_DIST ", MESH_X_DIST);
SERIAL_ECHOLNPAIR("MESH_Y_DIST ", MESH_Y_DIST);
safe_delay(50);
SERIAL_PROTOCOLPGM("X-Axis Mesh Points at: ");
for (uint8_t i = 0; i < GRID_MAX_POINTS_X; i++) {
SERIAL_PROTOCOL_F(LOGICAL_X_POSITION(mesh_index_to_xpos(i)), 3);
SERIAL_PROTOCOLPGM(" ");
safe_delay(25);
}
SERIAL_EOL();
SERIAL_PROTOCOLPGM("Y-Axis Mesh Points at: ");
for (uint8_t i = 0; i < GRID_MAX_POINTS_Y; i++) {
SERIAL_PROTOCOL_F(LOGICAL_Y_POSITION(mesh_index_to_ypos(i)), 3);
SERIAL_PROTOCOLPGM(" ");
safe_delay(25);
}
SERIAL_EOL();
#if HAS_KILL
SERIAL_PROTOCOLPAIR("Kill pin on :", KILL_PIN);
SERIAL_PROTOCOLLNPAIR(" state:", READ(KILL_PIN));
#endif
SERIAL_EOL();
safe_delay(50);
#if ENABLED(UBL_DEVEL_DEBUGGING)
SERIAL_PROTOCOLLNPAIR("ubl_state_at_invocation :", ubl_state_at_invocation);
SERIAL_EOL();
SERIAL_PROTOCOLLNPAIR("ubl_state_recursion_chk :", ubl_state_recursion_chk);
SERIAL_EOL();
safe_delay(50);
SERIAL_PROTOCOLPAIR("Meshes go from ", hex_address((void*)settings.meshes_start_index()));
SERIAL_PROTOCOLLNPAIR(" to ", hex_address((void*)settings.meshes_end_index()));
safe_delay(50);
SERIAL_PROTOCOLLNPAIR("sizeof(ubl) : ", (int)sizeof(ubl));
SERIAL_EOL();
SERIAL_PROTOCOLLNPAIR("z_value[][] size: ", (int)sizeof(z_values));
SERIAL_EOL();
safe_delay(25);
SERIAL_PROTOCOLLNPAIR("EEPROM free for UBL: ", hex_address((void*)(settings.meshes_end_index() - settings.meshes_start_index())));
safe_delay(50);
SERIAL_PROTOCOLPAIR("EEPROM can hold ", settings.calc_num_meshes());
SERIAL_PROTOCOLLNPGM(" meshes.\n");
safe_delay(25);
#endif // UBL_DEVEL_DEBUGGING
if (!sanity_check()) {
echo_name();
SERIAL_PROTOCOLLNPGM(" sanity checks passed.");
}
}
/**
* When we are fully debugged, the EEPROM dump command will get deleted also. But
* right now, it is good to have the extra information. Soon... we prune this.
*/
void unified_bed_leveling::g29_eeprom_dump() {
uint8_t cccc;
SERIAL_ECHO_START();
SERIAL_ECHOLNPGM("EEPROM Dump:");
persistentStore.access_start();
for (uint16_t i = 0; i < persistentStore.capacity(); i += 16) {
if (!(i & 0x3)) idle();
print_hex_word(i);
SERIAL_ECHOPGM(": ");
for (uint16_t j = 0; j < 16; j++) {
persistentStore.read_data(i + j, &cccc, sizeof(uint8_t));
print_hex_byte(cccc);
SERIAL_ECHO(' ');
}
SERIAL_EOL();
}
SERIAL_EOL();
persistentStore.access_finish();
}
/**
* When we are fully debugged, this may go away. But there are some valid
* use cases for the users. So we can wait and see what to do with it.
*/
void unified_bed_leveling::g29_compare_current_mesh_to_stored_mesh() {
int16_t a = settings.calc_num_meshes();
if (!a) {
SERIAL_PROTOCOLLNPGM("?EEPROM storage not available.");
return;
}
if (!parser.has_value()) {
SERIAL_PROTOCOLLNPGM("?Storage slot # required.");
SERIAL_PROTOCOLLNPAIR("?Use 0 to ", a - 1);
return;
}
g29_storage_slot = parser.value_int();
if (!WITHIN(g29_storage_slot, 0, a - 1)) {
SERIAL_PROTOCOLLNPGM("?Invalid storage slot.");
SERIAL_PROTOCOLLNPAIR("?Use 0 to ", a - 1);
return;
}
float tmp_z_values[GRID_MAX_POINTS_X][GRID_MAX_POINTS_Y];
settings.load_mesh(g29_storage_slot, &tmp_z_values);
SERIAL_PROTOCOLPAIR("Subtracting mesh in slot ", g29_storage_slot);
SERIAL_PROTOCOLLNPGM(" from current mesh.");
for (uint8_t x = 0; x < GRID_MAX_POINTS_X; x++)
for (uint8_t y = 0; y < GRID_MAX_POINTS_Y; y++)
z_values[x][y] -= tmp_z_values[x][y];
}
mesh_index_pair unified_bed_leveling::find_furthest_invalid_mesh_point() {
bool found_a_NAN = false, found_a_real = false;
@ -1338,118 +1288,6 @@
return out_mesh;
}
#if HAS_LCD_MENU
void abort_fine_tune() {
lcd_return_to_status();
do_blocking_move_to_z(Z_CLEARANCE_BETWEEN_PROBES);
set_message_with_feedback(PSTR(MSG_EDITING_STOPPED));
}
void unified_bed_leveling::fine_tune_mesh(const float &rx, const float &ry, const bool do_ubl_mesh_map) {
if (!parser.seen('R')) // fine_tune_mesh() is special. If no repetition count flag is specified
g29_repetition_cnt = 1; // do exactly one mesh location. Otherwise use what the parser decided.
#if ENABLED(UBL_MESH_EDIT_MOVES_Z)
const float h_offset = parser.seenval('H') ? parser.value_linear_units() : 0;
if (!WITHIN(h_offset, 0, 10)) {
SERIAL_PROTOCOLLNPGM("Offset out of bounds. (0 to 10mm)\n");
return;
}
#endif
mesh_index_pair location;
if (!position_is_reachable(rx, ry)) {
SERIAL_PROTOCOLLNPGM("(X,Y) outside printable radius.");
return;
}
save_ubl_active_state_and_disable();
LCD_MESSAGEPGM(MSG_UBL_FINE_TUNE_MESH);
lcd_external_control = true; // Take over control of the LCD encoder
do_blocking_move_to(rx, ry, Z_CLEARANCE_BETWEEN_PROBES); // Move to the given XY with probe clearance
#if ENABLED(UBL_MESH_EDIT_MOVES_Z)
do_blocking_move_to_z(h_offset); // Move Z to the given 'H' offset
#endif
uint16_t not_done[16];
memset(not_done, 0xFF, sizeof(not_done));
do {
location = find_closest_mesh_point_of_type(SET_IN_BITMAP, rx, ry, USE_NOZZLE_AS_REFERENCE, not_done);
if (location.x_index < 0) break; // Stop when there are no more reachable points
bitmap_clear(not_done, location.x_index, location.y_index); // Mark this location as 'adjusted' so a new
// location is used on the next loop
const float rawx = mesh_index_to_xpos(location.x_index),
rawy = mesh_index_to_ypos(location.y_index);
if (!position_is_reachable(rawx, rawy)) break; // SHOULD NOT OCCUR because find_closest_mesh_point_of_type will only return reachable
do_blocking_move_to(rawx, rawy, Z_CLEARANCE_BETWEEN_PROBES); // Move the nozzle to the edit point with probe clearance
#if ENABLED(UBL_MESH_EDIT_MOVES_Z)
do_blocking_move_to_z(h_offset); // Move Z to the given 'H' offset before editing
#endif
KEEPALIVE_STATE(PAUSED_FOR_USER);
if (do_ubl_mesh_map) display_map(g29_map_type); // Display the current point
lcd_refresh();
float new_z = z_values[location.x_index][location.y_index];
if (isnan(new_z)) new_z = 0; // Invalid points begin at 0
new_z = FLOOR(new_z * 1000) * 0.001f; // Chop off digits after the 1000ths place
lcd_mesh_edit_setup(new_z);
do {
new_z = lcd_mesh_edit();
#if ENABLED(UBL_MESH_EDIT_MOVES_Z)
do_blocking_move_to_z(h_offset + new_z); // Move the nozzle as the point is edited
#endif
idle();
SERIAL_FLUSH(); // Prevent host M105 buffer overrun.
} while (!is_lcd_clicked());
if (!lcd_map_control) lcd_return_to_status(); // Just editing a single point? Return to status
if (click_and_hold(abort_fine_tune)) goto FINE_TUNE_EXIT; // If the click is held down, abort editing
z_values[location.x_index][location.y_index] = new_z; // Save the updated Z value
safe_delay(20); // No switch noise
lcd_refresh();
} while (location.x_index >= 0 && --g29_repetition_cnt > 0);
FINE_TUNE_EXIT:
lcd_external_control = false;
KEEPALIVE_STATE(IN_HANDLER);
if (do_ubl_mesh_map) display_map(g29_map_type);
restore_ubl_active_state_and_leave();
do_blocking_move_to(rx, ry, Z_CLEARANCE_BETWEEN_PROBES);
LCD_MESSAGEPGM(MSG_UBL_DONE_EDITING_MESH);
SERIAL_ECHOLNPGM("Done Editing Mesh");
if (lcd_map_control)
lcd_goto_screen(_lcd_ubl_output_map_lcd);
else
lcd_return_to_status();
}
#endif // HAS_LCD_MENU
/**
* 'Smart Fill': Scan from the outward edges of the mesh towards the center.
* If an invalid location is found, use the next two points (if valid) to
@ -1823,4 +1661,158 @@
}
#endif // UBL_G29_P31
#if ENABLED(UBL_DEVEL_DEBUGGING)
/**
* Much of the 'What?' command can be eliminated. But until we are fully debugged, it is
* good to have the extra information. Soon... we prune this to just a few items
*/
void unified_bed_leveling::g29_what_command() {
report_state();
if (storage_slot == -1)
SERIAL_PROTOCOLPGM("No Mesh Loaded.");
else {
SERIAL_PROTOCOLPAIR("Mesh ", storage_slot);
SERIAL_PROTOCOLPGM(" Loaded.");
}
SERIAL_EOL();
safe_delay(50);
#if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
SERIAL_PROTOCOLPGM("planner.z_fade_height : ");
SERIAL_PROTOCOL_F(planner.z_fade_height, 4);
SERIAL_EOL();
#endif
adjust_mesh_to_mean(g29_c_flag, g29_constant);
#if HAS_BED_PROBE
SERIAL_PROTOCOLPGM("zprobe_zoffset: ");
SERIAL_PROTOCOL_F(zprobe_zoffset, 7);
SERIAL_EOL();
#endif
SERIAL_ECHOLNPAIR("MESH_MIN_X " STRINGIFY(MESH_MIN_X) "=", MESH_MIN_X); safe_delay(50);
SERIAL_ECHOLNPAIR("MESH_MIN_Y " STRINGIFY(MESH_MIN_Y) "=", MESH_MIN_Y); safe_delay(50);
SERIAL_ECHOLNPAIR("MESH_MAX_X " STRINGIFY(MESH_MAX_X) "=", MESH_MAX_X); safe_delay(50);
SERIAL_ECHOLNPAIR("MESH_MAX_Y " STRINGIFY(MESH_MAX_Y) "=", MESH_MAX_Y); safe_delay(50);
SERIAL_ECHOLNPAIR("GRID_MAX_POINTS_X ", GRID_MAX_POINTS_X); safe_delay(50);
SERIAL_ECHOLNPAIR("GRID_MAX_POINTS_Y ", GRID_MAX_POINTS_Y); safe_delay(50);
SERIAL_ECHOLNPAIR("MESH_X_DIST ", MESH_X_DIST);
SERIAL_ECHOLNPAIR("MESH_Y_DIST ", MESH_Y_DIST); safe_delay(50);
SERIAL_PROTOCOLPGM("X-Axis Mesh Points at: ");
for (uint8_t i = 0; i < GRID_MAX_POINTS_X; i++) {
SERIAL_PROTOCOL_F(LOGICAL_X_POSITION(mesh_index_to_xpos(i)), 3);
SERIAL_PROTOCOLPGM(" ");
safe_delay(25);
}
SERIAL_EOL();
SERIAL_PROTOCOLPGM("Y-Axis Mesh Points at: ");
for (uint8_t i = 0; i < GRID_MAX_POINTS_Y; i++) {
SERIAL_PROTOCOL_F(LOGICAL_Y_POSITION(mesh_index_to_ypos(i)), 3);
SERIAL_PROTOCOLPGM(" ");
safe_delay(25);
}
SERIAL_EOL();
#if HAS_KILL
SERIAL_PROTOCOLPAIR("Kill pin on :", KILL_PIN);
SERIAL_PROTOCOLLNPAIR(" state:", READ(KILL_PIN));
#endif
SERIAL_EOL();
safe_delay(50);
#if ENABLED(UBL_DEVEL_DEBUGGING)
SERIAL_PROTOCOLLNPAIR("ubl_state_at_invocation :", ubl_state_at_invocation); SERIAL_EOL();
SERIAL_PROTOCOLLNPAIR("ubl_state_recursion_chk :", ubl_state_recursion_chk); SERIAL_EOL();
safe_delay(50);
SERIAL_PROTOCOLPAIR("Meshes go from ", hex_address((void*)settings.meshes_start_index()));
SERIAL_PROTOCOLLNPAIR(" to ", hex_address((void*)settings.meshes_end_index()));
safe_delay(50);
SERIAL_PROTOCOLLNPAIR("sizeof(ubl) : ", (int)sizeof(ubl)); SERIAL_EOL();
SERIAL_PROTOCOLLNPAIR("z_value[][] size: ", (int)sizeof(z_values)); SERIAL_EOL();
safe_delay(25);
SERIAL_PROTOCOLLNPAIR("EEPROM free for UBL: ", hex_address((void*)(settings.meshes_end_index() - settings.meshes_start_index())));
safe_delay(50);
SERIAL_PROTOCOLPAIR("EEPROM can hold ", settings.calc_num_meshes());
SERIAL_PROTOCOLLNPGM(" meshes.\n");
safe_delay(25);
#endif // UBL_DEVEL_DEBUGGING
if (!sanity_check()) {
echo_name();
SERIAL_PROTOCOLLNPGM(" sanity checks passed.");
}
}
/**
* When we are fully debugged, the EEPROM dump command will get deleted also. But
* right now, it is good to have the extra information. Soon... we prune this.
*/
void unified_bed_leveling::g29_eeprom_dump() {
uint8_t cccc;
SERIAL_ECHO_START();
SERIAL_ECHOLNPGM("EEPROM Dump:");
persistentStore.access_start();
for (uint16_t i = 0; i < persistentStore.capacity(); i += 16) {
if (!(i & 0x3)) idle();
print_hex_word(i);
SERIAL_ECHOPGM(": ");
for (uint16_t j = 0; j < 16; j++) {
persistentStore.read_data(i + j, &cccc, sizeof(uint8_t));
print_hex_byte(cccc);
SERIAL_ECHO(' ');
}
SERIAL_EOL();
}
SERIAL_EOL();
persistentStore.access_finish();
}
/**
* When we are fully debugged, this may go away. But there are some valid
* use cases for the users. So we can wait and see what to do with it.
*/
void unified_bed_leveling::g29_compare_current_mesh_to_stored_mesh() {
int16_t a = settings.calc_num_meshes();
if (!a) {
SERIAL_PROTOCOLLNPGM("?EEPROM storage not available.");
return;
}
if (!parser.has_value()) {
SERIAL_PROTOCOLLNPGM("?Storage slot # required.");
SERIAL_PROTOCOLLNPAIR("?Use 0 to ", a - 1);
return;
}
g29_storage_slot = parser.value_int();
if (!WITHIN(g29_storage_slot, 0, a - 1)) {
SERIAL_PROTOCOLLNPGM("?Invalid storage slot.");
SERIAL_PROTOCOLLNPAIR("?Use 0 to ", a - 1);
return;
}
float tmp_z_values[GRID_MAX_POINTS_X][GRID_MAX_POINTS_Y];
settings.load_mesh(g29_storage_slot, &tmp_z_values);
SERIAL_PROTOCOLPAIR("Subtracting mesh in slot ", g29_storage_slot);
SERIAL_PROTOCOLLNPGM(" from current mesh.");
for (uint8_t x = 0; x < GRID_MAX_POINTS_X; x++)
for (uint8_t y = 0; y < GRID_MAX_POINTS_Y; y++)
z_values[x][y] -= tmp_z_values[x][y];
}
#endif // UBL_DEVEL_DEBUGGING
#endif // AUTO_BED_LEVELING_UBL