Browse Source

Encapsulate common display code in a singleton (#12395)

* Encapsulate common LCD code in a singleton
* Depend more UBL code on UBL_DEVEL_DEBUGGING
  - Since most users don't need the debugging on at all times, this helps reduce the default build size for UBL by over 2K, a little closer to fitting on 128K boards.
pull/1/head
Scott Lahteine 6 years ago
committed by GitHub
parent
commit
a0c795b097
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 14
      Marlin/src/Marlin.cpp
  2. 2
      Marlin/src/config/examples/Geeetech/GT2560/Configuration.h
  3. 2
      Marlin/src/feature/bedlevel/bedlevel.cpp
  4. 32
      Marlin/src/feature/bedlevel/ubl/ubl.cpp
  5. 16
      Marlin/src/feature/bedlevel/ubl/ubl.h
  6. 680
      Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp
  7. 2
      Marlin/src/feature/pause.cpp
  8. 57
      Marlin/src/gcode/bedlevel/G26.cpp
  9. 4
      Marlin/src/gcode/bedlevel/abl/G29.cpp
  10. 4
      Marlin/src/gcode/bedlevel/mbl/G29.cpp
  11. 2
      Marlin/src/gcode/calibrate/G28.cpp
  12. 8
      Marlin/src/gcode/calibrate/G33.cpp
  13. 2
      Marlin/src/gcode/control/M17_M18_M84.cpp
  14. 2
      Marlin/src/gcode/control/M80_M81.cpp
  15. 2
      Marlin/src/gcode/control/M999.cpp
  16. 6
      Marlin/src/gcode/lcd/M0_M1.cpp
  17. 2
      Marlin/src/gcode/lcd/M117.cpp
  18. 8
      Marlin/src/gcode/lcd/M145.cpp
  19. 6
      Marlin/src/gcode/lcd/M250.cpp
  20. 6
      Marlin/src/gcode/lcd/M73.cpp
  21. 2
      Marlin/src/gcode/motion/G4.cpp
  22. 2
      Marlin/src/gcode/stats/M31.cpp
  23. 4
      Marlin/src/gcode/temperature/M104_M109.cpp
  24. 2
      Marlin/src/gcode/temperature/M140_M190.cpp
  25. 85
      Marlin/src/inc/Conditionals_LCD.h
  26. 36
      Marlin/src/inc/Conditionals_post.h
  27. 2
      Marlin/src/inc/SanityCheck.h
  28. 66
      Marlin/src/lcd/HD44780/ultralcd_common_HD44780.h
  29. 246
      Marlin/src/lcd/HD44780/ultralcd_impl_HD44780.cpp
  30. 81
      Marlin/src/lcd/dogm/status_screen_DOGM.cpp
  31. 244
      Marlin/src/lcd/dogm/status_screen_lite_ST7920.cpp
  32. 4
      Marlin/src/lcd/dogm/status_screen_lite_ST7920_class.h
  33. 57
      Marlin/src/lcd/dogm/ultralcd_impl_DOGM.cpp
  34. 28
      Marlin/src/lcd/extensible_ui/ui_api.cpp
  35. 2
      Marlin/src/lcd/language/language_es.h
  36. 2
      Marlin/src/lcd/language/language_zh_CN.h
  37. 2
      Marlin/src/lcd/language/language_zh_TW.h
  38. 6
      Marlin/src/lcd/malyanlcd.cpp
  39. 131
      Marlin/src/lcd/menu/menu.cpp
  40. 151
      Marlin/src/lcd/menu/menu.h
  41. 12
      Marlin/src/lcd/menu/menu_advanced.cpp
  42. 8
      Marlin/src/lcd/menu/menu_bed_corners.cpp
  43. 60
      Marlin/src/lcd/menu/menu_bed_leveling.cpp
  44. 26
      Marlin/src/lcd/menu/menu_configuration.cpp
  45. 4
      Marlin/src/lcd/menu/menu_custom.cpp
  46. 12
      Marlin/src/lcd/menu/menu_delta_calibrate.cpp
  47. 16
      Marlin/src/lcd/menu/menu_filament.cpp
  48. 8
      Marlin/src/lcd/menu/menu_info.cpp
  49. 6
      Marlin/src/lcd/menu/menu_job_recovery.cpp
  50. 8
      Marlin/src/lcd/menu/menu_main.cpp
  51. 58
      Marlin/src/lcd/menu/menu_motion.cpp
  52. 57
      Marlin/src/lcd/menu/menu_sdcard.cpp
  53. 80
      Marlin/src/lcd/menu/menu_temperature.cpp
  54. 22
      Marlin/src/lcd/menu/menu_tune.cpp
  55. 62
      Marlin/src/lcd/menu/menu_ubl.cpp
  56. 537
      Marlin/src/lcd/ultralcd.cpp
  57. 602
      Marlin/src/lcd/ultralcd.h
  58. 169
      Marlin/src/libs/buzzer.h
  59. 85
      Marlin/src/module/configuration_store.cpp
  60. 2
      Marlin/src/module/endstops.cpp
  61. 4
      Marlin/src/module/motion.cpp
  62. 8
      Marlin/src/module/probe.cpp
  63. 20
      Marlin/src/module/temperature.cpp
  64. 2
      Marlin/src/module/tool_change.cpp
  65. 8
      Marlin/src/sd/cardreader.cpp

14
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)

2
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

2
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
}

32
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();
}

16
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(

680
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

2
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
}

57
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) {

4
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

4
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;

2
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)

8
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();
}

2
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
}

2
Marlin/src/gcode/control/M80_M81.cpp

@ -83,7 +83,7 @@
#endif
#if HAS_LCD_MENU
lcd_reset_status();
ui.reset_status();
#endif
}

2
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;

6
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;

2
Marlin/src/gcode/lcd/M117.cpp

@ -28,6 +28,6 @@
*/
void GcodeSuite::M117() {
lcd_setstatus(parser.string_arg);
ui.setstatus(parser.string_arg);
}

8
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
}

6
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

6
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

2
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);
}

2
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);

4
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();

2
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);
}

85
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

36
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

2
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."

66
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

246
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,34 +716,46 @@ 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|
*/
void lcd_impl_status_screen_0() {
const bool blink = lcd_blink();
/**
* 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|
*/
void MarlinUI::draw_status_screen() {
// ========== Line 1 ==========
const bool blink = get_blink();
lcd_moveto(0, 0);
#if LCD_INFO_SCREEN_STYLE == 0
lcd_moveto(0, 0);
// ========== Line 1 ==========
#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;

81
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) {
#if ENABLED(STATUS_MESSAGE_SCROLLING)
static bool last_blink = false;
void MarlinUI::draw_status_message(const bool blink) {
// Get the UTF8 character count of the string
uint8_t slen = utf8_strlen(lcd_status_message);
// Get the UTF8 character count of the string
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) {
#if ENABLED(STATUS_MESSAGE_SCROLLING)
// The string isn't scrolling and may not fill the screen
lcd_put_u8str(lcd_status_message);
static bool last_blink = false;
// Fill the rest with spaces
while (slen < LCD_WIDTH) {
lcd_put_wchar(' ');
++slen;
}
if (slen <= LCD_WIDTH) {
// 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
UNUSED(blink);
// Get the UTF8 character count of the string
uint8_t slen = utf8_strlen(lcd_status_message);
#else // !STATUS_MESSAGE_SCROLLING
UNUSED(blink);
// 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
}
}

244
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);
// Just print the string to the LCD
write_str(str, lcd_len);
uint8_t slen = utf8_strlen(str);
write_str(str, LCD_WIDTH);
for (; slen < LCD_WIDTH; ++slen) write_byte(' ');
// 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);
}

4
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();

57
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),

28
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);

2
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.")

2
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"

2
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"

6
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);

131
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<NAME ## _item_info>;
#define DEFINE_MENU_EDIT_ITEM(NAME) template class TMenuItem<NAME ## _item_info>;
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))

151
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<typename NAME>
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<NAME ## _item_info> menu_item_ ## NAME;
#define DECLARE_MENU_EDIT_ITEM(NAME) typedef TMenuItem<NAME ## _item_info> 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_<type>[_variant](sel, row, label, arg3...)
* draw_menu_item_<type>[_variant](sel, row, label, arg3...)
* menu_item_<type>::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

12
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() {

8
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

60
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

26
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);

4
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
}

12
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); }

16
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

8
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

6
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);

8
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)

58
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

57
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
lcd_goto_screen(menu_sdcard, last_sdfile_encoderPosition);
set_defer_return_to_status(true);
//#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
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);
}

80
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

22
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

62
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);
}
/**

537
Marlin/src/lcd/ultralcd.cpp

File diff suppressed because it is too large

602
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
#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))
#ifdef EN_C
#define BUTTON_CLICK() ((buttons & EN_C) || RRK(EN_REPRAPWORLD_KEYPAD_MIDDLE))
#else
#define BUTTON_CLICK() RRK(EN_REPRAPWORLD_KEYPAD_MIDDLE)
#endif
#if HAS_LCD_MENU
#elif ENABLED(LCD_I2C_VIKI)
extern volatile uint8_t buttons; // The last-checked buttons in a bit array.
void lcd_buttons_update();
#define B_I2C_BTN_OFFSET 3 // (the first three bit positions reserved for EN_A, EN_B, EN_C)
#else
// 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)
inline void lcd_buttons_update() {}
#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
#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
#if ENABLED(LCD_HAS_SLOW_BUTTONS)
extern volatile uint8_t slow_buttons;
#endif
#elif ENABLED(LCD_I2C_PANELOLU2)
#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))
#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
#ifdef EN_C
#define LCD_CLICKED() ((buttons & EN_C) || RRK(EN_REPRAPWORLD_KEYPAD_MIDDLE))
#else
#define LCD_CLICKED() RRK(EN_REPRAPWORLD_KEYPAD_MIDDLE)
#endif
#endif // REPRAPWORLD_KEYPAD
#else
// 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
#ifndef LCD_CLICKED
#ifndef BUTTON_CLICK
#ifdef EN_C
#define LCD_CLICKED() (buttons & EN_C)
#define BUTTON_CLICK() (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
MarlinUI() {
#if HAS_LCD_MENU
currentScreen = status_screen;
#endif
}
#if HAS_GRAPHICAL_LCD
extern bool drawing_screen, first_page;
#elif HAS_SPI_LCD
constexpr bool first_page = true;
#endif
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
#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
// LCD implementations
void lcd_implementation_clear();
void lcd_implementation_init();
static int16_t preheat_hotend_temp[2], preheat_bed_temp[2];
static uint8_t preheat_fan_speed[2];
#if HAS_CHARACTER_LCD
static void manage_manual_move();
enum HD44780CharSet : uint8_t { CHARSET_MENU, CHARSET_INFO, CHARSET_BOOT };
static bool lcd_clicked;
static bool use_click();
void lcd_set_custom_characters(
#if ENABLED(LCD_PROGRESS_BAR) || ENABLED(SHOW_BOOTSCREEN)
const HD44780CharSet screen_charset=CHARSET_INFO
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(LCD_PROGRESS_BAR)
#define LCD_SET_CHARSET(C) lcd_set_custom_characters(C)
#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
#define LCD_SET_CHARSET(C) lcd_set_custom_characters()
static constexpr bool wait_for_bl_move = false;
#endif
#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;

169
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
#elif PIN_EXISTS(BEEPER)
#include "circularqueue.h"
#define TONE_QUEUE_LENGTH 4
#define BUZZ(d,f) ui.buzz(d,f)
/**
* @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;
};
#elif PIN_EXISTS(BEEPER)
/**
* @brief Buzzer class
*/
class Buzzer {
public:
typedef struct {
tone_t tone;
uint32_t endtime;
} state_t;
private:
static state_t state;
protected:
static CircularQueue<tone_t, TONE_QUEUE_LENGTH> 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 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 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();
}
/**
* @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();
};
#include "circularqueue.h"
#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 Buzzer class
*/
class Buzzer {
public:
typedef struct {
tone_t tone;
uint32_t endtime;
} state_t;
private:
static state_t state;
protected:
static CircularQueue<tone_t, TONE_QUEUE_LENGTH> 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 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 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();
}
/**
* @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();
};
// Provide a buzzer instance
extern Buzzer buzzer;

85
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)

2
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)

4
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

8
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

20
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;

2
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)

8
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
}
}

Loading…
Cancel
Save