diff --git a/Marlin/src/Marlin.cpp b/Marlin/src/Marlin.cpp index 944c5ec96f..3d77548ee2 100644 --- a/Marlin/src/Marlin.cpp +++ b/Marlin/src/Marlin.cpp @@ -371,7 +371,7 @@ void manage_inactivity(const bool ignore_stepper_queue/*=false*/) { #if HAS_LCD_MENU && ENABLED(AUTO_BED_LEVELING_UBL) if (ubl.lcd_map_control) { ubl.lcd_map_control = false; - set_defer_return_to_status(false); + ui.defer_status_screen(false); } #endif } @@ -549,7 +549,7 @@ void idle( max7219.idle_tasks(); #endif - lcd_update(); + ui.update(); #if ENABLED(HOST_KEEPALIVE_FEATURE) gcode.host_keepalive(); @@ -609,8 +609,8 @@ void kill(PGM_P const lcd_msg/*=NULL*/) { SERIAL_ERROR_START(); SERIAL_ERRORLNPGM(MSG_ERR_KILLED); - #if ENABLED(ULTRA_LCD) || ENABLED(EXTENSIBLE_UI) - kill_screen(lcd_msg ? lcd_msg : PSTR(MSG_KILLED)); + #if HAS_SPI_LCD || ENABLED(EXTENSIBLE_UI) + ui.kill_screen(lcd_msg ? lcd_msg : PSTR(MSG_KILLED)); #else UNUSED(lcd_msg); #endif @@ -899,11 +899,11 @@ void setup() { fanmux_init(); #endif - lcd_init(); - lcd_reset_status(); + ui.init(); + ui.reset_status(); #if ENABLED(SHOW_BOOTSCREEN) - lcd_bootscreen(); + ui.show_bootscreen(); #endif #if ENABLED(MIXING_EXTRUDER) diff --git a/Marlin/src/config/examples/Geeetech/GT2560/Configuration.h b/Marlin/src/config/examples/Geeetech/GT2560/Configuration.h index f992c4b773..5c19c578b7 100644 --- a/Marlin/src/config/examples/Geeetech/GT2560/Configuration.h +++ b/Marlin/src/config/examples/Geeetech/GT2560/Configuration.h @@ -2035,7 +2035,7 @@ */ #if ENABLED(ULTIMAKERCONTROLLER) || ENABLED(REPRAP_DISCOUNT_SMART_CONTROLLER) || ENABLED(G3D_PANEL) || ENABLED(MKS_MINI_12864) #define SDSUPPORT // Force SD Card support on for these displays -#else +#elif DISABLED(LIGHTWEIGHT_UI) #define LCD_WIDTH_OVERRIDE 20 // Default is 22. For this Geeetech use 20. #endif diff --git a/Marlin/src/feature/bedlevel/bedlevel.cpp b/Marlin/src/feature/bedlevel/bedlevel.cpp index 737a971fb0..bc5bf2397d 100644 --- a/Marlin/src/feature/bedlevel/bedlevel.cpp +++ b/Marlin/src/feature/bedlevel/bedlevel.cpp @@ -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 } diff --git a/Marlin/src/feature/bedlevel/ubl/ubl.cpp b/Marlin/src/feature/bedlevel/ubl/ubl.cpp index bc5088f209..c5ff87466a 100644 --- a/Marlin/src/feature/bedlevel/ubl/ubl.cpp +++ b/Marlin/src/feature/bedlevel/ubl/ubl.cpp @@ -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(); } diff --git a/Marlin/src/feature/bedlevel/ubl/ubl.h b/Marlin/src/feature/bedlevel/ubl/ubl.h index 809e3827fe..cd13e081d9 100644 --- a/Marlin/src/feature/bedlevel/ubl/ubl.h +++ b/Marlin/src/feature/bedlevel/ubl/ubl.h @@ -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( diff --git a/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp b/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp index 71c0097f78..80016c2f46 100644 --- a/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp +++ b/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp @@ -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 diff --git a/Marlin/src/feature/pause.cpp b/Marlin/src/feature/pause.cpp index b26babf730..04d7682dfd 100644 --- a/Marlin/src/feature/pause.cpp +++ b/Marlin/src/feature/pause.cpp @@ -586,7 +586,7 @@ void resume_print(const float &slow_load_length/*=0*/, const float &fast_load_le #endif #if ENABLED(ULTRA_LCD) - lcd_reset_status(); + ui.reset_status(); #endif } diff --git a/Marlin/src/gcode/bedlevel/G26.cpp b/Marlin/src/gcode/bedlevel/G26.cpp index 6deeadb326..7a44109262 100644 --- a/Marlin/src/gcode/bedlevel/G26.cpp +++ b/Marlin/src/gcode/bedlevel/G26.cpp @@ -163,12 +163,12 @@ int8_t g26_prime_flag; * If the LCD is clicked, cancel, wait for release, return true */ bool user_canceled() { - if (!is_lcd_clicked()) return false; // Return if the button isn't pressed - lcd_setstatusPGM(PSTR("Mesh Validation Stopped."), 99); + if (!ui.button_pressed()) return false; // Return if the button isn't pressed + ui.setstatusPGM(PSTR("Mesh Validation Stopped."), 99); #if HAS_LCD_MENU - lcd_quick_feedback(); + ui.quick_feedback(); #endif - wait_for_release(); + ui.wait_for_release(); return true; } @@ -414,10 +414,10 @@ inline bool turn_on_heaters() { if (g26_bed_temp > 25) { #if ENABLED(ULTRA_LCD) - lcd_setstatusPGM(PSTR("G26 Heating Bed."), 99); - lcd_quick_feedback(); + ui.setstatusPGM(PSTR("G26 Heating Bed."), 99); + ui.quick_feedback(); #if HAS_LCD_MENU - lcd_external_control = true; + ui.capture(); #endif #endif thermalManager.setTargetBed(g26_bed_temp); @@ -435,8 +435,8 @@ inline bool turn_on_heaters() { // Start heating the active nozzle #if ENABLED(ULTRA_LCD) - lcd_setstatusPGM(PSTR("G26 Heating Nozzle."), 99); - lcd_quick_feedback(); + ui.setstatusPGM(PSTR("G26 Heating Nozzle."), 99); + ui.quick_feedback(); #endif thermalManager.setTargetHotend(g26_hotend_temp, active_extruder); @@ -449,8 +449,8 @@ inline bool turn_on_heaters() { ) return G26_ERR; #if ENABLED(ULTRA_LCD) - lcd_reset_status(); - lcd_quick_feedback(); + ui.reset_status(); + ui.quick_feedback(); #endif return G26_OK; @@ -468,16 +468,16 @@ inline bool prime_nozzle() { if (g26_prime_flag == -1) { // The user wants to control how much filament gets purged - lcd_external_control = true; - lcd_setstatusPGM(PSTR("User-Controlled Prime"), 99); - lcd_chirp(); + ui.capture(); + ui.setstatusPGM(PSTR("User-Controlled Prime"), 99); + ui.chirp(); set_destination_from_current(); recover_filament(destination); // Make sure G26 doesn't think the filament is retracted(). - while (!is_lcd_clicked()) { - lcd_chirp(); + while (!ui.button_pressed()) { + ui.chirp(); destination[E_AXIS] += 0.25; #if ENABLED(PREVENT_LENGTHY_EXTRUDE) Total_Prime += 0.25; @@ -491,18 +491,18 @@ inline bool prime_nozzle() { // action to give the user a more responsive 'Stop'. } - wait_for_release(); + ui.wait_for_release(); - lcd_setstatusPGM(PSTR("Done Priming"), 99); - lcd_quick_feedback(); - lcd_external_control = false; + ui.setstatusPGM(PSTR("Done Priming"), 99); + ui.quick_feedback(); + ui.release(); } else #endif { #if ENABLED(ULTRA_LCD) - lcd_setstatusPGM(PSTR("Fixed Length Prime."), 99); - lcd_quick_feedback(); + ui.setstatusPGM(PSTR("Fixed Length Prime."), 99); + ui.quick_feedback(); #endif set_destination_from_current(); destination[E_AXIS] += g26_prime_length; @@ -715,7 +715,7 @@ void GcodeSuite::G26() { move_to(destination, g26_ooze_amount); #if HAS_LCD_MENU - lcd_external_control = true; + ui.capture(); #endif //debug_current_and_destination(PSTR("Starting G26 Mesh Validation Pattern.")); @@ -881,8 +881,7 @@ void GcodeSuite::G26() { } while (--g26_repeats && location.x_index >= 0 && location.y_index >= 0); LEAVE: - lcd_setstatusPGM(PSTR("Leaving G26"), -1); - wait_for_release(); + ui.setstatusPGM(PSTR("Leaving G26"), -1); retract_filament(destination); destination[Z_AXIS] = Z_CLEARANCE_BETWEEN_PROBES; @@ -891,15 +890,15 @@ void GcodeSuite::G26() { move_to(destination, 0); // Raise the nozzle //debug_current_and_destination(PSTR("done doing Z-Raise.")); - destination[X_AXIS] = g26_x_pos; // Move back to the starting position + destination[X_AXIS] = g26_x_pos; // Move back to the starting position destination[Y_AXIS] = g26_y_pos; - //destination[Z_AXIS] = Z_CLEARANCE_BETWEEN_PROBES; // Keep the nozzle where it is + //destination[Z_AXIS] = Z_CLEARANCE_BETWEEN_PROBES; // Keep the nozzle where it is - move_to(destination, 0); // Move back to the starting position + move_to(destination, 0); // Move back to the starting position //debug_current_and_destination(PSTR("done doing X/Y move.")); #if HAS_LCD_MENU - lcd_external_control = false; // Give back control of the LCD Panel! + ui.release(); // Give back control of the LCD #endif if (!g26_keep_heaters_on) { diff --git a/Marlin/src/gcode/bedlevel/abl/G29.cpp b/Marlin/src/gcode/bedlevel/abl/G29.cpp index 547ef15612..ecc2196923 100644 --- a/Marlin/src/gcode/bedlevel/abl/G29.cpp +++ b/Marlin/src/gcode/bedlevel/abl/G29.cpp @@ -498,7 +498,7 @@ G29_TYPE GcodeSuite::G29() { set_bed_leveling_enabled(abl_should_enable); g29_in_progress = false; #if ENABLED(LCD_BED_LEVELING) - lcd_wait_for_move = false; + ui.wait_for_bl_move = false; #endif } @@ -790,7 +790,7 @@ G29_TYPE GcodeSuite::G29() { #if ENABLED(PROBE_MANUALLY) g29_in_progress = false; #if ENABLED(LCD_BED_LEVELING) - lcd_wait_for_move = false; + ui.wait_for_bl_move = false; #endif #endif diff --git a/Marlin/src/gcode/bedlevel/mbl/G29.cpp b/Marlin/src/gcode/bedlevel/mbl/G29.cpp index 16a7393e76..5bcc9e069a 100644 --- a/Marlin/src/gcode/bedlevel/mbl/G29.cpp +++ b/Marlin/src/gcode/bedlevel/mbl/G29.cpp @@ -90,7 +90,7 @@ void GcodeSuite::G29() { case MeshStart: mbl.reset(); mbl_probe_index = 0; - if (!lcd_wait_for_move) { + if (!ui.wait_for_bl_move) { enqueue_and_echo_commands_P(PSTR("G28\nG29 S2")); return; } @@ -151,7 +151,7 @@ void GcodeSuite::G29() { #endif #if ENABLED(LCD_BED_LEVELING) - lcd_wait_for_move = false; + ui.wait_for_bl_move = false; #endif } break; diff --git a/Marlin/src/gcode/calibrate/G28.cpp b/Marlin/src/gcode/calibrate/G28.cpp index 8a40e2bd61..29a0e6552c 100644 --- a/Marlin/src/gcode/calibrate/G28.cpp +++ b/Marlin/src/gcode/calibrate/G28.cpp @@ -425,7 +425,7 @@ void GcodeSuite::G28(const bool always_home_all) { tool_change(old_tool_index, 0, NO_FETCH); #endif - lcd_refresh(); + ui.refresh(); report_current_position(); #if ENABLED(NANODLP_Z_SYNC) diff --git a/Marlin/src/gcode/calibrate/G33.cpp b/Marlin/src/gcode/calibrate/G33.cpp index 3aba869824..bb515a6ea3 100644 --- a/Marlin/src/gcode/calibrate/G33.cpp +++ b/Marlin/src/gcode/calibrate/G33.cpp @@ -522,7 +522,7 @@ void GcodeSuite::G33() { if (verbose_level == 0) SERIAL_PROTOCOLPGM(" (DRY-RUN)"); if (set_up) SERIAL_PROTOCOLPGM(" (SET-UP)"); SERIAL_EOL(); - lcd_setstatusPGM(checkingac); + ui.setstatusPGM(checkingac); print_calibration_settings(_endstop_results, _angle_results); @@ -683,7 +683,7 @@ void GcodeSuite::G33() { sprintf_P(&mess[15], PSTR("0.%03i"), (int)LROUND(zero_std_dev_min * 1000.0)); else sprintf_P(&mess[15], PSTR("%03i.x"), (int)LROUND(zero_std_dev_min)); - lcd_setstatus(mess); + ui.setstatus(mess); print_calibration_settings(_endstop_results, _angle_results); serialprintPGM(save_message); SERIAL_EOL(); @@ -699,7 +699,7 @@ void GcodeSuite::G33() { SERIAL_PROTOCOLPGM("std dev:"); SERIAL_PROTOCOL_F(zero_std_dev, 3); SERIAL_EOL(); - lcd_setstatus(mess); + ui.setstatus(mess); if (verbose_level > 1) print_calibration_settings(_endstop_results, _angle_results); } @@ -719,7 +719,7 @@ void GcodeSuite::G33() { sprintf_P(&mess[15], PSTR("0.%03i"), (int)LROUND(zero_std_dev * 1000.0)); else sprintf_P(&mess[15], PSTR("%03i.x"), (int)LROUND(zero_std_dev)); - lcd_setstatus(mess); + ui.setstatus(mess); } ac_home(); } diff --git a/Marlin/src/gcode/control/M17_M18_M84.cpp b/Marlin/src/gcode/control/M17_M18_M84.cpp index e4b94d99b6..33a6eae5ff 100644 --- a/Marlin/src/gcode/control/M17_M18_M84.cpp +++ b/Marlin/src/gcode/control/M17_M18_M84.cpp @@ -63,7 +63,7 @@ void GcodeSuite::M18_M84() { #if HAS_LCD_MENU && ENABLED(AUTO_BED_LEVELING_UBL) if (ubl.lcd_map_control) { ubl.lcd_map_control = false; - set_defer_return_to_status(false); + ui.defer_status_screen(false); } #endif } diff --git a/Marlin/src/gcode/control/M80_M81.cpp b/Marlin/src/gcode/control/M80_M81.cpp index 573a44bfa3..3dbf15a794 100644 --- a/Marlin/src/gcode/control/M80_M81.cpp +++ b/Marlin/src/gcode/control/M80_M81.cpp @@ -83,7 +83,7 @@ #endif #if HAS_LCD_MENU - lcd_reset_status(); + ui.reset_status(); #endif } diff --git a/Marlin/src/gcode/control/M999.cpp b/Marlin/src/gcode/control/M999.cpp index 12c2cfdc59..18a7287aed 100644 --- a/Marlin/src/gcode/control/M999.cpp +++ b/Marlin/src/gcode/control/M999.cpp @@ -38,7 +38,7 @@ */ void GcodeSuite::M999() { Running = true; - lcd_reset_alert_level(); + ui.reset_alert_level(); if (parser.boolval('S')) return; diff --git a/Marlin/src/gcode/lcd/M0_M1.cpp b/Marlin/src/gcode/lcd/M0_M1.cpp index 505fef340e..3357e99c12 100644 --- a/Marlin/src/gcode/lcd/M0_M1.cpp +++ b/Marlin/src/gcode/lcd/M0_M1.cpp @@ -62,11 +62,11 @@ void GcodeSuite::M0_M1() { #if HAS_LCD_MENU if (has_message) - lcd_setstatus(args, true); + ui.setstatus(args, true); else { LCD_MESSAGEPGM(MSG_USERWAIT); #if ENABLED(LCD_PROGRESS_BAR) && PROGRESS_MSG_EXPIRE > 0 - dontExpireStatus(); + ui.reset_progress_bar_timeout(); #endif } @@ -94,7 +94,7 @@ void GcodeSuite::M0_M1() { #endif #if HAS_LCD_MENU - lcd_reset_status(); + ui.reset_status(); #endif wait_for_user = false; diff --git a/Marlin/src/gcode/lcd/M117.cpp b/Marlin/src/gcode/lcd/M117.cpp index 0f508d8eb9..c35a048a53 100644 --- a/Marlin/src/gcode/lcd/M117.cpp +++ b/Marlin/src/gcode/lcd/M117.cpp @@ -28,6 +28,6 @@ */ void GcodeSuite::M117() { - lcd_setstatus(parser.string_arg); + ui.setstatus(parser.string_arg); } diff --git a/Marlin/src/gcode/lcd/M145.cpp b/Marlin/src/gcode/lcd/M145.cpp index 9052a6493e..35fb525f48 100644 --- a/Marlin/src/gcode/lcd/M145.cpp +++ b/Marlin/src/gcode/lcd/M145.cpp @@ -37,7 +37,7 @@ */ void GcodeSuite::M145() { const uint8_t material = (uint8_t)parser.intval('S'); - if (material >= COUNT(lcd_preheat_hotend_temp)) { + if (material >= COUNT(ui.preheat_hotend_temp)) { SERIAL_ERROR_START(); SERIAL_ERRORLNPGM(MSG_ERR_MATERIAL_INDEX); } @@ -45,16 +45,16 @@ void GcodeSuite::M145() { int v; if (parser.seenval('H')) { v = parser.value_int(); - lcd_preheat_hotend_temp[material] = constrain(v, EXTRUDE_MINTEMP, HEATER_0_MAXTEMP - 15); + ui.preheat_hotend_temp[material] = constrain(v, EXTRUDE_MINTEMP, HEATER_0_MAXTEMP - 15); } if (parser.seenval('F')) { v = parser.value_int(); - lcd_preheat_fan_speed[material] = (uint8_t)constrain(v, 0, 255); + ui.preheat_fan_speed[material] = (uint8_t)constrain(v, 0, 255); } #if TEMP_SENSOR_BED != 0 if (parser.seenval('B')) { v = parser.value_int(); - lcd_preheat_bed_temp[material] = constrain(v, BED_MINTEMP, BED_MAXTEMP - 15); + ui.preheat_bed_temp[material] = constrain(v, BED_MINTEMP, BED_MAXTEMP - 15); } #endif } diff --git a/Marlin/src/gcode/lcd/M250.cpp b/Marlin/src/gcode/lcd/M250.cpp index bede88126a..9444779f54 100644 --- a/Marlin/src/gcode/lcd/M250.cpp +++ b/Marlin/src/gcode/lcd/M250.cpp @@ -31,10 +31,8 @@ * M250: Read and optionally set the LCD contrast */ void GcodeSuite::M250() { - if (parser.seen('C')) set_lcd_contrast(parser.value_int()); - SERIAL_PROTOCOLPGM("lcd contrast value: "); - SERIAL_PROTOCOL(lcd_contrast); - SERIAL_EOL(); + if (parser.seen('C')) ui.set_contrast(parser.value_int()); + SERIAL_PROTOCOLLNPAIR("LCD Contrast: ", ui.contrast); } #endif // HAS_LCD_CONTRAST diff --git a/Marlin/src/gcode/lcd/M73.cpp b/Marlin/src/gcode/lcd/M73.cpp index c721d5b363..78697aecf3 100644 --- a/Marlin/src/gcode/lcd/M73.cpp +++ b/Marlin/src/gcode/lcd/M73.cpp @@ -38,10 +38,8 @@ * This has no effect during an SD print job */ void GcodeSuite::M73() { - if (!IS_SD_PRINTING() && parser.seen('P')) { - progress_bar_percent = parser.value_byte(); - NOMORE(progress_bar_percent, 100); - } + if (parser.seen('P') && !IS_SD_PRINTING()) + ui.set_progress(parser.value_byte()); } #endif // ULTRA_LCD && LCD_SET_PROGRESS_MANUALLY diff --git a/Marlin/src/gcode/motion/G4.cpp b/Marlin/src/gcode/motion/G4.cpp index 7d53cb0304..6a0b6c2ddc 100644 --- a/Marlin/src/gcode/motion/G4.cpp +++ b/Marlin/src/gcode/motion/G4.cpp @@ -38,7 +38,7 @@ void GcodeSuite::G4() { SERIAL_ECHOLNPGM(MSG_Z_MOVE_COMP); #endif - if (!lcd_hasstatus()) LCD_MESSAGEPGM(MSG_DWELL); + if (!ui.hasstatus()) LCD_MESSAGEPGM(MSG_DWELL); dwell(dwell_ms); } diff --git a/Marlin/src/gcode/stats/M31.cpp b/Marlin/src/gcode/stats/M31.cpp index 958556e544..121a0cc806 100644 --- a/Marlin/src/gcode/stats/M31.cpp +++ b/Marlin/src/gcode/stats/M31.cpp @@ -40,7 +40,7 @@ void GcodeSuite::M31() { char buffer[21]; duration_t elapsed = print_job_timer.duration(); elapsed.toString(buffer); - lcd_setstatus(buffer); + ui.setstatus(buffer); SERIAL_ECHO_START_P(port); SERIAL_ECHOLNPAIR_P(port, "Print time: ", buffer); diff --git a/Marlin/src/gcode/temperature/M104_M109.cpp b/Marlin/src/gcode/temperature/M104_M109.cpp index 4868f2b4d3..c7499624c9 100644 --- a/Marlin/src/gcode/temperature/M104_M109.cpp +++ b/Marlin/src/gcode/temperature/M104_M109.cpp @@ -66,7 +66,7 @@ void GcodeSuite::M104() { */ if (temp <= (EXTRUDE_MINTEMP) / 2) { print_job_timer.stop(); - lcd_reset_status(); + ui.reset_status(); } #endif } @@ -108,7 +108,7 @@ void GcodeSuite::M109() { */ if (parser.value_celsius() <= (EXTRUDE_MINTEMP) / 2) { print_job_timer.stop(); - lcd_reset_status(); + ui.reset_status(); } else print_job_timer.start(); diff --git a/Marlin/src/gcode/temperature/M140_M190.cpp b/Marlin/src/gcode/temperature/M140_M190.cpp index 8a42eb85be..a70a6fdc85 100644 --- a/Marlin/src/gcode/temperature/M140_M190.cpp +++ b/Marlin/src/gcode/temperature/M140_M190.cpp @@ -64,7 +64,7 @@ void GcodeSuite::M190() { } else return; - lcd_setstatusPGM(thermalManager.isHeatingBed() ? PSTR(MSG_BED_HEATING) : PSTR(MSG_BED_COOLING)); + ui.setstatusPGM(thermalManager.isHeatingBed() ? PSTR(MSG_BED_HEATING) : PSTR(MSG_BED_COOLING)); thermalManager.wait_for_bed(no_wait_for_cooling); } diff --git a/Marlin/src/inc/Conditionals_LCD.h b/Marlin/src/inc/Conditionals_LCD.h index 0de18de582..b73370c787 100644 --- a/Marlin/src/inc/Conditionals_LCD.h +++ b/Marlin/src/inc/Conditionals_LCD.h @@ -296,47 +296,23 @@ #define ULTIPANEL #endif -#define HAS_GRAPHICAL_LCD ENABLED(DOGLCD) - -#if HAS_GRAPHICAL_LCD - #ifndef LCD_WIDTH - #ifdef LCD_WIDTH_OVERRIDE - #define LCD_WIDTH LCD_WIDTH_OVERRIDE - #else - #define LCD_WIDTH 22 - #endif - #endif - #ifndef LCD_HEIGHT - #define LCD_HEIGHT 5 - #endif -#endif - #if ENABLED(ULTIPANEL) #define NEWPANEL // Disable this if you actually have no click-encoder panel #define ULTRA_LCD - #ifndef LCD_WIDTH - #define LCD_WIDTH 20 - #endif - #ifndef LCD_HEIGHT - #define LCD_HEIGHT 4 - #endif -#elif ENABLED(ULTRA_LCD) // no panel but just LCD - #ifndef LCD_WIDTH - #define LCD_WIDTH 16 - #endif - #ifndef LCD_HEIGHT - #define LCD_HEIGHT 2 - #endif #endif // Aliases for LCD features #define HAS_SPI_LCD ENABLED(ULTRA_LCD) -#define HAS_CHARACTER_LCD (ENABLED(ULTRA_LCD) && DISABLED(DOGLCD)) +#define HAS_GRAPHICAL_LCD ENABLED(DOGLCD) +#define HAS_CHARACTER_LCD (HAS_SPI_LCD && !HAS_GRAPHICAL_LCD) #define HAS_LCD_MENU (ENABLED(ULTIPANEL) && DISABLED(NO_LCD_MENUS)) +#define HAS_DIGITAL_ENCODER ENABLED(NEWPANEL) #if HAS_GRAPHICAL_LCD - /* Custom characters defined in font Marlin_symbols.fon which was merged to ISO10646-0-3.bdf */ + // + // Custom characters from Marlin_symbols.fon which was merged into ISO10646-0-3.bdf // \x00 intentionally skipped to avoid problems in strings + // #define LCD_STR_REFRESH "\x01" #define LCD_STR_FOLDER "\x02" #define LCD_STR_ARROW_RIGHT "\x03" @@ -354,33 +330,18 @@ // Symbol characters #define LCD_STR_FILAM_DIA "\xf8" #define LCD_STR_FILAM_MUL "\xa4" -#else - // Custom characters defined in the first 8 characters of the LCD - #define LCD_BEDTEMP_CHAR 0x00 // Print only as a char. This will have 'unexpected' results when used in a string! - #define LCD_DEGREE_CHAR 0x01 - #define LCD_STR_THERMOMETER "\x02" // Still used with string concatenation - #define LCD_UPLEVEL_CHAR 0x03 - #define LCD_STR_REFRESH "\x04" - #define LCD_STR_FOLDER "\x05" - #define LCD_FEEDRATE_CHAR 0x06 - #define LCD_CLOCK_CHAR 0x07 - #define LCD_STR_ARROW_RIGHT ">" /* from the default character set */ -#endif -/** - * Default LCD contrast for dogm-like LCD displays - */ -#if HAS_GRAPHICAL_LCD - - #define HAS_LCD_CONTRAST ( \ - ENABLED(MAKRPANEL) \ - || ENABLED(CARTESIO_UI) \ - || ENABLED(VIKI2) \ - || ENABLED(AZSMZ_12864) \ - || ENABLED(miniVIKI) \ - || ENABLED(ELB_FULL_GRAPHIC_CONTROLLER) \ + /** + * Default LCD contrast for dogm-like LCD displays + */ + #define HAS_LCD_CONTRAST ( \ + ENABLED(MAKRPANEL) \ + || ENABLED(CARTESIO_UI) \ + || ENABLED(VIKI2) \ + || ENABLED(AZSMZ_12864) \ + || ENABLED(miniVIKI) \ + || ENABLED(ELB_FULL_GRAPHIC_CONTROLLER) \ ) - #if HAS_LCD_CONTRAST #ifndef LCD_CONTRAST_MIN #define LCD_CONTRAST_MIN 0 @@ -392,6 +353,20 @@ #define DEFAULT_LCD_CONTRAST 32 #endif #endif + +#else + + // Custom characters defined in the first 8 characters of the LCD + #define LCD_BEDTEMP_CHAR 0x00 // Print only as a char. This will have 'unexpected' results when used in a string! + #define LCD_DEGREE_CHAR 0x01 + #define LCD_STR_THERMOMETER "\x02" // Still used with string concatenation + #define LCD_UPLEVEL_CHAR 0x03 + #define LCD_STR_REFRESH "\x04" + #define LCD_STR_FOLDER "\x05" + #define LCD_FEEDRATE_CHAR 0x06 + #define LCD_CLOCK_CHAR 0x07 + #define LCD_STR_ARROW_RIGHT ">" /* from the default character set */ + #endif // Boot screens diff --git a/Marlin/src/inc/Conditionals_post.h b/Marlin/src/inc/Conditionals_post.h index a20ab25a73..1c7a3cb0b5 100644 --- a/Marlin/src/inc/Conditionals_post.h +++ b/Marlin/src/inc/Conditionals_post.h @@ -1628,3 +1628,39 @@ #else #define Z_STEPPER_COUNT 1 #endif + +// Get LCD character width/height, which may be overridden by pins, configs, etc. +#if HAS_GRAPHICAL_LCD + #ifndef LCD_WIDTH + #ifdef LCD_WIDTH_OVERRIDE + #define LCD_WIDTH LCD_WIDTH_OVERRIDE + #elif ENABLED(LIGHTWEIGHT_UI) + #define LCD_WIDTH 16 + #else + #define LCD_WIDTH 22 + #endif + #endif + #ifndef LCD_HEIGHT + #ifdef LCD_HEIGHT_OVERRIDE + #define LCD_HEIGHT LCD_HEIGHT_OVERRIDE + #elif ENABLED(LIGHTWEIGHT_UI) + #define LCD_HEIGHT 4 + #else + #define LCD_HEIGHT 5 + #endif + #endif +#elif ENABLED(ULTIPANEL) + #ifndef LCD_WIDTH + #define LCD_WIDTH 20 + #endif + #ifndef LCD_HEIGHT + #define LCD_HEIGHT 4 + #endif +#elif HAS_SPI_LCD + #ifndef LCD_WIDTH + #define LCD_WIDTH 16 + #endif + #ifndef LCD_HEIGHT + #define LCD_HEIGHT 2 + #endif +#endif diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index 2fd385aad2..80e022b82c 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -491,6 +491,8 @@ static_assert(X_MAX_LENGTH >= X_BED_SIZE && Y_MAX_LENGTH >= Y_BED_SIZE, #error "LCD_PROGRESS_BAR does not apply to graphical displays." #elif ENABLED(FILAMENT_LCD_DISPLAY) #error "LCD_PROGRESS_BAR and FILAMENT_LCD_DISPLAY are not fully compatible. Comment out this line to use both." + #elif PROGRESS_MSG_EXPIRE < 0 + #error "PROGRESS_MSG_EXPIRE must be greater than or equal to 0." #endif #elif ENABLED(LCD_SET_PROGRESS_MANUALLY) && !HAS_GRAPHICAL_LCD #error "LCD_SET_PROGRESS_MANUALLY requires LCD_PROGRESS_BAR or Graphical LCD." diff --git a/Marlin/src/lcd/HD44780/ultralcd_common_HD44780.h b/Marlin/src/lcd/HD44780/ultralcd_common_HD44780.h index 54ff9a5368..9829619f54 100644 --- a/Marlin/src/lcd/HD44780/ultralcd_common_HD44780.h +++ b/Marlin/src/lcd/HD44780/ultralcd_common_HD44780.h @@ -39,70 +39,6 @@ // macro name. The mapping is independent of whether the button is directly connected or // via a shift/i2c register. -#if HAS_LCD_MENU - - extern volatile uint8_t buttons; - - // - // Setup other button mappings of each panel - // - #if ENABLED(LCD_I2C_VIKI) - #define B_I2C_BTN_OFFSET 3 // (the first three bit positions reserved for EN_A, EN_B, EN_C) - - // button and encoder bit positions within 'buttons' - #define B_LE (BUTTON_LEFT << B_I2C_BTN_OFFSET) // The remaining normalized buttons are all read via I2C - #define B_UP (BUTTON_UP << B_I2C_BTN_OFFSET) - #define B_MI (BUTTON_SELECT << B_I2C_BTN_OFFSET) - #define B_DW (BUTTON_DOWN << B_I2C_BTN_OFFSET) - #define B_RI (BUTTON_RIGHT << B_I2C_BTN_OFFSET) - - #undef LCD_CLICKED - #if BUTTON_EXISTS(ENC) - // the pause/stop/restart button is connected to BTN_ENC when used - #define B_ST (EN_C) // Map the pause/stop/resume button into its normalized functional name - #define LCD_CLICKED() (buttons & (B_MI|B_RI|B_ST)) // pause/stop button also acts as click until we implement proper pause/stop. - #else - #define LCD_CLICKED() (buttons & (B_MI|B_RI)) - #endif - - // I2C buttons take too long to read inside an interrupt context and so we read them during lcd_update - #define LCD_HAS_SLOW_BUTTONS - - #elif ENABLED(LCD_I2C_PANELOLU2) - - #if !BUTTON_EXISTS(ENC) // Use I2C if not directly connected to a pin - - #define B_I2C_BTN_OFFSET 3 // (the first three bit positions reserved for EN_A, EN_B, EN_C) - - #define B_MI (PANELOLU2_ENCODER_C << B_I2C_BTN_OFFSET) // requires LiquidTWI2 library v1.2.3 or later - - #undef LCD_CLICKED - #define LCD_CLICKED() (buttons & B_MI) - - // I2C buttons take too long to read inside an interrupt context and so we read them during lcd_update - #define LCD_HAS_SLOW_BUTTONS - - #endif - - #elif DISABLED(NEWPANEL) // old style ULTIPANEL - // Shift register bits correspond to buttons: - #define BL_LE 7 // Left - #define BL_UP 6 // Up - #define BL_MI 5 // Middle - #define BL_DW 4 // Down - #define BL_RI 3 // Right - #define BL_ST 2 // Red Button - #define B_LE (_BV(BL_LE)) - #define B_UP (_BV(BL_UP)) - #define B_MI (_BV(BL_MI)) - #define B_DW (_BV(BL_DW)) - #define B_RI (_BV(BL_RI)) - #define B_ST (_BV(BL_ST)) - #define LCD_CLICKED() (buttons & (B_MI|B_ST)) - #endif - -#endif // HAS_LCD_MENU - //////////////////////////////////// // Create LCD class instance and chipset-specific information #if ENABLED(LCD_I2C_TYPE_PCF8575) @@ -122,7 +58,7 @@ #define LCD_CLASS LiquidCrystal_I2C #elif ENABLED(LCD_I2C_TYPE_MCP23017) - // For the LED indicators (which may be mapped to different events in lcd_implementation_update_indicators()) + // For the LED indicators (which may be mapped to different events in update_indicators()) #define LCD_HAS_STATUS_INDICATORS #define LED_A 0x04 //100 #define LED_B 0x02 //010 diff --git a/Marlin/src/lcd/HD44780/ultralcd_impl_HD44780.cpp b/Marlin/src/lcd/HD44780/ultralcd_impl_HD44780.cpp index f235366d29..edd38fb867 100644 --- a/Marlin/src/lcd/HD44780/ultralcd_impl_HD44780.cpp +++ b/Marlin/src/lcd/HD44780/ultralcd_impl_HD44780.cpp @@ -86,10 +86,6 @@ #endif -#if ENABLED(LCD_HAS_STATUS_INDICATORS) - static void lcd_implementation_update_indicators(); -#endif - static void createChar_P(const char c, const byte * const ptr) { byte temp[8]; for (uint8_t i = 0; i < 8; i++) @@ -101,7 +97,7 @@ static void createChar_P(const char c, const byte * const ptr) { #define LCD_STR_PROGRESS "\x03\x04\x05" #endif -void lcd_set_custom_characters( +void MarlinUI::set_custom_characters( #if ENABLED(LCD_PROGRESS_BAR) || ENABLED(SHOW_BOOTSCREEN) const HD44780CharSet screen_charset/*=CHARSET_INFO*/ #endif @@ -319,7 +315,7 @@ void lcd_set_custom_characters( } -void lcd_implementation_init() { +void MarlinUI::init_lcd() { #if ENABLED(LCD_I2C_TYPE_PCF8575) lcd.begin(LCD_WIDTH, LCD_HEIGHT); @@ -331,7 +327,7 @@ void lcd_implementation_init() { #elif ENABLED(LCD_I2C_TYPE_MCP23017) lcd.setMCPType(LTI_TYPE_MCP23017); lcd.begin(LCD_WIDTH, LCD_HEIGHT); - lcd_implementation_update_indicators(); + update_indicators(); #elif ENABLED(LCD_I2C_TYPE_MCP23008) lcd.setMCPType(LTI_TYPE_MCP23008); @@ -345,12 +341,12 @@ void lcd_implementation_init() { lcd.begin(LCD_WIDTH, LCD_HEIGHT); #endif - LCD_SET_CHARSET(currentScreen == lcd_status_screen ? CHARSET_INFO : CHARSET_MENU); + LCD_SET_CHARSET(on_status_screen() ? CHARSET_INFO : CHARSET_MENU); lcd.clear(); } -void lcd_implementation_clear() { lcd.clear(); } +void MarlinUI::clear_lcd() { lcd.clear(); } #if ENABLED(SHOW_BOOTSCREEN) @@ -408,7 +404,7 @@ void lcd_implementation_clear() { lcd.clear(); } lcd_moveto(indent, 2); lcd_put_wchar('\x02'); lcd_put_u8str_P(PSTR( "------" )); lcd_put_wchar('\x03'); } - void lcd_bootscreen() { + void MarlinUI::show_bootscreen() { LCD_SET_CHARSET(CHARSET_BOOT); lcd.clear(); @@ -454,6 +450,9 @@ void lcd_implementation_clear() { lcd.clear(); } CENTER_OR_SCROLL(STRING_SPLASH_LINE1, _SPLASH_WAIT_1); #ifdef STRING_SPLASH_LINE2 CENTER_OR_SCROLL(STRING_SPLASH_LINE2, 1500); + #ifdef STRING_SPLASH_LINE3 + CENTER_OR_SCROLL(STRING_SPLASH_LINE3, 1500); + #endif #endif } #elif defined(STRING_SPLASH_LINE2) @@ -484,9 +483,9 @@ void lcd_implementation_clear() { lcd.clear(); } #endif // SHOW_BOOTSCREEN -void lcd_kill_screen() { +void MarlinUI::draw_kill_screen() { lcd_moveto(0, 0); - lcd_put_u8str(lcd_status_message); + lcd_put_u8str(status_message); #if LCD_HEIGHT < 4 lcd_moveto(0, 2); #else @@ -572,13 +571,7 @@ FORCE_INLINE void _draw_bed_status(const bool blink) { #if HAS_PRINT_PROGRESS FORCE_INLINE void _draw_print_progress() { - const uint8_t percent = ( - #if ENABLED(SDSUPPORT) - IS_SD_PRINTING() ? card.percentDone() : 0 - #else - progress_bar_percent - #endif - ); + const uint8_t progress = ui.get_progress(); lcd_put_u8str_P(PSTR( #if ENABLED(SDSUPPORT) "SD" @@ -586,8 +579,8 @@ FORCE_INLINE void _draw_bed_status(const bool blink) { "P:" #endif )); - if (percent) - lcd_put_u8str(itostr3(percent)); + if (progress) + lcd_put_u8str(itostr3(progress)); else lcd_put_u8str_P(PSTR("---")); lcd_put_wchar('%'); @@ -616,7 +609,7 @@ FORCE_INLINE void _draw_bed_status(const bool blink) { #endif // LCD_PROGRESS_BAR -FORCE_INLINE void _draw_status_message(const bool blink) { +void MarlinUI::draw_status_message(const bool blink) { lcd_moveto(0, LCD_HEIGHT - 1); @@ -624,17 +617,15 @@ FORCE_INLINE void _draw_status_message(const bool blink) { // Draw the progress bar if the message has shown long enough // or if there is no message set. - #if DISABLED(LCD_SET_PROGRESS_MANUALLY) - const uint8_t progress_bar_percent = card.percentDone(); - #endif - if (progress_bar_percent > 2 && (ELAPSED(millis(), progress_bar_ms + PROGRESS_BAR_MSG_TIME) || !lcd_status_message[0])) - return lcd_draw_progress_bar(progress_bar_percent); + if (ELAPSED(millis(), progress_bar_ms + PROGRESS_BAR_MSG_TIME) || !has_status()) { + const uint8_t progress = get_progress(); + if (progress > 2) return lcd_draw_progress_bar(progress); + } #elif ENABLED(FILAMENT_LCD_DISPLAY) && ENABLED(SDSUPPORT) - // Show Filament Diameter and Volumetric Multiplier % - // After allowing lcd_status_message to show for 5 seconds - if (ELAPSED(millis(), previous_lcd_status_ms + 5000UL)) { + // Alternate Status message and Filament display + if (ELAPSED(millis(), next_filament_display)) { lcd_put_u8str_P(PSTR("Dia ")); lcd_put_u8str(ftostr12ns(filament_width_meas)); lcd_put_u8str_P(PSTR(" V")); @@ -654,13 +645,13 @@ FORCE_INLINE void _draw_status_message(const bool blink) { static bool last_blink = false; // Get the UTF8 character count of the string - uint8_t slen = utf8_strlen(lcd_status_message); + uint8_t slen = utf8_strlen(status_message); // If the string fits into the LCD, just print it and do not scroll it if (slen <= LCD_WIDTH) { // The string isn't scrolling and may not fill the screen - lcd_put_u8str(lcd_status_message); + lcd_put_u8str(status_message); // Fill the rest with spaces while (slen < LCD_WIDTH) { @@ -672,7 +663,7 @@ FORCE_INLINE void _draw_status_message(const bool blink) { // String is larger than the available space in screen. // Get a pointer to the next valid UTF8 character - const char *stat = lcd_status_message + status_scroll_offset; + const char *stat = status_message + status_scroll_offset; // Get the string remaining length const uint8_t rlen = utf8_strlen(stat); @@ -692,7 +683,7 @@ FORCE_INLINE void _draw_status_message(const bool blink) { if (--chars) { // Draw a second dot if there's space lcd_put_wchar('.'); if (--chars) - lcd_put_u8str_max(lcd_status_message, chars); // Print a second copy of the message + lcd_put_u8str_max(status_message, chars); // Print a second copy of the message } } if (last_blink != blink) { @@ -701,7 +692,7 @@ FORCE_INLINE void _draw_status_message(const bool blink) { // Adjust by complete UTF8 characters if (status_scroll_offset < slen) { status_scroll_offset++; - while (!START_OF_UTF8_CHAR(lcd_status_message[status_scroll_offset])) + while (!START_OF_UTF8_CHAR(status_message[status_scroll_offset])) status_scroll_offset++; } else @@ -712,10 +703,10 @@ FORCE_INLINE void _draw_status_message(const bool blink) { UNUSED(blink); // Get the UTF8 character count of the string - uint8_t slen = utf8_strlen(lcd_status_message); + uint8_t slen = utf8_strlen(status_message); // Just print the string to the LCD - lcd_put_u8str_max(lcd_status_message, LCD_WIDTH); + lcd_put_u8str_max(status_message, LCD_WIDTH); // Fill the rest with spaces if there are missing spaces while (slen < LCD_WIDTH) { @@ -725,35 +716,47 @@ FORCE_INLINE void _draw_status_message(const bool blink) { #endif } -#if LCD_INFO_SCREEN_STYLE == 0 +/** + * LCD_INFO_SCREEN_STYLE 0 : Classic Status Screen + * + * 16x2 |000/000 B000/000| + * |0123456789012345| + * + * 16x4 |000/000 B000/000| + * |SD---% Z 000.00| + * |F---% T--:--| + * |0123456789012345| + * + * 20x2 |T000/000° B000/000° | + * |01234567890123456789| + * + * 20x4 |T000/000° B000/000° | + * |X 000 Y 000 Z000.000| + * |F---% SD---% T--:--| + * |01234567890123456789| + * + * LCD_INFO_SCREEN_STYLE 1 : Prusa-style Status Screen + * + * |T000/000° Z 000.00 | + * |B000/000° F---% | + * |SD---% T--:-- | + * |01234567890123456789| + * + * |T000/000° Z 000.00 | + * |T000/000° F---% | + * |B000/000° SD---% | + * |01234567890123456789| + */ - /** - * LCD_INFO_SCREEN_STYLE 0 : Classic Status Screen - * - * 16x2 |000/000 B000/000| - * |0123456789012345| - * - * 16x4 |000/000 B000/000| - * |SD---% Z 000.00| - * |F---% T--:--| - * |0123456789012345| - * - * 20x2 |T000/000° B000/000° | - * |01234567890123456789| - * - * 20x4 |T000/000° B000/000° | - * |X 000 Y 000 Z000.000| - * |F---% SD---% T--:--| - * |01234567890123456789| - */ +void MarlinUI::draw_status_screen() { - void lcd_impl_status_screen_0() { - const bool blink = lcd_blink(); + const bool blink = get_blink(); + lcd_moveto(0, 0); + + #if LCD_INFO_SCREEN_STYLE == 0 // ========== Line 1 ========== - lcd_moveto(0, 0); - #if LCD_WIDTH < 20 // @@ -885,39 +888,13 @@ FORCE_INLINE void _draw_status_message(const bool blink) { #endif // LCD_HEIGHT > 3 - // ========= Last Line ======== - - // - // Status Message (which may be a Progress Bar or Filament display) - // - _draw_status_message(blink); - } - -#elif LCD_INFO_SCREEN_STYLE == 1 - - /** - * LCD_INFO_SCREEN_STYLE 1 : Prusa-style Status Screen - * - * |T000/000° Z 000.00 | - * |B000/000° F---% | - * |SD---% T--:-- | - * |01234567890123456789| - * - * |T000/000° Z 000.00 | - * |T000/000° F---% | - * |B000/000° SD---% | - * |01234567890123456789| - */ - - void lcd_impl_status_screen_1() { - const bool blink = lcd_blink(); + #elif LCD_INFO_SCREEN_STYLE == 1 // ========== Line 1 ========== // // Hotend 0 Temperature // - lcd_moveto(0, 0); _draw_heater_status(0, LCD_STR_THERMOMETER[0], blink); // @@ -977,30 +954,30 @@ FORCE_INLINE void _draw_status_message(const bool blink) { lcd_put_u8str(buffer); #endif - // ========== Line 4 ========== + #endif // LCD_INFO_SCREEN_STYLE 1 - // - // Status Message (which may be a Progress Bar or Filament display) - // - _draw_status_message(blink); - } + // ========= Last Line ======== -#endif + // + // Status Message (which may be a Progress Bar or Filament display) + // + draw_status_message(blink); +} #if HAS_LCD_MENU #if ENABLED(ADVANCED_PAUSE_FEATURE) - void lcd_implementation_hotend_status(const uint8_t row, const uint8_t extruder) { + void MarlinUI::draw_hotend_status(const uint8_t row, const uint8_t extruder) { if (row < LCD_HEIGHT) { lcd_moveto(LCD_WIDTH - 9, row); - _draw_heater_status(extruder, LCD_STR_THERMOMETER[0], lcd_blink()); + _draw_heater_status(extruder, LCD_STR_THERMOMETER[0], ui.get_blink()); } } #endif // ADVANCED_PAUSE_FEATURE - void lcd_implementation_drawmenu_static(const uint8_t row, PGM_P pstr, const bool center/*=true*/, const bool invert/*=false*/, const char *valstr/*=NULL*/) { + void draw_menu_item_static(const uint8_t row, PGM_P pstr, const bool center/*=true*/, const bool invert/*=false*/, const char *valstr/*=NULL*/) { UNUSED(invert); int8_t n = LCD_WIDTH; lcd_moveto(0, row); @@ -1013,35 +990,35 @@ FORCE_INLINE void _draw_status_message(const bool blink) { for (; n > 0; --n) lcd_put_wchar(' '); } - void lcd_implementation_drawmenu_generic(const bool sel, const uint8_t row, PGM_P pstr, const char pre_char, const char post_char) { + void draw_menu_item_generic(const bool isSelected, const uint8_t row, PGM_P pstr, const char pre_char, const char post_char) { uint8_t n = LCD_WIDTH - 2; lcd_moveto(0, row); - lcd_put_wchar(sel ? pre_char : ' '); + lcd_put_wchar(isSelected ? pre_char : ' '); n -= lcd_put_u8str_max_P(pstr, n); while (n--) lcd_put_wchar(' '); lcd_put_wchar(post_char); } - void lcd_implementation_drawmenu_setting_edit_generic(const bool sel, const uint8_t row, PGM_P pstr, const char pre_char, const char* const data) { + void draw_menu_item_setting_edit_generic(const bool isSelected, const uint8_t row, PGM_P pstr, const char pre_char, const char* const data) { uint8_t n = LCD_WIDTH - 2 - utf8_strlen(data); lcd_moveto(0, row); - lcd_put_wchar(sel ? pre_char : ' '); + lcd_put_wchar(isSelected ? pre_char : ' '); n -= lcd_put_u8str_max_P(pstr, n); lcd_put_wchar(':'); while (n--) lcd_put_wchar(' '); lcd_put_u8str(data); } - void lcd_implementation_drawmenu_setting_edit_generic_P(const bool sel, const uint8_t row, PGM_P pstr, const char pre_char, const char* const data) { + void draw_menu_item_setting_edit_generic_P(const bool isSelected, const uint8_t row, PGM_P pstr, const char pre_char, const char* const data) { uint8_t n = LCD_WIDTH - 2 - utf8_strlen_P(data); lcd_moveto(0, row); - lcd_put_wchar(sel ? pre_char : ' '); + lcd_put_wchar(isSelected ? pre_char : ' '); n -= lcd_put_u8str_max_P(pstr, n); lcd_put_wchar(':'); while (n--) lcd_put_wchar(' '); lcd_put_u8str_P(data); } - void lcd_implementation_drawedit(PGM_P pstr, const char* const value/*=NULL*/) { + void draw_edit_screen(PGM_P const pstr, const char* const value/*=NULL*/) { lcd_moveto(1, 1); lcd_put_u8str_P(pstr); if (value != NULL) { @@ -1056,27 +1033,29 @@ FORCE_INLINE void _draw_status_message(const bool blink) { #if ENABLED(SDSUPPORT) - static void lcd_implementation_drawmenu_sd(const bool sel, const uint8_t row, PGM_P const pstr, CardReader &theCard, const uint8_t concat, const char post_char) { + void draw_sd_menu_item(const bool isSelected, const uint8_t row, PGM_P const pstr, CardReader &theCard, const bool isDir) { + const char post_char = isDir ? LCD_STR_FOLDER[0] : ' ', + sel_char = isSelected ? '>' : ' '; UNUSED(pstr); lcd_moveto(0, row); - lcd_put_wchar(sel ? '>' : ' '); + lcd_put_wchar(sel_char); - uint8_t n = LCD_WIDTH - concat; + uint8_t n = LCD_WIDTH - 2; const char *outstr = theCard.longest_filename(); if (theCard.longFilename[0]) { #if ENABLED(SCROLL_LONG_FILENAMES) static uint8_t filename_scroll_hash; - if (sel) { + if (isSelected) { uint8_t name_hash = row; for (uint8_t l = FILENAME_LENGTH; l--;) name_hash = ((name_hash << 1) | (name_hash >> 7)) ^ theCard.filename[l]; // rotate, xor if (filename_scroll_hash != name_hash) { // If the hash changed... filename_scroll_hash = name_hash; // Save the new hash - filename_scroll_max = MAX(0, utf8_strlen(theCard.longFilename) - n); // Update the scroll limit - filename_scroll_pos = 0; // Reset scroll to the start - lcd_status_update_delay = 8; // Don't scroll right away + ui.filename_scroll_max = MAX(0, utf8_strlen(theCard.longFilename) - n); // Update the scroll limit + ui.filename_scroll_pos = 0; // Reset scroll to the start + ui.lcd_status_update_delay = 8; // Don't scroll right away } - outstr += filename_scroll_pos; + outstr += ui.filename_scroll_pos; } #else theCard.longFilename[n] = '\0'; // cutoff at screen edge @@ -1084,45 +1063,18 @@ FORCE_INLINE void _draw_status_message(const bool blink) { } lcd_moveto(0, row); - lcd_put_wchar(sel ? '>' : ' '); + lcd_put_wchar(sel_char); n -= lcd_put_u8str_max(outstr, n); - while (n) { --n; lcd_put_wchar(' '); } + for (; n; --n) lcd_put_wchar(' '); lcd_put_wchar(post_char); } - void lcd_implementation_drawmenu_sdfile(const bool sel, const uint8_t row, PGM_P pstr, CardReader &theCard) { - lcd_implementation_drawmenu_sd(sel, row, pstr, theCard, 2, ' '); - } - - void lcd_implementation_drawmenu_sddirectory(const bool sel, const uint8_t row, PGM_P pstr, CardReader &theCard) { - lcd_implementation_drawmenu_sd(sel, row, pstr, theCard, 2, LCD_STR_FOLDER[0]); - } - #endif // SDSUPPORT - #if ENABLED(LCD_HAS_SLOW_BUTTONS) - - extern millis_t next_button_update_ms; - - static uint8_t lcd_implementation_read_slow_buttons() { - #if ENABLED(LCD_I2C_TYPE_MCP23017) - // Reading these buttons this is likely to be too slow to call inside interrupt context - // so they are called during normal lcd_update - uint8_t slow_bits = lcd.readButtons() << B_I2C_BTN_OFFSET; - #if ENABLED(LCD_I2C_VIKI) - if ((slow_bits & (B_MI | B_RI)) && PENDING(millis(), next_button_update_ms)) // LCD clicked - slow_bits &= ~(B_MI | B_RI); // Disable LCD clicked buttons if screen is updated - #endif // LCD_I2C_VIKI - return slow_bits; - #endif // LCD_I2C_TYPE_MCP23017 - } - - #endif // LCD_HAS_SLOW_BUTTONS - #if ENABLED(LCD_HAS_STATUS_INDICATORS) - static void lcd_implementation_update_indicators() { + static void MarlinUI::update_indicators() { // Set the LEDS - referred to as backlights by the LiquidTWI2 library static uint8_t ledsprev = 0; uint8_t leds = 0; @@ -1242,7 +1194,7 @@ FORCE_INLINE void _draw_status_message(const bool blink) { lcd_put_wchar(c); } - void lcd_implementation_ubl_plot(const uint8_t x, const uint8_t inverted_y) { + void MarlinUI::ubl_plot(const uint8_t x, const uint8_t inverted_y) { #if LCD_WIDTH >= 20 #define _LCD_W_POS 12 @@ -1292,7 +1244,7 @@ FORCE_INLINE void _draw_status_message(const bool blink) { lower_right.column = 0; lower_right.row = 0; - lcd_implementation_clear(); + clear_lcd(); x_map_pixels = (HD44780_CHAR_WIDTH) * (MESH_MAP_COLS) - 2; // Minus 2 because we are drawing a box around the map y_map_pixels = (HD44780_CHAR_HEIGHT) * (MESH_MAP_ROWS) - 2; diff --git a/Marlin/src/lcd/dogm/status_screen_DOGM.cpp b/Marlin/src/lcd/dogm/status_screen_DOGM.cpp index c49fa50a05..af209a07df 100644 --- a/Marlin/src/lcd/dogm/status_screen_DOGM.cpp +++ b/Marlin/src/lcd/dogm/status_screen_DOGM.cpp @@ -135,35 +135,29 @@ FORCE_INLINE void _draw_axis_value(const AxisEnum axis, const char *value, const } } -FORCE_INLINE void lcd_implementation_status_message(const bool blink) { +void MarlinUI::draw_status_message(const bool blink) { + + // Get the UTF8 character count of the string + uint8_t slen = utf8_strlen(status_message); + #if ENABLED(STATUS_MESSAGE_SCROLLING) + static bool last_blink = false; - // Get the UTF8 character count of the string - uint8_t slen = utf8_strlen(lcd_status_message); - - // If the string fits into the LCD, just print it and do not scroll it if (slen <= LCD_WIDTH) { - - // The string isn't scrolling and may not fill the screen - lcd_put_u8str(lcd_status_message); - - // Fill the rest with spaces - while (slen < LCD_WIDTH) { - lcd_put_wchar(' '); - ++slen; - } + // The string fits within the line. Print with no scrolling + lcd_put_u8str(status_message); + for (; slen < LCD_WIDTH; ++slen) lcd_put_wchar(' '); } else { - // String is larger than the available space in screen. + // String is longer than the available space // Get a pointer to the next valid UTF8 character - const char *stat = lcd_status_message + status_scroll_offset; + const char *stat = status_message + status_scroll_offset; // Get the string remaining length const uint8_t rlen = utf8_strlen(stat); - // If we have enough characters to display if (rlen >= LCD_WIDTH) { // The remaining string fills the screen - Print it lcd_put_u8str_max(stat, LCD_PIXEL_WIDTH); @@ -178,7 +172,7 @@ FORCE_INLINE void lcd_implementation_status_message(const bool blink) { lcd_put_wchar('.'); if (--chars) { // Print a second copy of the message - lcd_put_u8str_max(lcd_status_message, LCD_PIXEL_WIDTH - ((rlen+2) * MENU_FONT_WIDTH)); + lcd_put_u8str_max(status_message, LCD_PIXEL_WIDTH - (rlen + 2) * (MENU_FONT_WIDTH)); } } } @@ -188,36 +182,33 @@ FORCE_INLINE void lcd_implementation_status_message(const bool blink) { // Adjust by complete UTF8 characters if (status_scroll_offset < slen) { status_scroll_offset++; - while (!START_OF_UTF8_CHAR(lcd_status_message[status_scroll_offset])) + while (!START_OF_UTF8_CHAR(status_message[status_scroll_offset])) status_scroll_offset++; } else status_scroll_offset = 0; } } - #else + + #else // !STATUS_MESSAGE_SCROLLING + UNUSED(blink); - // Get the UTF8 character count of the string - uint8_t slen = utf8_strlen(lcd_status_message); - // Just print the string to the LCD - lcd_put_u8str_max(lcd_status_message, LCD_PIXEL_WIDTH); + lcd_put_u8str_max(status_message, LCD_PIXEL_WIDTH); - // Fill the rest with spaces if there are missing spaces - while (slen < LCD_WIDTH) { - lcd_put_wchar(' '); - ++slen; - } - #endif + // Fill the rest with spaces + for (; slen < LCD_WIDTH; ++slen) lcd_put_wchar(' '); + + #endif // !STATUS_MESSAGE_SCROLLING } -void lcd_impl_status_screen_0() { +void MarlinUI::draw_status_screen() { - const bool blink = lcd_blink(); + const bool blink = get_blink(); // Status Menu Font - lcd_setFont(FONT_STATUSMENU); + set_font(FONT_STATUSMENU); // // Fan Animation @@ -318,11 +309,9 @@ void lcd_impl_status_screen_0() { PROGRESS_BAR_WIDTH, 4 ); - #if DISABLED(LCD_SET_PROGRESS_MANUALLY) - const uint8_t progress_bar_percent = card.percentDone(); - #endif + const uint8_t progress = get_progress(); - if (progress_bar_percent > 1) { + if (progress > 1) { // // Progress bar solid part @@ -331,7 +320,7 @@ void lcd_impl_status_screen_0() { if (PAGE_CONTAINS(50, 51)) // 50-51 (or just 50) u8g.drawBox( PROGRESS_BAR_X + 1, 50, - (uint16_t)((PROGRESS_BAR_WIDTH - 2) * progress_bar_percent * 0.01), 2 + (uint16_t)((PROGRESS_BAR_WIDTH - 2) * progress * 0.01), 2 ); // @@ -342,7 +331,7 @@ void lcd_impl_status_screen_0() { if (PAGE_CONTAINS(41, 48)) { // Percent complete lcd_moveto(55, 48); - lcd_put_u8str(itostr3(progress_bar_percent)); + lcd_put_u8str(itostr3(progress)); lcd_put_wchar('%'); } #endif @@ -449,11 +438,11 @@ void lcd_impl_status_screen_0() { #define EXTRAS_BASELINE 50 if (PAGE_CONTAINS(EXTRAS_BASELINE - (INFO_FONT_HEIGHT - 1), EXTRAS_BASELINE)) { - lcd_setFont(FONT_MENU); + set_font(FONT_MENU); lcd_moveto(3, EXTRAS_BASELINE); lcd_put_wchar(LCD_STR_FEEDRATE[0]); - lcd_setFont(FONT_STATUSMENU); + set_font(FONT_STATUSMENU); lcd_moveto(12, EXTRAS_BASELINE); lcd_put_u8str(itostr3(feedrate_percentage)); lcd_put_wchar('%'); @@ -467,7 +456,7 @@ void lcd_impl_status_screen_0() { lcd_moveto(102, EXTRAS_BASELINE); lcd_put_u8str(mstring); lcd_put_wchar('%'); - lcd_setFont(FONT_MENU); + set_font(FONT_MENU); lcd_moveto(47, EXTRAS_BASELINE); lcd_put_wchar(LCD_STR_FILAM_DIA[0]); // lcd_put_u8str_P(PSTR(LCD_STR_FILAM_DIA)); lcd_moveto(93, EXTRAS_BASELINE); @@ -485,9 +474,9 @@ void lcd_impl_status_screen_0() { lcd_moveto(0, STATUS_BASELINE); #if ENABLED(FILAMENT_LCD_DISPLAY) && ENABLED(SDSUPPORT) - if (PENDING(millis(), previous_lcd_status_ms + 5000UL)) { //Display both Status message line and Filament display on the last line - lcd_implementation_status_message(blink); - } + // Alternate Status message and Filament display + if (PENDING(millis(), next_filament_display)) + draw_status_message(blink); else { lcd_put_u8str_P(PSTR(LCD_STR_FILAM_DIA)); lcd_put_wchar(':'); @@ -498,7 +487,7 @@ void lcd_impl_status_screen_0() { lcd_put_wchar('%'); } #else - lcd_implementation_status_message(blink); + draw_status_message(blink); #endif } } diff --git a/Marlin/src/lcd/dogm/status_screen_lite_ST7920.cpp b/Marlin/src/lcd/dogm/status_screen_lite_ST7920.cpp index 515adb9389..40c47868f9 100644 --- a/Marlin/src/lcd/dogm/status_screen_lite_ST7920.cpp +++ b/Marlin/src/lcd/dogm/status_screen_lite_ST7920.cpp @@ -230,12 +230,8 @@ void ST7920_Lite_Status_Screen::load_cgram_icon(const uint16_t addr, const void */ void ST7920_Lite_Status_Screen::draw_gdram_icon(uint8_t x, uint8_t y, const void *data) { const uint16_t *p_word = (const uint16_t *)data; - if (y > 2) { // Handle display folding - y -= 2; - x += 8; - } - --x; - --y; + // Handle display folding + if (y > 1) y -= 2, x += 8; for (int i = 0; i < 16; i++) { set_gdram_address(x, i + y * 16); begin_data(); @@ -398,24 +394,20 @@ const uint16_t feedrate_icon[] PROGMEM = { /************************** MAIN SCREEN *************************************/ -// The ST7920 does not have a degree character, but we -// can fake it by writing it to GDRAM. -// This function takes as an argument character positions -// i.e x is [1-16], while the y position is [1-4] -void ST7920_Lite_Status_Screen::draw_degree_symbol(uint8_t x, uint8_t y, bool draw) { +/** + * The ST7920 has no degree character, so draw it to GDRAM. + * This function takes character position xy + * i.e., x is [0-15], while the y position is [0-3] + */ +void ST7920_Lite_Status_Screen::draw_degree_symbol(uint8_t x, uint8_t y, const bool draw) { const uint8_t *p_bytes = degree_symbol; - if (y > 2) { - // Handle display folding - y -= 2; - x += 16; - } - x -= 1; - y -= 1; + // Handle display folding + if (y > 1) y -= 2, x += 16; const bool oddChar = x & 1; - const uint8_t x_word = x >> 1; - const uint8_t y_top = degree_symbol_y_top; - const uint8_t y_bot = y_top + sizeof(degree_symbol)/sizeof(degree_symbol[0]); - for(uint8_t i = y_top; i < y_bot; i++) { + const uint8_t x_word = x >> 1, + y_top = degree_symbol_y_top, + y_bot = y_top + sizeof(degree_symbol)/sizeof(degree_symbol[0]); + for (uint8_t i = y_top; i < y_bot; i++) { uint8_t byte = pgm_read_byte(p_bytes++); set_gdram_address(x_word, i + y * 16); begin_data(); @@ -438,14 +430,14 @@ void ST7920_Lite_Status_Screen::draw_static_elements() { load_cgram_icon(CGRAM_ICON_4_ADDR, fan2_icon); // Draw the static icons in GDRAM - draw_gdram_icon(1, 1, nozzle_icon); + draw_gdram_icon(0, 0, nozzle_icon); #if HOTENDS > 1 - draw_gdram_icon(1,2,nozzle_icon); - draw_gdram_icon(1,3,bed_icon); + draw_gdram_icon(0, 1, nozzle_icon); + draw_gdram_icon(0, 2, bed_icon); #else - draw_gdram_icon(1,2,bed_icon); + draw_gdram_icon(0, 1, bed_icon); #endif - draw_gdram_icon(6,2,feedrate_icon); + draw_gdram_icon(5, 1, feedrate_icon); // Draw the initial fan icon draw_fan_icon(false); @@ -462,15 +454,15 @@ void ST7920_Lite_Status_Screen::draw_static_elements() { void ST7920_Lite_Status_Screen::draw_progress_bar(const uint8_t value) { #if HOTENDS == 1 // If we have only one extruder, draw a long progress bar on the third line - const uint8_t top = 1, // Top in pixels - bottom = 13, // Bottom in pixels - left = 12, // Left edge, in 16-bit words - width = 4; // Width of progress bar, in 16-bit words + constexpr uint8_t top = 1, // Top in pixels + bottom = 13, // Bottom in pixels + left = 12, // Left edge, in 16-bit words + width = 4; // Width of progress bar, in 16-bit words #else - const uint8_t top = 16 + 1, - bottom = 16 + 13, - left = 5, - width = 3; + constexpr uint8_t top = 16 + 1, + bottom = 16 + 13, + left = 5, + width = 3; #endif const uint8_t char_pcnt = 100 / width; // How many percent does each 16-bit word represent? @@ -557,10 +549,10 @@ static struct { void ST7920_Lite_Status_Screen::draw_temps(uint8_t line, const int16_t temp, const int16_t target, bool showTarget, bool targetStateChange) { switch (line) { - case 1: set_ddram_address(DDRAM_LINE_1 + 1); break; - case 2: set_ddram_address(DDRAM_LINE_2 + 1); break; + case 0: set_ddram_address(DDRAM_LINE_1 + 1); break; + case 1: set_ddram_address(DDRAM_LINE_2 + 1); break; + case 2: set_ddram_address(DDRAM_LINE_3 + 1); break; case 3: set_ddram_address(DDRAM_LINE_3 + 1); break; - case 4: set_ddram_address(DDRAM_LINE_3 + 1); break; } begin_data(); write_number(temp); @@ -572,27 +564,27 @@ void ST7920_Lite_Status_Screen::draw_temps(uint8_t line, const int16_t temp, con if (targetStateChange) { if (!showTarget) write_str(F(" ")); - draw_degree_symbol(6, line, !showTarget); - draw_degree_symbol(10, line, showTarget); + draw_degree_symbol(5, line, !showTarget); + draw_degree_symbol(9, line, showTarget); } } void ST7920_Lite_Status_Screen::draw_extruder_1_temp(const int16_t temp, const int16_t target, bool forceUpdate) { const bool show_target = target && FAR(temp, target); - draw_temps(1, temp, target, show_target, display_state.E1_show_target != show_target || forceUpdate); + draw_temps(0, temp, target, show_target, display_state.E1_show_target != show_target || forceUpdate); display_state.E1_show_target = show_target; } void ST7920_Lite_Status_Screen::draw_extruder_2_temp(const int16_t temp, const int16_t target, bool forceUpdate) { const bool show_target = target && FAR(temp, target); - draw_temps(2, temp, target, show_target, display_state.E2_show_target != show_target || forceUpdate); + draw_temps(1, temp, target, show_target, display_state.E2_show_target != show_target || forceUpdate); display_state.E2_show_target = show_target; } #if HAS_HEATED_BED void ST7920_Lite_Status_Screen::draw_bed_temp(const int16_t temp, const int16_t target, bool forceUpdate) { const bool show_target = target && FAR(temp, target); - draw_temps(2 + draw_temps(1 #if HOTENDS > 1 + 1 #endif @@ -632,44 +624,38 @@ void ST7920_Lite_Status_Screen::draw_feedrate_percentage(const uint16_t percenta #endif } -void ST7920_Lite_Status_Screen::draw_status_message(const char *str) { +void ST7920_Lite_Status_Screen::draw_status_message() { + const char *str = ui.status_message; + set_ddram_address(DDRAM_LINE_4); begin_data(); - const uint8_t lcd_len = 16; #if ENABLED(STATUS_MESSAGE_SCROLLING) uint8_t slen = utf8_strlen(str); - // If the string fits into the LCD, just print it and do not scroll it - if (slen <= lcd_len) { - - // The string isn't scrolling and may not fill the screen + if (slen <= LCD_WIDTH) { + // String fits the LCD, so just print it write_str(str); - - // Fill the rest with spaces - while (slen < lcd_len) { - write_byte(' '); - ++slen; - } + for (; slen < LCD_WIDTH; ++slen) write_byte(' '); } else { // String is larger than the available space in screen. // Get a pointer to the next valid UTF8 character - const char *stat = str + status_scroll_offset; + const char *stat = str + ui.status_scroll_offset; // Get the string remaining length const uint8_t rlen = utf8_strlen(stat); // If we have enough characters to display - if (rlen >= lcd_len) { + if (rlen >= LCD_WIDTH) { // The remaining string fills the screen - Print it - write_str(stat, lcd_len); + write_str(stat, LCD_WIDTH); } else { // The remaining string does not completely fill the screen write_str(stat); // The string leaves space - uint8_t chars = lcd_len - rlen; // Amount of space left in characters + uint8_t chars = LCD_WIDTH - rlen; // Amount of space left in characters write_byte('.'); // Always at 1+ spaces left, draw a dot if (--chars) { // Draw a second dot if there's space @@ -680,26 +666,21 @@ void ST7920_Lite_Status_Screen::draw_status_message(const char *str) { } // Adjust by complete UTF8 characters - if (status_scroll_offset < slen) { - status_scroll_offset++; - while (!START_OF_UTF8_CHAR(str[status_scroll_offset])) - status_scroll_offset++; + if (ui.status_scroll_offset < slen) { + ui.status_scroll_offset++; + while (!START_OF_UTF8_CHAR(str[ui.status_scroll_offset])) + ui.status_scroll_offset++; } else - status_scroll_offset = 0; + ui.status_scroll_offset = 0; } + #else - // Get the UTF8 character count of the string + uint8_t slen = utf8_strlen(str); + write_str(str, LCD_WIDTH); + for (; slen < LCD_WIDTH; ++slen) write_byte(' '); - // Just print the string to the LCD - write_str(str, lcd_len); - - // Fill the rest with spaces if there are missing spaces - while (slen < lcd_len) { - write_byte(' '); - ++slen; - } #endif } @@ -709,7 +690,7 @@ void ST7920_Lite_Status_Screen::draw_position(const float x, const float y, cons begin_data(); // If position is unknown, flash the labels. - const unsigned char alt_label = position_known ? 0 : (lcd_blink() ? ' ' : 0); + const unsigned char alt_label = position_known ? 0 : (ui.get_blink() ? ' ' : 0); dtostrf(x, -4, 0, str); write_byte(alt_label ? alt_label : 'X'); @@ -728,7 +709,7 @@ bool ST7920_Lite_Status_Screen::indicators_changed() { // We only add the target temperatures to the checksum // because the actual temps fluctuate so by updating // them only during blinks we gain a bit of stability. - const bool blink = lcd_blink(); + const bool blink = ui.get_blink(); const uint16_t feedrate_perc = feedrate_percentage; const uint8_t fs = (((uint16_t)fan_speed[0] + 1) * 100) / 256; const int16_t extruder_1_target = thermalManager.degTargetHotend(0); @@ -754,7 +735,7 @@ bool ST7920_Lite_Status_Screen::indicators_changed() { void ST7920_Lite_Status_Screen::update_indicators(const bool forceUpdate) { if (forceUpdate || indicators_changed()) { - const bool blink = lcd_blink(); + const bool blink = ui.get_blink(); const duration_t elapsed = print_job_timer.duration(); const uint16_t feedrate_perc = feedrate_percentage; const uint8_t fs = (((uint16_t)fan_speed[0] + 1) * 100) / 256; @@ -783,41 +764,32 @@ void ST7920_Lite_Status_Screen::update_indicators(const bool forceUpdate) { // Update the fan and bed animations if (fs) draw_fan_icon(blink); #if HAS_HEATED_BED - if (bed_target > 0) - draw_heat_icon(blink, true); - else - draw_heat_icon(false, false); + draw_heat_icon(bed_target > 0 && blink, bed_target > 0); #endif } } bool ST7920_Lite_Status_Screen::position_changed() { - const float x_pos = current_position[X_AXIS], - y_pos = current_position[Y_AXIS], - z_pos = current_position[Z_AXIS]; + const float x_pos = current_position[X_AXIS], y_pos = current_position[Y_AXIS], z_pos = current_position[Z_AXIS]; const uint8_t checksum = uint8_t(x_pos) ^ uint8_t(y_pos) ^ uint8_t(z_pos); - - static uint8_t last_checksum = 0; - if (last_checksum == checksum) return false; - last_checksum = checksum; - return true; + static uint8_t last_checksum = 0, changed = last_checksum != checksum; + if (changed) last_checksum = checksum; + return changed; } bool ST7920_Lite_Status_Screen::status_changed() { uint8_t checksum = 0; - for (const char *p = lcd_status_message; *p; p++) checksum ^= *p; - static uint8_t last_checksum = 0; - if (last_checksum == checksum) return false; - last_checksum = checksum; - return true; + for (const char *p = ui.status_message; *p; p++) checksum ^= *p; + static uint8_t last_checksum = 0, changed = last_checksum != checksum; + if (changed) last_checksum = checksum; + return changed; } bool ST7920_Lite_Status_Screen::blink_changed() { static uint8_t last_blink = 0; - const bool blink = lcd_blink(); - if (last_blink == blink) return false; - last_blink = blink; - return true; + const bool blink = ui.get_blink(), changed = last_blink != blink; + if (changed) last_blink = blink; + return changed; } #ifndef STATUS_EXPIRE_SECONDS @@ -831,60 +803,56 @@ void ST7920_Lite_Status_Screen::update_status_or_position(bool forceUpdate) { #endif /** - * There is only enough room in the display for either the - * status message or the position, not both, so we choose - * one or another. Whenever the status message changes, - * we show it for a number of consecutive seconds, but - * then go back to showing the position as soon as the - * head moves, i.e: + * There's only enough room for either the status message or the position, + * so draw one or the other. When the status message changes, show it for + * a few seconds, then return to the position display once the head moves. * - * countdown > 1 -- Show status - * countdown = 1 -- Show status, until movement - * countdown = 0 -- Show position + * countdown > 1 -- Show status + * countdown = 1 -- Show status, until movement + * countdown = 0 -- Show position * - * If STATUS_EXPIRE_SECONDS is zero, the position display - * will be disabled and only the status will be shown. + * If STATUS_EXPIRE_SECONDS is zero, only the status is shown. */ if (forceUpdate || status_changed()) { #if ENABLED(STATUS_MESSAGE_SCROLLING) - status_scroll_offset = 0; + ui.status_scroll_offset = 0; #endif #if STATUS_EXPIRE_SECONDS - countdown = lcd_status_message[0] ? STATUS_EXPIRE_SECONDS : 0; + countdown = ui.status_message[0] ? STATUS_EXPIRE_SECONDS : 0; #endif - draw_status_message(lcd_status_message); + draw_status_message(); blink_changed(); // Clear changed flag } #if !STATUS_EXPIRE_SECONDS #if ENABLED(STATUS_MESSAGE_SCROLLING) else - draw_status_message(lcd_status_message); + draw_status_message(); #endif #else - else if (countdown > 1 && blink_changed()) { - countdown--; - #if ENABLED(STATUS_MESSAGE_SCROLLING) - draw_status_message(lcd_status_message); - #endif - } - else if (countdown > 0 && blink_changed()) { - if (position_changed()) { + else if (blink_changed()) { + if (countdown > 1) { countdown--; - forceUpdate = true; + #if ENABLED(STATUS_MESSAGE_SCROLLING) + draw_status_message(); + #endif + } + else if (countdown > 0) { + if (position_changed()) { + countdown--; + forceUpdate = true; + } + #if ENABLED(STATUS_MESSAGE_SCROLLING) + draw_status_message(); + #endif } - #if ENABLED(STATUS_MESSAGE_SCROLLING) - draw_status_message(lcd_status_message); - #endif } + if (countdown == 0 && (forceUpdate || position_changed() || #if DISABLED(DISABLE_REDUCED_ACCURACY_WARNING) blink_changed() #endif )) { - draw_position( - current_position[X_AXIS], - current_position[Y_AXIS], - current_position[Z_AXIS], + draw_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], #if ENABLED(DISABLE_REDUCED_ACCURACY_WARNING) true #else @@ -898,24 +866,16 @@ void ST7920_Lite_Status_Screen::update_status_or_position(bool forceUpdate) { void ST7920_Lite_Status_Screen::update_progress(const bool forceUpdate) { #if ENABLED(LCD_SET_PROGRESS_MANUALLY) || ENABLED(SDSUPPORT) - #if DISABLED(LCD_SET_PROGRESS_MANUALLY) - uint8_t progress_bar_percent = 0; - #endif - - #if ENABLED(SDSUPPORT) - // Progress bar % comes from SD when actively printing - if (IS_SD_PRINTING()) progress_bar_percent = card.percentDone(); - #endif - // Since the progress bar involves writing // quite a few bytes to GDRAM, only do this // when an update is actually necessary. static uint8_t last_progress = 0; - if (!forceUpdate && last_progress == progress_bar_percent) return; - last_progress = progress_bar_percent; - - draw_progress_bar(progress_bar_percent); + const uint8_t progress = ui.get_progress(); + if (forceUpdate || last_progress != progress) { + last_progress = progress; + draw_progress_bar(progress); + } #else @@ -966,7 +926,7 @@ void ST7920_Lite_Status_Screen::clear_text_buffer() { ncs(); } -void lcd_impl_status_screen_0() { +void MarlinUI::draw_status_screen() { ST7920_Lite_Status_Screen::update(false); } diff --git a/Marlin/src/lcd/dogm/status_screen_lite_ST7920_class.h b/Marlin/src/lcd/dogm/status_screen_lite_ST7920_class.h index 323d951c36..79cc1b1fd8 100644 --- a/Marlin/src/lcd/dogm/status_screen_lite_ST7920_class.h +++ b/Marlin/src/lcd/dogm/status_screen_lite_ST7920_class.h @@ -74,7 +74,7 @@ class ST7920_Lite_Status_Screen { static uint8_t string_checksum(const char *str); protected: - static void draw_degree_symbol(uint8_t x, uint8_t y, bool draw); + static void draw_degree_symbol(uint8_t x, uint8_t y, const bool draw); static void draw_static_elements(); static void draw_progress_bar(const uint8_t value); static void draw_fan_icon(const bool whichIcon); @@ -86,7 +86,7 @@ class ST7920_Lite_Status_Screen { static void draw_fan_speed(const uint8_t value); static void draw_print_time(const duration_t &elapsed); static void draw_feedrate_percentage(const uint16_t percentage); - static void draw_status_message(const char *str); + static void draw_status_message(); static void draw_position(const float x, const float y, const float z, bool position_known = true); static bool indicators_changed(); diff --git a/Marlin/src/lcd/dogm/ultralcd_impl_DOGM.cpp b/Marlin/src/lcd/dogm/ultralcd_impl_DOGM.cpp index 47a70093f4..4d0b94b9d7 100644 --- a/Marlin/src/lcd/dogm/ultralcd_impl_DOGM.cpp +++ b/Marlin/src/lcd/dogm/ultralcd_impl_DOGM.cpp @@ -75,16 +75,16 @@ U8GLIB *pu8g = &u8g; #if HAS_LCD_CONTRAST - int16_t lcd_contrast; // Initialized by settings.load() + int16_t MarlinUI::contrast; // Initialized by settings.load() - void set_lcd_contrast(const int16_t value) { - lcd_contrast = constrain(value, LCD_CONTRAST_MIN, LCD_CONTRAST_MAX); - u8g.setContrast(lcd_contrast); + void MarlinUI::set_contrast(const int16_t value) { + contrast = constrain(value, LCD_CONTRAST_MIN, LCD_CONTRAST_MAX); + u8g.setContrast(contrast); } #endif -void lcd_setFont(const MarlinFont font_nr) { +void MarlinUI::set_font(const MarlinFont font_nr) { static char currentfont = 0; if (font_nr != currentfont) { switch ((currentfont = font_nr)) { @@ -141,7 +141,7 @@ void lcd_setFont(const MarlinFont font_nr) { #endif // SHOW_CUSTOM_BOOTSCREEN - void lcd_bootscreen() { + void MarlinUI::show_bootscreen() { #if ENABLED(SHOW_CUSTOM_BOOTSCREEN) lcd_custom_bootscreen(); #endif @@ -160,7 +160,7 @@ void lcd_setFont(const MarlinFont font_nr) { u8g.firstPage(); do { u8g.drawBitmapP(offx, offy, (START_BMPWIDTH + 7) / 8, START_BMPHEIGHT, start_bmp); - lcd_setFont(FONT_MENU); + ui.set_font(FONT_MENU); #ifndef STRING_SPLASH_LINE2 const uint8_t txt1X = width - (sizeof(STRING_SPLASH_LINE1) - 1) * (MENU_FONT_WIDTH); u8g.drawStr(txt1X, (height + MENU_FONT_HEIGHT) / 2, STRING_SPLASH_LINE1); @@ -181,7 +181,7 @@ void lcd_setFont(const MarlinFont font_nr) { #endif // Initialize or re-initialize the LCD -void lcd_implementation_init() { +void MarlinUI::init_lcd() { #if PIN_EXISTS(LCD_BACKLIGHT) // Enable LCD backlight OUT_WRITE(LCD_BACKLIGHT_PIN, HIGH); @@ -206,7 +206,7 @@ void lcd_implementation_init() { #endif #if HAS_LCD_CONTRAST - set_lcd_contrast(lcd_contrast); + refresh_contrast(); #endif #if ENABLED(LCD_SCREEN_ROT_90) @@ -221,16 +221,16 @@ void lcd_implementation_init() { } // The kill screen is displayed for unrecoverable conditions -void lcd_kill_screen() { +void MarlinUI::draw_kill_screen() { #if ENABLED(LIGHTWEIGHT_UI) ST7920_Lite_Status_Screen::clear_text_buffer(); #endif const uint8_t h4 = u8g.getHeight() / 4; u8g.firstPage(); do { - lcd_setFont(FONT_MENU); + set_font(FONT_MENU); lcd_moveto(0, h4 * 1); - lcd_put_u8str(lcd_status_message); + lcd_put_u8str(status_message); lcd_moveto(0, h4 * 2); lcd_put_u8str_P(PSTR(MSG_HALTED)); lcd_moveto(0, h4 * 3); @@ -238,7 +238,7 @@ void lcd_kill_screen() { } while (u8g.nextPage()); } -void lcd_implementation_clear() { } // Automatically cleared by Picture Loop +void MarlinUI::clear_lcd() { } // Automatically cleared by Picture Loop #if HAS_LCD_MENU @@ -246,7 +246,7 @@ void lcd_implementation_clear() { } // Automatically cleared by Picture Loop #if ENABLED(ADVANCED_PAUSE_FEATURE) - void lcd_implementation_hotend_status(const uint8_t row, const uint8_t extruder) { + void MarlinUI::draw_hotend_status(const uint8_t row, const uint8_t extruder) { row_y1 = row * (MENU_FONT_HEIGHT) + 1; row_y2 = row_y1 + MENU_FONT_HEIGHT - 1; @@ -259,7 +259,7 @@ void lcd_implementation_clear() { } // Automatically cleared by Picture Loop lcd_put_u8str(itostr3(thermalManager.degHotend(extruder))); lcd_put_wchar('/'); - if (lcd_blink() || !thermalManager.is_heater_idle(extruder)) + if (get_blink() || !thermalManager.is_heater_idle(extruder)) lcd_put_u8str(itostr3(thermalManager.degTargetHotend(extruder))); } @@ -295,7 +295,7 @@ void lcd_implementation_clear() { } // Automatically cleared by Picture Loop } // Draw a static line of text in the same idiom as a menu item - void lcd_implementation_drawmenu_static(const uint8_t row, PGM_P pstr, const bool center/*=true*/, const bool invert/*=false*/, const char* valstr/*=NULL*/) { + void draw_menu_item_static(const uint8_t row, PGM_P pstr, const bool center/*=true*/, const bool invert/*=false*/, const char* valstr/*=NULL*/) { if (mark_as_selected(row, invert)) { @@ -315,7 +315,7 @@ void lcd_implementation_clear() { } // Automatically cleared by Picture Loop } // Draw a generic menu item - void lcd_implementation_drawmenu_generic(const bool isSelected, const uint8_t row, PGM_P pstr, const char pre_char, const char post_char) { + void draw_menu_item_generic(const bool isSelected, const uint8_t row, PGM_P const pstr, const char pre_char, const char post_char) { UNUSED(pre_char); if (mark_as_selected(row, isSelected)) { @@ -330,7 +330,7 @@ void lcd_implementation_clear() { } // Automatically cleared by Picture Loop } // Draw a menu item with an editable value - void _drawmenu_setting_edit_generic(const bool isSelected, const uint8_t row, PGM_P pstr, const char* const data, const bool pgm) { + void _drawmenu_setting_edit_generic(const bool isSelected, const uint8_t row, PGM_P const pstr, const char* const data, const bool pgm) { if (mark_as_selected(row, isSelected)) { const uint8_t vallen = (pgm ? utf8_strlen_P(data) : utf8_strlen((char*)data)); uint8_t n = LCD_WIDTH - 2 - vallen; @@ -343,7 +343,7 @@ void lcd_implementation_clear() { } // Automatically cleared by Picture Loop } } - void lcd_implementation_drawedit(PGM_P const pstr, const char* const value/*=NULL*/) { + void draw_edit_screen(PGM_P const pstr, const char* const value/*=NULL*/) { const uint8_t labellen = utf8_strlen_P(pstr), vallen = utf8_strlen(value); bool extra_row = labellen > LCD_WIDTH - 2 - vallen; @@ -356,12 +356,12 @@ void lcd_implementation_clear() { } // Automatically cleared by Picture Loop if (labellen + vallen + 1 > lcd_edit_width) extra_row = true; lcd_chr_fit = lcd_edit_width + 1; one_chr_width = EDIT_FONT_WIDTH; - lcd_setFont(FONT_EDIT); + ui.set_font(FONT_EDIT); } else { lcd_chr_fit = LCD_WIDTH; one_chr_width = MENU_FONT_WIDTH; - lcd_setFont(FONT_MENU); + ui.set_font(FONT_MENU); } #else constexpr uint8_t lcd_chr_fit = LCD_WIDTH, @@ -397,7 +397,7 @@ void lcd_implementation_clear() { } // Automatically cleared by Picture Loop #if ENABLED(SDSUPPORT) - void _drawmenu_sd(const bool isSelected, const uint8_t row, PGM_P const pstr, CardReader &theCard, const bool isDir) { + void draw_sd_menu_item(const bool isSelected, const uint8_t row, PGM_P const pstr, CardReader &theCard, const bool isDir) { UNUSED(pstr); mark_as_selected(row, isSelected); @@ -415,11 +415,11 @@ void lcd_implementation_clear() { } // Automatically cleared by Picture Loop name_hash = ((name_hash << 1) | (name_hash >> 7)) ^ theCard.filename[l]; // rotate, xor if (filename_scroll_hash != name_hash) { // If the hash changed... filename_scroll_hash = name_hash; // Save the new hash - filename_scroll_max = MAX(0, utf8_strlen(theCard.longFilename) - maxlen); // Update the scroll limit - filename_scroll_pos = 0; // Reset scroll to the start - lcd_status_update_delay = 8; // Don't scroll right away + ui.filename_scroll_max = MAX(0, utf8_strlen(theCard.longFilename) - maxlen); // Update the scroll limit + ui.filename_scroll_pos = 0; // Reset scroll to the start + ui.lcd_status_update_delay = 8; // Don't scroll right away } - outstr += filename_scroll_pos; + outstr += ui.filename_scroll_pos; } #else theCard.longFilename[maxlen] = '\0'; // cutoff at screen edge @@ -428,8 +428,7 @@ void lcd_implementation_clear() { } // Automatically cleared by Picture Loop if (isDir) lcd_put_wchar(LCD_STR_FOLDER[0]); - int n; - n = lcd_put_u8str_max(outstr, maxlen * (MENU_FONT_WIDTH)); + uint8_t n = lcd_put_u8str_max(outstr, maxlen * (MENU_FONT_WIDTH)); n = maxlen * (MENU_FONT_WIDTH) - n; while (n - MENU_FONT_WIDTH > 0) { n -= lcd_put_wchar(' '); } } @@ -446,7 +445,7 @@ void lcd_implementation_clear() { } // Automatically cleared by Picture Loop #define MAP_MAX_PIXELS_X 53 #define MAP_MAX_PIXELS_Y 49 - void lcd_implementation_ubl_plot(const uint8_t x_plot, const uint8_t y_plot) { + void MarlinUI::ubl_plot(const uint8_t x_plot, const uint8_t y_plot) { // Scale the box pixels appropriately uint8_t x_map_pixels = ((MAP_MAX_PIXELS_X - 4) / (GRID_MAX_POINTS_X)) * (GRID_MAX_POINTS_X), y_map_pixels = ((MAP_MAX_PIXELS_Y - 4) / (GRID_MAX_POINTS_Y)) * (GRID_MAX_POINTS_Y), diff --git a/Marlin/src/lcd/extensible_ui/ui_api.cpp b/Marlin/src/lcd/extensible_ui/ui_api.cpp index 8d329642c0..343910e13b 100644 --- a/Marlin/src/lcd/extensible_ui/ui_api.cpp +++ b/Marlin/src/lcd/extensible_ui/ui_api.cpp @@ -681,14 +681,14 @@ namespace UI { // At the moment, we piggy-back off the ultralcd calls, but this could be cleaned up in the future -void lcd_init() { +void MarlinUI::init() { #if ENABLED(SDSUPPORT) && PIN_EXISTS(SD_DETECT) SET_INPUT_PULLUP(SD_DETECT_PIN); #endif UI::onStartup(); } -void lcd_update() { +void MarlinUI::update() { #if ENABLED(SDSUPPORT) static bool last_sd_status; const bool sd_status = IS_SD_INSERTED(); @@ -712,15 +712,15 @@ void lcd_update() { UI::onIdle(); } -bool lcd_hasstatus() { return true; } -bool lcd_detected() { return true; } -void lcd_reset_alert_level() { } -void lcd_refresh() { } -void lcd_setstatus(const char * const message, const bool persist /* = false */) { UI::onStatusChanged(message); } -void lcd_setstatusPGM(const char * const message, int8_t level /* = 0 */) { UI::onStatusChanged((progmem_str)message); } -void lcd_setalertstatusPGM(const char * const message) { lcd_setstatusPGM(message, 0); } +bool MarlinUI::hasstatus() { return true; } +bool MarlinUI::detected() { return true; } +void MarlinUI::reset_alert_level() { } +void MarlinUI::refresh() { } +void MarlinUI::setstatus(const char * const message, const bool persist /* = false */) { UI::onStatusChanged(message); } +void MarlinUI::setstatusPGM(const char * const message, int8_t level /* = 0 */) { UI::onStatusChanged((progmem_str)message); } +void MarlinUI::setalertstatusPGM(const char * const message) { setstatusPGM(message, 0); } -void lcd_reset_status() { +void MarlinUI::reset_status() { static const char paused[] PROGMEM = MSG_PRINT_PAUSED; static const char printing[] PROGMEM = MSG_PRINTING; static const char welcome[] PROGMEM = WELCOME_MSG; @@ -729,17 +729,17 @@ void lcd_reset_status() { msg = paused; #if ENABLED(SDSUPPORT) else if (IS_SD_PRINTING()) - return lcd_setstatus(card.longest_filename(), true); + return setstatus(card.longest_filename(), true); #endif else if (print_job_timer.isRunning()) msg = printing; else msg = welcome; - lcd_setstatusPGM(msg, -1); + setstatusPGM(msg, -1); } -void lcd_status_printf_P(const uint8_t level, const char * const fmt, ...) { +void MarlinUI::status_printf_P(const uint8_t level, const char * const fmt, ...) { char buff[64]; va_list args; va_start(args, fmt); @@ -749,7 +749,7 @@ void lcd_status_printf_P(const uint8_t level, const char * const fmt, ...) { UI::onStatusChanged(buff); } -void kill_screen(PGM_P msg) { +void MarlinUI::kill_screen(PGM_P const msg) { if (!flags.printer_killed) { flags.printer_killed = true; UI::onPrinterKilled(msg); diff --git a/Marlin/src/lcd/language/language_es.h b/Marlin/src/lcd/language/language_es.h index 0852215550..c7c193580c 100644 --- a/Marlin/src/lcd/language/language_es.h +++ b/Marlin/src/lcd/language/language_es.h @@ -204,7 +204,7 @@ #define MSG_INFO_PROTOCOL _UxGT("Protocolo") #define MSG_CASE_LIGHT _UxGT("Luz cabina") -#if LCD_WIDTH > 19 +#if LCD_WIDTH >= 20 #define MSG_INFO_PRINT_COUNT _UxGT("Conteo de impresión") #define MSG_INFO_COMPLETED_PRINTS _UxGT("Completadas") #define MSG_INFO_PRINT_TIME _UxGT("Tiempo total de imp.") diff --git a/Marlin/src/lcd/language/language_zh_CN.h b/Marlin/src/lcd/language/language_zh_CN.h index adee5d5bdb..fcdaecc861 100644 --- a/Marlin/src/lcd/language/language_zh_CN.h +++ b/Marlin/src/lcd/language/language_zh_CN.h @@ -324,7 +324,7 @@ #define MSG_CASE_LIGHT _UxGT("外壳灯") // "Case light" #define MSG_CASE_LIGHT_BRIGHTNESS _UxGT("灯亮度") // "Light BRIGHTNESS" -#if LCD_WIDTH > 19 +#if LCD_WIDTH >= 20 #define MSG_INFO_PRINT_COUNT _UxGT("打印计数") //"Print Count" #define MSG_INFO_COMPLETED_PRINTS _UxGT("完成了") //"Completed" #define MSG_INFO_PRINT_TIME _UxGT("总打印时间") //"Total print time" diff --git a/Marlin/src/lcd/language/language_zh_TW.h b/Marlin/src/lcd/language/language_zh_TW.h index c64ac2f2b6..5f28b48d0b 100644 --- a/Marlin/src/lcd/language/language_zh_TW.h +++ b/Marlin/src/lcd/language/language_zh_TW.h @@ -324,7 +324,7 @@ #define MSG_CASE_LIGHT _UxGT("外殼燈") // "Case light" #define MSG_CASE_LIGHT_BRIGHTNESS _UxGT("燈亮度") // "Light BRIGHTNESS" -#if LCD_WIDTH > 19 +#if LCD_WIDTH >= 20 #define MSG_INFO_PRINT_COUNT _UxGT("列印計數") //"Print Count" #define MSG_INFO_COMPLETED_PRINTS _UxGT("已完成") //"Completed" #define MSG_INFO_PRINT_TIME _UxGT("總列印時間") //"Total print time" diff --git a/Marlin/src/lcd/malyanlcd.cpp b/Marlin/src/lcd/malyanlcd.cpp index 1e90cea24a..efc46f42e2 100644 --- a/Marlin/src/lcd/malyanlcd.cpp +++ b/Marlin/src/lcd/malyanlcd.cpp @@ -417,7 +417,7 @@ void update_usb_status(const bool forceUpdate) { * The optimize attribute fixes a register Compile * error for amtel. */ -void lcd_update() { +void MarlinUI::update() { static char inbound_buffer[MAX_CURLY_COMMAND]; // First report USB status. @@ -461,7 +461,7 @@ void lcd_update() { * it and translate into gcode, which then gets injected into * the command queue where possible. */ -void lcd_init() { +void MarlinUI::init() { inbound_count = 0; LCD_SERIAL.begin(500000); @@ -479,7 +479,7 @@ void lcd_init() { /** * Set an alert. */ -void lcd_setalertstatusPGM(PGM_P message) { +void MarlinUI::setalertstatusPGM(PGM_P message) { char message_buffer[MAX_CURLY_COMMAND]; sprintf_P(message_buffer, PSTR("{E:%s}"), message); write_to_lcd(message_buffer); diff --git a/Marlin/src/lcd/menu/menu.cpp b/Marlin/src/lcd/menu/menu.cpp index 346a81729d..e3d9f09d49 100644 --- a/Marlin/src/lcd/menu/menu.cpp +++ b/Marlin/src/lcd/menu/menu.cpp @@ -30,6 +30,7 @@ #include "../../module/motion.h" #include "../../gcode/queue.h" #include "../../sd/cardreader.h" +#include "../../libs/buzzer.h" #if ENABLED(EEPROM_SETTINGS) #include "../../module/configuration_store.h" @@ -61,10 +62,6 @@ menuPosition screen_history[6]; uint8_t screen_history_depth = 0; bool screen_changed; -#if LCD_TIMEOUT_TO_STATUS - bool defer_return_to_status; -#endif - // Value Editing PGM_P editLabel; void *editValue; @@ -79,9 +76,9 @@ bool no_reentry = false; //////// Menu Navigation & History ///////// //////////////////////////////////////////// -void lcd_return_to_status() { lcd_goto_screen(lcd_status_screen); } +void MarlinUI::return_to_status() { goto_screen(status_screen); } -void lcd_save_previous_screen() { +void MarlinUI::save_previous_screen() { if (screen_history_depth < COUNT(screen_history)) { screen_history[screen_history_depth].menu_function = currentScreen; screen_history[screen_history_depth].encoder_position = encoderPosition; @@ -89,25 +86,18 @@ void lcd_save_previous_screen() { } } -void lcd_goto_previous_menu() { +void MarlinUI::goto_previous_screen() { if (screen_history_depth > 0) { --screen_history_depth; - lcd_goto_screen( + goto_screen( screen_history[screen_history_depth].menu_function, screen_history[screen_history_depth].encoder_position ); } else - lcd_return_to_status(); + return_to_status(); } -#if LCD_TIMEOUT_TO_STATUS - void lcd_goto_previous_menu_no_defer() { - set_defer_return_to_status(false); - lcd_goto_previous_menu(); - } -#endif - //////////////////////////////////////////// /////////// Common Menu Actions //////////// //////////////////////////////////////////// @@ -142,34 +132,33 @@ void menu_item_gcode::action(PGM_P pgcode) { enqueue_and_echo_commands_P(pgcode) * ...which calls: * menu_item_int3::action_setting_edit(PSTR(MSG_SPEED), &feedrate_percentage, 10, 999) */ -void menu_item_invariants::edit(strfunc_t strfunc, loadfunc_t loadfunc) { - ENCODER_DIRECTION_NORMAL(); - if ((int32_t)encoderPosition < 0) encoderPosition = 0; - if ((int32_t)encoderPosition > maxEditValue) encoderPosition = maxEditValue; - if (lcdDrawUpdate) - lcd_implementation_drawedit(editLabel, strfunc(encoderPosition + minEditValue)); - if (lcd_clicked || (liveEdit && lcdDrawUpdate)) { - if (editValue != NULL) loadfunc(editValue, encoderPosition + minEditValue); - if (callbackFunc && (liveEdit || lcd_clicked)) (*callbackFunc)(); - if (lcd_clicked) lcd_goto_previous_menu(); - lcd_clicked = false; +void MenuItemBase::edit(strfunc_t strfunc, loadfunc_t loadfunc) { + ui.encoder_direction_normal(); + if ((int32_t)ui.encoderPosition < 0) ui.encoderPosition = 0; + if ((int32_t)ui.encoderPosition > maxEditValue) ui.encoderPosition = maxEditValue; + if (ui.should_draw()) + draw_edit_screen(editLabel, strfunc(ui.encoderPosition + minEditValue)); + if (ui.lcd_clicked || (liveEdit && ui.should_draw())) { + if (editValue != NULL) loadfunc(editValue, ui.encoderPosition + minEditValue); + if (callbackFunc && (liveEdit || ui.lcd_clicked)) (*callbackFunc)(); + if (ui.use_click()) ui.goto_previous_screen(); } } -void menu_item_invariants::init(PGM_P const el, void * const ev, const int32_t minv, const int32_t maxv, const uint32_t ep, const screenFunc_t cs, const screenFunc_t cb, const bool le) { - lcd_save_previous_screen(); - lcd_refresh(); +void MenuItemBase::init(PGM_P const el, void * const ev, const int32_t minv, const int32_t maxv, const uint32_t ep, const screenFunc_t cs, const screenFunc_t cb, const bool le) { + ui.save_previous_screen(); + ui.refresh(); editLabel = el; editValue = ev; minEditValue = minv; maxEditValue = maxv; - encoderPosition = ep; - currentScreen = cs; + ui.encoderPosition = ep; + ui.currentScreen = cs; callbackFunc = cb; liveEdit = le; } -#define DEFINE_MENU_EDIT_ITEM(NAME) template class menu_item_template; +#define DEFINE_MENU_EDIT_ITEM(NAME) template class TMenuItem; DEFINE_MENU_EDIT_ITEM(int3); DEFINE_MENU_EDIT_ITEM(int4); @@ -184,7 +173,7 @@ DEFINE_MENU_EDIT_ITEM(float62); DEFINE_MENU_EDIT_ITEM(long5); void menu_item_bool::action_setting_edit(PGM_P pstr, bool *ptr, screenFunc_t callback) { - UNUSED(pstr); *ptr ^= true; lcd_refresh(); + UNUSED(pstr); *ptr ^= true; ui.refresh(); if (callback) (*callback)(); } @@ -202,7 +191,7 @@ bool printer_busy() { return planner.movesplanned() || IS_SD_PRINTING(); } /** * General function to go directly to a screen */ -void lcd_goto_screen(screenFunc_t screen, const uint32_t encoder/*=0*/) { +void MarlinUI::goto_screen(screenFunc_t screen, const uint32_t encoder/*=0*/) { if (currentScreen != screen) { #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT) @@ -215,10 +204,10 @@ void lcd_goto_screen(screenFunc_t screen, const uint32_t encoder/*=0*/) { // Going to menu_main from status screen? Remember first click time. // Going back to status screen within a very short time? Go to Z babystepping. if (screen == menu_main) { - if (currentScreen == lcd_status_screen) + if (on_status_screen()) doubleclick_expire_ms = millis() + DOUBLECLICK_MAX_INTERVAL; } - else if (screen == lcd_status_screen && currentScreen == menu_main && PENDING(millis(), doubleclick_expire_ms)) { + else if (screen == status_screen && currentScreen == menu_main && PENDING(millis(), doubleclick_expire_ms)) { if (printer_busy()) { screen = #if ENABLED(BABYSTEP_ZPROBE_OFFSET) @@ -239,25 +228,25 @@ void lcd_goto_screen(screenFunc_t screen, const uint32_t encoder/*=0*/) { currentScreen = screen; encoderPosition = encoder; - if (screen == lcd_status_screen) { - set_defer_return_to_status(false); + if (screen == status_screen) { + ui.defer_status_screen(false); #if ENABLED(AUTO_BED_LEVELING_UBL) ubl.lcd_map_control = false; #endif screen_history_depth = 0; } - lcd_implementation_clear(); + clear_lcd(); // Re-initialize custom characters that may be re-used #if HAS_CHARACTER_LCD #if ENABLED(AUTO_BED_LEVELING_UBL) if (!ubl.lcd_map_control) #endif - LCD_SET_CHARSET(screen == lcd_status_screen ? CHARSET_INFO : CHARSET_MENU); + LCD_SET_CHARSET(screen == status_screen ? CHARSET_INFO : CHARSET_MENU); #endif - lcdDrawUpdate = LCDVIEW_CALL_REDRAW_NEXT; + refresh(LCDVIEW_CALL_REDRAW_NEXT); screen_changed = true; #if HAS_GRAPHICAL_LCD drawing_screen = false; @@ -276,24 +265,24 @@ void lcd_goto_screen(screenFunc_t screen, const uint32_t encoder/*=0*/) { // static PGM_P sync_message; -void _lcd_synchronize() { - if (lcdDrawUpdate) lcd_implementation_drawmenu_static(LCD_HEIGHT >= 4 ? 1 : 0, sync_message); +void MarlinUI::_synchronize() { + if (should_draw()) draw_menu_item_static(LCD_HEIGHT >= 4 ? 1 : 0, sync_message); if (no_reentry) return; // Make this the current handler till all moves are done no_reentry = true; const screenFunc_t old_screen = currentScreen; - lcd_goto_screen(_lcd_synchronize); + goto_screen(_synchronize); planner.synchronize(); // idle() is called until moves complete no_reentry = false; - lcd_goto_screen(old_screen); + goto_screen(old_screen); } // Display the synchronize screen with a custom message // ** This blocks the command queue! ** -void lcd_synchronize(PGM_P const msg/*=NULL*/) { +void MarlinUI::synchronize(PGM_P const msg/*=NULL*/) { static const char moving[] PROGMEM = MSG_MOVING; sync_message = msg ? msg : moving; - _lcd_synchronize(); + _synchronize(); } /** @@ -308,16 +297,16 @@ void lcd_synchronize(PGM_P const msg/*=NULL*/) { */ int8_t encoderLine, screen_items; void scroll_screen(const uint8_t limit, const bool is_menu) { - ENCODER_DIRECTION_MENUS(); + ui.encoder_direction_menus(); ENCODER_RATE_MULTIPLY(false); - if (encoderPosition > 0x8000) encoderPosition = 0; - if (first_page) { - encoderLine = encoderPosition / (ENCODER_STEPS_PER_MENU_ITEM); + if (ui.encoderPosition > 0x8000) ui.encoderPosition = 0; + if (ui.first_page) { + encoderLine = ui.encoderPosition / (ENCODER_STEPS_PER_MENU_ITEM); screen_changed = false; } if (screen_items > 0 && encoderLine >= screen_items - limit) { encoderLine = MAX(0, screen_items - limit); - encoderPosition = encoderLine * (ENCODER_STEPS_PER_MENU_ITEM); + ui.encoderPosition = encoderLine * (ENCODER_STEPS_PER_MENU_ITEM); } if (is_menu) { NOMORE(encoderTopLine, encoderLine); @@ -328,12 +317,12 @@ void scroll_screen(const uint8_t limit, const bool is_menu) { encoderTopLine = encoderLine; } -void lcd_completion_feedback(const bool good/*=true*/) { +void MarlinUI::completion_feedback(const bool good/*=true*/) { if (good) { - lcd_buzz(100, 659); - lcd_buzz(100, 698); + BUZZ(100, 659); + BUZZ(100, 698); } - else lcd_buzz(20, 440); + else BUZZ(20, 440); } #if HAS_LINE_TO_Z @@ -348,17 +337,17 @@ void lcd_completion_feedback(const bool good/*=true*/) { #if ENABLED(BABYSTEP_ZPROBE_OFFSET) void lcd_babystep_zoffset() { - if (use_click()) { return lcd_goto_previous_menu_no_defer(); } - set_defer_return_to_status(true); + if (ui.use_click()) return ui.goto_previous_screen_no_defer(); + ui.defer_status_screen(true); #if ENABLED(BABYSTEP_HOTEND_Z_OFFSET) const bool do_probe = (active_extruder == 0); #else constexpr bool do_probe = true; #endif - ENCODER_DIRECTION_NORMAL(); - if (encoderPosition) { - const int16_t babystep_increment = (int32_t)encoderPosition * (BABYSTEP_MULTIPLICATOR); - encoderPosition = 0; + ui.encoder_direction_normal(); + if (ui.encoderPosition) { + const int16_t babystep_increment = (int32_t)ui.encoderPosition * (BABYSTEP_MULTIPLICATOR); + ui.encoderPosition = 0; const float diff = planner.steps_to_mm[Z_AXIS] * babystep_increment, new_probe_offset = zprobe_zoffset + diff, @@ -378,16 +367,16 @@ void lcd_completion_feedback(const bool good/*=true*/) { else hotend_offset[Z_AXIS][active_extruder] = new_offs; #endif - lcdDrawUpdate = LCDVIEW_CALL_REDRAW_NEXT; + ui.refresh(LCDVIEW_CALL_REDRAW_NEXT); } } - if (lcdDrawUpdate) { + if (ui.should_draw()) { #if ENABLED(BABYSTEP_HOTEND_Z_OFFSET) if (!do_probe) - lcd_implementation_drawedit(PSTR(MSG_IDEX_Z_OFFSET), ftostr43sign(hotend_offset[Z_AXIS][active_extruder])); + draw_edit_screen(PSTR(MSG_IDEX_Z_OFFSET), ftostr43sign(hotend_offset[Z_AXIS][active_extruder])); else #endif - lcd_implementation_drawedit(PSTR(MSG_ZPROBE_ZOFFSET), ftostr43sign(zprobe_zoffset)); + draw_edit_screen(PSTR(MSG_ZPROBE_ZOFFSET), ftostr43sign(zprobe_zoffset)); #if ENABLED(BABYSTEP_ZPROBE_GFX_OVERLAY) if (do_probe) _lcd_zoffset_overlay_gfx(zprobe_zoffset); @@ -447,14 +436,14 @@ void watch_temp_callback_bed() { #endif #if ENABLED(EEPROM_SETTINGS) - void lcd_store_settings() { lcd_completion_feedback(settings.save()); } - void lcd_load_settings() { lcd_completion_feedback(settings.load()); } + void lcd_store_settings() { ui.completion_feedback(settings.save()); } + void lcd_load_settings() { ui.completion_feedback(settings.load()); } #endif void _lcd_draw_homing() { constexpr uint8_t line = (LCD_HEIGHT - 1) / 2; - if (lcdDrawUpdate) lcd_implementation_drawmenu_static(line, PSTR(MSG_LEVEL_BED_HOMING)); - lcdDrawUpdate = LCDVIEW_CALL_NO_REDRAW; + if (ui.should_draw()) draw_menu_item_static(line, PSTR(MSG_LEVEL_BED_HOMING)); + ui.refresh(LCDVIEW_CALL_NO_REDRAW); } #if ENABLED(LCD_BED_LEVELING) || (HAS_LEVELING && DISABLED(SLIM_LCD_MENUS)) diff --git a/Marlin/src/lcd/menu/menu.h b/Marlin/src/lcd/menu/menu.h index 2dffc7e1c1..d54e0a831d 100644 --- a/Marlin/src/lcd/menu/menu.h +++ b/Marlin/src/lcd/menu/menu.h @@ -31,14 +31,6 @@ constexpr int16_t heater_maxtemp[HOTENDS] = ARRAY_BY_HOTENDS(HEATER_0_MAXTEMP, H void scroll_screen(const uint8_t limit, const bool is_menu); bool printer_busy(); -void lcd_completion_feedback(const bool good=true); -void lcd_save_previous_screen(); -void lcd_goto_previous_menu(); -#if LCD_TIMEOUT_TO_STATUS - void lcd_goto_previous_menu_no_defer(); -#else - #define lcd_goto_previous_menu_no_defer() lcd_goto_previous_menu() -#endif //////////////////////////////////////////// ////////// Menu Item Numeric Types ///////// @@ -67,60 +59,46 @@ DECLARE_MENU_EDIT_TYPE(uint32_t, long5, ftostr5rj, 0.01f); ///////// Menu Item Draw Functions ///////// //////////////////////////////////////////// +void draw_menu_item_generic(const bool isSelected, const uint8_t row, PGM_P const pstr, const char pre_char, const char post_char); +void draw_menu_item_static(const uint8_t row, PGM_P const pstr, const bool center=true, const bool invert=false, const char *valstr=NULL); +void draw_edit_screen(PGM_P const pstr, const char* const value=NULL); #if ENABLED(SDSUPPORT) class CardReader; -#endif - -void lcd_implementation_drawmenu_generic(const bool isSelected, const uint8_t row, const char* pstr, const char pre_char, const char post_char); -void lcd_implementation_drawmenu_static(const uint8_t row, const char* pstr, const bool center=true, const bool invert=false, const char *valstr=NULL); -void lcd_implementation_drawedit(const char* const pstr, const char* const value=NULL); -#if ENABLED(ADVANCED_PAUSE_FEATURE) - void lcd_implementation_hotend_status(const uint8_t row, const uint8_t extruder); + void draw_sd_menu_item(const bool isSelected, const uint8_t row, PGM_P const pstr, CardReader &theCard, const bool isDir); + inline void draw_menu_item_sdfile(const bool sel, const uint8_t row, PGM_P const pstr, CardReader &theCard) { draw_sd_menu_item(sel, row, pstr, theCard, false); } + inline void draw_menu_item_sdfolder(const bool sel, const uint8_t row, PGM_P const pstr, CardReader &theCard) { draw_sd_menu_item(sel, row, pstr, theCard, true); } #endif #if HAS_GRAPHICAL_LCD void _drawmenu_setting_edit_generic(const bool isSelected, const uint8_t row, const char* pstr, const char* const data, const bool pgm); - #define lcd_implementation_drawmenu_back(sel, row, pstr) lcd_implementation_drawmenu_generic(sel, row, pstr, LCD_STR_UPLEVEL[0], LCD_STR_UPLEVEL[0]) - #define lcd_implementation_drawmenu_setting_edit_generic(sel, row, pstr, data) _drawmenu_setting_edit_generic(sel, row, pstr, data, false) - #define lcd_implementation_drawmenu_setting_edit_generic_P(sel, row, pstr, data) _drawmenu_setting_edit_generic(sel, row, pstr, data, true) - #define DRAWMENU_SETTING_EDIT_GENERIC(SRC) lcd_implementation_drawmenu_setting_edit_generic(sel, row, pstr, SRC) - #define DRAW_BOOL_SETTING(sel, row, pstr, data) lcd_implementation_drawmenu_setting_edit_generic_P(sel, row, pstr, (*(data))?PSTR(MSG_ON):PSTR(MSG_OFF)) - #if ENABLED(SDSUPPORT) - void _drawmenu_sd(const bool isSelected, const uint8_t row, PGM_P const pstr, CardReader &theCard, const bool isDir); - #define lcd_implementation_drawmenu_sdfile(sel, row, pstr, theCard) _drawmenu_sd(sel, row, pstr, theCard, false) - #define lcd_implementation_drawmenu_sddirectory(sel, row, pstr, theCard) _drawmenu_sd(sel, row, pstr, theCard, true) - #endif + #define draw_menu_item_back(sel, row, pstr) draw_menu_item_generic(sel, row, pstr, LCD_STR_UPLEVEL[0], LCD_STR_UPLEVEL[0]) + #define draw_menu_item_setting_edit_generic(sel, row, pstr, data) _drawmenu_setting_edit_generic(sel, row, pstr, data, false) + #define draw_menu_item_setting_edit_generic_P(sel, row, pstr, data) _drawmenu_setting_edit_generic(sel, row, pstr, data, true) + #define DRAWMENU_SETTING_EDIT_GENERIC(SRC) draw_menu_item_setting_edit_generic(sel, row, pstr, SRC) + #define DRAW_BOOL_SETTING(sel, row, pstr, data) draw_menu_item_setting_edit_generic_P(sel, row, pstr, (*(data))?PSTR(MSG_ON):PSTR(MSG_OFF)) #if ENABLED(BABYSTEP_ZPROBE_GFX_OVERLAY) || ENABLED(MESH_EDIT_GFX_OVERLAY) void _lcd_zoffset_overlay_gfx(const float zvalue); #endif #else - #define lcd_implementation_drawmenu_back(sel, row, pstr) lcd_implementation_drawmenu_generic(sel, row, pstr, LCD_UPLEVEL_CHAR, LCD_UPLEVEL_CHAR) - void lcd_implementation_drawmenu_setting_edit_generic(const bool sel, const uint8_t row, const char* pstr, const char pre_char, const char* const data); - void lcd_implementation_drawmenu_setting_edit_generic_P(const bool sel, const uint8_t row, const char* pstr, const char pre_char, const char* const data); - #define DRAWMENU_SETTING_EDIT_GENERIC(SRC) lcd_implementation_drawmenu_setting_edit_generic(sel, row, pstr, '>', SRC) - #define DRAW_BOOL_SETTING(sel, row, pstr, data) lcd_implementation_drawmenu_setting_edit_generic_P(sel, row, pstr, '>', (*(data))?PSTR(MSG_ON):PSTR(MSG_OFF)) - #if ENABLED(SDSUPPORT) - void lcd_implementation_drawmenu_sdfile(const bool sel, const uint8_t row, PGM_P pstr, CardReader &theCard); - void lcd_implementation_drawmenu_sddirectory(const bool sel, const uint8_t row, PGM_P pstr, CardReader &theCard); - #endif -#endif -#define lcd_implementation_drawmenu_submenu(sel, row, pstr, data) lcd_implementation_drawmenu_generic(sel, row, pstr, '>', LCD_STR_ARROW_RIGHT[0]) -#define lcd_implementation_drawmenu_gcode(sel, row, pstr, gcode) lcd_implementation_drawmenu_generic(sel, row, pstr, '>', ' ') -#define lcd_implementation_drawmenu_function(sel, row, pstr, data) lcd_implementation_drawmenu_generic(sel, row, pstr, '>', ' ') - -#if ENABLED(AUTO_BED_LEVELING_UBL) - void lcd_implementation_ubl_plot(const uint8_t x, const uint8_t inverted_y); + #define draw_menu_item_back(sel, row, pstr) draw_menu_item_generic(sel, row, pstr, LCD_UPLEVEL_CHAR, LCD_UPLEVEL_CHAR) + void draw_menu_item_setting_edit_generic(const bool sel, const uint8_t row, const char* pstr, const char pre_char, const char* const data); + void draw_menu_item_setting_edit_generic_P(const bool sel, const uint8_t row, const char* pstr, const char pre_char, const char* const data); + #define DRAWMENU_SETTING_EDIT_GENERIC(SRC) draw_menu_item_setting_edit_generic(sel, row, pstr, '>', SRC) + #define DRAW_BOOL_SETTING(sel, row, pstr, data) draw_menu_item_setting_edit_generic_P(sel, row, pstr, '>', (*(data))?PSTR(MSG_ON):PSTR(MSG_OFF)) #endif +#define draw_menu_item_submenu(sel, row, pstr, data) draw_menu_item_generic(sel, row, pstr, '>', LCD_STR_ARROW_RIGHT[0]) +#define draw_menu_item_gcode(sel, row, pstr, gcode) draw_menu_item_generic(sel, row, pstr, '>', ' ') +#define draw_menu_item_function(sel, row, pstr, data) draw_menu_item_generic(sel, row, pstr, '>', ' ') //////////////////////////////////////////// /////// Edit Setting Draw Functions //////// //////////////////////////////////////////// #define _DEFINE_LCD_IMPLEMENTATION_DRAWMENU_SETTING_EDIT_TYPE(TYPE, NAME, STRFUNC) \ - FORCE_INLINE void lcd_implementation_drawmenu_setting_edit_ ## NAME (const bool sel, const uint8_t row, PGM_P pstr, PGM_P pstr2, TYPE * const data, ...) { \ + FORCE_INLINE void draw_menu_item_setting_edit_ ## NAME (const bool sel, const uint8_t row, PGM_P const pstr, PGM_P const pstr2, TYPE * const data, ...) { \ UNUSED(pstr2); \ DRAWMENU_SETTING_EDIT_GENERIC(STRFUNC(*(data))); \ } \ - FORCE_INLINE void lcd_implementation_drawmenu_setting_edit_accessor_ ## NAME (const bool sel, const uint8_t row, PGM_P pstr, PGM_P pstr2, TYPE (*pget)(), void (*pset)(TYPE), ...) { \ + FORCE_INLINE void draw_menu_item_setting_edit_accessor_ ## NAME (const bool sel, const uint8_t row, PGM_P const pstr, PGM_P const pstr2, TYPE (*pget)(), void (*pset)(TYPE), ...) { \ UNUSED(pstr2); UNUSED(pset); \ DRAWMENU_SETTING_EDIT_GENERIC(STRFUNC(pget())); \ } \ @@ -139,8 +117,8 @@ DEFINE_LCD_IMPLEMENTATION_DRAWMENU_SETTING_EDIT_TYPE(float52sign); DEFINE_LCD_IMPLEMENTATION_DRAWMENU_SETTING_EDIT_TYPE(float62); DEFINE_LCD_IMPLEMENTATION_DRAWMENU_SETTING_EDIT_TYPE(long5); -#define lcd_implementation_drawmenu_setting_edit_bool(sel, row, pstr, pstr2, data, ...) DRAW_BOOL_SETTING(sel, row, pstr, data) -#define lcd_implementation_drawmenu_setting_edit_accessor_bool(sel, row, pstr, pstr2, pget, pset) DRAW_BOOL_SETTING(sel, row, pstr, data) +#define draw_menu_item_setting_edit_bool(sel, row, pstr, pstr2, data, ...) DRAW_BOOL_SETTING(sel, row, pstr, data) +#define draw_menu_item_setting_edit_accessor_bool(sel, row, pstr, pstr2, pget, pset) DRAW_BOOL_SETTING(sel, row, pstr, data) //////////////////////////////////////////// /////////////// Menu Actions /////////////// @@ -148,12 +126,12 @@ DEFINE_LCD_IMPLEMENTATION_DRAWMENU_SETTING_EDIT_TYPE(long5); class menu_item_back { public: - static inline void action() { lcd_goto_previous_menu(); } + static inline void action() { ui.goto_previous_screen(); } }; class menu_item_submenu { public: - static inline void action(const screenFunc_t func) { lcd_save_previous_screen(); lcd_goto_screen(func); } + static inline void action(const screenFunc_t func) { ui.save_previous_screen(); ui.goto_screen(func); } }; class menu_item_gcode { @@ -170,7 +148,7 @@ class menu_item_function { /////////// Menu Editing Actions /////////// //////////////////////////////////////////// -class menu_item_invariants { +class MenuItemBase { protected: typedef char* (*strfunc_t)(const int32_t); typedef void (*loadfunc_t)(void *, const int32_t); @@ -179,7 +157,7 @@ class menu_item_invariants { }; template -class menu_item_template : menu_item_invariants { +class TMenuItem : MenuItemBase { private: typedef typename NAME::type_t type_t; inline static float unscale(const float value) {return value * (1.0f / NAME::scale);} @@ -191,10 +169,10 @@ class menu_item_template : menu_item_invariants { const int32_t minv = scale(minValue); init(pstr, ptr, minv, int32_t(scale(maxValue)) - minv, int32_t(scale(*ptr)) - minv, edit, callback, live); } - static void edit() {menu_item_invariants::edit(to_string, load);} + static void edit() { MenuItemBase::edit(to_string, load); } }; -#define DECLARE_MENU_EDIT_ITEM(NAME) typedef menu_item_template menu_item_ ## NAME; +#define DECLARE_MENU_EDIT_ITEM(NAME) typedef TMenuItem menu_item_ ## NAME; DECLARE_MENU_EDIT_ITEM(int3); DECLARE_MENU_EDIT_ITEM(int4); @@ -210,7 +188,7 @@ DECLARE_MENU_EDIT_ITEM(long5); class menu_item_bool { public: - static void action_setting_edit(PGM_P pstr, bool* ptr, const screenFunc_t callbackFunc=NULL); + static void action_setting_edit(PGM_P const pstr, bool* ptr, const screenFunc_t callbackFunc=NULL); }; //////////////////////////////////////////// @@ -256,69 +234,47 @@ class menu_item_bool { screen_items = _thisItemNr; \ UNUSED(_skipStatic) -/** - * REVERSE_MENU_DIRECTION - * - * To reverse the menu direction we need a general way to reverse - * the direction of the encoder everywhere. So encoderDirection is - * added to allow the encoder to go the other way. - * - * This behavior is limited to scrolling Menus and SD card listings, - * and is disabled in other contexts. - */ -#if ENABLED(REVERSE_MENU_DIRECTION) - extern int8_t encoderDirection; - #define ENCODER_DIRECTION_NORMAL() (encoderDirection = 1) - #define ENCODER_DIRECTION_MENUS() (encoderDirection = -1) -#else - #define ENCODER_DIRECTION_NORMAL() NOOP - #define ENCODER_DIRECTION_MENUS() NOOP -#endif - #if ENABLED(ENCODER_RATE_MULTIPLIER) - extern millis_t lastEncoderMovementMillis; - extern bool encoderRateMultiplierEnabled; - #define ENCODER_RATE_MULTIPLY(F) (encoderRateMultiplierEnabled = F) - #define _MENU_ITEM_MULTIPLIER_CHECK(USE_MULTIPLIER) if (USE_MULTIPLIER) { encoderRateMultiplierEnabled = true; lastEncoderMovementMillis = 0; } + #define ENCODER_RATE_MULTIPLY(F) (ui.encoderRateMultiplierEnabled = F) + #define _MENU_ITEM_MULTIPLIER_CHECK(USE_MULTIPLIER) do{ if (USE_MULTIPLIER) ui.enable_encoder_multiplier(true); }while(0) //#define ENCODER_RATE_MULTIPLIER_DEBUG // If defined, output the encoder steps per second value -#else // !ENCODER_RATE_MULTIPLIER +#else #define ENCODER_RATE_MULTIPLY(F) NOOP #define _MENU_ITEM_MULTIPLIER_CHECK(USE_MULTIPLIER) -#endif // !ENCODER_RATE_MULTIPLIER +#endif /** * MENU_ITEM generates draw & handler code for a menu item, potentially calling: * - * lcd_implementation_drawmenu_[_variant](sel, row, label, arg3...) + * draw_menu_item_[_variant](sel, row, label, arg3...) * menu_item_::action[_variant](arg3...) * * Examples: * MENU_ITEM(back, MSG_WATCH, 0 [dummy parameter] ) * or * MENU_BACK(MSG_WATCH) - * lcd_implementation_drawmenu_back(sel, row, PSTR(MSG_WATCH)) + * draw_menu_item_back(sel, row, PSTR(MSG_WATCH)) * menu_item_back::action() * * MENU_ITEM(function, MSG_PAUSE_PRINT, lcd_sdcard_pause) - * lcd_implementation_drawmenu_function(sel, row, PSTR(MSG_PAUSE_PRINT), lcd_sdcard_pause) + * draw_menu_item_function(sel, row, PSTR(MSG_PAUSE_PRINT), lcd_sdcard_pause) * menu_item_function::action(lcd_sdcard_pause) * * MENU_ITEM_EDIT(int3, MSG_SPEED, &feedrate_percentage, 10, 999) - * lcd_implementation_drawmenu_setting_edit_int3(sel, row, PSTR(MSG_SPEED), PSTR(MSG_SPEED), &feedrate_percentage, 10, 999) + * draw_menu_item_setting_edit_int3(sel, row, PSTR(MSG_SPEED), PSTR(MSG_SPEED), &feedrate_percentage, 10, 999) * menu_item_int3::action_setting_edit(PSTR(MSG_SPEED), &feedrate_percentage, 10, 999) * */ #define _MENU_ITEM_VARIANT_P(TYPE, VARIANT, USE_MULTIPLIER, PLABEL, ...) do { \ _skipStatic = false; \ if (_menuLineNr == _thisItemNr) { \ - if (encoderLine == _thisItemNr && lcd_clicked) { \ - lcd_clicked = false; \ + if (encoderLine == _thisItemNr && ui.use_click()) { \ _MENU_ITEM_MULTIPLIER_CHECK(USE_MULTIPLIER); \ menu_item_ ## TYPE ::action ## VARIANT(__VA_ARGS__); \ if (screen_changed) return; \ } \ - if (lcdDrawUpdate) \ - lcd_implementation_drawmenu ## VARIANT ## _ ## TYPE(encoderLine == _thisItemNr, _lcdLineNr, PLABEL, ## __VA_ARGS__); \ + if (ui.should_draw()) \ + draw_menu_item ## VARIANT ## _ ## TYPE(encoderLine == _thisItemNr, _lcdLineNr, PLABEL, ## __VA_ARGS__); \ } \ ++_thisItemNr; \ }while(0) @@ -328,17 +284,17 @@ class menu_item_bool { #define STATIC_ITEM_P(PLABEL, ...) do{ \ if (_menuLineNr == _thisItemNr) { \ if (_skipStatic && encoderLine <= _thisItemNr) { \ - encoderPosition += ENCODER_STEPS_PER_MENU_ITEM; \ + ui.encoderPosition += ENCODER_STEPS_PER_MENU_ITEM; \ ++encoderLine; \ } \ - if (lcdDrawUpdate) \ - lcd_implementation_drawmenu_static(_lcdLineNr, PLABEL, ## __VA_ARGS__); \ + if (ui.should_draw()) \ + draw_menu_item_static(_lcdLineNr, PLABEL, ## __VA_ARGS__); \ } \ ++_thisItemNr; \ } while(0) #define MENU_ITEM_ADDON_START(X) \ - if (lcdDrawUpdate && _menuLineNr == _thisItemNr - 1) { \ + if (ui.should_draw() && _menuLineNr == _thisItemNr - 1) { \ SETCURSOR(X, _lcdLineNr) #define MENU_ITEM_ADDON_END() } (0) @@ -347,12 +303,12 @@ class menu_item_bool { #define MENU_BACK(LABEL) MENU_ITEM(back, LABEL) #define MENU_ITEM_DUMMY() do { _thisItemNr++; }while(0) -#define MENU_ITEM_P(TYPE, PLABEL, ...) _MENU_ITEM_VARIANT_P(TYPE, , 0, PLABEL, ## __VA_ARGS__) -#define MENU_ITEM(TYPE, LABEL, ...) _MENU_ITEM_VARIANT_P(TYPE, , 0, PSTR(LABEL), ## __VA_ARGS__) -#define MENU_ITEM_EDIT(TYPE, LABEL, ...) _MENU_ITEM_VARIANT_P(TYPE, _setting_edit, 0, PSTR(LABEL), PSTR(LABEL), ## __VA_ARGS__) -#define MENU_ITEM_EDIT_CALLBACK(TYPE, LABEL, ...) _MENU_ITEM_VARIANT_P(TYPE, _setting_edit, 0, PSTR(LABEL), PSTR(LABEL), ## __VA_ARGS__) -#define MENU_MULTIPLIER_ITEM_EDIT(TYPE, LABEL, ...) _MENU_ITEM_VARIANT_P(TYPE, _setting_edit, 1, PSTR(LABEL), PSTR(LABEL), ## __VA_ARGS__) -#define MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(TYPE, LABEL, ...) _MENU_ITEM_VARIANT_P(TYPE, _setting_edit, 1, PSTR(LABEL), PSTR(LABEL), ## __VA_ARGS__) +#define MENU_ITEM_P(TYPE, PLABEL, ...) _MENU_ITEM_VARIANT_P(TYPE, , false, PLABEL, ## __VA_ARGS__) +#define MENU_ITEM(TYPE, LABEL, ...) _MENU_ITEM_VARIANT_P(TYPE, , false, PSTR(LABEL), ## __VA_ARGS__) +#define MENU_ITEM_EDIT(TYPE, LABEL, ...) _MENU_ITEM_VARIANT_P(TYPE, _setting_edit, false, PSTR(LABEL), PSTR(LABEL), ## __VA_ARGS__) +#define MENU_ITEM_EDIT_CALLBACK(TYPE, LABEL, ...) _MENU_ITEM_VARIANT_P(TYPE, _setting_edit, false, PSTR(LABEL), PSTR(LABEL), ## __VA_ARGS__) +#define MENU_MULTIPLIER_ITEM_EDIT(TYPE, LABEL, ...) _MENU_ITEM_VARIANT_P(TYPE, _setting_edit, true, PSTR(LABEL), PSTR(LABEL), ## __VA_ARGS__) +#define MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(TYPE, LABEL, ...) _MENU_ITEM_VARIANT_P(TYPE, _setting_edit, true, PSTR(LABEL), PSTR(LABEL), ## __VA_ARGS__) //////////////////////////////////////////// /////////////// Menu Screens /////////////// @@ -379,7 +335,6 @@ void menu_move(); //////////////////////////////////////////// void lcd_move_z(); -void lcd_synchronize(PGM_P const msg=NULL); void _lcd_draw_homing(); void watch_temp_callback_E0(); @@ -426,3 +381,7 @@ void watch_temp_callback_bed(); void lcd_store_settings(); void lcd_load_settings(); #endif + +#if ENABLED(POWER_LOSS_RECOVERY) + void menu_job_recovery(); +#endif diff --git a/Marlin/src/lcd/menu/menu_advanced.cpp b/Marlin/src/lcd/menu/menu_advanced.cpp index a6174d5a70..bebf749214 100644 --- a/Marlin/src/lcd/menu/menu_advanced.cpp +++ b/Marlin/src/lcd/menu/menu_advanced.cpp @@ -52,7 +52,7 @@ // void _lcd_set_home_offsets() { enqueue_and_echo_commands_P(PSTR("M428")); - lcd_return_to_status(); + ui.return_to_status(); } #endif @@ -65,9 +65,9 @@ // static void _lcd_toggle_sd_update() { const bool new_state = !settings.sd_update_status(); - lcd_completion_feedback(settings.set_sd_update_status(new_state)); - lcd_return_to_status(); - if (new_state) LCD_MESSAGEPGM(MSG_RESET_PRINTER); else lcd_reset_status(); + ui.completion_feedback(settings.set_sd_update_status(new_state)); + ui.return_to_status(); + if (new_state) LCD_MESSAGEPGM(MSG_RESET_PRINTER); else ui.reset_status(); } #endif @@ -539,8 +539,8 @@ void menu_advanced_temperature() { #include "../../module/configuration_store.h" static void lcd_init_eeprom() { - lcd_completion_feedback(settings.init_eeprom()); - lcd_goto_previous_menu(); + ui.completion_feedback(settings.init_eeprom()); + ui.goto_previous_screen(); } static void lcd_init_eeprom_confirm() { diff --git a/Marlin/src/lcd/menu/menu_bed_corners.cpp b/Marlin/src/lcd/menu/menu_bed_corners.cpp index 0d51ef346d..037d6be03a 100644 --- a/Marlin/src/lcd/menu/menu_bed_corners.cpp +++ b/Marlin/src/lcd/menu/menu_bed_corners.cpp @@ -77,7 +77,7 @@ void menu_level_bed_corners() { MSG_NEXT_CORNER #endif , _lcd_goto_next_corner); - MENU_ITEM(function, MSG_BACK, lcd_goto_previous_menu_no_defer); + MENU_ITEM(function, MSG_BACK, ui.goto_previous_screen_no_defer); END_MENU(); } @@ -85,18 +85,18 @@ void _lcd_level_bed_corners_homing() { _lcd_draw_homing(); if (all_axes_homed()) { bed_corner = 0; - lcd_goto_screen(menu_level_bed_corners); + ui.goto_screen(menu_level_bed_corners); _lcd_goto_next_corner(); } } void _lcd_level_bed_corners() { - set_defer_return_to_status(true); + ui.defer_status_screen(true); if (!all_axes_known()) { set_all_unhomed(); enqueue_and_echo_commands_P(PSTR("G28")); } - lcd_goto_screen(_lcd_level_bed_corners_homing); + ui.goto_screen(_lcd_level_bed_corners_homing); } #endif // HAS_LCD_MENU && LEVEL_BED_CORNERS diff --git a/Marlin/src/lcd/menu/menu_bed_leveling.cpp b/Marlin/src/lcd/menu/menu_bed_leveling.cpp index ae43ca12b4..40c51b5726 100644 --- a/Marlin/src/lcd/menu/menu_bed_leveling.cpp +++ b/Marlin/src/lcd/menu/menu_bed_leveling.cpp @@ -26,7 +26,7 @@ #include "../../inc/MarlinConfigPre.h" -#if HAS_LCD_MENU && ENABLED(LCD_BED_LEVELING) +#if ENABLED(LCD_BED_LEVELING) #include "menu.h" #include "../../module/planner.h" @@ -56,7 +56,7 @@ #endif ); - bool lcd_wait_for_move; + bool MarlinUI::wait_for_bl_move; // = false // // Bed leveling is done. Wait for G29 to complete. @@ -70,17 +70,17 @@ // ** This blocks the command queue! ** // void _lcd_level_bed_done() { - if (!lcd_wait_for_move) { + if (!ui.wait_for_bl_move) { #if MANUAL_PROBE_HEIGHT > 0 && DISABLED(MESH_BED_LEVELING) // Display "Done" screen and wait for moves to complete line_to_z(MANUAL_PROBE_HEIGHT); - lcd_synchronize(PSTR(MSG_LEVEL_BED_DONE)); + ui.synchronize(PSTR(MSG_LEVEL_BED_DONE)); #endif - lcd_goto_previous_menu_no_defer(); - lcd_completion_feedback(); + ui.goto_previous_screen_no_defer(); + ui.completion_feedback(); } - if (lcdDrawUpdate) lcd_implementation_drawmenu_static(LCD_HEIGHT >= 4 ? 1 : 0, PSTR(MSG_LEVEL_BED_DONE)); - lcdDrawUpdate = LCDVIEW_CALL_REDRAW_NEXT; + if (ui.should_draw()) draw_menu_item_static(LCD_HEIGHT >= 4 ? 1 : 0, PSTR(MSG_LEVEL_BED_DONE)); + ui.refresh(LCDVIEW_CALL_REDRAW_NEXT); } void _lcd_level_goto_next_point(); @@ -89,9 +89,9 @@ // Step 7: Get the Z coordinate, click goes to the next point or exits // void _lcd_level_bed_get_z() { - ENCODER_DIRECTION_NORMAL(); + ui.encoder_direction_normal(); - if (use_click()) { + if (ui.use_click()) { // // Save the current Z position and move @@ -102,8 +102,8 @@ // // The last G29 records the point and enables bed leveling // - lcd_wait_for_move = true; - lcd_goto_screen(_lcd_level_bed_done); + ui.wait_for_bl_move = true; + ui.goto_screen(_lcd_level_bed_done); #if ENABLED(MESH_BED_LEVELING) enqueue_and_echo_commands_P(PSTR("G29 S2")); #elif ENABLED(PROBE_MANUALLY) @@ -119,19 +119,19 @@ // // Encoder knob or keypad buttons adjust the Z position // - if (encoderPosition) { - const float z = current_position[Z_AXIS] + float((int32_t)encoderPosition) * (MESH_EDIT_Z_STEP); + if (ui.encoderPosition) { + const float z = current_position[Z_AXIS] + float((int32_t)ui.encoderPosition) * (MESH_EDIT_Z_STEP); line_to_z(constrain(z, -(LCD_PROBE_Z_RANGE) * 0.5f, (LCD_PROBE_Z_RANGE) * 0.5f)); - lcdDrawUpdate = LCDVIEW_CALL_REDRAW_NEXT; - encoderPosition = 0; + ui.refresh(LCDVIEW_CALL_REDRAW_NEXT); + ui.encoderPosition = 0; } // // Draw on first display, then only on Z change // - if (lcdDrawUpdate) { + if (ui.should_draw()) { const float v = current_position[Z_AXIS]; - lcd_implementation_drawedit(PSTR(MSG_MOVE_Z), ftostr43sign(v + (v < 0 ? -0.0001f : 0.0001f), '+')); + draw_edit_screen(PSTR(MSG_MOVE_Z), ftostr43sign(v + (v < 0 ? -0.0001f : 0.0001f), '+')); } } @@ -139,23 +139,23 @@ // Step 6: Display "Next point: 1 / 9" while waiting for move to finish // void _lcd_level_bed_moving() { - if (lcdDrawUpdate) { + if (ui.should_draw()) { char msg[10]; sprintf_P(msg, PSTR("%i / %u"), (int)(manual_probe_index + 1), total_probe_points); - lcd_implementation_drawedit(PSTR(MSG_LEVEL_BED_NEXT_POINT), msg); + draw_edit_screen(PSTR(MSG_LEVEL_BED_NEXT_POINT), msg); } - lcdDrawUpdate = LCDVIEW_CALL_NO_REDRAW; - if (!lcd_wait_for_move) lcd_goto_screen(_lcd_level_bed_get_z); + ui.refresh(LCDVIEW_CALL_NO_REDRAW); + if (!ui.wait_for_bl_move) ui.goto_screen(_lcd_level_bed_get_z); } // // Step 5: Initiate a move to the next point // void _lcd_level_goto_next_point() { - lcd_goto_screen(_lcd_level_bed_moving); + ui.goto_screen(_lcd_level_bed_moving); // G29 Records Z, moves, and signals when it pauses - lcd_wait_for_move = true; + ui.wait_for_bl_move = true; #if ENABLED(MESH_BED_LEVELING) enqueue_and_echo_commands_P(manual_probe_index ? PSTR("G29 S2") : PSTR("G29 S1")); #elif ENABLED(PROBE_MANUALLY) @@ -168,8 +168,8 @@ // Move to the first probe position // void _lcd_level_bed_homing_done() { - if (lcdDrawUpdate) lcd_implementation_drawedit(PSTR(MSG_LEVEL_BED_WAITING)); - if (use_click()) { + if (ui.should_draw()) draw_edit_screen(PSTR(MSG_LEVEL_BED_WAITING)); + if (ui.use_click()) { manual_probe_index = 0; _lcd_level_goto_next_point(); } @@ -180,7 +180,7 @@ // void _lcd_level_bed_homing() { _lcd_draw_homing(); - if (all_axes_homed()) lcd_goto_screen(_lcd_level_bed_homing_done); + if (all_axes_homed()) ui.goto_screen(_lcd_level_bed_homing_done); } #if ENABLED(PROBE_MANUALLY) @@ -191,9 +191,9 @@ // Step 2: Continue Bed Leveling... // void _lcd_level_bed_continue() { - set_defer_return_to_status(true); + ui.defer_status_screen(true); set_all_unhomed(); - lcd_goto_screen(_lcd_level_bed_homing); + ui.goto_screen(_lcd_level_bed_homing); enqueue_and_echo_commands_P(PSTR("G28")); } @@ -292,4 +292,4 @@ void menu_bed_leveling() { END_MENU(); } -#endif // HAS_LCD_MENU && LCD_BED_LEVELING +#endif // LCD_BED_LEVELING diff --git a/Marlin/src/lcd/menu/menu_configuration.cpp b/Marlin/src/lcd/menu/menu_configuration.cpp index f8fcd5c9c0..b6348519f6 100644 --- a/Marlin/src/lcd/menu/menu_configuration.cpp +++ b/Marlin/src/lcd/menu/menu_configuration.cpp @@ -41,35 +41,31 @@ void menu_advanced_settings(); void menu_delta_calibrate(); -#if HAS_LCD_CONTRAST - void lcd_callback_set_contrast() { set_lcd_contrast(lcd_contrast); } -#endif - static void lcd_factory_settings() { settings.reset(); - lcd_completion_feedback(); + ui.completion_feedback(); } #if ENABLED(LCD_PROGRESS_BAR_TEST) static void progress_bar_test() { static int8_t bar_percent = 0; - if (use_click()) { - lcd_goto_previous_menu(); + if (ui.use_click()) { + ui.goto_previous_screen(); LCD_SET_CHARSET(CHARSET_MENU); return; } - bar_percent += (int8_t)encoderPosition; + bar_percent += (int8_t)ui.encoderPosition; bar_percent = constrain(bar_percent, 0, 100); - encoderPosition = 0; - lcd_implementation_drawmenu_static(0, PSTR(MSG_PROGRESS_BAR_TEST), true, true); + ui.encoderPosition = 0; + draw_menu_item_static(0, PSTR(MSG_PROGRESS_BAR_TEST), true, true); lcd_moveto((LCD_WIDTH) / 2 - 2, LCD_HEIGHT - 2); lcd_put_u8str(int(bar_percent)); lcd_put_wchar('%'); lcd_moveto(0, LCD_HEIGHT - 1); lcd_draw_progress_bar(bar_percent); } void _progress_bar_test() { - lcd_goto_screen(progress_bar_test); + ui.goto_screen(progress_bar_test); LCD_SET_CHARSET(CHARSET_INFO); } @@ -271,12 +267,12 @@ static void lcd_factory_settings() { #endif START_MENU(); MENU_BACK(MSG_CONFIGURATION); - MENU_ITEM_EDIT(int8, MSG_FAN_SPEED, &lcd_preheat_fan_speed[material], 0, 255); + MENU_ITEM_EDIT(int8, MSG_FAN_SPEED, &ui.preheat_fan_speed[material], 0, 255); #if HAS_TEMP_HOTEND - MENU_ITEM_EDIT(int3, MSG_NOZZLE, &lcd_preheat_hotend_temp[material], MINTEMP_ALL, MAXTEMP_ALL - 15); + MENU_ITEM_EDIT(int3, MSG_NOZZLE, &ui.preheat_hotend_temp[material], MINTEMP_ALL, MAXTEMP_ALL - 15); #endif #if HAS_HEATED_BED - MENU_ITEM_EDIT(int3, MSG_BED, &lcd_preheat_bed_temp[material], BED_MINTEMP, BED_MAXTEMP - 15); + MENU_ITEM_EDIT(int3, MSG_BED, &ui.preheat_bed_temp[material], BED_MINTEMP, BED_MAXTEMP - 15); #endif #if ENABLED(EEPROM_SETTINGS) MENU_ITEM(function, MSG_STORE_EEPROM, lcd_store_settings); @@ -338,7 +334,7 @@ void menu_configuration() { #endif #if HAS_LCD_CONTRAST - MENU_ITEM_EDIT_CALLBACK(int3, MSG_CONTRAST, &lcd_contrast, LCD_CONTRAST_MIN, LCD_CONTRAST_MAX, lcd_callback_set_contrast, true); + MENU_ITEM_EDIT_CALLBACK(int3, MSG_CONTRAST, &ui.contrast, LCD_CONTRAST_MIN, LCD_CONTRAST_MAX, ui.refresh_contrast, true); #endif #if ENABLED(FWRETRACT) MENU_ITEM(submenu, MSG_RETRACT, menu_config_retract); diff --git a/Marlin/src/lcd/menu/menu_custom.cpp b/Marlin/src/lcd/menu/menu_custom.cpp index f823a1049f..6b16bbc792 100644 --- a/Marlin/src/lcd/menu/menu_custom.cpp +++ b/Marlin/src/lcd/menu/menu_custom.cpp @@ -40,10 +40,10 @@ void _lcd_user_gcode(PGM_P const cmd) { enqueue_and_echo_commands_P(cmd); #if ENABLED(USER_SCRIPT_AUDIBLE_FEEDBACK) - lcd_completion_feedback(); + ui.completion_feedback(); #endif #if ENABLED(USER_SCRIPT_RETURN) - lcd_return_to_status(); + ui.return_to_status(); #endif } diff --git a/Marlin/src/lcd/menu/menu_delta_calibrate.cpp b/Marlin/src/lcd/menu/menu_delta_calibrate.cpp index 231a044f44..f83057b658 100644 --- a/Marlin/src/lcd/menu/menu_delta_calibrate.cpp +++ b/Marlin/src/lcd/menu/menu_delta_calibrate.cpp @@ -38,9 +38,9 @@ void _man_probe_pt(const float &rx, const float &ry) { do_blocking_move_to(rx, ry, Z_CLEARANCE_BETWEEN_PROBES); - lcd_synchronize(); + ui.synchronize(); move_menu_scale = MAX(PROBE_MANUALLY_STEP, MIN_STEPS_PER_SEGMENT / float(DEFAULT_XYZ_STEPS_PER_UNIT)); - lcd_goto_screen(lcd_move_z); + ui.goto_screen(lcd_move_z); } #if ENABLED(DELTA_AUTO_CALIBRATION) @@ -50,11 +50,11 @@ void _man_probe_pt(const float &rx, const float &ry) { float lcd_probe_pt(const float &rx, const float &ry) { _man_probe_pt(rx, ry); KEEPALIVE_STATE(PAUSED_FOR_USER); - set_defer_return_to_status(true); + ui.defer_status_screen(true); wait_for_user = true; while (wait_for_user) idle(); KEEPALIVE_STATE(IN_HANDLER); - lcd_goto_previous_menu_no_defer(); + ui.goto_previous_screen_no_defer(); return current_position[Z_AXIS]; } @@ -66,12 +66,12 @@ void _man_probe_pt(const float &rx, const float &ry) { void _lcd_calibrate_homing() { _lcd_draw_homing(); - if (all_axes_homed()) lcd_goto_previous_menu(); + if (all_axes_homed()) ui.goto_previous_screen(); } void _lcd_delta_calibrate_home() { enqueue_and_echo_commands_P(PSTR("G28")); - lcd_goto_screen(_lcd_calibrate_homing); + ui.goto_screen(_lcd_calibrate_homing); } void _goto_tower_x() { _man_probe_pt(cos(RADIANS(210)) * delta_calibration_radius, sin(RADIANS(210)) * delta_calibration_radius); } diff --git a/Marlin/src/lcd/menu/menu_filament.cpp b/Marlin/src/lcd/menu/menu_filament.cpp index 7eb5241797..b5938d0a98 100644 --- a/Marlin/src/lcd/menu/menu_filament.cpp +++ b/Marlin/src/lcd/menu/menu_filament.cpp @@ -323,15 +323,15 @@ static PGM_P advanced_pause_header() { // Portions from STATIC_ITEM... #define HOTEND_STATUS_ITEM() do { \ if (_menuLineNr == _thisItemNr) { \ - if (lcdDrawUpdate) { \ - lcd_implementation_drawmenu_static(_lcdLineNr, PSTR(MSG_FILAMENT_CHANGE_NOZZLE), false, true); \ - lcd_implementation_hotend_status(_lcdLineNr, hotend_status_extruder); \ + if (ui.should_draw()) { \ + draw_menu_item_static(_lcdLineNr, PSTR(MSG_FILAMENT_CHANGE_NOZZLE), false, true); \ + ui.draw_hotend_status(_lcdLineNr, hotend_status_extruder); \ } \ if (_skipStatic && encoderLine <= _thisItemNr) { \ - encoderPosition += ENCODER_STEPS_PER_MENU_ITEM; \ + ui.encoderPosition += ENCODER_STEPS_PER_MENU_ITEM; \ ++encoderLine; \ } \ - lcdDrawUpdate = LCDVIEW_CALL_REDRAW_NEXT; \ + ui.refresh(LCDVIEW_CALL_REDRAW_NEXT); \ } \ ++_thisItemNr; \ }while(0) @@ -507,11 +507,11 @@ void lcd_advanced_pause_show_message( hotend_status_extruder = extruder; const screenFunc_t next_screen = ap_message_screen(message); if (next_screen) { - set_defer_return_to_status(true); - lcd_goto_screen(next_screen); + ui.defer_status_screen(true); + ui.goto_screen(next_screen); } else - lcd_return_to_status(); + ui.return_to_status(); } #endif // HAS_LCD_MENU && ADVANCED_PAUSE_FEATURE diff --git a/Marlin/src/lcd/menu/menu_info.cpp b/Marlin/src/lcd/menu/menu_info.cpp index a4860093eb..3bd7054cdc 100644 --- a/Marlin/src/lcd/menu/menu_info.cpp +++ b/Marlin/src/lcd/menu/menu_info.cpp @@ -47,7 +47,7 @@ // About Printer > Printer Stats // void menu_info_stats() { - if (use_click()) { return lcd_goto_previous_menu(); } + if (ui.use_click()) return ui.goto_previous_screen(); char buffer[21]; printStatistics stats = print_job_timer.getStats(); @@ -80,7 +80,7 @@ // About Printer > Thermistors // void menu_info_thermistors() { - if (use_click()) { return lcd_goto_previous_menu(); } + if (ui.use_click()) return ui.goto_previous_screen(); START_SCREEN(); #define THERMISTOR_ID TEMP_SENSOR_0 #include "../thermistornames.h" @@ -139,7 +139,7 @@ void menu_info_thermistors() { // About Printer > Board Info // void menu_info_board() { - if (use_click()) { return lcd_goto_previous_menu(); } + if (ui.use_click()) return ui.goto_previous_screen(); START_SCREEN(); STATIC_ITEM(BOARD_NAME, true, true); // MyPrinterController STATIC_ITEM(MSG_INFO_BAUDRATE ": " STRINGIFY(BAUDRATE), true); // Baud: 250000 @@ -158,7 +158,7 @@ void menu_info_board() { // About Printer > Printer Info // void menu_info_printer() { - if (use_click()) { return lcd_goto_previous_menu(); } + if (ui.use_click()) return ui.goto_previous_screen(); START_SCREEN(); STATIC_ITEM(MSG_MARLIN, true, true); // Marlin STATIC_ITEM(SHORT_BUILD_VERSION, true); // x.x.x-Branch diff --git a/Marlin/src/lcd/menu/menu_job_recovery.cpp b/Marlin/src/lcd/menu/menu_job_recovery.cpp index 31b375d0de..c0a38525d4 100644 --- a/Marlin/src/lcd/menu/menu_job_recovery.cpp +++ b/Marlin/src/lcd/menu/menu_job_recovery.cpp @@ -37,7 +37,7 @@ static void lcd_power_loss_recovery_resume() { char cmd[20]; // Return to status now - lcd_return_to_status(); + ui.return_to_status(); // Turn leveling off and home enqueue_and_echo_commands_P(PSTR("M420 S0\nG28 R0" @@ -91,11 +91,11 @@ static void lcd_power_loss_recovery_resume() { static void lcd_power_loss_recovery_cancel() { card.removeJobRecoveryFile(); card.autostart_index = 0; - lcd_return_to_status(); + ui.return_to_status(); } void menu_job_recovery() { - set_defer_return_to_status(true); + ui.defer_status_screen(true); START_MENU(); STATIC_ITEM(MSG_POWER_LOSS_RECOVERY); MENU_ITEM(function, MSG_RESUME_PRINT, lcd_power_loss_recovery_resume); diff --git a/Marlin/src/lcd/menu/menu_main.cpp b/Marlin/src/lcd/menu/menu_main.cpp index ae661a3b54..e3332d538a 100644 --- a/Marlin/src/lcd/menu/menu_main.cpp +++ b/Marlin/src/lcd/menu/menu_main.cpp @@ -43,7 +43,7 @@ #if ENABLED(PARK_HEAD_ON_PAUSE) enqueue_and_echo_commands_P(PSTR("M125")); #endif - lcd_reset_status(); + ui.reset_status(); } void lcd_sdcard_resume() { @@ -53,14 +53,14 @@ card.startFileprint(); print_job_timer.start(); #endif - lcd_reset_status(); + ui.reset_status(); } void lcd_sdcard_stop() { wait_for_heatup = wait_for_user = false; card.abort_sd_printing = true; - lcd_setstatusPGM(PSTR(MSG_PRINT_ABORTED), -1); - lcd_return_to_status(); + ui.setstatusPGM(PSTR(MSG_PRINT_ABORTED), -1); + ui.return_to_status(); } #if ENABLED(MENU_ADDAUTOSTART) diff --git a/Marlin/src/lcd/menu/menu_motion.cpp b/Marlin/src/lcd/menu/menu_motion.cpp index e4d6f50944..e4c29ad18c 100644 --- a/Marlin/src/lcd/menu/menu_motion.cpp +++ b/Marlin/src/lcd/menu/menu_motion.cpp @@ -46,9 +46,6 @@ extern millis_t manual_move_start_time; extern int8_t manual_move_axis; -#if ENABLED(DUAL_X_CARRIAGE) || E_MANUAL > 1 - extern int8_t manual_move_e_index; -#endif #if ENABLED(MANUAL_E_MOVES_RELATIVE) float manual_move_e_origin = 0; #endif @@ -57,18 +54,15 @@ extern int8_t manual_move_axis; #endif // -// Tell lcd_update() to start a move to current_position" after a short delay. +// Tell ui.update() to start a move to current_position" after a short delay. // inline void manual_move_to_current(AxisEnum axis #if E_MANUAL > 1 , const int8_t eindex=-1 #endif ) { - #if ENABLED(DUAL_X_CARRIAGE) || E_MANUAL > 1 - #if E_MANUAL > 1 - if (axis == E_AXIS) - #endif - manual_move_e_index = eindex >= 0 ? eindex : active_extruder; + #if E_MANUAL > 1 + if (axis == E_AXIS) ui.manual_move_e_index = eindex >= 0 ? eindex : active_extruder; #endif manual_move_start_time = millis() + (move_menu_scale < 0.99f ? 0UL : 250UL); // delay for bigger moves manual_move_axis = (int8_t)axis; @@ -79,9 +73,9 @@ inline void manual_move_to_current(AxisEnum axis // static void _lcd_move_xyz(PGM_P name, AxisEnum axis) { - if (use_click()) { return lcd_goto_previous_menu_no_defer(); } - ENCODER_DIRECTION_NORMAL(); - if (encoderPosition && !processing_manual_move) { + if (ui.use_click()) return ui.goto_previous_screen_no_defer(); + ui.encoder_direction_normal(); + if (ui.encoderPosition && !ui.processing_manual_move) { // Start with no limits to movement float min = current_position[axis] - 1000, @@ -127,32 +121,32 @@ static void _lcd_move_xyz(PGM_P name, AxisEnum axis) { #endif // Get the new position - const float diff = float((int32_t)encoderPosition) * move_menu_scale; + const float diff = float((int32_t)ui.encoderPosition) * move_menu_scale; #if IS_KINEMATIC manual_move_offset += diff; - if ((int32_t)encoderPosition < 0) + if ((int32_t)ui.encoderPosition < 0) NOLESS(manual_move_offset, min - current_position[axis]); else NOMORE(manual_move_offset, max - current_position[axis]); #else current_position[axis] += diff; - if ((int32_t)encoderPosition < 0) + if ((int32_t)ui.encoderPosition < 0) NOLESS(current_position[axis], min); else NOMORE(current_position[axis], max); #endif manual_move_to_current(axis); - lcdDrawUpdate = LCDVIEW_REDRAW_NOW; + ui.refresh(LCDVIEW_REDRAW_NOW); } - encoderPosition = 0; - if (lcdDrawUpdate) { - const float pos = NATIVE_TO_LOGICAL(processing_manual_move ? destination[axis] : current_position[axis] + ui.encoderPosition = 0; + if (ui.should_draw()) { + const float pos = NATIVE_TO_LOGICAL(ui.processing_manual_move ? destination[axis] : current_position[axis] #if IS_KINEMATIC + manual_move_offset #endif , axis); - lcd_implementation_drawedit(name, move_menu_scale >= 0.1f ? ftostr41sign(pos) : ftostr43sign(pos)); + draw_edit_screen(name, move_menu_scale >= 0.1f ? ftostr41sign(pos) : ftostr43sign(pos)); } } void lcd_move_x() { _lcd_move_xyz(PSTR(MSG_MOVE_X), X_AXIS); } @@ -163,11 +157,11 @@ static void _lcd_move_e( const int8_t eindex=-1 #endif ) { - if (use_click()) { return lcd_goto_previous_menu_no_defer(); } - ENCODER_DIRECTION_NORMAL(); - if (encoderPosition) { - if (!processing_manual_move) { - const float diff = float((int32_t)encoderPosition) * move_menu_scale; + if (ui.use_click()) return ui.goto_previous_screen_no_defer(); + ui.encoder_direction_normal(); + if (ui.encoderPosition) { + if (!ui.processing_manual_move) { + const float diff = float((int32_t)ui.encoderPosition) * move_menu_scale; #if IS_KINEMATIC manual_move_offset += diff; #else @@ -178,11 +172,11 @@ static void _lcd_move_e( , eindex #endif ); - lcdDrawUpdate = LCDVIEW_REDRAW_NOW; + ui.refresh(LCDVIEW_REDRAW_NOW); } - encoderPosition = 0; + ui.encoderPosition = 0; } - if (lcdDrawUpdate) { + if (ui.should_draw()) { PGM_P pos_label; #if E_MANUAL == 1 pos_label = PSTR(MSG_MOVE_E); @@ -205,7 +199,7 @@ static void _lcd_move_e( } #endif // E_MANUAL > 1 - lcd_implementation_drawedit(pos_label, ftostr41sign(current_position[E_AXIS] + draw_edit_screen(pos_label, ftostr41sign(current_position[E_AXIS] #if IS_KINEMATIC + manual_move_offset #endif @@ -241,9 +235,9 @@ inline void lcd_move_e() { _lcd_move_e(); } screenFunc_t _manual_move_func_ptr; void _goto_manual_move(const float scale) { - set_defer_return_to_status(true); + ui.defer_status_screen(true); move_menu_scale = scale; - lcd_goto_screen(_manual_move_func_ptr); + ui.goto_screen(_manual_move_func_ptr); } void menu_move_10mm() { _goto_manual_move(10); } void menu_move_1mm() { _goto_manual_move( 1); } @@ -305,7 +299,7 @@ void lcd_move_get_e_amount() { _menu_move_distance(E_AXIS, lcd_move_e, -1); } #if ENABLED(DELTA) void lcd_lower_z_to_clip_height() { line_to_z(delta_clip_start_height); - lcd_synchronize(); + ui.synchronize(); } #endif diff --git a/Marlin/src/lcd/menu/menu_sdcard.cpp b/Marlin/src/lcd/menu/menu_sdcard.cpp index 7677025207..85caa17a23 100644 --- a/Marlin/src/lcd/menu/menu_sdcard.cpp +++ b/Marlin/src/lcd/menu/menu_sdcard.cpp @@ -39,35 +39,36 @@ #endif void lcd_sd_updir() { - encoderPosition = card.updir() ? ENCODER_STEPS_PER_MENU_ITEM : 0; + ui.encoderPosition = card.updir() ? ENCODER_STEPS_PER_MENU_ITEM : 0; encoderTopLine = 0; screen_changed = true; - lcd_refresh(); + ui.refresh(); } #if ENABLED(SD_REPRINT_LAST_SELECTED_FILE) + uint32_t last_sdfile_encoderPosition = 0xFFFF; - void lcd_reselect_last_file() { + void MarlinUI::reselect_last_file() { if (last_sdfile_encoderPosition == 0xFFFF) return; - #if HAS_GRAPHICAL_LCD - // Some of this is a hack to force the screen update to work. - // TODO: Fix the real issue that causes this! - lcdDrawUpdate = LCDVIEW_CALL_REDRAW_NEXT; - lcd_synchronize(); - safe_delay(50); - lcd_synchronize(); - lcdDrawUpdate = LCDVIEW_CALL_REDRAW_NEXT; - drawing_screen = screen_changed = true; - #endif + //#if HAS_GRAPHICAL_LCD + // // This is a hack to force a screen update. + // ui.refresh(LCDVIEW_CALL_REDRAW_NEXT); + // ui.synchronize(); + // safe_delay(50); + // ui.synchronize(); + // ui.refresh(LCDVIEW_CALL_REDRAW_NEXT); + // ui.drawing_screen = screen_changed = true; + //#endif - lcd_goto_screen(menu_sdcard, last_sdfile_encoderPosition); - set_defer_return_to_status(true); + goto_screen(menu_sdcard, last_sdfile_encoderPosition); last_sdfile_encoderPosition = 0xFFFF; - #if HAS_GRAPHICAL_LCD - lcd_update(); - #endif + defer_status_screen(true); + + //#if HAS_GRAPHICAL_LCD + // update(); + //#endif } #endif @@ -75,30 +76,30 @@ class menu_item_sdfile { public: static void action(CardReader &theCard) { #if ENABLED(SD_REPRINT_LAST_SELECTED_FILE) - last_sdfile_encoderPosition = encoderPosition; // Save which file was selected for later use + last_sdfile_encoderPosition = ui.encoderPosition; // Save which file was selected for later use #endif card.openAndPrintFile(theCard.filename); - lcd_return_to_status(); - lcd_reset_status(); + ui.return_to_status(); + ui.reset_status(); } }; -class menu_item_sddirectory { +class menu_item_sdfolder { public: static void action(CardReader &theCard) { card.chdir(theCard.filename); encoderTopLine = 0; - encoderPosition = 2 * ENCODER_STEPS_PER_MENU_ITEM; + ui.encoderPosition = 2 * ENCODER_STEPS_PER_MENU_ITEM; screen_changed = true; #if HAS_GRAPHICAL_LCD - drawing_screen = false; + ui.drawing_screen = false; #endif - lcd_refresh(); + ui.refresh(); } }; void menu_sdcard() { - ENCODER_DIRECTION_MENUS(); + ui.encoder_direction_menus(); const uint16_t fileCnt = card.get_num_Files(); @@ -125,7 +126,7 @@ void menu_sdcard() { card.getfilename_sorted(nr); if (card.filenameIsDir) - MENU_ITEM(sddirectory, MSG_CARD_MENU, card); + MENU_ITEM(sdfolder, MSG_CARD_MENU, card); else MENU_ITEM(sdfile, MSG_CARD_MENU, card); } diff --git a/Marlin/src/lcd/menu/menu_temperature.cpp b/Marlin/src/lcd/menu/menu_temperature.cpp index 2f0434dc69..2883fe752e 100644 --- a/Marlin/src/lcd/menu/menu_temperature.cpp +++ b/Marlin/src/lcd/menu/menu_temperature.cpp @@ -36,8 +36,8 @@ #endif // Initialized by settings.load() -int16_t lcd_preheat_hotend_temp[2], lcd_preheat_bed_temp[2]; -uint8_t lcd_preheat_fan_speed[2]; +int16_t MarlinUI::preheat_hotend_temp[2], MarlinUI::preheat_bed_temp[2]; +uint8_t MarlinUI::preheat_fan_speed[2]; // // "Temperature" submenu items @@ -59,44 +59,44 @@ void _lcd_preheat(const int16_t endnum, const int16_t temph, const int16_t tempb #else UNUSED(fan); #endif - lcd_return_to_status(); + ui.return_to_status(); } #if HOTENDS > 1 - void lcd_preheat_m1_e1_only() { _lcd_preheat(1, lcd_preheat_hotend_temp[0], -1, lcd_preheat_fan_speed[0]); } - void lcd_preheat_m2_e1_only() { _lcd_preheat(1, lcd_preheat_hotend_temp[1], -1, lcd_preheat_fan_speed[1]); } + void lcd_preheat_m1_e1_only() { _lcd_preheat(1, ui.preheat_hotend_temp[0], -1, ui.preheat_fan_speed[0]); } + void lcd_preheat_m2_e1_only() { _lcd_preheat(1, ui.preheat_hotend_temp[1], -1, ui.preheat_fan_speed[1]); } #if HAS_HEATED_BED - void lcd_preheat_m1_e1() { _lcd_preheat(1, lcd_preheat_hotend_temp[0], lcd_preheat_bed_temp[0], lcd_preheat_fan_speed[0]); } - void lcd_preheat_m2_e1() { _lcd_preheat(1, lcd_preheat_hotend_temp[1], lcd_preheat_bed_temp[1], lcd_preheat_fan_speed[1]); } + void lcd_preheat_m1_e1() { _lcd_preheat(1, ui.preheat_hotend_temp[0], ui.preheat_bed_temp[0], ui.preheat_fan_speed[0]); } + void lcd_preheat_m2_e1() { _lcd_preheat(1, ui.preheat_hotend_temp[1], ui.preheat_bed_temp[1], ui.preheat_fan_speed[1]); } #endif #if HOTENDS > 2 - void lcd_preheat_m1_e2_only() { _lcd_preheat(2, lcd_preheat_hotend_temp[0], -1, lcd_preheat_fan_speed[0]); } - void lcd_preheat_m2_e2_only() { _lcd_preheat(2, lcd_preheat_hotend_temp[1], -1, lcd_preheat_fan_speed[1]); } + void lcd_preheat_m1_e2_only() { _lcd_preheat(2, ui.preheat_hotend_temp[0], -1, ui.preheat_fan_speed[0]); } + void lcd_preheat_m2_e2_only() { _lcd_preheat(2, ui.preheat_hotend_temp[1], -1, ui.preheat_fan_speed[1]); } #if HAS_HEATED_BED - void lcd_preheat_m1_e2() { _lcd_preheat(2, lcd_preheat_hotend_temp[0], lcd_preheat_bed_temp[0], lcd_preheat_fan_speed[0]); } - void lcd_preheat_m2_e2() { _lcd_preheat(2, lcd_preheat_hotend_temp[1], lcd_preheat_bed_temp[1], lcd_preheat_fan_speed[1]); } + void lcd_preheat_m1_e2() { _lcd_preheat(2, ui.preheat_hotend_temp[0], ui.preheat_bed_temp[0], ui.preheat_fan_speed[0]); } + void lcd_preheat_m2_e2() { _lcd_preheat(2, ui.preheat_hotend_temp[1], ui.preheat_bed_temp[1], ui.preheat_fan_speed[1]); } #endif #if HOTENDS > 3 - void lcd_preheat_m1_e3_only() { _lcd_preheat(3, lcd_preheat_hotend_temp[0], -1, lcd_preheat_fan_speed[0]); } - void lcd_preheat_m2_e3_only() { _lcd_preheat(3, lcd_preheat_hotend_temp[1], -1, lcd_preheat_fan_speed[1]); } + void lcd_preheat_m1_e3_only() { _lcd_preheat(3, ui.preheat_hotend_temp[0], -1, ui.preheat_fan_speed[0]); } + void lcd_preheat_m2_e3_only() { _lcd_preheat(3, ui.preheat_hotend_temp[1], -1, ui.preheat_fan_speed[1]); } #if HAS_HEATED_BED - void lcd_preheat_m1_e3() { _lcd_preheat(3, lcd_preheat_hotend_temp[0], lcd_preheat_bed_temp[0], lcd_preheat_fan_speed[0]); } - void lcd_preheat_m2_e3() { _lcd_preheat(3, lcd_preheat_hotend_temp[1], lcd_preheat_bed_temp[1], lcd_preheat_fan_speed[1]); } + void lcd_preheat_m1_e3() { _lcd_preheat(3, ui.preheat_hotend_temp[0], ui.preheat_bed_temp[0], ui.preheat_fan_speed[0]); } + void lcd_preheat_m2_e3() { _lcd_preheat(3, ui.preheat_hotend_temp[1], ui.preheat_bed_temp[1], ui.preheat_fan_speed[1]); } #endif #if HOTENDS > 4 - void lcd_preheat_m1_e4_only() { _lcd_preheat(4, lcd_preheat_hotend_temp[0], -1, lcd_preheat_fan_speed[0]); } - void lcd_preheat_m2_e4_only() { _lcd_preheat(4, lcd_preheat_hotend_temp[1], -1, lcd_preheat_fan_speed[1]); } + void lcd_preheat_m1_e4_only() { _lcd_preheat(4, ui.preheat_hotend_temp[0], -1, ui.preheat_fan_speed[0]); } + void lcd_preheat_m2_e4_only() { _lcd_preheat(4, ui.preheat_hotend_temp[1], -1, ui.preheat_fan_speed[1]); } #if HAS_HEATED_BED - void lcd_preheat_m1_e4() { _lcd_preheat(4, lcd_preheat_hotend_temp[0], lcd_preheat_bed_temp[0], lcd_preheat_fan_speed[0]); } - void lcd_preheat_m2_e4() { _lcd_preheat(4, lcd_preheat_hotend_temp[1], lcd_preheat_bed_temp[1], lcd_preheat_fan_speed[1]); } + void lcd_preheat_m1_e4() { _lcd_preheat(4, ui.preheat_hotend_temp[0], ui.preheat_bed_temp[0], ui.preheat_fan_speed[0]); } + void lcd_preheat_m2_e4() { _lcd_preheat(4, ui.preheat_hotend_temp[1], ui.preheat_bed_temp[1], ui.preheat_fan_speed[1]); } #endif #if HOTENDS > 5 - void lcd_preheat_m1_e5_only() { _lcd_preheat(5, lcd_preheat_hotend_temp[0], -1, lcd_preheat_fan_speed[0]); } - void lcd_preheat_m2_e5_only() { _lcd_preheat(5, lcd_preheat_hotend_temp[1], -1, lcd_preheat_fan_speed[1]); } + void lcd_preheat_m1_e5_only() { _lcd_preheat(5, ui.preheat_hotend_temp[0], -1, ui.preheat_fan_speed[0]); } + void lcd_preheat_m2_e5_only() { _lcd_preheat(5, ui.preheat_hotend_temp[1], -1, ui.preheat_fan_speed[1]); } #if HAS_HEATED_BED - void lcd_preheat_m1_e5() { _lcd_preheat(5, lcd_preheat_hotend_temp[0], lcd_preheat_bed_temp[0], lcd_preheat_fan_speed[0]); } - void lcd_preheat_m2_e5() { _lcd_preheat(5, lcd_preheat_hotend_temp[1], lcd_preheat_bed_temp[1], lcd_preheat_fan_speed[1]); } + void lcd_preheat_m1_e5() { _lcd_preheat(5, ui.preheat_hotend_temp[0], ui.preheat_bed_temp[0], ui.preheat_fan_speed[0]); } + void lcd_preheat_m2_e5() { _lcd_preheat(5, ui.preheat_hotend_temp[1], ui.preheat_bed_temp[1], ui.preheat_fan_speed[1]); } #endif #endif // HOTENDS > 5 #endif // HOTENDS > 4 @@ -113,15 +113,15 @@ void _lcd_preheat(const int16_t endnum, const int16_t temph, const int16_t tempb void lcd_preheat_m1_all() { #if HOTENDS > 1 - thermalManager.setTargetHotend(lcd_preheat_hotend_temp[0], 1); + thermalManager.setTargetHotend(ui.preheat_hotend_temp[0], 1); #if HOTENDS > 2 - thermalManager.setTargetHotend(lcd_preheat_hotend_temp[0], 2); + thermalManager.setTargetHotend(ui.preheat_hotend_temp[0], 2); #if HOTENDS > 3 - thermalManager.setTargetHotend(lcd_preheat_hotend_temp[0], 3); + thermalManager.setTargetHotend(ui.preheat_hotend_temp[0], 3); #if HOTENDS > 4 - thermalManager.setTargetHotend(lcd_preheat_hotend_temp[0], 4); + thermalManager.setTargetHotend(ui.preheat_hotend_temp[0], 4); #if HOTENDS > 5 - thermalManager.setTargetHotend(lcd_preheat_hotend_temp[0], 5); + thermalManager.setTargetHotend(ui.preheat_hotend_temp[0], 5); #endif // HOTENDS > 5 #endif // HOTENDS > 4 #endif // HOTENDS > 3 @@ -136,15 +136,15 @@ void _lcd_preheat(const int16_t endnum, const int16_t temph, const int16_t tempb void lcd_preheat_m2_all() { #if HOTENDS > 1 - thermalManager.setTargetHotend(lcd_preheat_hotend_temp[1], 1); + thermalManager.setTargetHotend(ui.preheat_hotend_temp[1], 1); #if HOTENDS > 2 - thermalManager.setTargetHotend(lcd_preheat_hotend_temp[1], 2); + thermalManager.setTargetHotend(ui.preheat_hotend_temp[1], 2); #if HOTENDS > 3 - thermalManager.setTargetHotend(lcd_preheat_hotend_temp[1], 3); + thermalManager.setTargetHotend(ui.preheat_hotend_temp[1], 3); #if HOTENDS > 4 - thermalManager.setTargetHotend(lcd_preheat_hotend_temp[1], 4); + thermalManager.setTargetHotend(ui.preheat_hotend_temp[1], 4); #if HOTENDS > 5 - thermalManager.setTargetHotend(lcd_preheat_hotend_temp[1], 5); + thermalManager.setTargetHotend(ui.preheat_hotend_temp[1], 5); #endif // HOTENDS > 5 #endif // HOTENDS > 4 #endif // HOTENDS > 3 @@ -161,14 +161,14 @@ void _lcd_preheat(const int16_t endnum, const int16_t temph, const int16_t tempb #if HAS_TEMP_HOTEND || HAS_HEATED_BED - void lcd_preheat_m1_e0_only() { _lcd_preheat(0, lcd_preheat_hotend_temp[0], -1, lcd_preheat_fan_speed[0]); } - void lcd_preheat_m2_e0_only() { _lcd_preheat(0, lcd_preheat_hotend_temp[1], -1, lcd_preheat_fan_speed[1]); } + void lcd_preheat_m1_e0_only() { _lcd_preheat(0, ui.preheat_hotend_temp[0], -1, ui.preheat_fan_speed[0]); } + void lcd_preheat_m2_e0_only() { _lcd_preheat(0, ui.preheat_hotend_temp[1], -1, ui.preheat_fan_speed[1]); } #if HAS_HEATED_BED - void lcd_preheat_m1_e0() { _lcd_preheat(0, lcd_preheat_hotend_temp[0], lcd_preheat_bed_temp[0], lcd_preheat_fan_speed[0]); } - void lcd_preheat_m2_e0() { _lcd_preheat(0, lcd_preheat_hotend_temp[1], lcd_preheat_bed_temp[1], lcd_preheat_fan_speed[1]); } - void lcd_preheat_m1_bedonly() { _lcd_preheat(0, 0, lcd_preheat_bed_temp[0], lcd_preheat_fan_speed[0]); } - void lcd_preheat_m2_bedonly() { _lcd_preheat(0, 0, lcd_preheat_bed_temp[1], lcd_preheat_fan_speed[1]); } + void lcd_preheat_m1_e0() { _lcd_preheat(0, ui.preheat_hotend_temp[0], ui.preheat_bed_temp[0], ui.preheat_fan_speed[0]); } + void lcd_preheat_m2_e0() { _lcd_preheat(0, ui.preheat_hotend_temp[1], ui.preheat_bed_temp[1], ui.preheat_fan_speed[1]); } + void lcd_preheat_m1_bedonly() { _lcd_preheat(0, 0, ui.preheat_bed_temp[0], ui.preheat_fan_speed[0]); } + void lcd_preheat_m2_bedonly() { _lcd_preheat(0, 0, ui.preheat_bed_temp[1], ui.preheat_fan_speed[1]); } #endif void menu_preheat_m1() { @@ -294,7 +294,7 @@ void _lcd_preheat(const int16_t endnum, const int16_t temph, const int16_t tempb void lcd_cooldown() { zero_fan_speeds(); thermalManager.disable_all_heaters(); - lcd_return_to_status(); + ui.return_to_status(); } #endif // HAS_TEMP_HOTEND || HAS_HEATED_BED diff --git a/Marlin/src/lcd/menu/menu_tune.cpp b/Marlin/src/lcd/menu/menu_tune.cpp index b4f3476585..b3e41fa5d0 100644 --- a/Marlin/src/lcd/menu/menu_tune.cpp +++ b/Marlin/src/lcd/menu/menu_tune.cpp @@ -62,29 +62,29 @@ void _lcd_refresh_e_factor_0() { planner.refresh_e_factor(0); } long babysteps_done = 0; void _lcd_babystep(const AxisEnum axis, PGM_P msg) { - if (use_click()) { return lcd_goto_previous_menu_no_defer(); } - ENCODER_DIRECTION_NORMAL(); - if (encoderPosition) { - const int16_t babystep_increment = (int32_t)encoderPosition * (BABYSTEP_MULTIPLICATOR); - encoderPosition = 0; - lcdDrawUpdate = LCDVIEW_REDRAW_NOW; + if (ui.use_click()) return ui.goto_previous_screen_no_defer(); + ui.encoder_direction_normal(); + if (ui.encoderPosition) { + const int16_t babystep_increment = (int32_t)ui.encoderPosition * (BABYSTEP_MULTIPLICATOR); + ui.encoderPosition = 0; + ui.refresh(LCDVIEW_REDRAW_NOW); thermalManager.babystep_axis(axis, babystep_increment); babysteps_done += babystep_increment; } - if (lcdDrawUpdate) - lcd_implementation_drawedit(msg, ftostr43sign(planner.steps_to_mm[axis] * babysteps_done)); + if (ui.should_draw()) + draw_edit_screen(msg, ftostr43sign(planner.steps_to_mm[axis] * babysteps_done)); } #if ENABLED(BABYSTEP_XY) void _lcd_babystep_x() { _lcd_babystep(X_AXIS, PSTR(MSG_BABYSTEP_X)); } void _lcd_babystep_y() { _lcd_babystep(Y_AXIS, PSTR(MSG_BABYSTEP_Y)); } - void lcd_babystep_x() { lcd_goto_screen(_lcd_babystep_x); babysteps_done = 0; set_defer_return_to_status(true); } - void lcd_babystep_y() { lcd_goto_screen(_lcd_babystep_y); babysteps_done = 0; set_defer_return_to_status(true); } + void lcd_babystep_x() { ui.goto_screen(_lcd_babystep_x); babysteps_done = 0; ui.defer_status_screen(true); } + void lcd_babystep_y() { ui.goto_screen(_lcd_babystep_y); babysteps_done = 0; ui.defer_status_screen(true); } #endif #if DISABLED(BABYSTEP_ZPROBE_OFFSET) void _lcd_babystep_z() { _lcd_babystep(Z_AXIS, PSTR(MSG_BABYSTEP_Z)); } - void lcd_babystep_z() { lcd_goto_screen(_lcd_babystep_z); babysteps_done = 0; set_defer_return_to_status(true); } + void lcd_babystep_z() { ui.goto_screen(_lcd_babystep_z); babysteps_done = 0; ui.defer_status_screen(true); } #endif #endif // BABYSTEPPING diff --git a/Marlin/src/lcd/menu/menu_ubl.cpp b/Marlin/src/lcd/menu/menu_ubl.cpp index 2686e6b0c3..146c9268f1 100644 --- a/Marlin/src/lcd/menu/menu_ubl.cpp +++ b/Marlin/src/lcd/menu/menu_ubl.cpp @@ -51,22 +51,22 @@ float mesh_edit_value, mesh_edit_accumulator; // We round mesh_edit_value to 2.5 static int16_t ubl_encoderPosition = 0; static void _lcd_mesh_fine_tune(PGM_P msg) { - set_defer_return_to_status(true); + ui.defer_status_screen(true); if (ubl.encoder_diff) { ubl_encoderPosition = (ubl.encoder_diff > 0) ? 1 : -1; ubl.encoder_diff = 0; mesh_edit_accumulator += float(ubl_encoderPosition) * 0.005f * 0.5f; mesh_edit_value = mesh_edit_accumulator; - encoderPosition = 0; - lcdDrawUpdate = LCDVIEW_CALL_REDRAW_NEXT; + 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 (lcdDrawUpdate) { - lcd_implementation_drawedit(msg, ftostr43sign(mesh_edit_value)); + if (ui.should_draw()) { + draw_edit_screen(msg, ftostr43sign(mesh_edit_value)); #if ENABLED(MESH_EDIT_GFX_OVERLAY) _lcd_zoffset_overlay_gfx(mesh_edit_value); #endif @@ -74,19 +74,19 @@ static void _lcd_mesh_fine_tune(PGM_P msg) { } void _lcd_mesh_edit_NOP() { - set_defer_return_to_status(true); + ui.defer_status_screen(true); } float lcd_mesh_edit() { - lcd_goto_screen(_lcd_mesh_edit_NOP); - lcdDrawUpdate = LCDVIEW_CALL_REDRAW_NEXT; + ui.goto_screen(_lcd_mesh_edit_NOP); + ui.refresh(LCDVIEW_CALL_REDRAW_NEXT); _lcd_mesh_fine_tune(PSTR("Mesh Editor")); return mesh_edit_value; } void lcd_mesh_edit_setup(const float &initial) { mesh_edit_value = mesh_edit_accumulator = initial; - lcd_goto_screen(_lcd_mesh_edit_NOP); + ui.goto_screen(_lcd_mesh_edit_NOP); } void _lcd_z_offset_edit() { @@ -94,13 +94,13 @@ void _lcd_z_offset_edit() { } float lcd_z_offset_edit() { - lcd_goto_screen(_lcd_z_offset_edit); + ui.goto_screen(_lcd_z_offset_edit); return mesh_edit_value; } void lcd_z_offset_edit_setup(const float &initial) { mesh_edit_value = mesh_edit_accumulator = initial; - lcd_goto_screen(_lcd_z_offset_edit); + ui.goto_screen(_lcd_z_offset_edit); } /** @@ -160,7 +160,7 @@ void _menu_ubl_height_adjust() { START_MENU(); MENU_BACK(MSG_EDIT_MESH); MENU_ITEM_EDIT_CALLBACK(int3, MSG_UBL_MESH_HEIGHT_AMOUNT, &ubl_height_amount, -9, 9, _lcd_ubl_adjust_height_cmd); - MENU_ITEM(function, MSG_WATCH, lcd_return_to_status); + MENU_ITEM(function, MSG_WATCH, ui.return_to_status); END_MENU(); } @@ -179,7 +179,7 @@ void _lcd_ubl_edit_mesh() { MENU_ITEM(gcode, MSG_UBL_FINE_TUNE_ALL, PSTR("G29 P4 R999 T")); MENU_ITEM(gcode, MSG_UBL_FINE_TUNE_CLOSEST, PSTR("G29 P4 T")); MENU_ITEM(submenu, MSG_UBL_MESH_HEIGHT_ADJUST, _menu_ubl_height_adjust); - MENU_ITEM(function, MSG_WATCH, lcd_return_to_status); + MENU_ITEM(function, MSG_WATCH, ui.return_to_status); END_MENU(); } @@ -220,7 +220,7 @@ void _lcd_ubl_validate_mesh() { MENU_ITEM(gcode, MSG_UBL_VALIDATE_MESH_M2, PSTR("G28\nG26 C B0 H" STRINGIFY(PREHEAT_2_TEMP_HOTEND) " P")); #endif MENU_ITEM(function, MSG_UBL_VALIDATE_CUSTOM_MESH, _lcd_ubl_validate_custom_mesh); - MENU_ITEM(function, MSG_WATCH, lcd_return_to_status); + MENU_ITEM(function, MSG_WATCH, ui.return_to_status); END_MENU(); } @@ -261,7 +261,7 @@ void _lcd_ubl_mesh_leveling() { MENU_BACK(MSG_UBL_TOOLS); MENU_ITEM(gcode, MSG_UBL_3POINT_MESH_LEVELING, PSTR("G29 J0")); MENU_ITEM(submenu, MSG_UBL_GRID_MESH_LEVELING, _lcd_ubl_grid_level); - MENU_ITEM(function, MSG_WATCH, lcd_return_to_status); + MENU_ITEM(function, MSG_WATCH, ui.return_to_status); END_MENU(); } @@ -290,7 +290,7 @@ void _menu_ubl_fillin() { MENU_ITEM_EDIT_CALLBACK(int3, MSG_UBL_FILLIN_AMOUNT, &ubl_fillin_amount, 0, 9, _lcd_ubl_fillin_amount_cmd); MENU_ITEM(gcode, MSG_UBL_SMART_FILLIN, PSTR("G29 P3 T0")); MENU_ITEM(gcode, MSG_UBL_MANUAL_FILLIN, PSTR("G29 P2 B T0")); - MENU_ITEM(function, MSG_WATCH, lcd_return_to_status); + MENU_ITEM(function, MSG_WATCH, ui.return_to_status); END_MENU(); } @@ -353,7 +353,7 @@ void _lcd_ubl_build_mesh() { MENU_ITEM(gcode, MSG_UBL_CONTINUE_MESH, PSTR("G29 P1 C")); MENU_ITEM(function, MSG_UBL_INVALIDATE_ALL, _lcd_ubl_invalidate); MENU_ITEM(gcode, MSG_UBL_INVALIDATE_CLOSEST, PSTR("G29 I")); - MENU_ITEM(function, MSG_WATCH, lcd_return_to_status); + MENU_ITEM(function, MSG_WATCH, ui.return_to_status); END_MENU(); } @@ -408,11 +408,11 @@ void _lcd_ubl_storage_mesh() { void _lcd_ubl_output_map_lcd(); void _lcd_ubl_map_homing() { - set_defer_return_to_status(true); + ui.defer_status_screen(true); _lcd_draw_homing(); if (all_axes_homed()) { ubl.lcd_map_control = true; // Return to the map screen - lcd_goto_screen(_lcd_ubl_output_map_lcd); + ui.goto_screen(_lcd_ubl_output_map_lcd); } } @@ -444,10 +444,10 @@ void sync_plan_position(); void _lcd_do_nothing() {} void _lcd_hard_stop() { - const screenFunc_t old_screen = currentScreen; - currentScreen = _lcd_do_nothing; + const screenFunc_t old_screen = ui.currentScreen; + ui.currentScreen = _lcd_do_nothing; planner.quick_stop(); - currentScreen = old_screen; + ui.currentScreen = old_screen; set_current_from_steppers_for_axis(ALL_AXES); sync_plan_position(); } @@ -455,15 +455,15 @@ void _lcd_hard_stop() { void _lcd_ubl_output_map_lcd() { static int16_t step_scaler = 0; - if (use_click()) return _lcd_ubl_map_lcd_edit_cmd(); - ENCODER_DIRECTION_NORMAL(); + if (ui.use_click()) return _lcd_ubl_map_lcd_edit_cmd(); + ui.encoder_direction_normal(); - if (encoderPosition) { - step_scaler += (int32_t)encoderPosition; + if (ui.encoderPosition) { + step_scaler += (int32_t)ui.encoderPosition; x_plot += step_scaler / (ENCODER_STEPS_PER_MENU_ITEM); if (ABS(step_scaler) >= ENCODER_STEPS_PER_MENU_ITEM) step_scaler = 0; - encoderPosition = 0; - lcdDrawUpdate = LCDVIEW_REDRAW_NOW; + ui.encoderPosition = 0; + ui.refresh(LCDVIEW_REDRAW_NOW); } // Encoder to the right (++) @@ -487,8 +487,8 @@ void _lcd_ubl_output_map_lcd() { n_edit_pts = yc ? (xc ? 9 : 6) : (xc ? 6 : 4); // Corners #endif - if (lcdDrawUpdate) { - lcd_implementation_ubl_plot(x_plot, y_plot); + if (ui.should_draw()) { + ui.ubl_plot(x_plot, y_plot); if (planner.movesplanned()) // If the nozzle is already moving, cancel the move. _lcd_hard_stop(); @@ -505,7 +505,7 @@ void _lcd_ubl_output_map_lcd_cmd() { set_all_unhomed(); enqueue_and_echo_commands_P(PSTR("G28")); } - lcd_goto_screen(_lcd_ubl_map_homing); + ui.goto_screen(_lcd_ubl_map_homing); } /** diff --git a/Marlin/src/lcd/ultralcd.cpp b/Marlin/src/lcd/ultralcd.cpp index 14b8e0d1a4..5b639e18e9 100644 --- a/Marlin/src/lcd/ultralcd.cpp +++ b/Marlin/src/lcd/ultralcd.cpp @@ -22,11 +22,14 @@ #include "../inc/MarlinConfigPre.h" -#if ENABLED(ULTRA_LCD) +#if HAS_SPI_LCD #include #include "ultralcd.h" + +MarlinUI ui; + #include "lcdprint.h" #include "../sd/cardreader.h" @@ -49,19 +52,12 @@ #if ENABLED(POWER_LOSS_RECOVERY) #include "../feature/power_loss_recovery.h" - #if HAS_LCD_MENU - void menu_job_recovery(); - #endif #endif #if ENABLED(PRINTCOUNTER) && ENABLED(LCD_INFO_MENU) #include "../libs/duration_t.h" #endif -#if ENABLED(FILAMENT_LCD_DISPLAY) - #include "../feature/filwidth.h" -#endif - #if ENABLED(BLTOUCH) #include "../module/endstops.h" #endif @@ -74,15 +70,19 @@ #include "../libs/buzzer.h" #endif -// Buttons -volatile uint8_t buttons; +#if HAS_ENCODER_ACTION + volatile uint8_t MarlinUI::buttons; + #if ENABLED(LCD_HAS_SLOW_BUTTONS) + volatile uint8_t MarlinUI::slow_buttons; + #endif +#endif #if ENABLED(SDSUPPORT) && PIN_EXISTS(SD_DETECT) uint8_t lcd_sd_status; #endif #if ENABLED(STATUS_MESSAGE_SCROLLING) - uint8_t status_scroll_offset = 0; + uint8_t MarlinUI::status_scroll_offset; // = 0 #if LONG_FILENAME_LENGTH > CHARSIZE * 2 * (LCD_WIDTH) #define MAX_MESSAGE_LENGTH LONG_FILENAME_LENGTH #else @@ -92,69 +92,84 @@ volatile uint8_t buttons; #define MAX_MESSAGE_LENGTH CHARSIZE * (LCD_WIDTH) #endif -char lcd_status_message[MAX_MESSAGE_LENGTH + 1]; -uint8_t lcd_status_update_delay = 1, // First update one loop delayed - lcd_status_message_level; // Higher level blocks lower level - -#if ENABLED(FILAMENT_LCD_DISPLAY) && ENABLED(SDSUPPORT) - millis_t previous_lcd_status_ms = 0; +#if HAS_LCD_MENU && LCD_TIMEOUT_TO_STATUS + bool MarlinUI::defer_return_to_status; #endif -#if HAS_LCD_MENU && ENABLED(SDSUPPORT) && ENABLED(SCROLL_LONG_FILENAMES) - uint8_t filename_scroll_pos, filename_scroll_max; +char MarlinUI::status_message[MAX_MESSAGE_LENGTH + 1]; +uint8_t MarlinUI::lcd_status_update_delay = 1; // First update one loop delayed +uint8_t MarlinUI::status_message_level; // = 0 + +#if ENABLED(FILAMENT_LCD_DISPLAY) && ENABLED(SDSUPPORT) + millis_t MarlinUI::next_filament_display; // = 0 #endif #if ENABLED(LCD_SET_PROGRESS_MANUALLY) - uint8_t progress_bar_percent; + uint8_t MarlinUI::progress_bar_percent; // = 0 #endif millis_t next_button_update_ms; #if HAS_GRAPHICAL_LCD - bool drawing_screen, first_page; // = false + bool MarlinUI::drawing_screen, MarlinUI::first_page; // = false #endif // Encoder Handling #if HAS_ENCODER_ACTION - uint32_t encoderPosition; - volatile int8_t encoderDiff; // Updated in lcd_buttons_update, added to encoderPosition every LCD update - #if ENABLED(ENCODER_RATE_MULTIPLIER) - bool encoderRateMultiplierEnabled; - #endif - #if ENABLED(REVERSE_MENU_DIRECTION) - int8_t encoderDirection = 1; - #endif + uint32_t MarlinUI::encoderPosition; + volatile int8_t encoderDiff; // Updated in update_buttons, added to encoderPosition every LCD update #endif #if HAS_LCD_MENU #include "menu/menu.h" - screenFunc_t currentScreen = lcd_status_screen; - - #if ENABLED(ENCODER_RATE_MULTIPLIER) - millis_t lastEncoderMovementMillis = 0; + #if ENABLED(SDSUPPORT) && ENABLED(SCROLL_LONG_FILENAMES) + uint8_t MarlinUI::filename_scroll_pos, MarlinUI::filename_scroll_max; #endif - bool lcd_clicked, wait_for_unclick; + screenFunc_t MarlinUI::currentScreen; // Initialized in CTOR + + #if ENABLED(ENCODER_RATE_MULTIPLIER) + bool MarlinUI::encoderRateMultiplierEnabled; + millis_t MarlinUI::lastEncoderMovementMillis = 0; + void MarlinUI::enable_encoder_multiplier(const bool onoff) { + encoderRateMultiplierEnabled = onoff; + lastEncoderMovementMillis = 0; + } + #endif + + #if ENABLED(REVERSE_MENU_DIRECTION) + int8_t MarlinUI::encoderDirection = 1; + #endif + + bool MarlinUI::lcd_clicked; float move_menu_scale; - bool use_click() { + bool MarlinUI::use_click() { const bool click = lcd_clicked; lcd_clicked = false; return click; } -#else + #if ENABLED(AUTO_BED_LEVELING_UBL) || ENABLED(G26_MESH_VALIDATION) - constexpr bool lcd_clicked = false; + bool MarlinUI::external_control; // = false + + void MarlinUI::wait_for_release() { + while (button_pressed()) safe_delay(50); + safe_delay(50); + } + + #endif #endif -void lcd_init() { +void MarlinUI::init() { - lcd_implementation_init(); + init_lcd(); + + #if HAS_DIGITAL_ENCODER - #if ENABLED(NEWPANEL) #if BUTTON_EXISTS(EN1) SET_INPUT_PULLUP(BTN_EN1); #endif @@ -184,7 +199,7 @@ void lcd_init() { SET_INPUT(BTN_RT); #endif - #else // !NEWPANEL + #else // !HAS_DIGITAL_ENCODER #if ENABLED(SR_LCD_2W_NL) // Non latching 2 wire shift register SET_OUTPUT(SR_DATA_PIN); @@ -196,25 +211,25 @@ void lcd_init() { SET_INPUT_PULLUP(SHIFT_OUT); #endif // SR_LCD_2W_NL - #endif // !NEWPANEL + #endif // !HAS_DIGITAL_ENCODER #if ENABLED(SDSUPPORT) && PIN_EXISTS(SD_DETECT) SET_INPUT_PULLUP(SD_DETECT_PIN); lcd_sd_status = 2; // UNKNOWN #endif - #if ENABLED(LCD_HAS_SLOW_BUTTONS) + #if HAS_ENCODER_ACTION && ENABLED(LCD_HAS_SLOW_BUTTONS) slow_buttons = 0; #endif - lcd_buttons_update(); + update_buttons(); #if HAS_ENCODER_ACTION encoderDiff = 0; #endif } -bool lcd_blink() { +bool MarlinUI::get_blink() { static uint8_t blink = 0; static millis_t next_blink_ms = 0; millis_t ms = millis(); @@ -239,13 +254,13 @@ bool lcd_blink() { #define ADC_MIN_KEY_DELAY 100 if (buttons_reprapworld_keypad) { #if HAS_ENCODER_ACTION - lcdDrawUpdate = LCDVIEW_REDRAW_NOW; + ui.refresh(LCDVIEW_REDRAW_NOW); if (encoderDirection == -1) { // side effect which signals we are inside a menu #if HAS_LCD_MENU if (RRK(EN_REPRAPWORLD_KEYPAD_DOWN)) encoderPosition -= ENCODER_STEPS_PER_MENU_ITEM; else if (RRK(EN_REPRAPWORLD_KEYPAD_UP)) encoderPosition += ENCODER_STEPS_PER_MENU_ITEM; - else if (RRK(EN_REPRAPWORLD_KEYPAD_LEFT)) { menu_item_back::action(); lcd_quick_feedback(); } - else if (RRK(EN_REPRAPWORLD_KEYPAD_RIGHT)) { lcd_return_to_status(); lcd_quick_feedback(); } + else if (RRK(EN_REPRAPWORLD_KEYPAD_LEFT)) { menu_item_back::action(); ui.quick_feedback(); } + else if (RRK(EN_REPRAPWORLD_KEYPAD_RIGHT)) { ui.return_to_status(); ui.quick_feedback(); } #endif } else if (RRK(EN_REPRAPWORLD_KEYPAD_DOWN)) encoderPosition += ENCODER_PULSES_PER_STEP; @@ -298,7 +313,7 @@ bool lcd_blink() { #if HAS_LCD_MENU - if (RRK(EN_REPRAPWORLD_KEYPAD_MIDDLE)) lcd_goto_screen(menu_move); + if (RRK(EN_REPRAPWORLD_KEYPAD_MIDDLE)) ui.goto_screen(menu_move); #if DISABLED(DELTA) && Z_HOME_DIR == -1 if (RRK(EN_REPRAPWORLD_KEYPAD_F2)) _reprapworld_keypad_move(Z_AXIS, 1); @@ -330,32 +345,33 @@ bool lcd_blink() { */ #if ENABLED(LCD_PROGRESS_BAR) - millis_t progress_bar_ms = 0; // Start millis of the current progress bar cycle + millis_t MarlinUI::progress_bar_ms; // = 0 #if PROGRESS_MSG_EXPIRE > 0 - static millis_t expire_status_ms = 0; - void dontExpireStatus() { expire_status_ms = 0; } + millis_t MarlinUI::expire_status_ms; // = 0 #endif #endif -#if LCD_INFO_SCREEN_STYLE == 0 - void lcd_impl_status_screen_0(); -#elif LCD_INFO_SCREEN_STYLE == 1 - void lcd_impl_status_screen_1(); +#if HAS_PRINT_PROGRESS + uint8_t MarlinUI::get_progress() { + #if ENABLED(LCD_SET_PROGRESS_MANUALLY) + uint8_t &progress = progress_bar_percent; + #else + uint8_t progress = 0; + #endif + #if ENABLED(SDSUPPORT) + if (IS_SD_PRINTING()) progress = card.percentDone(); + #endif + return progress; + } #endif -void lcd_status_screen() { +void MarlinUI::status_screen() { #if HAS_LCD_MENU - ENCODER_DIRECTION_NORMAL(); + encoder_direction_normal(); ENCODER_RATE_MULTIPLY(false); #endif - #if ENABLED(LCD_SET_PROGRESS_MANUALLY) && ENABLED(SDSUPPORT) && (ENABLED(LCD_PROGRESS_BAR) || HAS_GRAPHICAL_LCD) - // Progress bar % comes from SD when actively printing - if (IS_SD_PRINTING()) - progress_bar_percent = card.percentDone(); - #endif - #if ENABLED(LCD_PROGRESS_BAR) // @@ -377,14 +393,10 @@ void lcd_status_screen() { // Handle message expire if (expire_status_ms > 0) { - #if DISABLED(LCD_SET_PROGRESS_MANUALLY) - const uint8_t progress_bar_percent = card.percentDone(); - #endif - // Expire the message if a job is active and the bar has ticks - if (progress_bar_percent > 2 && !print_job_timer.isPaused()) { + if (get_progress() > 2 && !print_job_timer.isPaused()) { if (ELAPSED(ms, expire_status_ms)) { - lcd_status_message[0] = '\0'; + status_message[0] = '\0'; expire_status_ms = 0; } } @@ -403,10 +415,10 @@ void lcd_status_screen() { if (use_click()) { #if ENABLED(FILAMENT_LCD_DISPLAY) && ENABLED(SDSUPPORT) - previous_lcd_status_ms = millis(); // get status message to show up for a while + next_filament_display = millis() + 5000UL; // Show status message for 5s #endif - lcd_goto_screen(menu_main); - lcd_implementation_init(); // May revive the LCD if static electricity killed it + goto_screen(menu_main); + init_lcd(); // May revive the LCD if static electricity killed it return; } @@ -439,17 +451,13 @@ void lcd_status_screen() { #endif // ULTIPANEL_FEEDMULTIPLY - #if LCD_INFO_SCREEN_STYLE == 0 - lcd_impl_status_screen_0(); - #elif LCD_INFO_SCREEN_STYLE == 1 - lcd_impl_status_screen_1(); - #endif + draw_status_screen(); } /** * Reset the status message */ -void lcd_reset_status() { +void MarlinUI::reset_status() { static const char paused[] PROGMEM = MSG_PRINT_PAUSED; static const char printing[] PROGMEM = MSG_PRINTING; static const char welcome[] PROGMEM = WELCOME_MSG; @@ -458,36 +466,29 @@ void lcd_reset_status() { msg = paused; #if ENABLED(SDSUPPORT) else if (IS_SD_PRINTING()) - return lcd_setstatus(card.longest_filename(), true); + return setstatus(card.longest_filename(), true); #endif else if (print_job_timer.isRunning()) msg = printing; else msg = welcome; - lcd_setstatusPGM(msg, -1); + setstatusPGM(msg, -1); } -void kill_screen(PGM_P lcd_msg) { - lcd_init(); - lcd_setalertstatusPGM(lcd_msg); - lcd_kill_screen(); +void MarlinUI::kill_screen(PGM_P lcd_msg) { + init(); + setalertstatusPGM(lcd_msg); + draw_kill_screen(); } -#if HAS_BUZZER - void lcd_buzz(const long duration, const uint16_t freq) { - #if ENABLED(LCD_USE_I2C_BUZZER) - lcd.buzz(duration, freq); - #elif PIN_EXISTS(BEEPER) - buzzer.tone(duration, freq); - #endif - } -#endif - -void lcd_quick_feedback(const bool clear_buttons/*=true*/) { +void MarlinUI::quick_feedback(const bool clear_buttons/*=true*/) { #if HAS_LCD_MENU - lcd_refresh(); + refresh(); + #endif + + #if HAS_ENCODER_ACTION if (clear_buttons) buttons = 0; next_button_update_ms = millis() + 500; #else @@ -495,7 +496,7 @@ void lcd_quick_feedback(const bool clear_buttons/*=true*/) { #endif // Buzz and wait. The delay is needed for buttons to settle! - lcd_buzz(LCD_FEEDBACK_FREQUENCY_DURATION_MS, LCD_FEEDBACK_FREQUENCY_HZ); + buzz(LCD_FEEDBACK_FREQUENCY_DURATION_MS, LCD_FEEDBACK_FREQUENCY_HZ); #if HAS_LCD_MENU #if ENABLED(LCD_USE_I2C_BUZZER) @@ -514,21 +515,19 @@ void lcd_quick_feedback(const bool clear_buttons/*=true*/) { millis_t manual_move_start_time = 0; #if IS_KINEMATIC - bool processing_manual_move = false; + bool MarlinUI::processing_manual_move = false; float manual_move_offset = 0; #endif - #if !IS_KINEMATIC || (IS_KINEMATIC && EXTRUDERS > 1) - int8_t manual_move_e_index = 0; - #else - constexpr int8_t manual_move_e_index = 0; + #if E_MANUAL > 1 + int8_t MarlinUI::manual_move_e_index = 0; #endif /** * If the most recent manual move hasn't been fed to the planner yet, * and the planner can accept one, send a move immediately. */ - void manage_manual_move() { + void MarlinUI::manage_manual_move() { if (processing_manual_move) return; @@ -583,7 +582,7 @@ void lcd_quick_feedback(const bool clear_buttons/*=true*/) { * - Act on RepRap World keypad input * - Update the encoder position * - Apply acceleration to the encoder position - * - Set lcdDrawUpdate = LCDVIEW_CALL_REDRAW_NOW on controller events + * - Do refresh(LCDVIEW_CALL_REDRAW_NOW) on controller events * - Reset the Info Screen timeout if there's any input * - Update status indicators, if any * @@ -593,7 +592,7 @@ void lcd_quick_feedback(const bool clear_buttons/*=true*/) { * - Call the menu handler. Menu handlers should do the following: * - If a value changes, set lcdDrawUpdate to LCDVIEW_REDRAW_NOW and draw the value * (Encoder events automatically set lcdDrawUpdate for you.) - * - if (lcdDrawUpdate) { redraw } + * - if (should_draw()) { redraw } * - Before exiting the handler set lcdDrawUpdate to: * - LCDVIEW_CLEAR_CALL_REDRAW to clear screen and set LCDVIEW_CALL_REDRAW_NEXT. * - LCDVIEW_REDRAW_NOW to draw now (including remaining stripes). @@ -609,17 +608,9 @@ void lcd_quick_feedback(const bool clear_buttons/*=true*/) { * This function is only called from the main thread. */ -LCDViewAction lcdDrawUpdate = LCDVIEW_CLEAR_CALL_REDRAW; +LCDViewAction MarlinUI::lcdDrawUpdate = LCDVIEW_CLEAR_CALL_REDRAW; -#if ENABLED(AUTO_BED_LEVELING_UBL) || ENABLED(G26_MESH_VALIDATION) - bool lcd_external_control; // = false -#endif - -#if ENABLED(LCD_HAS_SLOW_BUTTONS) - volatile uint8_t slow_buttons; -#endif - -bool lcd_detected() { +bool MarlinUI::detected() { return #if (ENABLED(LCD_I2C_TYPE_MCP23017) || ENABLED(LCD_I2C_TYPE_MCP23008)) && defined(DETECT_DEVICE) lcd.LcdDetected() == 1 @@ -629,7 +620,7 @@ bool lcd_detected() { ; } -void lcd_update() { +void MarlinUI::update() { static uint16_t max_display_update_time = 0; static millis_t next_lcd_update_ms; @@ -643,33 +634,26 @@ void lcd_update() { // Handle any queued Move Axis motion manage_manual_move(); - // Update button states for LCD_CLICKED(), etc. - // After state changes the next button update - // may be delayed 300-500ms. - lcd_buttons_update(); - - #if ENABLED(AUTO_BED_LEVELING_UBL) - // Don't run the debouncer if UBL owns the display - #define UBL_CONDITION !lcd_external_control - #else - #define UBL_CONDITION true - #endif + // Update button states for button_pressed(), etc. + // If the state changes the next update may be delayed 300-500ms. + update_buttons(); // If the action button is pressed... - if (UBL_CONDITION && LCD_CLICKED()) { - if (!wait_for_unclick) { // If not waiting for a debounce release: - wait_for_unclick = true; // Set debounce flag to ignore continous clicks - lcd_clicked = !wait_for_user && !no_reentry; // Keep the click if not waiting for a user-click - wait_for_user = false; // Any click clears wait for user - lcd_quick_feedback(); // Always make a click sound + static bool wait_for_unclick; // = 0 + if (!external_control && button_pressed()) { + if (!wait_for_unclick) { // If not waiting for a debounce release: + wait_for_unclick = true; // - Set debounce flag to ignore continous clicks + lcd_clicked = !wait_for_user && !no_reentry; // - Keep the click if not waiting for a user-click + wait_for_user = false; // - Any click clears wait for user + quick_feedback(); // - Always make a click sound } } else wait_for_unclick = false; #if BUTTON_EXISTS(BACK) - if (LCD_BACK_CLICKED) { - lcd_quick_feedback(); - lcd_goto_previous_menu(); + if (LCD_BACK_CLICKED()) { + quick_feedback(); + goto_previous_screen(); } #endif @@ -678,7 +662,7 @@ void lcd_update() { #if ENABLED(SDSUPPORT) && PIN_EXISTS(SD_DETECT) const uint8_t sd_status = (uint8_t)IS_SD_INSERTED(); - if (sd_status != lcd_sd_status && lcd_detected()) { + if (sd_status != lcd_sd_status && detected()) { uint8_t old_sd_status = lcd_sd_status; // prevent re-entry to this block! lcd_sd_status = sd_status; @@ -689,22 +673,22 @@ void lcd_update() { if (old_sd_status == 2) card.beginautostart(); // Initial boot else - LCD_MESSAGEPGM(MSG_SD_INSERTED); + setstatusPGM(PSTR(MSG_SD_INSERTED)); } else { card.release(); - if (old_sd_status != 2) LCD_MESSAGEPGM(MSG_SD_REMOVED); + if (old_sd_status != 2) setstatusPGM(PSTR(MSG_SD_REMOVED)); } - lcd_refresh(); - lcd_implementation_init(); // May revive the LCD if static electricity killed it + refresh(); + init_lcd(); // May revive the LCD if static electricity killed it } #endif // SDSUPPORT && SD_DETECT_PIN #if ENABLED(POWER_LOSS_RECOVERY) if (job_recovery_commands_count && job_recovery_phase == JOB_RECOVERY_IDLE) { - lcd_goto_screen(menu_job_recovery); + goto_screen(menu_job_recovery); job_recovery_phase = JOB_RECOVERY_MAYBE; // Waiting for a response } #endif @@ -719,19 +703,15 @@ void lcd_update() { next_lcd_update_ms = ms + LCD_UPDATE_INTERVAL; #if ENABLED(LCD_HAS_STATUS_INDICATORS) - lcd_implementation_update_indicators(); + update_indicators(); #endif - #if HAS_LCD_MENU + #if HAS_ENCODER_ACTION #if ENABLED(LCD_HAS_SLOW_BUTTONS) - slow_buttons = lcd_implementation_read_slow_buttons(); // buttons which take too long to read in interrupt context + slow_buttons = read_slow_buttons(); // Buttons that take too long to read in interrupt context #endif - #endif // HAS_LCD_MENU - - #if HAS_ENCODER_ACTION - #if ENABLED(ADC_KEYPAD) if (handle_adc_keypad()) { @@ -746,7 +726,8 @@ void lcd_update() { #endif - const bool encoderPastThreshold = (ABS(encoderDiff) >= ENCODER_PULSES_PER_STEP); + const float abs_diff = ABS(encoderDiff); + const bool encoderPastThreshold = (abs_diff >= (ENCODER_PULSES_PER_STEP)); if (encoderPastThreshold || lcd_clicked) { if (encoderPastThreshold) { @@ -755,12 +736,12 @@ void lcd_update() { int32_t encoderMultiplier = 1; if (encoderRateMultiplierEnabled) { - int32_t encoderMovementSteps = ABS(encoderDiff) / ENCODER_PULSES_PER_STEP; + const float encoderMovementSteps = abs_diff / (ENCODER_PULSES_PER_STEP); if (lastEncoderMovementMillis) { // Note that the rate is always calculated between two passes through the // loop and that the abs of the encoderDiff value is tracked. - float encoderStepRate = float(encoderMovementSteps) / float(ms - lastEncoderMovementMillis) * 1000; + const float encoderStepRate = encoderMovementSteps / float(ms - lastEncoderMovementMillis) * 1000; if (encoderStepRate >= ENCODER_100X_STEPS_PER_SEC) encoderMultiplier = 100; else if (encoderStepRate >= ENCODER_10X_STEPS_PER_SEC) encoderMultiplier = 10; @@ -784,32 +765,27 @@ void lcd_update() { #endif // ENCODER_RATE_MULTIPLIER - encoderPosition += (encoderDiff * encoderMultiplier) / ENCODER_PULSES_PER_STEP; + encoderPosition += (encoderDiff * encoderMultiplier) / (ENCODER_PULSES_PER_STEP); encoderDiff = 0; } #if HAS_LCD_MENU && LCD_TIMEOUT_TO_STATUS return_to_status_ms = ms + LCD_TIMEOUT_TO_STATUS; #endif - lcdDrawUpdate = LCDVIEW_REDRAW_NOW; + refresh(LCDVIEW_REDRAW_NOW); } #endif // This runs every ~100ms when idling often enough. // Instead of tracking changes just redraw the Status Screen once per second. - if ( - #if HAS_LCD_MENU - currentScreen == lcd_status_screen && - #endif - !lcd_status_update_delay-- - ) { + if (on_status_screen() && !lcd_status_update_delay--) { lcd_status_update_delay = 9 #if HAS_GRAPHICAL_LCD + 3 #endif ; max_display_update_time--; - lcdDrawUpdate = LCDVIEW_REDRAW_NOW; + refresh(LCDVIEW_REDRAW_NOW); } #if HAS_LCD_MENU && ENABLED(SCROLL_LONG_FILENAMES) @@ -817,7 +793,7 @@ void lcd_update() { // cause a refresh to occur until all the text has scrolled into view. if (currentScreen == menu_sdcard && filename_scroll_pos < filename_scroll_max && !lcd_status_update_delay--) { lcd_status_update_delay = 6; - lcdDrawUpdate = LCDVIEW_REDRAW_NOW; + refresh(LCDVIEW_REDRAW_NOW); filename_scroll_pos++; #if LCD_TIMEOUT_TO_STATUS return_to_status_ms = ms + LCD_TIMEOUT_TO_STATUS; @@ -828,22 +804,16 @@ void lcd_update() { // then we want to use 1/2 of the time only. uint16_t bbr2 = planner.block_buffer_runtime() >> 1; - #if HAS_GRAPHICAL_LCD - const bool &is_drawing = drawing_screen; - #else - constexpr bool is_drawing = false; - #endif - - if ((lcdDrawUpdate || is_drawing) && (!bbr2 || bbr2 > max_display_update_time)) { + if ((should_draw() || drawing_screen) && (!bbr2 || bbr2 > max_display_update_time)) { // Change state of drawing flag between screen updates - if (!is_drawing) switch (lcdDrawUpdate) { + if (!drawing_screen) switch (lcdDrawUpdate) { case LCDVIEW_CALL_NO_REDRAW: - lcdDrawUpdate = LCDVIEW_NONE; + refresh(LCDVIEW_NONE); break; case LCDVIEW_CLEAR_CALL_REDRAW: case LCDVIEW_CALL_REDRAW_NEXT: - lcdDrawUpdate = LCDVIEW_REDRAW_NOW; + refresh(LCDVIEW_REDRAW_NOW); case LCDVIEW_REDRAW_NOW: // set above, or by a handler through LCDVIEW_CALL_REDRAW_NEXT case LCDVIEW_NONE: break; @@ -853,33 +823,25 @@ void lcd_update() { buttons_reprapworld_keypad = 0; #endif - #if HAS_LCD_MENU - #define CURRENTSCREEN() (*currentScreen)() - #else - #define CURRENTSCREEN() lcd_status_screen() - #endif - #if HAS_GRAPHICAL_LCD + #if ENABLED(LIGHTWEIGHT_UI) - #if HAS_LCD_MENU - const bool in_status = currentScreen == lcd_status_screen; - #else - constexpr bool in_status = true; - #endif - const bool do_u8g_loop = !in_status; + const bool in_status = on_status_screen(), + do_u8g_loop = !in_status; lcd_in_status(in_status); - if (in_status) lcd_status_screen(); + if (in_status) status_screen(); #else constexpr bool do_u8g_loop = true; #endif + if (do_u8g_loop) { if (!drawing_screen) { // If not already drawing pages u8g.firstPage(); // Start the first page drawing_screen = first_page = true; // Flag as drawing pages } - lcd_setFont(FONT_MENU); // Setup font for every page draw + set_font(FONT_MENU); // Setup font for every page draw u8g.setColorIndex(1); // And reset the color - CURRENTSCREEN(); // Draw and process the current screen + run_current_screen(); // Draw and process the current screen first_page = false; // The screen handler can clear drawing_screen for an action that changes the screen. @@ -890,8 +852,11 @@ void lcd_update() { return; } } + #else - CURRENTSCREEN(); + + run_current_screen(); + #endif #if HAS_LCD_MENU @@ -905,18 +870,18 @@ void lcd_update() { #if HAS_LCD_MENU && LCD_TIMEOUT_TO_STATUS // Return to Status Screen after a timeout - if (currentScreen == lcd_status_screen || defer_return_to_status) + if (on_status_screen() || defer_return_to_status) return_to_status_ms = ms + LCD_TIMEOUT_TO_STATUS; else if (ELAPSED(ms, return_to_status_ms)) - lcd_return_to_status(); + return_to_status(); #endif // Change state of drawing flag between screen updates - if (!is_drawing) switch (lcdDrawUpdate) { + if (!drawing_screen) switch (lcdDrawUpdate) { case LCDVIEW_CLEAR_CALL_REDRAW: - lcd_implementation_clear(); break; + clear_lcd(); break; case LCDVIEW_REDRAW_NOW: - lcdDrawUpdate = LCDVIEW_NONE; + refresh(LCDVIEW_NONE); case LCDVIEW_NONE: case LCDVIEW_CALL_REDRAW_NEXT: case LCDVIEW_CALL_NO_REDRAW: @@ -926,7 +891,7 @@ void lcd_update() { } // ELAPSED(ms, next_lcd_update_ms) } -void lcd_finishstatus(const bool persist=false) { +void MarlinUI::finishstatus(const bool persist) { #if !(ENABLED(LCD_PROGRESS_BAR) && (PROGRESS_MSG_EXPIRE > 0)) UNUSED(persist); @@ -939,21 +904,21 @@ void lcd_finishstatus(const bool persist=false) { #endif #endif - lcd_refresh(); - #if ENABLED(FILAMENT_LCD_DISPLAY) && ENABLED(SDSUPPORT) - previous_lcd_status_ms = millis(); //get status message to show up for a while + next_filament_display = millis() + 5000UL; // Show status message for 5s #endif #if ENABLED(STATUS_MESSAGE_SCROLLING) status_scroll_offset = 0; #endif + + refresh(); } -bool lcd_hasstatus() { return (lcd_status_message[0] != '\0'); } +bool MarlinUI::hasstatus() { return (status_message[0] != '\0'); } -void lcd_setstatus(const char * const message, const bool persist) { - if (lcd_status_message_level > 0) return; +void MarlinUI::setstatus(const char * const message, const bool persist) { + if (status_message_level > 0) return; // Here we have a problem. The message is encoded in UTF8, so // arbitrarily cutting it will be a problem. We MUST be sure @@ -971,16 +936,16 @@ void lcd_setstatus(const char * const message, const bool persist) { // At this point, we have the proper cut point. Use it uint8_t maxLen = pend - message; - strncpy(lcd_status_message, message, maxLen); - lcd_status_message[maxLen] = '\0'; + strncpy(status_message, message, maxLen); + status_message[maxLen] = '\0'; - lcd_finishstatus(persist); + finishstatus(persist); } -void lcd_setstatusPGM(PGM_P const message, int8_t level) { - if (level < 0) level = lcd_status_message_level = 0; - if (level < lcd_status_message_level) return; - lcd_status_message_level = level; +void MarlinUI::setstatusPGM(PGM_P const message, int8_t level) { + if (level < 0) level = status_message_level = 0; + if (level < status_message_level) return; + status_message_level = level; // Here we have a problem. The message is encoded in UTF8, so // arbitrarily cutting it will be a problem. We MUST be sure @@ -998,31 +963,29 @@ void lcd_setstatusPGM(PGM_P const message, int8_t level) { // At this point, we have the proper cut point. Use it uint8_t maxLen = pend - message; - strncpy_P(lcd_status_message, message, maxLen); - lcd_status_message[maxLen] = '\0'; + strncpy_P(status_message, message, maxLen); + status_message[maxLen] = '\0'; - lcd_finishstatus(level > 0); + finishstatus(level > 0); } -void lcd_status_printf_P(const uint8_t level, PGM_P const fmt, ...) { - if (level < lcd_status_message_level) return; - lcd_status_message_level = level; +void MarlinUI::status_printf_P(const uint8_t level, PGM_P const fmt, ...) { + if (level < status_message_level) return; + status_message_level = level; va_list args; va_start(args, fmt); - vsnprintf_P(lcd_status_message, MAX_MESSAGE_LENGTH, fmt, args); + vsnprintf_P(status_message, MAX_MESSAGE_LENGTH, fmt, args); va_end(args); - lcd_finishstatus(level > 0); + finishstatus(level > 0); } -void lcd_setalertstatusPGM(PGM_P const message) { - lcd_setstatusPGM(message, 1); +void MarlinUI::setalertstatusPGM(PGM_P const message) { + setstatusPGM(message, 1); #if HAS_LCD_MENU - lcd_return_to_status(); + return_to_status(); #endif } -void lcd_reset_alert_level() { lcd_status_message_level = 0; } - #if ENABLED(ADC_KEYPAD) typedef struct { @@ -1058,13 +1021,29 @@ void lcd_reset_alert_level() { lcd_status_message_level = 0; } } #endif -#if HAS_LCD_MENU +#if HAS_ENCODER_ACTION + + #if DISABLED(ADC_KEYPAD) && (ENABLED(REPRAPWORLD_KEYPAD) || !HAS_DIGITAL_ENCODER) + + /** + * Setup Rotary Encoder Bit Values (for two pin encoders to indicate movement) + * These values are independent of which pins are used for EN_A and EN_B indications + * The rotary encoder part is also independent to the chipset used for the LCD + */ + #define GET_SHIFT_BUTTON_STATES(DST) \ + uint8_t new_##DST = 0; \ + WRITE(SHIFT_LD, LOW); \ + WRITE(SHIFT_LD, HIGH); \ + for (int8_t i = 0; i < 8; i++) { \ + new_##DST >>= 1; \ + if (READ(SHIFT_OUT)) SBI(new_##DST, 7); \ + WRITE(SHIFT_CLK, HIGH); \ + WRITE(SHIFT_CLK, LOW); \ + } \ + DST = ~new_##DST; //invert it, because a pressed switch produces a logical 0 + + #endif - /** - * Setup Rotary Encoder Bit Values (for two pin encoders to indicate movement) - * These values are independent of which pins are used for EN_A and EN_B indications - * The rotary encoder part is also independent to the chipset used for the LCD - */ #if defined(EN_A) && defined(EN_B) #define encrot0 0 #define encrot1 2 @@ -1072,42 +1051,16 @@ void lcd_reset_alert_level() { lcd_status_message_level = 0; } #define encrot3 1 #endif - #define GET_SHIFT_BUTTON_STATES(DST) \ - uint8_t new_##DST = 0; \ - WRITE(SHIFT_LD, LOW); \ - WRITE(SHIFT_LD, HIGH); \ - for (int8_t i = 0; i < 8; i++) { \ - new_##DST >>= 1; \ - if (READ(SHIFT_OUT)) SBI(new_##DST, 7); \ - WRITE(SHIFT_CLK, HIGH); \ - WRITE(SHIFT_CLK, LOW); \ - } \ - DST = ~new_##DST; //invert it, because a pressed switch produces a logical 0 - - #if ENABLED(G26_MESH_VALIDATION) - void lcd_chirp() { - lcd_buzz(LCD_FEEDBACK_FREQUENCY_DURATION_MS, LCD_FEEDBACK_FREQUENCY_HZ); - } - #endif - - #if ENABLED(AUTO_BED_LEVELING_UBL) || ENABLED(G26_MESH_VALIDATION) - bool is_lcd_clicked() { return LCD_CLICKED(); } - void wait_for_release() { - while (is_lcd_clicked()) safe_delay(50); - safe_delay(50); - } - #endif - /** * Read encoder buttons from the hardware registers * Warning: This function is called from interrupt context! */ - void lcd_buttons_update() { + void MarlinUI::update_buttons() { static uint8_t lastEncoderBits; const millis_t now = millis(); if (ELAPSED(now, next_button_update_ms)) { - #if ENABLED(NEWPANEL) + #if HAS_DIGITAL_ENCODER uint8_t newbutton = 0; #if BUTTON_EXISTS(EN1) @@ -1128,53 +1081,43 @@ void lcd_reset_alert_level() { lcd_status_message_level = 0; } // #if LCD_HAS_DIRECTIONAL_BUTTONS - #if ENABLED(REVERSE_MENU_DIRECTION) - #define _ENCODER_UD_STEPS (ENCODER_STEPS_PER_MENU_ITEM * encoderDirection) - #else - #define _ENCODER_UD_STEPS ENCODER_STEPS_PER_MENU_ITEM - #endif - #if ENABLED(REVERSE_ENCODER_DIRECTION) - #define ENCODER_UD_STEPS _ENCODER_UD_STEPS - #define ENCODER_LR_PULSES ENCODER_PULSES_PER_STEP - #else - #define ENCODER_UD_STEPS -(_ENCODER_UD_STEPS) - #define ENCODER_LR_PULSES -(ENCODER_PULSES_PER_STEP) - #endif + const int8_t pulses = (ENCODER_PULSES_PER_STEP) * encoderDirection; if (false) { // for the else-ifs below } #if BUTTON_EXISTS(UP) else if (BUTTON_PRESSED(UP)) { - encoderDiff = -(ENCODER_UD_STEPS); + encoderDiff = (ENCODER_STEPS_PER_MENU_ITEM) * pulses; next_button_update_ms = now + 300; } #endif #if BUTTON_EXISTS(DWN) else if (BUTTON_PRESSED(DWN)) { - encoderDiff = ENCODER_UD_STEPS; + encoderDiff = -(ENCODER_STEPS_PER_MENU_ITEM) * pulses; next_button_update_ms = now + 300; } #endif #if BUTTON_EXISTS(LFT) else if (BUTTON_PRESSED(LFT)) { - encoderDiff = -(ENCODER_LR_PULSES); + encoderDiff = -pulses; next_button_update_ms = now + 300; } #endif #if BUTTON_EXISTS(RT) else if (BUTTON_PRESSED(RT)) { - encoderDiff = ENCODER_LR_PULSES; + encoderDiff = pulses; next_button_update_ms = now + 300; } #endif #endif // LCD_HAS_DIRECTIONAL_BUTTONS - buttons = newbutton; - #if ENABLED(LCD_HAS_SLOW_BUTTONS) - buttons |= slow_buttons; - #endif + buttons = newbutton + #if ENABLED(LCD_HAS_SLOW_BUTTONS) + | slow_buttons + #endif + ; #if ENABLED(ADC_KEYPAD) @@ -1192,7 +1135,7 @@ void lcd_reset_alert_level() { lcd_status_message_level = 0; } #endif - #else // !NEWPANEL + #else // !HAS_DIGITAL_ENCODER GET_SHIFT_BUTTON_STATES(buttons); @@ -1201,20 +1144,7 @@ void lcd_reset_alert_level() { lcd_status_message_level = 0; } } // next_button_update_ms // Manage encoder rotation - #if ENABLED(REVERSE_MENU_DIRECTION) && ENABLED(REVERSE_ENCODER_DIRECTION) - #define ENCODER_DIFF_CW (encoderDiff -= encoderDirection) - #define ENCODER_DIFF_CCW (encoderDiff += encoderDirection) - #elif ENABLED(REVERSE_MENU_DIRECTION) - #define ENCODER_DIFF_CW (encoderDiff += encoderDirection) - #define ENCODER_DIFF_CCW (encoderDiff -= encoderDirection) - #elif ENABLED(REVERSE_ENCODER_DIRECTION) - #define ENCODER_DIFF_CW (encoderDiff--) - #define ENCODER_DIFF_CCW (encoderDiff++) - #else - #define ENCODER_DIFF_CW (encoderDiff++) - #define ENCODER_DIFF_CCW (encoderDiff--) - #endif - #define ENCODER_SPIN(_E1, _E2) switch (lastEncoderBits) { case _E1: ENCODER_DIFF_CW; break; case _E2: ENCODER_DIFF_CCW; } + #define ENCODER_SPIN(_E1, _E2) switch (lastEncoderBits) { case _E1: encoderDiff += encoderDirection; break; case _E2: encoderDiff -= encoderDirection; } uint8_t enc = 0; if (buttons & EN_A) enc |= B01; @@ -1226,16 +1156,33 @@ void lcd_reset_alert_level() { lcd_status_message_level = 0; } case encrot2: ENCODER_SPIN(encrot1, encrot3); break; case encrot3: ENCODER_SPIN(encrot2, encrot0); break; } - #if ENABLED(AUTO_BED_LEVELING_UBL) - if (lcd_external_control) { + if (external_control) { + #if ENABLED(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. - } - #endif + #endif + encoderDiff = 0; // Hide the encoder event from the current screen handler. + } lastEncoderBits = enc; } } -#endif // HAS_LCD_MENU + #if ENABLED(LCD_HAS_SLOW_BUTTONS) -#endif // ULTRA_LCD + uint8_t MarlinUI::read_slow_buttons() { + #if ENABLED(LCD_I2C_TYPE_MCP23017) + // Reading these buttons this is likely to be too slow to call inside interrupt context + // so they are called during normal lcd_update + uint8_t slow_bits = lcd.readButtons() << B_I2C_BTN_OFFSET; + #if ENABLED(LCD_I2C_VIKI) + if ((slow_bits & (B_MI | B_RI)) && PENDING(millis(), next_button_update_ms)) // LCD clicked + slow_bits &= ~(B_MI | B_RI); // Disable LCD clicked buttons if screen is updated + #endif // LCD_I2C_VIKI + return slow_bits; + #endif // LCD_I2C_TYPE_MCP23017 + } + + #endif // LCD_HAS_SLOW_BUTTONS + +#endif // HAS_ENCODER_ACTION + +#endif // HAS_SPI_LCD diff --git a/Marlin/src/lcd/ultralcd.h b/Marlin/src/lcd/ultralcd.h index 42f8e82bf7..b3a7038c95 100644 --- a/Marlin/src/lcd/ultralcd.h +++ b/Marlin/src/lcd/ultralcd.h @@ -23,6 +23,21 @@ #include "../inc/MarlinConfig.h" +#if HAS_SPI_LCD + + #include "../Marlin.h" + + #if ENABLED(ADVANCED_PAUSE_FEATURE) + #include "../feature/pause.h" + #include "../module/motion.h" // for active_extruder + #endif + +#endif + +#if HAS_BUZZER + #include "../libs/buzzer.h" +#endif + #if HAS_GRAPHICAL_LCD #ifndef LCD_PIXEL_WIDTH @@ -171,13 +186,11 @@ #define INFO_FONT_DESCENT 2 #define INFO_FONT_HEIGHT (INFO_FONT_ASCENT + INFO_FONT_DESCENT) - // Font IDs enum MarlinFont : uint8_t { FONT_STATUSMENU = 1, FONT_EDIT, FONT_MENU }; - void lcd_setFont(const MarlinFont font_nr); #if ENABLED(LIGHTWEIGHT_UI) void lcd_in_status(const bool inStatus); @@ -185,46 +198,10 @@ #endif // HAS_GRAPHICAL_LCD -#if HAS_SPI_LCD || ENABLED(MALYAN_LCD) || ENABLED(EXTENSIBLE_UI) - void lcd_init(); - bool lcd_detected(); - void lcd_update(); - void lcd_setalertstatusPGM(PGM_P message); - void kill_screen(PGM_P lcd_msg); -#else - inline void lcd_init() {} - inline bool lcd_detected() { return true; } - inline void lcd_update() {} - inline void lcd_setalertstatusPGM(PGM_P message) { UNUSED(message); } -#endif - #define HAS_ENCODER_ACTION (HAS_LCD_MENU || ENABLED(ULTIPANEL_FEEDMULTIPLY)) -#if HAS_ENCODER_ACTION - extern uint32_t encoderPosition; -#endif - #if HAS_SPI_LCD - #include "../Marlin.h" - - #if ENABLED(ADVANCED_PAUSE_FEATURE) - #include "../feature/pause.h" - #include "../module/motion.h" // for active_extruder - #endif - - void lcd_status_screen(); - void lcd_return_to_status(); - bool lcd_hasstatus(); - void lcd_setstatus(const char* message, const bool persist=false); - void lcd_setstatusPGM(PGM_P message, const int8_t level=0); - void lcd_setalertstatusPGM(PGM_P message); - void lcd_reset_alert_level(); - void lcd_reset_status(); - void lcd_status_printf_P(const uint8_t level, PGM_P const fmt, ...); - void lcd_kill_screen(); - void kill_screen(PGM_P lcd_msg); - enum LCDViewAction : uint8_t { LCDVIEW_NONE, LCDVIEW_REDRAW_NOW, @@ -233,37 +210,10 @@ LCDVIEW_CALL_NO_REDRAW }; - extern LCDViewAction lcdDrawUpdate; - inline void lcd_refresh() { lcdDrawUpdate = LCDVIEW_CLEAR_CALL_REDRAW; } - - #if HAS_BUZZER - void lcd_buzz(const long duration, const uint16_t freq); - #else - inline void lcd_buzz(const long duration, const uint16_t freq) { UNUSED(duration); UNUSED(freq); } - #endif - - void lcd_quick_feedback(const bool clear_buttons=true); // Audible feedback for a button click - could also be visual - - #if ENABLED(LCD_PROGRESS_BAR) - extern millis_t progress_bar_ms; // Start time for the current progress bar cycle - #if PROGRESS_MSG_EXPIRE > 0 - void dontExpireStatus(); - #endif - #endif - - #if ENABLED(LCD_SET_PROGRESS_MANUALLY) - extern uint8_t progress_bar_percent; - #endif - #if ENABLED(ADC_KEYPAD) uint8_t get_ADC_keyValue(); #endif - #if HAS_LCD_CONTRAST - extern int16_t lcd_contrast; - void set_lcd_contrast(const int16_t value); - #endif - #if HAS_GRAPHICAL_LCD #define SETCURSOR(col, row) lcd_moveto(col * (MENU_FONT_WIDTH), (row + 1) * (MENU_FONT_HEIGHT)) #define SETCURSOR_RJ(len, row) lcd_moveto(LCD_PIXEL_WIDTH - len * (MENU_FONT_WIDTH), (row + 1) * (MENU_FONT_HEIGHT)) @@ -272,10 +222,6 @@ #define SETCURSOR_RJ(len, row) lcd_moveto(LCD_WIDTH - len, row) #endif - #if ENABLED(SHOW_BOOTSCREEN) - void lcd_bootscreen(); - #endif - #define LCD_UPDATE_INTERVAL 100 #define BUTTON_EXISTS(BN) (defined(BTN_## BN) && BTN_## BN >= 0) #define BUTTON_PRESSED(BN) !READ(BTN_## BN) @@ -284,41 +230,10 @@ typedef void (*screenFunc_t)(); typedef void (*menuAction_t)(); - extern screenFunc_t currentScreen; - void lcd_goto_screen(const screenFunc_t screen, const uint32_t encoder=0); - - extern bool lcd_clicked; - #if LCD_TIMEOUT_TO_STATUS - extern bool defer_return_to_status; - inline void set_defer_return_to_status(const bool defer) { defer_return_to_status = defer; } - #else - constexpr bool defer_return_to_status = false; - #define set_defer_return_to_status(D) NOOP - #endif - - extern int16_t lcd_preheat_hotend_temp[2], lcd_preheat_bed_temp[2]; - extern uint8_t lcd_preheat_fan_speed[2]; - - #if ENABLED(AUTO_BED_LEVELING_UBL) || ENABLED(G26_MESH_VALIDATION) - extern bool lcd_external_control; - #else - constexpr bool lcd_external_control = false; - #endif - - #if ENABLED(LCD_BED_LEVELING) - extern bool lcd_wait_for_move; - #else - constexpr bool lcd_wait_for_move = false; - #endif // Manual Movement constexpr float manual_feedrate_mm_m[XYZE] = MANUAL_FEEDRATE; extern float move_menu_scale; - #if IS_KINEMATIC - extern bool processing_manual_move; - #else - constexpr bool processing_manual_move = false; - #endif #if ENABLED(ADVANCED_PAUSE_FEATURE) void lcd_advanced_pause_show_message(const AdvancedPauseMessage message, @@ -326,65 +241,15 @@ const uint8_t extruder=active_extruder); #endif - #if ENABLED(G26_MESH_VALIDATION) - void lcd_chirp(); - #endif - #if ENABLED(AUTO_BED_LEVELING_UBL) void lcd_mesh_edit_setup(const float &initial); float lcd_mesh_edit(); #endif - #if ENABLED(SCROLL_LONG_FILENAMES) - extern uint8_t filename_scroll_pos, filename_scroll_max; - #endif - #endif // HAS_LCD_MENU - #if ENABLED(FILAMENT_LCD_DISPLAY) && ENABLED(SDSUPPORT) - extern millis_t previous_lcd_status_ms; - #endif - - #if ENABLED(STATUS_MESSAGE_SCROLLING) - extern uint8_t status_scroll_offset; - #endif - - bool lcd_blink(); - - bool use_click(); - - #if ENABLED(AUTO_BED_LEVELING_UBL) || ENABLED(G26_MESH_VALIDATION) - bool is_lcd_clicked(); - void wait_for_release(); - #endif - -#elif ENABLED(EXTENSIBLE_UI) - - // These functions are defined elsewhere - void lcd_setstatus(const char* const message, const bool persist=false); - void lcd_setstatusPGM(const char* const message, const int8_t level=0); - void lcd_status_printf_P(const uint8_t level, const char * const fmt, ...); - void lcd_reset_status(); - void lcd_refresh(); - void lcd_reset_alert_level(); - bool lcd_hasstatus(); - -#else // MALYAN_LCD or no LCD - - constexpr bool lcd_wait_for_move = false; - - inline void lcd_refresh() {} - inline bool lcd_hasstatus() { return false; } - inline void lcd_setstatus(const char* const message, const bool persist=false) { UNUSED(message); UNUSED(persist); } - inline void lcd_setstatusPGM(PGM_P const message, const int8_t level=0) { UNUSED(message); UNUSED(level); } - inline void lcd_status_printf_P(const uint8_t level, PGM_P const fmt, ...) { UNUSED(level); UNUSED(fmt); } - inline void lcd_reset_alert_level() {} - inline void lcd_reset_status() {} - #endif -#define HAS_DIGITAL_ENCODER (HAS_SPI_LCD && ENABLED(NEWPANEL)) - #if HAS_DIGITAL_ENCODER // Wheel spin pins where BA is 00, 10, 11, 01 (1 bit always changes) @@ -402,103 +267,400 @@ #if BUTTON_EXISTS(BACK) #define BLEN_D 3 #define EN_D _BV(BLEN_D) - #define LCD_BACK_CLICKED (buttons & EN_D) + #define LCD_BACK_CLICKED() (buttons & EN_D) #endif -#endif // HAS_DIGITAL_ENCODER + #if ENABLED(REPRAPWORLD_KEYPAD) + #define REPRAPWORLD_BTN_OFFSET 0 // Bit offset into buttons for shift register values -#if HAS_LCD_MENU + #define BLEN_REPRAPWORLD_KEYPAD_F3 0 + #define BLEN_REPRAPWORLD_KEYPAD_F2 1 + #define BLEN_REPRAPWORLD_KEYPAD_F1 2 + #define BLEN_REPRAPWORLD_KEYPAD_DOWN 3 + #define BLEN_REPRAPWORLD_KEYPAD_RIGHT 4 + #define BLEN_REPRAPWORLD_KEYPAD_MIDDLE 5 + #define BLEN_REPRAPWORLD_KEYPAD_UP 6 + #define BLEN_REPRAPWORLD_KEYPAD_LEFT 7 - extern volatile uint8_t buttons; // The last-checked buttons in a bit array. - void lcd_buttons_update(); + #define EN_REPRAPWORLD_KEYPAD_F1 (_BV(REPRAPWORLD_BTN_OFFSET + BLEN_REPRAPWORLD_KEYPAD_F1)) + #define EN_REPRAPWORLD_KEYPAD_F2 (_BV(REPRAPWORLD_BTN_OFFSET + BLEN_REPRAPWORLD_KEYPAD_F2)) + #define EN_REPRAPWORLD_KEYPAD_F3 (_BV(REPRAPWORLD_BTN_OFFSET + BLEN_REPRAPWORLD_KEYPAD_F3)) + #define EN_REPRAPWORLD_KEYPAD_DOWN (_BV(REPRAPWORLD_BTN_OFFSET + BLEN_REPRAPWORLD_KEYPAD_DOWN)) + #define EN_REPRAPWORLD_KEYPAD_RIGHT (_BV(REPRAPWORLD_BTN_OFFSET + BLEN_REPRAPWORLD_KEYPAD_RIGHT)) + #define EN_REPRAPWORLD_KEYPAD_MIDDLE (_BV(REPRAPWORLD_BTN_OFFSET + BLEN_REPRAPWORLD_KEYPAD_MIDDLE)) + #define EN_REPRAPWORLD_KEYPAD_UP (_BV(REPRAPWORLD_BTN_OFFSET + BLEN_REPRAPWORLD_KEYPAD_UP)) + #define EN_REPRAPWORLD_KEYPAD_LEFT (_BV(REPRAPWORLD_BTN_OFFSET + BLEN_REPRAPWORLD_KEYPAD_LEFT)) + + #define RRK(B) (buttons_reprapworld_keypad & (B)) + + #ifdef EN_C + #define BUTTON_CLICK() ((buttons & EN_C) || RRK(EN_REPRAPWORLD_KEYPAD_MIDDLE)) + #else + #define BUTTON_CLICK() RRK(EN_REPRAPWORLD_KEYPAD_MIDDLE) + #endif + + #elif ENABLED(LCD_I2C_VIKI) + + #define B_I2C_BTN_OFFSET 3 // (the first three bit positions reserved for EN_A, EN_B, EN_C) + + // button and encoder bit positions within 'buttons' + #define B_LE (BUTTON_LEFT << B_I2C_BTN_OFFSET) // The remaining normalized buttons are all read via I2C + #define B_UP (BUTTON_UP << B_I2C_BTN_OFFSET) + #define B_MI (BUTTON_SELECT << B_I2C_BTN_OFFSET) + #define B_DW (BUTTON_DOWN << B_I2C_BTN_OFFSET) + #define B_RI (BUTTON_RIGHT << B_I2C_BTN_OFFSET) + + #if BUTTON_EXISTS(ENC) // The pause/stop/restart button is connected to BTN_ENC when used + #define B_ST (EN_C) // Map the pause/stop/resume button into its normalized functional name + #define BUTTON_CLICK() (buttons & (B_MI|B_RI|B_ST)) // Pause/stop also acts as click until a proper pause/stop is implemented. + #else + #define BUTTON_CLICK() (buttons & (B_MI|B_RI)) + #endif + + // I2C buttons take too long to read inside an interrupt context and so we read them during lcd_update + #define LCD_HAS_SLOW_BUTTONS + + #elif ENABLED(LCD_I2C_PANELOLU2) + + #if !BUTTON_EXISTS(ENC) // Use I2C if not directly connected to a pin + + #define B_I2C_BTN_OFFSET 3 // (the first three bit positions reserved for EN_A, EN_B, EN_C) + + #define B_MI (PANELOLU2_ENCODER_C << B_I2C_BTN_OFFSET) // requires LiquidTWI2 library v1.2.3 or later + + #define BUTTON_CLICK() (buttons & B_MI) + + // I2C buttons take too long to read inside an interrupt context and so we read them during lcd_update + #define LCD_HAS_SLOW_BUTTONS + + #endif + + #endif #else - inline void lcd_buttons_update() {} + // Shift register bits correspond to buttons: + #define BL_LE 7 // Left + #define BL_UP 6 // Up + #define BL_MI 5 // Middle + #define BL_DW 4 // Down + #define BL_RI 3 // Right + #define BL_ST 2 // Red Button + #define B_LE (_BV(BL_LE)) + #define B_UP (_BV(BL_UP)) + #define B_MI (_BV(BL_MI)) + #define B_DW (_BV(BL_DW)) + #define B_RI (_BV(BL_RI)) + #define B_ST (_BV(BL_ST)) + #define BUTTON_CLICK() (buttons & (B_MI|B_ST)) #endif -#if ENABLED(LCD_HAS_SLOW_BUTTONS) - extern volatile uint8_t slow_buttons; -#endif - -#if ENABLED(REPRAPWORLD_KEYPAD) - #define REPRAPWORLD_BTN_OFFSET 0 // Bit offset into buttons for shift register values - - #define BLEN_REPRAPWORLD_KEYPAD_F3 0 - #define BLEN_REPRAPWORLD_KEYPAD_F2 1 - #define BLEN_REPRAPWORLD_KEYPAD_F1 2 - #define BLEN_REPRAPWORLD_KEYPAD_DOWN 3 - #define BLEN_REPRAPWORLD_KEYPAD_RIGHT 4 - #define BLEN_REPRAPWORLD_KEYPAD_MIDDLE 5 - #define BLEN_REPRAPWORLD_KEYPAD_UP 6 - #define BLEN_REPRAPWORLD_KEYPAD_LEFT 7 - - #define EN_REPRAPWORLD_KEYPAD_F1 (_BV(REPRAPWORLD_BTN_OFFSET + BLEN_REPRAPWORLD_KEYPAD_F1)) - #define EN_REPRAPWORLD_KEYPAD_F2 (_BV(REPRAPWORLD_BTN_OFFSET + BLEN_REPRAPWORLD_KEYPAD_F2)) - #define EN_REPRAPWORLD_KEYPAD_F3 (_BV(REPRAPWORLD_BTN_OFFSET + BLEN_REPRAPWORLD_KEYPAD_F3)) - #define EN_REPRAPWORLD_KEYPAD_DOWN (_BV(REPRAPWORLD_BTN_OFFSET + BLEN_REPRAPWORLD_KEYPAD_DOWN)) - #define EN_REPRAPWORLD_KEYPAD_RIGHT (_BV(REPRAPWORLD_BTN_OFFSET + BLEN_REPRAPWORLD_KEYPAD_RIGHT)) - #define EN_REPRAPWORLD_KEYPAD_MIDDLE (_BV(REPRAPWORLD_BTN_OFFSET + BLEN_REPRAPWORLD_KEYPAD_MIDDLE)) - #define EN_REPRAPWORLD_KEYPAD_UP (_BV(REPRAPWORLD_BTN_OFFSET + BLEN_REPRAPWORLD_KEYPAD_UP)) - #define EN_REPRAPWORLD_KEYPAD_LEFT (_BV(REPRAPWORLD_BTN_OFFSET + BLEN_REPRAPWORLD_KEYPAD_LEFT)) - - #define RRK(B) (buttons_reprapworld_keypad & (B)) - +#ifndef BUTTON_CLICK #ifdef EN_C - #define LCD_CLICKED() ((buttons & EN_C) || RRK(EN_REPRAPWORLD_KEYPAD_MIDDLE)) + #define BUTTON_CLICK() (buttons & EN_C) #else - #define LCD_CLICKED() RRK(EN_REPRAPWORLD_KEYPAD_MIDDLE) - #endif - -#endif // REPRAPWORLD_KEYPAD - -#ifndef LCD_CLICKED - #ifdef EN_C - #define LCD_CLICKED() (buttons & EN_C) - #else - #define LCD_CLICKED() false + #define BUTTON_CLICK() false #endif #endif -extern uint8_t lcd_status_update_delay; -extern char lcd_status_message[]; +#define LCD_MESSAGEPGM(x) ui.setstatusPGM(PSTR(x)) +#define LCD_ALERTMESSAGEPGM(x) ui.setalertstatusPGM(PSTR(x)) -#define LCD_MESSAGEPGM(x) lcd_setstatusPGM(PSTR(x)) -#define LCD_ALERTMESSAGEPGM(x) lcd_setalertstatusPGM(PSTR(x)) +//////////////////////////////////////////// +//////////// MarlinUI Singleton //////////// +//////////////////////////////////////////// -// For i2c define BUZZ to use lcd_buzz -#if ENABLED(LCD_USE_I2C_BUZZER) - #define BUZZ(d,f) lcd_buzz(d, f) -#endif +class MarlinUI { +public: -#if ENABLED(SD_REPRINT_LAST_SELECTED_FILE) - void lcd_reselect_last_file(); -#endif - -#if HAS_GRAPHICAL_LCD - extern bool drawing_screen, first_page; -#elif HAS_SPI_LCD - constexpr bool first_page = true; -#endif - -// LCD implementations -void lcd_implementation_clear(); -void lcd_implementation_init(); - -#if HAS_CHARACTER_LCD - - enum HD44780CharSet : uint8_t { CHARSET_MENU, CHARSET_INFO, CHARSET_BOOT }; - - void lcd_set_custom_characters( - #if ENABLED(LCD_PROGRESS_BAR) || ENABLED(SHOW_BOOTSCREEN) - const HD44780CharSet screen_charset=CHARSET_INFO + MarlinUI() { + #if HAS_LCD_MENU + currentScreen = status_screen; #endif - ); - #if ENABLED(LCD_PROGRESS_BAR) - #define LCD_SET_CHARSET(C) lcd_set_custom_characters(C) - #else - #define LCD_SET_CHARSET(C) lcd_set_custom_characters() + } + + static inline void buzz(const long duration, const uint16_t freq) { + #if ENABLED(LCD_USE_I2C_BUZZER) + lcd.buzz(duration, freq); + #elif PIN_EXISTS(BEEPER) + buzzer.tone(duration, freq); + #else + UNUSED(duration); UNUSED(freq); + #endif + } + + // LCD implementations + static void clear_lcd(); + static void init_lcd(); + + #if HAS_SPI_LCD || ENABLED(MALYAN_LCD) || ENABLED(EXTENSIBLE_UI) + static void init(); + static void update(); + static bool detected(); + static void setalertstatusPGM(PGM_P message); + #else // NO LCD + static inline void init() {} + static inline void update() {} + static constexpr bool detected() { return true; } + static inline void setalertstatusPGM(PGM_P message) { UNUSED(message); } #endif -#endif + #if HAS_SPI_LCD || ENABLED(EXTENSIBLE_UI) + + #if HAS_SPI_LCD + + static LCDViewAction lcdDrawUpdate; + static inline bool should_draw() { return bool(lcdDrawUpdate); } + static inline void refresh(const LCDViewAction type) { lcdDrawUpdate = type; } + static inline void refresh() { refresh(LCDVIEW_CLEAR_CALL_REDRAW); } + + #if ENABLED(SHOW_BOOTSCREEN) + static void show_bootscreen(); + #endif + + #if HAS_GRAPHICAL_LCD + + static bool drawing_screen, first_page; + + static void set_font(const MarlinFont font_nr); + + #else + + static constexpr bool drawing_screen = false, first_page = true; + + enum HD44780CharSet : uint8_t { CHARSET_MENU, CHARSET_INFO, CHARSET_BOOT }; + + static void set_custom_characters( + #if ENABLED(LCD_PROGRESS_BAR) || ENABLED(SHOW_BOOTSCREEN) + const HD44780CharSet screen_charset=CHARSET_INFO + #endif + ); + + #if ENABLED(LCD_PROGRESS_BAR) + static millis_t progress_bar_ms; // Start time for the current progress bar cycle + #if PROGRESS_MSG_EXPIRE > 0 + static millis_t MarlinUI::expire_status_ms; // = 0 + static inline void reset_progress_bar_timeout() { expire_status_ms = 0; } + #endif + #define LCD_SET_CHARSET(C) set_custom_characters(C) + #else + #define LCD_SET_CHARSET(C) set_custom_characters() + #endif + + #endif + + // Status message + static char status_message[]; + #if ENABLED(STATUS_MESSAGE_SCROLLING) + static uint8_t status_scroll_offset; + #endif + + static uint8_t lcd_status_update_delay; + static uint8_t status_message_level; // Higher levels block lower levels + static inline void reset_alert_level() { status_message_level = 0; } + + #if HAS_PRINT_PROGRESS + #if ENABLED(LCD_SET_PROGRESS_MANUALLY) + static uint8_t progress_bar_percent; + static void set_progress(const uint8_t progress) { progress_bar_percent = MIN(progress, 100); } + #endif + static uint8_t get_progress(); + #else + static constexpr uint8_t get_progress() { return 0; } + #endif + + #if HAS_LCD_CONTRAST + static int16_t contrast; + static void set_contrast(const int16_t value); + static inline void refresh_contrast() { set_contrast(contrast); } + #endif + + #if ENABLED(FILAMENT_LCD_DISPLAY) && ENABLED(SDSUPPORT) + static millis_t next_filament_display; + #endif + + static void quick_feedback(const bool clear_buttons=true); + static void completion_feedback(const bool good=true); + + #if DISABLED(LIGHTWEIGHT_UI) + static void draw_status_message(const bool blink); + #endif + + #if ENABLED(ADVANCED_PAUSE_FEATURE) + static void draw_hotend_status(const uint8_t row, const uint8_t extruder); + #endif + + static void status_screen(); + + #else + + static void refresh(); + static void reset_alert_level(); + + #endif + + static bool get_blink(); + static void kill_screen(PGM_P const lcd_msg); + static void draw_kill_screen(); + static bool hasstatus(); + static void setstatus(const char* const message, const bool persist=false); + static void setstatusPGM(PGM_P const message, const int8_t level=0); + static void status_printf_P(const uint8_t level, PGM_P const fmt, ...); + static void reset_status(); + + #else // MALYAN_LCD or NO LCD + + static inline void refresh() {} + static constexpr bool hasstatus() { return false; } + static inline void setstatus(const char* const message, const bool persist=false) { UNUSED(message); UNUSED(persist); } + static inline void setstatusPGM(PGM_P const message, const int8_t level=0) { UNUSED(message); UNUSED(level); } + static inline void status_printf_P(const uint8_t level, PGM_P const fmt, ...) { UNUSED(level); UNUSED(fmt); } + static inline void reset_status() {} + static inline void reset_alert_level() {} + + #endif + + #if HAS_LCD_MENU + + #if ENABLED(ENCODER_RATE_MULTIPLIER) + static bool encoderRateMultiplierEnabled; + static millis_t lastEncoderMovementMillis; + static void enable_encoder_multiplier(const bool onoff); + #endif + + #if ENABLED(SCROLL_LONG_FILENAMES) + static uint8_t filename_scroll_pos, filename_scroll_max; + #endif + + #if IS_KINEMATIC + 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 + + static int16_t preheat_hotend_temp[2], preheat_bed_temp[2]; + static uint8_t preheat_fan_speed[2]; + + static void manage_manual_move(); + + static bool lcd_clicked; + static bool use_click(); + + static void synchronize(PGM_P const msg=NULL); + + static screenFunc_t currentScreen; + static void goto_screen(const screenFunc_t screen, const uint32_t encoder=0); + static void save_previous_screen(); + static void goto_previous_screen(); + static void return_to_status(); + static inline bool on_status_screen() { return currentScreen == status_screen; } + static inline void run_current_screen() { (*currentScreen)(); } + + static inline void defer_status_screen(const bool defer) { + #if LCD_TIMEOUT_TO_STATUS + defer_return_to_status = defer; + #else + UNUSED(defer); + #endif + } + + static inline void goto_previous_screen_no_defer() { + defer_status_screen(false); + goto_previous_screen(); + } + + #if ENABLED(SD_REPRINT_LAST_SELECTED_FILE) + static void reselect_last_file(); + #endif + + #if ENABLED(G26_MESH_VALIDATION) + static inline void chirp() { buzz(LCD_FEEDBACK_FREQUENCY_DURATION_MS, LCD_FEEDBACK_FREQUENCY_HZ); } + #endif + + #if ENABLED(AUTO_BED_LEVELING_UBL) + static void ubl_plot(const uint8_t x, const uint8_t inverted_y); + #endif + + #elif HAS_SPI_LCD + + static constexpr bool lcd_clicked = false; + static constexpr bool on_status_screen() { return true; } + static inline void run_current_screen() { status_screen(); } + + #endif + + #if ENABLED(LCD_BED_LEVELING) && (ENABLED(PROBE_MANUALLY) || ENABLED(MESH_BED_LEVELING)) + static bool wait_for_bl_move; + #else + static constexpr bool wait_for_bl_move = false; + #endif + + #if HAS_LCD_MENU && (ENABLED(AUTO_BED_LEVELING_UBL) || ENABLED(G26_MESH_VALIDATION)) + static bool external_control; + FORCE_INLINE static void capture() { external_control = true; } + FORCE_INLINE static void release() { external_control = false; } + #else + static constexpr bool external_control = false; + #endif + + #if HAS_ENCODER_ACTION + + static volatile uint8_t buttons; + #if ENABLED(LCD_HAS_SLOW_BUTTONS) + static volatile uint8_t slow_buttons; + static uint8_t read_slow_buttons(); + #endif + static void update_buttons(); + static inline bool button_pressed() { return BUTTON_CLICK(); } + #if ENABLED(AUTO_BED_LEVELING_UBL) || ENABLED(G26_MESH_VALIDATION) + static void wait_for_release(); + #endif + + static uint32_t encoderPosition; + + #if ENABLED(REVERSE_ENCODER_DIRECTION) + #define ENCODERBASE -1 + #else + #define ENCODERBASE +1 + #endif + #if ENABLED(REVERSE_MENU_DIRECTION) + static int8_t encoderDirection; + static inline void encoder_direction_normal() { encoderDirection = +(ENCODERBASE); } + static inline void encoder_direction_menus() { encoderDirection = -(ENCODERBASE); } + #else + static constexpr int8_t encoderDirection = ENCODERBASE; + static inline void encoder_direction_normal() { } + static inline void encoder_direction_menus() { } + #endif + + #else + + static inline void update_buttons() { } + + #endif + +private: + + static void _synchronize(); + + #if HAS_SPI_LCD + #if HAS_LCD_MENU + #if LCD_TIMEOUT_TO_STATUS + static bool defer_return_to_status; + #else + static constexpr bool defer_return_to_status = false; + #endif + #endif + static void draw_status_screen(); + static void finishstatus(const bool persist); + #endif +}; + +extern MarlinUI ui; diff --git a/Marlin/src/libs/buzzer.h b/Marlin/src/libs/buzzer.h index 2a150e267c..c0ed8d9fa2 100644 --- a/Marlin/src/libs/buzzer.h +++ b/Marlin/src/libs/buzzer.h @@ -23,94 +23,95 @@ #include "../inc/MarlinConfig.h" -// Make a buzzer and macro #if ENABLED(LCD_USE_I2C_BUZZER) - // BUZZ() will be defined in ultralcd.h + + #define BUZZ(d,f) ui.buzz(d,f) + #elif PIN_EXISTS(BEEPER) -#include "circularqueue.h" + #include "circularqueue.h" -#define TONE_QUEUE_LENGTH 4 + #define TONE_QUEUE_LENGTH 4 -/** - * @brief Tone structure - * @details Simple abstraction of a tone based on a duration and a frequency. - */ -struct tone_t { - uint16_t duration; - uint16_t frequency; -}; + /** + * @brief Tone structure + * @details Simple abstraction of a tone based on a duration and a frequency. + */ + struct tone_t { + uint16_t duration; + uint16_t frequency; + }; -/** - * @brief Buzzer class - */ -class Buzzer { - public: + /** + * @brief Buzzer class + */ + class Buzzer { + public: - typedef struct { - tone_t tone; - uint32_t endtime; - } state_t; + typedef struct { + tone_t tone; + uint32_t endtime; + } state_t; - private: - static state_t state; + private: + static state_t state; - protected: - static CircularQueue buffer; + protected: + static CircularQueue buffer; - /** - * @brief Inverts the sate of a digital PIN - * @details This will invert the current state of an digital IO pin. - */ - FORCE_INLINE static void invert() { TOGGLE(BEEPER_PIN); } + /** + * @brief Inverts the sate of a digital PIN + * @details This will invert the current state of an digital IO pin. + */ + FORCE_INLINE static void invert() { TOGGLE(BEEPER_PIN); } - /** - * @brief Turn off a digital PIN - * @details Alias of digitalWrite(PIN, LOW) using FastIO - */ - FORCE_INLINE static void off() { WRITE(BEEPER_PIN, LOW); } + /** + * @brief Turn off a digital PIN + * @details Alias of digitalWrite(PIN, LOW) using FastIO + */ + FORCE_INLINE static void off() { WRITE(BEEPER_PIN, LOW); } - /** - * @brief Turn on a digital PIN - * @details Alias of digitalWrite(PIN, HIGH) using FastIO - */ - FORCE_INLINE static void on() { WRITE(BEEPER_PIN, HIGH); } + /** + * @brief Turn on a digital PIN + * @details Alias of digitalWrite(PIN, HIGH) using FastIO + */ + FORCE_INLINE static void on() { WRITE(BEEPER_PIN, HIGH); } - /** - * @brief Resets the state of the class - * @details Brings the class state to a known one. - */ - static inline void reset() { - off(); - state.endtime = 0; - } + /** + * @brief Resets the state of the class + * @details Brings the class state to a known one. + */ + static inline void reset() { + off(); + state.endtime = 0; + } - public: - /** - * @brief Class constructor - */ - Buzzer() { - SET_OUTPUT(BEEPER_PIN); - reset(); - } + public: + /** + * @brief Class constructor + */ + Buzzer() { + SET_OUTPUT(BEEPER_PIN); + reset(); + } - /** - * @brief Add a tone to the queue - * @details Adds a tone_t structure to the ring buffer, will block IO if the - * queue is full waiting for one slot to get available. - * - * @param duration Duration of the tone in milliseconds - * @param frequency Frequency of the tone in hertz - */ - static void tone(const uint16_t duration, const uint16_t frequency=0); + /** + * @brief Add a tone to the queue + * @details Adds a tone_t structure to the ring buffer, will block IO if the + * queue is full waiting for one slot to get available. + * + * @param duration Duration of the tone in milliseconds + * @param frequency Frequency of the tone in hertz + */ + static void tone(const uint16_t duration, const uint16_t frequency=0); - /** - * @brief Tick function - * @details This function should be called at loop, it will take care of - * playing the tones in the queue. - */ - static void tick(); -}; + /** + * @brief Tick function + * @details This function should be called at loop, it will take care of + * playing the tones in the queue. + */ + static void tick(); + }; // Provide a buzzer instance extern Buzzer buzzer; diff --git a/Marlin/src/module/configuration_store.cpp b/Marlin/src/module/configuration_store.cpp index 9e8e9e3fc5..3919f99ea7 100644 --- a/Marlin/src/module/configuration_store.cpp +++ b/Marlin/src/module/configuration_store.cpp @@ -201,9 +201,9 @@ typedef struct SettingsDataStruct { // // ULTIPANEL // - int16_t lcd_preheat_hotend_temp[2], // M145 S0 H - lcd_preheat_bed_temp[2]; // M145 S0 B - uint8_t lcd_preheat_fan_speed[2]; // M145 S0 F + int16_t ui_preheat_hotend_temp[2], // M145 S0 H + ui_preheat_bed_temp[2]; // M145 S0 B + uint8_t ui_preheat_fan_speed[2]; // M145 S0 F // // PIDTEMP @@ -680,15 +680,19 @@ void MarlinSettings::postprocess() { { _FIELD_TEST(lcd_preheat_hotend_temp); - #if !HAS_LCD_MENU - constexpr int16_t lcd_preheat_hotend_temp[2] = { PREHEAT_1_TEMP_HOTEND, PREHEAT_2_TEMP_HOTEND }, - lcd_preheat_bed_temp[2] = { PREHEAT_1_TEMP_BED, PREHEAT_2_TEMP_BED }; - constexpr uint8_t lcd_preheat_fan_speed[2] = { PREHEAT_1_FAN_SPEED, PREHEAT_2_FAN_SPEED }; + #if HAS_LCD_MENU + const int16_t (&ui_preheat_hotend_temp)[2] = ui.preheat_hotend_temp, + (&ui_preheat_bed_temp)[2] = ui.preheat_bed_temp; + const uint8_t (&ui_preheat_fan_speed)[2] = ui.preheat_fan_speed; + #else + constexpr int16_t ui_preheat_hotend_temp[2] = { PREHEAT_1_TEMP_HOTEND, PREHEAT_2_TEMP_HOTEND }, + ui_preheat_bed_temp[2] = { PREHEAT_1_TEMP_BED, PREHEAT_2_TEMP_BED }; + constexpr uint8_t ui_preheat_fan_speed[2] = { PREHEAT_1_FAN_SPEED, PREHEAT_2_FAN_SPEED }; #endif - EEPROM_WRITE(lcd_preheat_hotend_temp); - EEPROM_WRITE(lcd_preheat_bed_temp); - EEPROM_WRITE(lcd_preheat_fan_speed); + EEPROM_WRITE(ui_preheat_hotend_temp); + EEPROM_WRITE(ui_preheat_bed_temp); + EEPROM_WRITE(ui_preheat_fan_speed); } // @@ -717,6 +721,7 @@ void MarlinSettings::postprocess() { // { _FIELD_TEST(bedPID); + #if DISABLED(PIDTEMPBED) const PID_t bed_pid = { DUMMY_PID_VALUE, DUMMY_PID_VALUE, DUMMY_PID_VALUE }; EEPROM_WRITE(bed_pid); @@ -731,9 +736,13 @@ void MarlinSettings::postprocess() { { _FIELD_TEST(lcd_contrast); - #if !HAS_LCD_CONTRAST - const int16_t lcd_contrast = 32; - #endif + const int16_t lcd_contrast = + #if HAS_LCD_CONTRAST + ui.contrast + #else + 32 + #endif + ; EEPROM_WRITE(lcd_contrast); } @@ -1304,15 +1313,19 @@ void MarlinSettings::postprocess() { // LCD Preheat settings // { - _FIELD_TEST(lcd_preheat_hotend_temp); + _FIELD_TEST(ui_preheat_hotend_temp); - #if !HAS_LCD_MENU - int16_t lcd_preheat_hotend_temp[2], lcd_preheat_bed_temp[2]; - uint8_t lcd_preheat_fan_speed[2]; + #if HAS_LCD_MENU + int16_t (&ui_preheat_hotend_temp)[2] = ui.preheat_hotend_temp, + (&ui_preheat_bed_temp)[2] = ui.preheat_bed_temp; + uint8_t (&ui_preheat_fan_speed)[2] = ui.preheat_fan_speed; + #else + int16_t ui_preheat_hotend_temp[2], ui_preheat_bed_temp[2]; + uint8_t ui_preheat_fan_speed[2]; #endif - EEPROM_READ(lcd_preheat_hotend_temp); // 2 floats - EEPROM_READ(lcd_preheat_bed_temp); // 2 floats - EEPROM_READ(lcd_preheat_fan_speed); // 2 floats + EEPROM_READ(ui_preheat_hotend_temp); // 2 floats + EEPROM_READ(ui_preheat_bed_temp); // 2 floats + EEPROM_READ(ui_preheat_fan_speed); // 2 floats } // @@ -1366,10 +1379,12 @@ void MarlinSettings::postprocess() { // { _FIELD_TEST(lcd_contrast); - #if !HAS_LCD_CONTRAST - int16_t lcd_contrast; - #endif + + int16_t lcd_contrast; EEPROM_READ(lcd_contrast); + #if HAS_LCD_CONTRAST + ui.set_contrast(lcd_contrast); + #endif } // @@ -2028,12 +2043,12 @@ void MarlinSettings::reset(PORTARG_SOLO) { #endif #if HAS_LCD_MENU - lcd_preheat_hotend_temp[0] = PREHEAT_1_TEMP_HOTEND; - lcd_preheat_hotend_temp[1] = PREHEAT_2_TEMP_HOTEND; - lcd_preheat_bed_temp[0] = PREHEAT_1_TEMP_BED; - lcd_preheat_bed_temp[1] = PREHEAT_2_TEMP_BED; - lcd_preheat_fan_speed[0] = PREHEAT_1_FAN_SPEED; - lcd_preheat_fan_speed[1] = PREHEAT_2_FAN_SPEED; + ui.preheat_hotend_temp[0] = PREHEAT_1_TEMP_HOTEND; + ui.preheat_hotend_temp[1] = PREHEAT_2_TEMP_HOTEND; + ui.preheat_bed_temp[0] = PREHEAT_1_TEMP_BED; + ui.preheat_bed_temp[1] = PREHEAT_2_TEMP_BED; + ui.preheat_fan_speed[0] = PREHEAT_1_FAN_SPEED; + ui.preheat_fan_speed[1] = PREHEAT_2_FAN_SPEED; #endif #if ENABLED(PIDTEMP) @@ -2057,7 +2072,7 @@ void MarlinSettings::reset(PORTARG_SOLO) { #endif #if HAS_LCD_CONTRAST - lcd_contrast = DEFAULT_LCD_CONTRAST; + ui.set_contrast(DEFAULT_LCD_CONTRAST); #endif #if ENABLED(FWRETRACT) @@ -2561,12 +2576,12 @@ void MarlinSettings::reset(PORTARG_SOLO) { CONFIG_ECHO_START; SERIAL_ECHOLNPGM_P(port, "Material heatup parameters:"); } - for (uint8_t i = 0; i < COUNT(lcd_preheat_hotend_temp); i++) { + for (uint8_t i = 0; i < COUNT(ui.preheat_hotend_temp); i++) { CONFIG_ECHO_START; SERIAL_ECHOPAIR_P(port, " M145 S", (int)i); - SERIAL_ECHOPAIR_P(port, " H", TEMP_UNIT(lcd_preheat_hotend_temp[i])); - SERIAL_ECHOPAIR_P(port, " B", TEMP_UNIT(lcd_preheat_bed_temp[i])); - SERIAL_ECHOLNPAIR_P(port, " F", int(lcd_preheat_fan_speed[i])); + SERIAL_ECHOPAIR_P(port, " H", TEMP_UNIT(ui.preheat_hotend_temp[i])); + SERIAL_ECHOPAIR_P(port, " B", TEMP_UNIT(ui.preheat_bed_temp[i])); + SERIAL_ECHOLNPAIR_P(port, " F", int(ui.preheat_fan_speed[i])); } #endif @@ -2625,7 +2640,7 @@ void MarlinSettings::reset(PORTARG_SOLO) { SERIAL_ECHOLNPGM_P(port, "LCD Contrast:"); } CONFIG_ECHO_START; - SERIAL_ECHOLNPAIR_P(port, " M250 C", lcd_contrast); + SERIAL_ECHOLNPAIR_P(port, " M250 C", ui.contrast); #endif #if ENABLED(FWRETRACT) diff --git a/Marlin/src/module/endstops.cpp b/Marlin/src/module/endstops.cpp index 28e0d92f69..1e2d805b6e 100644 --- a/Marlin/src/module/endstops.cpp +++ b/Marlin/src/module/endstops.cpp @@ -337,7 +337,7 @@ void Endstops::event_handler() { SERIAL_EOL(); #if ENABLED(ULTRA_LCD) - lcd_status_printf_P(0, PSTR(MSG_LCD_ENDSTOPS " %c %c %c %c"), chrX, chrY, chrZ, chrP); + ui.status_printf_P(0, PSTR(MSG_LCD_ENDSTOPS " %c %c %c %c"), chrX, chrY, chrZ, chrP); #endif #if ENABLED(ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED) && ENABLED(SDSUPPORT) diff --git a/Marlin/src/module/motion.cpp b/Marlin/src/module/motion.cpp index 9cd83907c1..ec888f12b5 100644 --- a/Marlin/src/module/motion.cpp +++ b/Marlin/src/module/motion.cpp @@ -1026,7 +1026,7 @@ void prepare_move_to_destination() { SERIAL_ECHOLNPGM(" " MSG_FIRST); #if ENABLED(ULTRA_LCD) - lcd_status_printf_P(0, PSTR(MSG_HOME " %s%s%s " MSG_FIRST), xx ? MSG_X : "", yy ? MSG_Y : "", zz ? MSG_Z : ""); + ui.status_printf_P(0, PSTR(MSG_HOME " %s%s%s " MSG_FIRST), xx ? MSG_X : "", yy ? MSG_Y : "", zz ? MSG_Z : ""); #endif return true; } @@ -1121,7 +1121,7 @@ void do_homing_move(const AxisEnum axis, const float distance, const float fr_mm serialprintPGM(msg_wait_for_bed_heating); LCD_MESSAGEPGM(MSG_BED_HEATING); while (thermalManager.isHeatingBed()) safe_delay(200); - lcd_reset_status(); + ui.reset_status(); } #endif diff --git a/Marlin/src/module/probe.cpp b/Marlin/src/module/probe.cpp index bec70918a6..5597714416 100644 --- a/Marlin/src/module/probe.cpp +++ b/Marlin/src/module/probe.cpp @@ -370,15 +370,15 @@ FORCE_INLINE void probe_specific_action(const bool deploy) { BUZZ(100, 698); PGM_P const ds_str = deploy ? PSTR(MSG_MANUAL_DEPLOY) : PSTR(MSG_MANUAL_STOW); - lcd_return_to_status(); // To display the new status message - lcd_setstatusPGM(ds_str, 99); + ui.return_to_status(); // To display the new status message + ui.setstatusPGM(ds_str, 99); serialprintPGM(ds_str); SERIAL_EOL(); KEEPALIVE_STATE(PAUSED_FOR_USER); wait_for_user = true; while (wait_for_user) idle(); - lcd_reset_status(); + ui.reset_status(); KEEPALIVE_STATE(IN_HANDLER); #endif // PAUSE_BEFORE_DEPLOY_STOW @@ -527,7 +527,7 @@ static bool do_probe_move(const float z, const float fr_mm_s) { serialprintPGM(msg_wait_for_bed_heating); LCD_MESSAGEPGM(MSG_BED_HEATING); while (thermalManager.isHeatingBed()) safe_delay(200); - lcd_reset_status(); + ui.reset_status(); } #endif diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp index 4750b7dcd6..77ac6f7a73 100644 --- a/Marlin/src/module/temperature.cpp +++ b/Marlin/src/module/temperature.cpp @@ -498,7 +498,7 @@ uint8_t Temperature::soft_pwm_amount[HOTENDS]; return; } - lcd_update(); + ui.update(); } disable_all_heaters(); #if ENABLED(PRINTER_EVENT_LEDS) @@ -2123,7 +2123,7 @@ void Temperature::isr() { // Update lcd buttons 488 times per second // static bool do_buttons; - if ((do_buttons ^= true)) lcd_buttons_update(); + if ((do_buttons ^= true)) ui.update_buttons(); /** * One sensor is sampled on every other call of the ISR. @@ -2425,9 +2425,9 @@ void Temperature::isr() { void Temperature::set_heating_message(const uint8_t e) { const bool heating = isHeatingHotend(e); #if HOTENDS > 1 - lcd_status_printf_P(0, heating ? PSTR("E%i " MSG_HEATING) : PSTR("E%i " MSG_COOLING), int(e + 1)); + ui.status_printf_P(0, heating ? PSTR("E%i " MSG_HEATING) : PSTR("E%i " MSG_COOLING), int(e + 1)); #else - lcd_setstatusPGM(heating ? PSTR("E " MSG_HEATING) : PSTR("E " MSG_COOLING)); + ui.setstatusPGM(heating ? PSTR("E " MSG_HEATING) : PSTR("E " MSG_COOLING)); #endif } #endif @@ -2530,16 +2530,16 @@ void Temperature::isr() { } #if G26_CLICK_CAN_CANCEL - if (click_to_cancel && use_click()) { + if (click_to_cancel && ui.use_click()) { wait_for_heatup = false; - lcd_quick_feedback(); + ui.quick_feedback(); } #endif } while (wait_for_heatup && TEMP_CONDITIONS); if (wait_for_heatup) { - lcd_reset_status(); + ui.reset_status(); #if ENABLED(PRINTER_EVENT_LEDS) printerEventLEDs.onHeatingDone(); #endif @@ -2655,15 +2655,15 @@ void Temperature::isr() { } #if G26_CLICK_CAN_CANCEL - if (click_to_cancel && use_click()) { + if (click_to_cancel && ui.use_click()) { wait_for_heatup = false; - lcd_quick_feedback(); + ui.quick_feedback(); } #endif } while (wait_for_heatup && TEMP_BED_CONDITIONS); - if (wait_for_heatup) lcd_reset_status(); + if (wait_for_heatup) ui.reset_status(); #if DISABLED(BUSY_WHILE_HEATING) && ENABLED(HOST_KEEPALIVE_FEATURE) gcode.busy_state = old_busy_state; diff --git a/Marlin/src/module/tool_change.cpp b/Marlin/src/module/tool_change.cpp index 1d255a88fb..274a64ee47 100644 --- a/Marlin/src/module/tool_change.cpp +++ b/Marlin/src/module/tool_change.cpp @@ -540,7 +540,7 @@ void tool_change(const uint8_t tmp_extruder, const float fr_mm_s/*=0.0*/, bool n } #if HAS_LCD_MENU - lcd_return_to_status(); + ui.return_to_status(); #endif #if ENABLED(TOOLCHANGE_FILAMENT_SWAP) diff --git a/Marlin/src/sd/cardreader.cpp b/Marlin/src/sd/cardreader.cpp index c221475c1f..9c86f48fae 100644 --- a/Marlin/src/sd/cardreader.cpp +++ b/Marlin/src/sd/cardreader.cpp @@ -446,7 +446,7 @@ void CardReader::openFile(char * const path, const bool read, const bool subcall SERIAL_PROTOCOLLNPGM(MSG_SD_FILE_SELECTED); getfilename(0, fname); - lcd_setstatus(longFilename[0] ? longFilename : fname); + ui.setstatus(longFilename[0] ? longFilename : fname); //if (longFilename[0]) { // SERIAL_PROTOCOLPAIR(MSG_SD_FILE_LONG_NAME, longFilename); //} @@ -470,7 +470,7 @@ void CardReader::openFile(char * const path, const bool read, const bool subcall emergency_parser.disable(); #endif SERIAL_PROTOCOLLNPAIR(MSG_SD_WRITE_TO_FILE, fname); - lcd_setstatus(fname); + ui.setstatus(fname); } } } @@ -963,10 +963,10 @@ void CardReader::printingHasFinished() { presort(); #endif #if ENABLED(ULTRA_LCD) && ENABLED(LCD_SET_PROGRESS_MANUALLY) - progress_bar_percent = 0; + ui.progress_bar_percent = 0; #endif #if ENABLED(SD_REPRINT_LAST_SELECTED_FILE) - lcd_reselect_last_file(); + ui.reselect_last_file(); #endif } }