1
0
mirror of https://github.com/MarlinFirmware/Marlin.git synced 2024-11-27 13:56:24 +00:00
MarlinFirmware/Marlin/ultralcd.cpp

4237 lines
141 KiB
C++
Raw Normal View History

/**
2016-03-24 18:01:20 +00:00
* Marlin 3D Printer Firmware
* Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "ultralcd.h"
#if ENABLED(ULTRA_LCD)
#include "Marlin.h"
#include "language.h"
#include "cardreader.h"
#include "temperature.h"
#include "stepper.h"
2015-04-26 04:04:54 +00:00
#include "configuration_store.h"
#include "utility.h"
2016-10-10 20:34:35 +00:00
#if HAS_BUZZER && DISABLED(LCD_USE_I2C_BUZZER)
#include "buzzer.h"
#endif
#if ENABLED(PRINTCOUNTER)
#include "printcounter.h"
2016-07-24 02:13:35 +00:00
#include "duration_t.h"
#endif
#if ENABLED(BLTOUCH)
#include "endstops.h"
#endif
int lcd_preheat_hotend_temp[2], lcd_preheat_bed_temp[2], lcd_preheat_fan_speed[2];
#if ENABLED(FILAMENT_LCD_DISPLAY) && ENABLED(SDSUPPORT)
2015-04-13 01:07:08 +00:00
millis_t previous_lcd_status_ms = 0;
#endif
#if ENABLED(BABYSTEPPING)
long babysteps_done = 0;
#if ENABLED(BABYSTEP_ZPROBE_OFFSET)
static void lcd_babystep_zoffset();
#else
static void lcd_babystep_z();
#endif
#endif
uint8_t lcd_status_message_level;
2016-03-13 06:38:55 +00:00
char lcd_status_message[3 * (LCD_WIDTH) + 1] = WELCOME_MSG; // worst case is kana with up to 3*LCD_WIDTH+1
#if ENABLED(DOGLCD)
#include "ultralcd_impl_DOGM.h"
#include <U8glib.h>
#else
#include "ultralcd_impl_HD44780.h"
#endif
// The main status screen
void lcd_status_screen();
2016-06-11 21:12:00 +00:00
millis_t next_lcd_update_ms;
uint8_t lcdDrawUpdate = LCDVIEW_CLEAR_CALL_REDRAW; // Set when the LCD needs to draw, decrements after every draw. Set to 2 in LCD routines so the LCD gets at least 1 full redraw (first redraw is partial)
uint16_t max_display_update_time = 0;
Distribute GLCD screen updates in time Currently we draw and send the screens for a graphical LCD all at once. We draw in two or four parts but draw them directly behind each other. For the tested status screen this takes 59-62ms in a single block. During this time nothing else (except the interrupts) can be done. When printing a sequence of very short moves the buffer drains - sometimes until it's empty. This PR splits the screen update into parts. Currently we have 10 time slots. During the first one the complete screen is drawn. (60,0,0,0,0,0,0,0,0,0,0) Here i introduce pauses for doing other things. (30,30,0,0,0,0,0,0) or (15,15,15,15,0,0,0,0,0,0) Drawing in consecutive time slots prevents from lagging too much. Even with a 4 stripe display all the drawing is done after 400ms. Previous experiments with a even better distribution of the time slots like (30,0,0,0,0,30,0,0,0,0) and (15,0,15,0,15,0,15,0,0,0) did not feel good when using the menu, because of too much lag. Because of the previous PRs to speed up the display updates and especially reducing the difference between drawing 2 or 4 stripes, it now makes sense for the REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER to go from 2 to 4 stripes. This costs about 1-2ms per complete screen update, but is payed back by having partial updates lasting only the half time and two additional brakes. Also ~256 byte of framebuffer are saved in RAM. 13:45:59.213 : echo: #:17 >:13 s:30; #:16 >:13 s:29; S#:33 S>:26 S:59 13:46:00.213 : echo: #:16 >:14 s:30; #:17 >:13 s:30; S#:33 S>:27 S:60 13:46:01.215 : echo: #:17 >:13 s:30; #:16 >:13 s:29; S#:33 S>:26 S:59 13:46:02.215 : echo: #:16 >:13 s:29; #:16 >:14 s:30; S#:32 S>:27 S:59 13:46:03.214 : echo: #:17 >:13 s:30; #:17 >:13 s:30; S#:34 S>:26 S:60 13:46:04.214 : echo: #:16 >:13 s:29; #:16 >:14 s:30; S#:32 S>:27 S:59 13:46:05.212 : echo: #:16 >:14 s:30; #:17 >:13 s:30; S#:33 S>:27 S:60 13:46:06.212 : echo: #:17 >:13 s:30; #:16 >:13 s:29; S#:33 S>:26 S:59 03:30:36.779 : echo: #:8 >:7 s:15; #:10 >:7 s:17; #:8 >:6 s:14; #:8 >:7 s:15; S#:34 S>:27 S:61 03:30:37.778 : echo: #:8 >:6 s:14; #:10 >:7 s:17; #:9 >:7 s:16; #:8 >:6 s:14; S#:35 S>:26 S:61 03:30:38.778 : echo: #:8 >:6 s:14; #:11 >:7 s:18; #:8 >:6 s:14; #:8 >:7 s:15; S#:35 S>:26 S:61 03:30:39.777 : echo: #:8 >:6 s:14; #:10 >:7 s:17; #:8 >:8 s:16; #:8 >:6 s:14; S#:34 S>:27 S:61 03:30:40.780 : echo: #:8 >:6 s:14; #:11 >:7 s:18; #:8 >:6 s:14; #:8 >:6 s:14; S#:35 S>:25 S:60 03:30:41.780 : echo: #:9 >:6 s:15; #:10 >:7 s:17; #:8 >:6 s:14; #:9 >:6 s:15; S#:36 S>:25 S:61 03:30:42.779 : echo: #:8 >:6 s:14; #:10 >:8 s:18; #:8 >:6 s:14; #:8 >:6 s:14; S#:34 S>:26 S:60 03:30:43.778 : echo: #:9 >:6 s:15; #:10 >:7 s:17; #:8 >:7 s:15; #:9 >:6 s:15; S#:36 S>:26 S:62 #: draw a stripe >: transfer a stripe s: sum of of draw and transfer for one stripe S#: sum of draws for a complete screen S>: sum of transfers for a complete screen S: time to draw and transfer a complete screen
2016-11-24 20:17:25 +00:00
#if ENABLED(DOGLCD)
bool drawing_screen = false;
2017-02-18 05:57:13 +00:00
#define LCDVIEW_KEEP_REDRAWING LCDVIEW_CALL_REDRAW_NEXT
#else
#define LCDVIEW_KEEP_REDRAWING LCDVIEW_REDRAW_NOW
Distribute GLCD screen updates in time Currently we draw and send the screens for a graphical LCD all at once. We draw in two or four parts but draw them directly behind each other. For the tested status screen this takes 59-62ms in a single block. During this time nothing else (except the interrupts) can be done. When printing a sequence of very short moves the buffer drains - sometimes until it's empty. This PR splits the screen update into parts. Currently we have 10 time slots. During the first one the complete screen is drawn. (60,0,0,0,0,0,0,0,0,0,0) Here i introduce pauses for doing other things. (30,30,0,0,0,0,0,0) or (15,15,15,15,0,0,0,0,0,0) Drawing in consecutive time slots prevents from lagging too much. Even with a 4 stripe display all the drawing is done after 400ms. Previous experiments with a even better distribution of the time slots like (30,0,0,0,0,30,0,0,0,0) and (15,0,15,0,15,0,15,0,0,0) did not feel good when using the menu, because of too much lag. Because of the previous PRs to speed up the display updates and especially reducing the difference between drawing 2 or 4 stripes, it now makes sense for the REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER to go from 2 to 4 stripes. This costs about 1-2ms per complete screen update, but is payed back by having partial updates lasting only the half time and two additional brakes. Also ~256 byte of framebuffer are saved in RAM. 13:45:59.213 : echo: #:17 >:13 s:30; #:16 >:13 s:29; S#:33 S>:26 S:59 13:46:00.213 : echo: #:16 >:14 s:30; #:17 >:13 s:30; S#:33 S>:27 S:60 13:46:01.215 : echo: #:17 >:13 s:30; #:16 >:13 s:29; S#:33 S>:26 S:59 13:46:02.215 : echo: #:16 >:13 s:29; #:16 >:14 s:30; S#:32 S>:27 S:59 13:46:03.214 : echo: #:17 >:13 s:30; #:17 >:13 s:30; S#:34 S>:26 S:60 13:46:04.214 : echo: #:16 >:13 s:29; #:16 >:14 s:30; S#:32 S>:27 S:59 13:46:05.212 : echo: #:16 >:14 s:30; #:17 >:13 s:30; S#:33 S>:27 S:60 13:46:06.212 : echo: #:17 >:13 s:30; #:16 >:13 s:29; S#:33 S>:26 S:59 03:30:36.779 : echo: #:8 >:7 s:15; #:10 >:7 s:17; #:8 >:6 s:14; #:8 >:7 s:15; S#:34 S>:27 S:61 03:30:37.778 : echo: #:8 >:6 s:14; #:10 >:7 s:17; #:9 >:7 s:16; #:8 >:6 s:14; S#:35 S>:26 S:61 03:30:38.778 : echo: #:8 >:6 s:14; #:11 >:7 s:18; #:8 >:6 s:14; #:8 >:7 s:15; S#:35 S>:26 S:61 03:30:39.777 : echo: #:8 >:6 s:14; #:10 >:7 s:17; #:8 >:8 s:16; #:8 >:6 s:14; S#:34 S>:27 S:61 03:30:40.780 : echo: #:8 >:6 s:14; #:11 >:7 s:18; #:8 >:6 s:14; #:8 >:6 s:14; S#:35 S>:25 S:60 03:30:41.780 : echo: #:9 >:6 s:15; #:10 >:7 s:17; #:8 >:6 s:14; #:9 >:6 s:15; S#:36 S>:25 S:61 03:30:42.779 : echo: #:8 >:6 s:14; #:10 >:8 s:18; #:8 >:6 s:14; #:8 >:6 s:14; S#:34 S>:26 S:60 03:30:43.778 : echo: #:9 >:6 s:15; #:10 >:7 s:17; #:8 >:7 s:15; #:9 >:6 s:15; S#:36 S>:26 S:62 #: draw a stripe >: transfer a stripe s: sum of of draw and transfer for one stripe S#: sum of draws for a complete screen S>: sum of transfers for a complete screen S: time to draw and transfer a complete screen
2016-11-24 20:17:25 +00:00
#endif
2016-06-11 21:12:00 +00:00
2016-10-03 22:15:29 +00:00
#if ENABLED(DAC_STEPPER_CURRENT)
#include "stepper_dac.h" //was dac_mcp4728.h MarlinMain uses stepper dac for the m-codes
int16_t driverPercent[XYZE];
2016-10-03 22:15:29 +00:00
#endif
#if ENABLED(ULTIPANEL)
2017-04-17 02:32:52 +00:00
#ifndef TALL_FONT_CORRECTION
#define TALL_FONT_CORRECTION 0
2016-06-11 21:12:00 +00:00
#endif
2017-04-17 02:32:52 +00:00
// Function pointer to menu functions.
typedef void (*screenFunc_t)();
2016-06-11 21:12:00 +00:00
2017-04-17 02:32:52 +00:00
#if HAS_POWER_SWITCH
extern bool powersupply_on;
#endif
2016-06-11 21:12:00 +00:00
2017-03-18 15:15:54 +00:00
#if ENABLED(AUTO_BED_LEVELING_UBL)
#include "ubl.h"
2017-03-18 15:15:54 +00:00
#endif
2017-04-17 02:32:52 +00:00
////////////////////////////////////////////
///////////////// Menu Tree ////////////////
////////////////////////////////////////////
2016-11-28 05:51:51 +00:00
void lcd_main_menu();
void lcd_tune_menu();
void lcd_prepare_menu();
void lcd_move_menu();
void lcd_control_menu();
void lcd_control_temperature_menu();
2016-11-28 06:39:06 +00:00
void lcd_control_temperature_preheat_material1_settings_menu();
void lcd_control_temperature_preheat_material2_settings_menu();
void lcd_control_motion_menu();
void lcd_control_filament_menu();
#if ENABLED(LCD_INFO_MENU)
#if ENABLED(PRINTCOUNTER)
void lcd_info_stats_menu();
#endif
void lcd_info_thermistors_menu();
void lcd_info_board_menu();
void lcd_info_menu();
#endif // LCD_INFO_MENU
#if ENABLED(FILAMENT_CHANGE_FEATURE)
2016-12-20 07:47:46 +00:00
void lcd_filament_change_toocold_menu();
void lcd_filament_change_option_menu();
void lcd_filament_change_init_message();
void lcd_filament_change_unload_message();
void lcd_filament_change_insert_message();
void lcd_filament_change_load_message();
void lcd_filament_change_heat_nozzle();
void lcd_filament_change_extrude_message();
void lcd_filament_change_resume_message();
#endif
2017-04-17 02:32:52 +00:00
#if ENABLED(DAC_STEPPER_CURRENT)
void dac_driver_commit();
void dac_driver_getValues();
void lcd_dac_menu();
void lcd_dac_write_eeprom();
#endif
2016-05-31 18:47:02 +00:00
#if HAS_LCD_CONTRAST
void lcd_set_contrast();
#endif
#if ENABLED(FWRETRACT)
void lcd_control_retract_menu();
#endif
#if ENABLED(DELTA_CALIBRATION_MENU)
void lcd_delta_calibrate_menu();
#endif
2017-03-15 08:32:00 +00:00
#if ENABLED(MESH_BED_LEVELING) && ENABLED(LCD_BED_LEVELING)
#include "mesh_bed_leveling.h"
extern void mesh_probing_done();
#endif
2017-04-17 02:32:52 +00:00
////////////////////////////////////////////
//////////// Menu System Actions ///////////
////////////////////////////////////////////
2016-06-11 21:12:00 +00:00
#define menu_action_back(dummy) _menu_action_back()
void _menu_action_back();
void menu_action_submenu(screenFunc_t data);
void menu_action_gcode(const char* pgcode);
void menu_action_function(screenFunc_t data);
#define DECLARE_MENU_EDIT_TYPE(_type, _name) \
bool _menu_edit_ ## _name(); \
void menu_edit_ ## _name(); \
void menu_edit_callback_ ## _name(); \
void _menu_action_setting_edit_ ## _name(const char * const pstr, _type* const ptr, const _type minValue, const _type maxValue); \
void menu_action_setting_edit_ ## _name(const char * const pstr, _type * const ptr, const _type minValue, const _type maxValue); \
void menu_action_setting_edit_callback_ ## _name(const char * const pstr, _type * const ptr, const _type minValue, const _type maxValue, const screenFunc_t callback); \
typedef void _name##_void
DECLARE_MENU_EDIT_TYPE(int, int3);
DECLARE_MENU_EDIT_TYPE(float, float3);
DECLARE_MENU_EDIT_TYPE(float, float32);
DECLARE_MENU_EDIT_TYPE(float, float43);
DECLARE_MENU_EDIT_TYPE(float, float5);
DECLARE_MENU_EDIT_TYPE(float, float51);
DECLARE_MENU_EDIT_TYPE(float, float52);
DECLARE_MENU_EDIT_TYPE(float, float62);
DECLARE_MENU_EDIT_TYPE(unsigned long, long5);
2017-04-20 22:43:19 +00:00
void menu_action_setting_edit_bool(const char* pstr, bool* ptr);
void menu_action_setting_edit_callback_bool(const char* pstr, bool* ptr, screenFunc_t callbackFunc);
#if ENABLED(SDSUPPORT)
void lcd_sdcard_menu();
void menu_action_sdfile(const char* filename, char* longFilename);
void menu_action_sddirectory(const char* filename, char* longFilename);
#endif
2017-04-17 02:32:52 +00:00
////////////////////////////////////////////
//////////// Menu System Macros ////////////
////////////////////////////////////////////
#ifndef ENCODER_FEEDRATE_DEADZONE
#define ENCODER_FEEDRATE_DEADZONE 10
#endif
#ifndef ENCODER_STEPS_PER_MENU_ITEM
#define ENCODER_STEPS_PER_MENU_ITEM 5
#endif
#ifndef ENCODER_PULSES_PER_STEP
#define ENCODER_PULSES_PER_STEP 1
#endif
/**
* MENU_ITEM generates draw & handler code for a menu item, potentially calling:
*
* lcd_implementation_drawmenu_[type](sel, row, label, arg3...)
* menu_action_[type](arg3...)
*
* Examples:
* MENU_ITEM(back, MSG_WATCH, 0 [dummy parameter] )
* or
* MENU_BACK(MSG_WATCH)
* lcd_implementation_drawmenu_back(sel, row, PSTR(MSG_WATCH))
* menu_action_back()
*
* MENU_ITEM(function, MSG_PAUSE_PRINT, lcd_sdcard_pause)
* lcd_implementation_drawmenu_function(sel, row, PSTR(MSG_PAUSE_PRINT), lcd_sdcard_pause)
* menu_action_function(lcd_sdcard_pause)
*
2016-07-16 01:49:34 +00:00
* MENU_ITEM_EDIT(int3, MSG_SPEED, &feedrate_percentage, 10, 999)
* MENU_ITEM(setting_edit_int3, MSG_SPEED, PSTR(MSG_SPEED), &feedrate_percentage, 10, 999)
* lcd_implementation_drawmenu_setting_edit_int3(sel, row, PSTR(MSG_SPEED), PSTR(MSG_SPEED), &feedrate_percentage, 10, 999)
* menu_action_setting_edit_int3(PSTR(MSG_SPEED), &feedrate_percentage, 10, 999)
*
*/
#define _MENU_ITEM_PART_1(TYPE, LABEL, ...) \
if (_menuLineNr == _thisItemNr) { \
if (lcdDrawUpdate) \
lcd_implementation_drawmenu_ ## TYPE(encoderLine == _thisItemNr, _lcdLineNr, PSTR(LABEL), ## __VA_ARGS__); \
if (lcd_clicked && encoderLine == _thisItemNr) {
2016-04-12 06:28:20 +00:00
#define _MENU_ITEM_PART_2(TYPE, ...) \
menu_action_ ## TYPE(__VA_ARGS__); \
if (screen_changed) return; \
2015-02-20 10:17:16 +00:00
} \
} \
2016-08-03 00:39:20 +00:00
++_thisItemNr
2016-04-12 06:28:20 +00:00
#define MENU_ITEM(TYPE, LABEL, ...) do { \
2016-07-15 02:01:57 +00:00
_skipStatic = false; \
_MENU_ITEM_PART_1(TYPE, LABEL, ## __VA_ARGS__); \
_MENU_ITEM_PART_2(TYPE, ## __VA_ARGS__); \
2016-04-12 06:28:20 +00:00
} while(0)
#define MENU_BACK(LABEL) MENU_ITEM(back, LABEL, 0)
// Used to print static text with no visible cursor.
// Parameters: label [, bool center [, bool invert [, char *value] ] ]
#define STATIC_ITEM(LABEL, ...) \
if (_menuLineNr == _thisItemNr) { \
2016-07-15 02:01:57 +00:00
if (_skipStatic && encoderLine <= _thisItemNr) { \
encoderPosition += ENCODER_STEPS_PER_MENU_ITEM; \
++encoderLine; \
} \
if (lcdDrawUpdate) \
lcd_implementation_drawmenu_static(_lcdLineNr, PSTR(LABEL), ## __VA_ARGS__); \
} \
2016-08-03 00:39:20 +00:00
++_thisItemNr
#if ENABLED(ENCODER_RATE_MULTIPLIER)
2017-04-17 02:32:52 +00:00
bool encoderRateMultiplierEnabled;
#define ENCODER_RATE_MULTIPLY(F) (encoderRateMultiplierEnabled = F)
//#define ENCODER_RATE_MULTIPLIER_DEBUG // If defined, output the encoder steps per second value
/**
* MENU_MULTIPLIER_ITEM generates drawing and handling code for a multiplier menu item
*/
#define MENU_MULTIPLIER_ITEM(type, label, ...) do { \
_MENU_ITEM_PART_1(type, label, ## __VA_ARGS__); \
2016-04-12 06:28:20 +00:00
encoderRateMultiplierEnabled = true; \
lastEncoderMovementMillis = 0; \
_MENU_ITEM_PART_2(type, ## __VA_ARGS__); \
2016-04-12 06:28:20 +00:00
} while(0)
2017-05-09 17:35:43 +00:00
#else // !ENCODER_RATE_MULTIPLIER
2017-04-17 02:32:52 +00:00
#define ENCODER_RATE_MULTIPLY(F) NOOP
#endif // !ENCODER_RATE_MULTIPLIER
#define MENU_ITEM_DUMMY() do { _thisItemNr++; } while(0)
#define MENU_ITEM_EDIT(type, label, ...) MENU_ITEM(setting_edit_ ## type, label, PSTR(label), ## __VA_ARGS__)
#define MENU_ITEM_EDIT_CALLBACK(type, label, ...) MENU_ITEM(setting_edit_callback_ ## type, label, PSTR(label), ## __VA_ARGS__)
#if ENABLED(ENCODER_RATE_MULTIPLIER)
#define MENU_MULTIPLIER_ITEM_EDIT(type, label, ...) MENU_MULTIPLIER_ITEM(setting_edit_ ## type, label, PSTR(label), ## __VA_ARGS__)
#define MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(type, label, ...) MENU_MULTIPLIER_ITEM(setting_edit_callback_ ## type, label, PSTR(label), ## __VA_ARGS__)
2017-05-09 17:35:43 +00:00
#else // !ENCODER_RATE_MULTIPLIER
#define MENU_MULTIPLIER_ITEM_EDIT(type, label, ...) MENU_ITEM(setting_edit_ ## type, label, PSTR(label), ## __VA_ARGS__)
#define MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(type, label, ...) MENU_ITEM(setting_edit_callback_ ## type, label, PSTR(label), ## __VA_ARGS__)
2017-05-09 17:35:43 +00:00
#endif // !ENCODER_RATE_MULTIPLIER
2017-04-17 02:32:52 +00:00
/**
* START_SCREEN_OR_MENU generates init code for a screen or menu
*
* encoderLine is the position based on the encoder
* encoderTopLine is the top menu line to display
* _lcdLineNr is the index of the LCD line (e.g., 0-3)
* _menuLineNr is the menu item to draw and process
* _thisItemNr is the index of each MENU_ITEM or STATIC_ITEM
* _countedItems is the total number of items in the menu (after one call)
*/
#define START_SCREEN_OR_MENU(LIMIT) \
ENCODER_DIRECTION_MENUS(); \
ENCODER_RATE_MULTIPLY(false); \
if (encoderPosition > 0x8000) encoderPosition = 0; \
static int8_t _countedItems = 0; \
int8_t encoderLine = encoderPosition / (ENCODER_STEPS_PER_MENU_ITEM); \
if (_countedItems > 0 && encoderLine >= _countedItems - (LIMIT)) { \
encoderLine = max(0, _countedItems - (LIMIT)); \
encoderPosition = encoderLine * (ENCODER_STEPS_PER_MENU_ITEM); \
}
2017-04-17 02:32:52 +00:00
#define SCREEN_OR_MENU_LOOP() \
int8_t _menuLineNr = encoderTopLine, _thisItemNr; \
for (int8_t _lcdLineNr = 0; _lcdLineNr < LCD_HEIGHT - (TALL_FONT_CORRECTION); _lcdLineNr++, _menuLineNr++) { \
_thisItemNr = 0
/**
* START_SCREEN Opening code for a screen having only static items.
* Do simplified scrolling of the entire screen.
*
* START_MENU Opening code for a screen with menu items.
* Scroll as-needed to keep the selected line in view.
*/
#define START_SCREEN() \
START_SCREEN_OR_MENU(LCD_HEIGHT - (TALL_FONT_CORRECTION)); \
encoderTopLine = encoderLine; \
bool _skipStatic = false; \
SCREEN_OR_MENU_LOOP()
#define START_MENU() \
START_SCREEN_OR_MENU(1); \
screen_changed = false; \
NOMORE(encoderTopLine, encoderLine); \
if (encoderLine >= encoderTopLine + LCD_HEIGHT - (TALL_FONT_CORRECTION)) { \
encoderTopLine = encoderLine - (LCD_HEIGHT - (TALL_FONT_CORRECTION) - 1); \
} \
bool _skipStatic = true; \
SCREEN_OR_MENU_LOOP()
#define END_SCREEN() \
} \
_countedItems = _thisItemNr
#define END_MENU() \
} \
_countedItems = _thisItemNr; \
UNUSED(_skipStatic)
////////////////////////////////////////////
///////////// Global Variables /////////////
////////////////////////////////////////////
/**
* 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)
int8_t encoderDirection = 1;
#define ENCODER_DIRECTION_NORMAL() (encoderDirection = 1)
#define ENCODER_DIRECTION_MENUS() (encoderDirection = -1)
#else
#define ENCODER_DIRECTION_NORMAL() ;
#define ENCODER_DIRECTION_MENUS() ;
#endif
2017-04-17 02:32:52 +00:00
// Encoder Movement
volatile int8_t encoderDiff; // Updated in lcd_buttons_update, added to encoderPosition every LCD update
uint32_t encoderPosition;
2017-04-17 02:32:52 +00:00
millis_t lastEncoderMovementMillis = 0;
// Button States
bool lcd_clicked, wait_for_unclick;
volatile uint8_t buttons;
millis_t next_button_update_ms;
#if ENABLED(REPRAPWORLD_KEYPAD)
volatile uint8_t buttons_reprapworld_keypad;
#endif
#if ENABLED(LCD_HAS_SLOW_BUTTONS)
volatile uint8_t slow_buttons;
#endif
2017-04-17 02:32:52 +00:00
// Menu System Navigation
screenFunc_t currentScreen = lcd_status_screen;
int8_t encoderTopLine;
2016-06-11 21:12:00 +00:00
typedef struct {
2016-06-11 21:19:17 +00:00
screenFunc_t menu_function;
uint32_t encoder_position;
2016-06-11 21:12:00 +00:00
} menuPosition;
2017-04-17 02:32:52 +00:00
menuPosition screen_history[6];
uint8_t screen_history_depth = 0;
bool screen_changed, defer_return_to_status;
2017-04-17 02:32:52 +00:00
// Value Editing
const char *editLabel;
void *editValue;
2017-04-17 02:32:52 +00:00
int32_t minEditValue, maxEditValue;
screenFunc_t callbackFunc;
2017-04-17 02:32:52 +00:00
// Manual Moves
const float manual_feedrate_mm_m[] = MANUAL_FEEDRATE;
millis_t manual_move_start_time = 0;
int8_t manual_move_axis = (int8_t)NO_AXIS;
#if EXTRUDERS > 1
int8_t manual_move_e_index = 0;
#else
#define manual_move_e_index 0
#endif
2016-04-02 23:09:56 +00:00
2017-04-17 02:32:52 +00:00
#if PIN_EXISTS(SD_DETECT)
uint8_t lcd_sd_status;
#endif
2016-04-02 23:09:56 +00:00
2017-04-17 02:32:52 +00:00
#if ENABLED(PIDTEMP)
float raw_Ki, raw_Kd; // place-holders for Ki and Kd edits
#endif
2016-06-11 21:12:00 +00:00
/**
* General function to go directly to a screen
2016-06-11 21:12:00 +00:00
*/
void lcd_goto_screen(screenFunc_t screen, const uint32_t encoder = 0) {
2016-06-11 21:19:17 +00:00
if (currentScreen != screen) {
2017-03-03 01:15:21 +00:00
#if ENABLED(DOUBLECLICK_FOR_Z_BABYSTEPPING) && ENABLED(BABYSTEPPING)
static millis_t doubleclick_expire_ms = 0;
// Going to lcd_main_menu from status screen? Remember first click time.
// Going back to status screen within a very short time? Go to Z babystepping.
if (screen == lcd_main_menu) {
if (currentScreen == lcd_status_screen)
doubleclick_expire_ms = millis() + DOUBLECLICK_MAX_INTERVAL;
}
else if (screen == lcd_status_screen && currentScreen == lcd_main_menu && PENDING(millis(), doubleclick_expire_ms))
screen =
#if ENABLED(BABYSTEP_ZPROBE_OFFSET)
lcd_babystep_zoffset
#else
lcd_babystep_z
#endif
;
2017-03-17 02:25:36 +00:00
#endif
2017-03-03 01:15:21 +00:00
2016-06-11 21:19:17 +00:00
currentScreen = screen;
encoderPosition = encoder;
2016-06-11 21:19:17 +00:00
if (screen == lcd_status_screen) {
2016-06-11 21:12:00 +00:00
defer_return_to_status = false;
2016-06-11 21:19:17 +00:00
screen_history_depth = 0;
2016-06-11 21:12:00 +00:00
}
lcd_implementation_clear();
2016-06-11 21:12:00 +00:00
#if ENABLED(LCD_PROGRESS_BAR)
// For LCD_PROGRESS_BAR re-initialize custom characters
2016-06-11 21:19:17 +00:00
lcd_set_custom_characters(screen == lcd_status_screen);
2016-06-11 21:12:00 +00:00
#endif
lcdDrawUpdate = LCDVIEW_CALL_REDRAW_NEXT;
screen_changed = true;
Distribute GLCD screen updates in time Currently we draw and send the screens for a graphical LCD all at once. We draw in two or four parts but draw them directly behind each other. For the tested status screen this takes 59-62ms in a single block. During this time nothing else (except the interrupts) can be done. When printing a sequence of very short moves the buffer drains - sometimes until it's empty. This PR splits the screen update into parts. Currently we have 10 time slots. During the first one the complete screen is drawn. (60,0,0,0,0,0,0,0,0,0,0) Here i introduce pauses for doing other things. (30,30,0,0,0,0,0,0) or (15,15,15,15,0,0,0,0,0,0) Drawing in consecutive time slots prevents from lagging too much. Even with a 4 stripe display all the drawing is done after 400ms. Previous experiments with a even better distribution of the time slots like (30,0,0,0,0,30,0,0,0,0) and (15,0,15,0,15,0,15,0,0,0) did not feel good when using the menu, because of too much lag. Because of the previous PRs to speed up the display updates and especially reducing the difference between drawing 2 or 4 stripes, it now makes sense for the REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER to go from 2 to 4 stripes. This costs about 1-2ms per complete screen update, but is payed back by having partial updates lasting only the half time and two additional brakes. Also ~256 byte of framebuffer are saved in RAM. 13:45:59.213 : echo: #:17 >:13 s:30; #:16 >:13 s:29; S#:33 S>:26 S:59 13:46:00.213 : echo: #:16 >:14 s:30; #:17 >:13 s:30; S#:33 S>:27 S:60 13:46:01.215 : echo: #:17 >:13 s:30; #:16 >:13 s:29; S#:33 S>:26 S:59 13:46:02.215 : echo: #:16 >:13 s:29; #:16 >:14 s:30; S#:32 S>:27 S:59 13:46:03.214 : echo: #:17 >:13 s:30; #:17 >:13 s:30; S#:34 S>:26 S:60 13:46:04.214 : echo: #:16 >:13 s:29; #:16 >:14 s:30; S#:32 S>:27 S:59 13:46:05.212 : echo: #:16 >:14 s:30; #:17 >:13 s:30; S#:33 S>:27 S:60 13:46:06.212 : echo: #:17 >:13 s:30; #:16 >:13 s:29; S#:33 S>:26 S:59 03:30:36.779 : echo: #:8 >:7 s:15; #:10 >:7 s:17; #:8 >:6 s:14; #:8 >:7 s:15; S#:34 S>:27 S:61 03:30:37.778 : echo: #:8 >:6 s:14; #:10 >:7 s:17; #:9 >:7 s:16; #:8 >:6 s:14; S#:35 S>:26 S:61 03:30:38.778 : echo: #:8 >:6 s:14; #:11 >:7 s:18; #:8 >:6 s:14; #:8 >:7 s:15; S#:35 S>:26 S:61 03:30:39.777 : echo: #:8 >:6 s:14; #:10 >:7 s:17; #:8 >:8 s:16; #:8 >:6 s:14; S#:34 S>:27 S:61 03:30:40.780 : echo: #:8 >:6 s:14; #:11 >:7 s:18; #:8 >:6 s:14; #:8 >:6 s:14; S#:35 S>:25 S:60 03:30:41.780 : echo: #:9 >:6 s:15; #:10 >:7 s:17; #:8 >:6 s:14; #:9 >:6 s:15; S#:36 S>:25 S:61 03:30:42.779 : echo: #:8 >:6 s:14; #:10 >:8 s:18; #:8 >:6 s:14; #:8 >:6 s:14; S#:34 S>:26 S:60 03:30:43.778 : echo: #:9 >:6 s:15; #:10 >:7 s:17; #:8 >:7 s:15; #:9 >:6 s:15; S#:36 S>:26 S:62 #: draw a stripe >: transfer a stripe s: sum of of draw and transfer for one stripe S#: sum of draws for a complete screen S>: sum of transfers for a complete screen S: time to draw and transfer a complete screen
2016-11-24 20:17:25 +00:00
#if ENABLED(DOGLCD)
drawing_screen = false;
#endif
2016-06-11 21:12:00 +00:00
}
}
/**
* Synchronize safely while holding the current screen
* This blocks all further screen or stripe updates once called
*/
extern uint8_t commands_in_queue;
inline void lcd_synchronize() {
2017-04-11 00:17:14 +00:00
static bool no_reentry = false;
lcd_implementation_drawmenu_static(LCD_HEIGHT >= 4 ? 1 : 0, PSTR(MSG_MOVING));
2017-04-11 00:17:14 +00:00
if (no_reentry) return;
no_reentry = true;
screenFunc_t old_screen = currentScreen;
lcd_goto_screen(lcd_synchronize);
while (commands_in_queue) {
idle();
stepper.synchronize();
}
2017-04-11 00:17:14 +00:00
no_reentry = false;
lcd_goto_screen(old_screen);
}
void lcd_return_to_status() { lcd_goto_screen(lcd_status_screen); }
void lcd_save_previous_screen() {
2016-06-11 21:19:17 +00:00
if (screen_history_depth < COUNT(screen_history)) {
screen_history[screen_history_depth].menu_function = currentScreen;
screen_history[screen_history_depth].encoder_position = encoderPosition;
2016-06-11 21:19:17 +00:00
++screen_history_depth;
}
2014-12-18 15:30:05 +00:00
}
void lcd_goto_previous_menu() {
2016-06-11 21:19:17 +00:00
if (screen_history_depth > 0) {
--screen_history_depth;
lcd_goto_screen(
screen_history[screen_history_depth].menu_function,
screen_history[screen_history_depth].encoder_position
2016-06-11 21:12:00 +00:00
);
}
else
lcd_return_to_status();
}
2016-06-11 21:12:00 +00:00
#endif // ULTIPANEL
/**
*
* "Info Screen"
*
* This is very display-dependent, so the lcd implementation draws this.
*/
void lcd_status_screen() {
2016-06-11 21:12:00 +00:00
#if ENABLED(ULTIPANEL)
ENCODER_DIRECTION_NORMAL();
2017-04-17 02:32:52 +00:00
ENCODER_RATE_MULTIPLY(false);
2016-06-11 21:12:00 +00:00
#endif
#if ENABLED(LCD_PROGRESS_BAR)
2015-04-13 01:07:08 +00:00
millis_t ms = millis();
#if DISABLED(PROGRESS_MSG_ONCE)
2016-04-10 22:55:12 +00:00
if (ELAPSED(ms, progress_bar_ms + PROGRESS_BAR_MSG_TIME + PROGRESS_BAR_BAR_TIME)) {
progress_bar_ms = ms;
2014-12-28 06:26:14 +00:00
}
#endif
#if PROGRESS_MSG_EXPIRE > 0
// Handle message expire
if (expire_status_ms > 0) {
#if ENABLED(SDSUPPORT)
if (card.isFileOpen()) {
// Expire the message when printing is active
if (IS_SD_PRINTING) {
2016-04-10 22:55:12 +00:00
if (ELAPSED(ms, expire_status_ms)) {
lcd_status_message[0] = '\0';
expire_status_ms = 0;
}
}
else {
expire_status_ms += LCD_UPDATE_INTERVAL;
2014-12-28 06:26:14 +00:00
}
}
else {
expire_status_ms = 0;
2014-12-28 06:26:14 +00:00
}
#else
expire_status_ms = 0;
2017-05-09 17:35:43 +00:00
#endif // SDSUPPORT
2014-12-28 06:26:14 +00:00
}
#endif
2017-05-09 17:35:43 +00:00
#endif // LCD_PROGRESS_BAR
2014-12-28 06:26:14 +00:00
lcd_implementation_status_screen();
#if ENABLED(ULTIPANEL)
if (lcd_clicked) {
#if ENABLED(FILAMENT_LCD_DISPLAY) && ENABLED(SDSUPPORT)
2016-08-06 23:24:26 +00:00
previous_lcd_status_ms = millis(); // get status message to show up for a while
#endif
lcd_implementation_init( // to maybe revive the LCD if static electricity killed it.
#if ENABLED(LCD_PROGRESS_BAR)
false
2014-12-28 06:26:14 +00:00
#endif
);
lcd_goto_screen(lcd_main_menu);
}
#if ENABLED(ULTIPANEL_FEEDMULTIPLY)
2016-07-16 01:49:34 +00:00
int new_frm = feedrate_percentage + (int32_t)encoderPosition;
// Dead zone at 100% feedrate
2016-07-16 01:49:34 +00:00
if ((feedrate_percentage < 100 && new_frm > 100) || (feedrate_percentage > 100 && new_frm < 100)) {
feedrate_percentage = 100;
2016-04-05 21:06:52 +00:00
encoderPosition = 0;
}
2016-07-16 01:49:34 +00:00
else if (feedrate_percentage == 100) {
if ((int32_t)encoderPosition > ENCODER_FEEDRATE_DEADZONE) {
2016-07-16 01:49:34 +00:00
feedrate_percentage += (int32_t)encoderPosition - (ENCODER_FEEDRATE_DEADZONE);
2015-04-11 11:56:08 +00:00
encoderPosition = 0;
}
else if ((int32_t)encoderPosition < -(ENCODER_FEEDRATE_DEADZONE)) {
2016-07-16 01:49:34 +00:00
feedrate_percentage += (int32_t)encoderPosition + ENCODER_FEEDRATE_DEADZONE;
2015-04-11 11:56:08 +00:00
encoderPosition = 0;
}
}
2015-04-11 11:56:08 +00:00
else {
2016-07-16 01:49:34 +00:00
feedrate_percentage = new_frm;
encoderPosition = 0;
}
#endif // ULTIPANEL_FEEDMULTIPLY
2016-07-16 01:49:34 +00:00
feedrate_percentage = constrain(feedrate_percentage, 10, 999);
2017-05-09 17:35:43 +00:00
#endif // ULTIPANEL
}
2016-07-10 02:50:45 +00:00
/**
*
* draw the kill screen
*
*/
void kill_screen(const char* lcd_msg) {
lcd_init();
lcd_setalertstatuspgm(lcd_msg);
#if ENABLED(DOGLCD)
u8g.firstPage();
do {
lcd_kill_screen();
} while (u8g.nextPage());
#else
lcd_kill_screen();
#endif
}
#if ENABLED(ULTIPANEL)
2014-12-28 06:26:14 +00:00
/**
*
* Audio feedback for controller clicks
*
*/
void lcd_buzz(long duration, 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
}
void lcd_quick_feedback() {
lcdDrawUpdate = LCDVIEW_CLEAR_CALL_REDRAW;
buttons = 0;
next_button_update_ms = millis() + 500;
// Buzz and wait. The delay is needed for buttons to settle!
lcd_buzz(LCD_FEEDBACK_FREQUENCY_DURATION_MS, LCD_FEEDBACK_FREQUENCY_HZ);
#if ENABLED(LCD_USE_I2C_BUZZER)
delay(10);
#elif PIN_EXISTS(BEEPER)
for (int8_t i = 5; i--;) { buzzer.tick(); delay(2); }
#endif
}
void lcd_completion_feedback(const bool good/*=true*/) {
if (good) {
lcd_buzz(100, 659);
lcd_buzz(100, 698);
}
else lcd_buzz(20, 440);
}
2016-06-11 21:12:00 +00:00
inline void line_to_current(AxisEnum axis) {
planner.buffer_line_kinematic(current_position, MMM_TO_MMS(manual_feedrate_mm_m[axis]), active_extruder);
}
2016-06-11 21:12:00 +00:00
#if ENABLED(SDSUPPORT)
void lcd_sdcard_pause() {
2016-06-11 21:12:00 +00:00
card.pauseSDPrint();
print_job_timer.pause();
2017-03-19 09:26:22 +00:00
#if ENABLED(PARK_HEAD_ON_PAUSE)
enqueue_and_echo_commands_P(PSTR("M125"));
2017-03-19 09:26:22 +00:00
#endif
2016-06-11 21:12:00 +00:00
}
void lcd_sdcard_resume() {
2017-03-19 09:26:22 +00:00
#if ENABLED(PARK_HEAD_ON_PAUSE)
enqueue_and_echo_commands_P(PSTR("M24"));
2017-03-19 09:26:22 +00:00
#else
card.startFileprint();
print_job_timer.start();
#endif
2016-06-11 21:12:00 +00:00
}
void lcd_sdcard_stop() {
card.stopSDPrint();
2016-06-11 21:12:00 +00:00
clear_command_queue();
quickstop_stepper();
2016-06-11 21:12:00 +00:00
print_job_timer.stop();
thermalManager.disable_all_heaters();
#if FAN_COUNT > 0
for (uint8_t i = 0; i < FAN_COUNT; i++) fanSpeeds[i] = 0;
2016-10-10 20:34:35 +00:00
#endif
wait_for_heatup = false;
LCD_MESSAGEPGM(MSG_PRINT_ABORTED);
2016-06-11 21:12:00 +00:00
}
2017-03-19 09:26:22 +00:00
#endif // SDSUPPORT
2016-12-02 05:31:03 +00:00
#if ENABLED(MENU_ITEM_CASE_LIGHT)
2016-11-28 05:51:51 +00:00
extern bool case_light_on;
extern void update_case_light();
void toggle_case_light() {
2017-04-09 12:58:47 +00:00
case_light_on ^= true;
2016-11-28 05:51:51 +00:00
lcdDrawUpdate = LCDVIEW_CALL_REDRAW_NEXT;
update_case_light();
}
#endif // MENU_ITEM_CASE_LIGHT
#if ENABLED(BLTOUCH)
/**
*
* "BLTouch" submenu
*
*/
static void bltouch_menu() {
START_MENU();
//
// ^ Main
//
MENU_BACK(MSG_MAIN);
MENU_ITEM(gcode, MSG_BLTOUCH_RESET, PSTR("M280 P" STRINGIFY(Z_ENDSTOP_SERVO_NR) " S" STRINGIFY(BLTOUCH_RESET)));
MENU_ITEM(gcode, MSG_BLTOUCH_SELFTEST, PSTR("M280 P" STRINGIFY(Z_ENDSTOP_SERVO_NR) " S" STRINGIFY(BLTOUCH_SELFTEST)));
MENU_ITEM(gcode, MSG_BLTOUCH_DEPLOY, PSTR("M280 P" STRINGIFY(Z_ENDSTOP_SERVO_NR) " S" STRINGIFY(BLTOUCH_DEPLOY)));
MENU_ITEM(gcode, MSG_BLTOUCH_STOW, PSTR("M280 P" STRINGIFY(Z_ENDSTOP_SERVO_NR) " S" STRINGIFY(BLTOUCH_STOW)));
END_MENU();
}
#endif // BLTOUCH
#if ENABLED(LCD_PROGRESS_BAR_TEST)
static void progress_bar_test() {
static int8_t bar_percent = 0;
if (lcd_clicked) {
lcd_goto_previous_menu();
lcd_set_custom_characters(false);
return;
}
bar_percent += (int8_t)encoderPosition;
bar_percent = constrain(bar_percent, 0, 100);
encoderPosition = 0;
lcd_implementation_drawmenu_static(0, PSTR(MSG_PROGRESS_BAR_TEST), true, true);
lcd.setCursor((LCD_WIDTH) / 2 - 2, LCD_HEIGHT - 2);
lcd.print(itostr3(bar_percent)); lcd.print('%');
lcd.setCursor(0, LCD_HEIGHT - 1); lcd_draw_progress_bar(bar_percent);
}
void _progress_bar_test() {
lcd_goto_screen(progress_bar_test);
lcd_set_custom_characters();
}
#endif // LCD_PROGRESS_BAR_TEST
#if HAS_DEBUG_MENU
void lcd_debug_menu() {
START_MENU();
MENU_BACK(MSG_MAIN); // ^ Main
#if ENABLED(LCD_PROGRESS_BAR_TEST)
MENU_ITEM(submenu, MSG_PROGRESS_BAR_TEST, _progress_bar_test);
#endif
END_MENU();
}
#endif // HAS_DEBUG_MENU
2016-06-11 21:12:00 +00:00
/**
*
* "Main" menu
*
*/
void lcd_main_menu() {
2016-06-11 21:12:00 +00:00
START_MENU();
MENU_BACK(MSG_WATCH);
2016-09-18 23:02:53 +00:00
//
// Debug Menu when certain options are enabled
//
#if HAS_DEBUG_MENU
MENU_ITEM(submenu, MSG_DEBUG_MENU, lcd_debug_menu);
#endif
2016-11-19 10:17:39 +00:00
//
// Switch case light on/off
//
2016-12-02 05:31:03 +00:00
#if ENABLED(MENU_ITEM_CASE_LIGHT)
2016-11-28 05:51:51 +00:00
if (case_light_on)
MENU_ITEM(function, MSG_LIGHTS_OFF, toggle_case_light);
2016-11-19 10:17:39 +00:00
else
2016-11-28 05:51:51 +00:00
MENU_ITEM(function, MSG_LIGHTS_ON, toggle_case_light);
2016-11-19 10:17:39 +00:00
#endif
2016-06-11 21:12:00 +00:00
if (planner.movesplanned() || IS_SD_PRINTING) {
MENU_ITEM(submenu, MSG_TUNE, lcd_tune_menu);
}
else {
MENU_ITEM(submenu, MSG_PREPARE, lcd_prepare_menu);
#if ENABLED(DELTA_CALIBRATION_MENU)
MENU_ITEM(submenu, MSG_DELTA_CALIBRATE, lcd_delta_calibrate_menu);
#endif
}
MENU_ITEM(submenu, MSG_CONTROL, lcd_control_menu);
#if ENABLED(SDSUPPORT)
if (card.cardOK) {
if (card.isFileOpen()) {
if (card.sdprinting)
MENU_ITEM(function, MSG_PAUSE_PRINT, lcd_sdcard_pause);
else
MENU_ITEM(function, MSG_RESUME_PRINT, lcd_sdcard_resume);
MENU_ITEM(function, MSG_STOP_PRINT, lcd_sdcard_stop);
}
else {
MENU_ITEM(submenu, MSG_CARD_MENU, lcd_sdcard_menu);
#if !PIN_EXISTS(SD_DETECT)
MENU_ITEM(gcode, MSG_CNG_SDCARD, PSTR("M21")); // SD-card changed by user
#endif
}
}
else {
2016-06-11 21:12:00 +00:00
MENU_ITEM(submenu, MSG_NO_CARD, lcd_sdcard_menu);
#if !PIN_EXISTS(SD_DETECT)
2016-06-11 21:12:00 +00:00
MENU_ITEM(gcode, MSG_INIT_SDCARD, PSTR("M21")); // Manually initialize the SD-card via user interface
#endif
}
2017-05-09 17:35:43 +00:00
#endif // SDSUPPORT
#if ENABLED(LCD_INFO_MENU)
MENU_ITEM(submenu, MSG_INFO_MENU, lcd_info_menu);
#endif
2016-06-11 21:12:00 +00:00
END_MENU();
2014-12-18 15:30:05 +00:00
}
2016-06-11 21:12:00 +00:00
/**
*
* "Tune" submenu items
*
*/
#if HAS_M206_COMMAND
2017-03-06 08:20:31 +00:00
/**
* Set the home offset based on the current_position
*/
void lcd_set_home_offsets() {
// M428 Command
enqueue_and_echo_commands_P(PSTR("M428"));
lcd_return_to_status();
}
#endif
2016-06-11 21:12:00 +00:00
#if ENABLED(BABYSTEPPING)
void _lcd_babystep(const AxisEnum axis, const char* msg) {
if (lcd_clicked) { defer_return_to_status = false; return lcd_goto_previous_menu(); }
2016-06-11 21:12:00 +00:00
ENCODER_DIRECTION_NORMAL();
if (encoderPosition) {
const int babystep_increment = (int32_t)encoderPosition * (BABYSTEP_MULTIPLICATOR);
2016-06-11 21:12:00 +00:00
encoderPosition = 0;
lcdDrawUpdate = LCDVIEW_REDRAW_NOW;
thermalManager.babystep_axis(axis, babystep_increment);
babysteps_done += babystep_increment;
2016-06-11 21:12:00 +00:00
}
if (lcdDrawUpdate)
lcd_implementation_drawedit(msg, ftostr43sign(planner.steps_to_mm[axis] * babysteps_done));
2016-06-11 21:12:00 +00:00
}
2016-06-11 21:12:00 +00:00
#if ENABLED(BABYSTEP_XY)
void _lcd_babystep_x() { _lcd_babystep(X_AXIS, PSTR(MSG_BABYSTEPPING_X)); }
void _lcd_babystep_y() { _lcd_babystep(Y_AXIS, PSTR(MSG_BABYSTEPPING_Y)); }
void lcd_babystep_x() { lcd_goto_screen(_lcd_babystep_x); babysteps_done = 0; defer_return_to_status = true; }
void lcd_babystep_y() { lcd_goto_screen(_lcd_babystep_y); babysteps_done = 0; defer_return_to_status = true; }
2016-06-11 21:12:00 +00:00
#endif
#if ENABLED(BABYSTEP_ZPROBE_OFFSET)
void lcd_babystep_zoffset() {
if (lcd_clicked) { defer_return_to_status = false; return lcd_goto_previous_menu(); }
defer_return_to_status = true;
ENCODER_DIRECTION_NORMAL();
if (encoderPosition) {
const int babystep_increment = (int32_t)encoderPosition * (BABYSTEP_MULTIPLICATOR);
encoderPosition = 0;
const float new_zoffset = zprobe_zoffset + planner.steps_to_mm[Z_AXIS] * babystep_increment;
if (WITHIN(new_zoffset, Z_PROBE_OFFSET_RANGE_MIN, Z_PROBE_OFFSET_RANGE_MAX)) {
if (planner.abl_enabled)
thermalManager.babystep_axis(Z_AXIS, babystep_increment);
zprobe_zoffset = new_zoffset;
refresh_zprobe_zoffset(true);
lcdDrawUpdate = LCDVIEW_REDRAW_NOW;
}
}
if (lcdDrawUpdate)
lcd_implementation_drawedit(PSTR(MSG_ZPROBE_ZOFFSET), ftostr43sign(zprobe_zoffset));
}
#else // !BABYSTEP_ZPROBE_OFFSET
void _lcd_babystep_z() { _lcd_babystep(Z_AXIS, PSTR(MSG_BABYSTEPPING_Z)); }
void lcd_babystep_z() { lcd_goto_screen(_lcd_babystep_z); babysteps_done = 0; defer_return_to_status = true; }
#endif // !BABYSTEP_ZPROBE_OFFSET
#endif // BABYSTEPPING
2017-03-18 15:15:54 +00:00
#if ENABLED(AUTO_BED_LEVELING_UBL)
2017-03-20 06:42:41 +00:00
float mesh_edit_value, mesh_edit_accumulator; // We round mesh_edit_value to 2.5 decimal places. So we keep a
2017-03-18 15:15:54 +00:00
// seperate value that doesn't lose precision.
2017-03-20 06:42:41 +00:00
static int ubl_encoderPosition = 0;
2017-03-18 15:15:54 +00:00
2017-03-20 06:42:41 +00:00
static void _lcd_mesh_fine_tune(const char* msg) {
2017-03-18 15:15:54 +00:00
defer_return_to_status = true;
if (ubl.encoder_diff) {
ubl_encoderPosition = (ubl.encoder_diff > 0) ? 1 : -1;
ubl.encoder_diff = 0;
2017-03-29 00:45:54 +00:00
mesh_edit_accumulator += float(ubl_encoderPosition) * 0.005 / 2.0;
2017-03-20 06:42:41 +00:00
mesh_edit_value = mesh_edit_accumulator;
encoderPosition = 0;
lcdDrawUpdate = LCDVIEW_REDRAW_NOW;
2017-03-18 15:15:54 +00:00
2017-03-29 00:45:54 +00:00
const int32_t rounded = (int32_t)(mesh_edit_value * 1000.0);
mesh_edit_value = float(rounded - (rounded % 5L)) / 1000.0;
2017-03-18 15:15:54 +00:00
}
2017-03-20 06:42:41 +00:00
if (lcdDrawUpdate)
lcd_implementation_drawedit(msg, ftostr43sign(mesh_edit_value));
2017-03-18 15:15:54 +00:00
}
void _lcd_mesh_edit_NOP() {
defer_return_to_status = true;
}
2017-03-18 15:15:54 +00:00
void _lcd_mesh_edit() {
_lcd_mesh_fine_tune(PSTR("Mesh Editor"));
2017-03-18 15:15:54 +00:00
}
float lcd_mesh_edit() {
lcd_goto_screen(_lcd_mesh_edit_NOP);
_lcd_mesh_fine_tune(PSTR("Mesh Editor"));
2017-03-20 06:42:41 +00:00
return mesh_edit_value;
2017-03-18 15:15:54 +00:00
}
2017-03-20 06:42:41 +00:00
void lcd_mesh_edit_setup(float initial) {
mesh_edit_value = mesh_edit_accumulator = initial;
lcd_goto_screen(_lcd_mesh_edit_NOP);
2017-03-18 15:15:54 +00:00
}
void _lcd_z_offset_edit() {
2017-03-20 06:42:41 +00:00
_lcd_mesh_fine_tune(PSTR("Z-Offset: "));
2017-03-18 15:15:54 +00:00
}
float lcd_z_offset_edit() {
lcd_goto_screen(_lcd_z_offset_edit);
2017-03-20 06:42:41 +00:00
return mesh_edit_value;
2017-03-18 15:15:54 +00:00
}
2017-03-20 06:42:41 +00:00
void lcd_z_offset_edit_setup(float initial) {
mesh_edit_value = mesh_edit_accumulator = initial;
2017-03-18 15:15:54 +00:00
lcd_goto_screen(_lcd_z_offset_edit);
}
#endif // AUTO_BED_LEVELING_UBL
2016-06-11 21:12:00 +00:00
/**
* Watch temperature callbacks
*/
2017-04-09 08:23:05 +00:00
#if HAS_TEMP_HOTEND
#if WATCH_HOTENDS
#define _WATCH_FUNC(N) thermalManager.start_watching_heater(N)
#else
#define _WATCH_FUNC(N) NOOP
#endif
2017-04-09 08:23:05 +00:00
void watch_temp_callback_E0() { _WATCH_FUNC(0); }
#if HOTENDS > 1
void watch_temp_callback_E1() { _WATCH_FUNC(1); }
#if HOTENDS > 2
void watch_temp_callback_E2() { _WATCH_FUNC(2); }
#if HOTENDS > 3
void watch_temp_callback_E3() { _WATCH_FUNC(3); }
#if HOTENDS > 4
void watch_temp_callback_E4() { _WATCH_FUNC(4); }
#endif // HOTENDS > 4
#endif // HOTENDS > 3
#endif // HOTENDS > 2
#endif // HOTENDS > 1
#endif // HAS_TEMP_HOTEND
#if WATCH_THE_BED
void watch_temp_callback_bed() { thermalManager.start_watching_bed(); }
#endif
#if ENABLED(FILAMENT_CHANGE_FEATURE)
void lcd_enqueue_filament_change() {
2016-12-22 01:30:51 +00:00
if (!DEBUGGING(DRYRUN) && thermalManager.tooColdToExtrude(active_extruder)) {
2016-12-20 07:47:46 +00:00
lcd_save_previous_screen();
lcd_goto_screen(lcd_filament_change_toocold_menu);
return;
}
lcd_filament_change_show_message(FILAMENT_CHANGE_MESSAGE_INIT);
enqueue_and_echo_commands_P(PSTR("M600"));
}
#endif
2016-06-11 21:12:00 +00:00
/**
*
* "Tune" submenu
*
*/
void lcd_tune_menu() {
2016-06-11 21:12:00 +00:00
START_MENU();
2016-06-11 21:12:00 +00:00
//
// ^ Main
//
MENU_BACK(MSG_MAIN);
2016-06-11 21:12:00 +00:00
//
// Speed:
//
2016-07-16 01:49:34 +00:00
MENU_ITEM_EDIT(int3, MSG_SPEED, &feedrate_percentage, 10, 999);
2016-06-11 21:12:00 +00:00
// Manual bed leveling, Bed Z:
#if ENABLED(MESH_BED_LEVELING) && ENABLED(LCD_BED_LEVELING)
2016-06-11 21:12:00 +00:00
MENU_ITEM_EDIT(float43, MSG_BED_Z, &mbl.z_offset, -1, 1);
#endif
2015-01-23 22:13:06 +00:00
2016-06-11 21:12:00 +00:00
//
// Nozzle:
// Nozzle [1-4]:
//
#if HOTENDS == 1
MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_NOZZLE, &thermalManager.target_temperature[0], 0, HEATER_0_MAXTEMP - 15, watch_temp_callback_E0);
2017-05-09 17:35:43 +00:00
#else // HOTENDS > 1
MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_NOZZLE MSG_N1, &thermalManager.target_temperature[0], 0, HEATER_0_MAXTEMP - 15, watch_temp_callback_E0);
MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_NOZZLE MSG_N2, &thermalManager.target_temperature[1], 0, HEATER_1_MAXTEMP - 15, watch_temp_callback_E1);
2016-05-27 00:43:20 +00:00
#if HOTENDS > 2
MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_NOZZLE MSG_N3, &thermalManager.target_temperature[2], 0, HEATER_2_MAXTEMP - 15, watch_temp_callback_E2);
2016-05-27 00:43:20 +00:00
#if HOTENDS > 3
MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_NOZZLE MSG_N4, &thermalManager.target_temperature[3], 0, HEATER_3_MAXTEMP - 15, watch_temp_callback_E3);
#if HOTENDS > 4
MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_NOZZLE MSG_N5, &thermalManager.target_temperature[4], 0, HEATER_4_MAXTEMP - 15, watch_temp_callback_E4);
#endif // HOTENDS > 4
2016-06-11 21:12:00 +00:00
#endif // HOTENDS > 3
#endif // HOTENDS > 2
#endif // HOTENDS > 1
//
// Bed:
//
#if WATCH_THE_BED
2016-06-11 21:12:00 +00:00
MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_BED, &thermalManager.target_temperature_bed, 0, BED_MAXTEMP - 15, watch_temp_callback_bed);
#endif
//
// Fan Speed:
//
#if FAN_COUNT > 0
#if HAS_FAN0
#if FAN_COUNT > 1
#define MSG_1ST_FAN_SPEED MSG_FAN_SPEED " 1"
#else
#define MSG_1ST_FAN_SPEED MSG_FAN_SPEED
2016-04-29 01:18:13 +00:00
#endif
2016-06-11 21:12:00 +00:00
MENU_MULTIPLIER_ITEM_EDIT(int3, MSG_1ST_FAN_SPEED, &fanSpeeds[0], 0, 255);
#endif
#if HAS_FAN1
MENU_MULTIPLIER_ITEM_EDIT(int3, MSG_FAN_SPEED " 2", &fanSpeeds[1], 0, 255);
2016-04-29 01:18:13 +00:00
#endif
2016-06-11 21:12:00 +00:00
#if HAS_FAN2
MENU_MULTIPLIER_ITEM_EDIT(int3, MSG_FAN_SPEED " 3", &fanSpeeds[2], 0, 255);
#endif
#endif // FAN_COUNT > 0
//
// Flow:
// Flow [1-5]:
2016-06-11 21:12:00 +00:00
//
#if EXTRUDERS == 1
2016-08-19 03:13:47 +00:00
MENU_ITEM_EDIT(int3, MSG_FLOW, &flow_percentage[0], 10, 999);
2016-06-11 21:12:00 +00:00
#else // EXTRUDERS > 1
2016-08-19 03:13:47 +00:00
MENU_ITEM_EDIT(int3, MSG_FLOW, &flow_percentage[active_extruder], 10, 999);
MENU_ITEM_EDIT(int3, MSG_FLOW MSG_N1, &flow_percentage[0], 10, 999);
MENU_ITEM_EDIT(int3, MSG_FLOW MSG_N2, &flow_percentage[1], 10, 999);
2016-06-11 21:12:00 +00:00
#if EXTRUDERS > 2
2016-08-19 03:13:47 +00:00
MENU_ITEM_EDIT(int3, MSG_FLOW MSG_N3, &flow_percentage[2], 10, 999);
2016-06-11 21:12:00 +00:00
#if EXTRUDERS > 3
2016-08-19 03:13:47 +00:00
MENU_ITEM_EDIT(int3, MSG_FLOW MSG_N4, &flow_percentage[3], 10, 999);
#if EXTRUDERS > 4
MENU_ITEM_EDIT(int3, MSG_FLOW MSG_N5, &flow_percentage[4], 10, 999);
#endif // EXTRUDERS > 4
#endif // EXTRUDERS > 3
#endif // EXTRUDERS > 2
#endif // EXTRUDERS > 1
2016-06-11 21:12:00 +00:00
//
// Babystep X:
// Babystep Y:
// Babystep Z:
//
#if ENABLED(BABYSTEPPING)
#if ENABLED(BABYSTEP_XY)
MENU_ITEM(submenu, MSG_BABYSTEP_X, lcd_babystep_x);
MENU_ITEM(submenu, MSG_BABYSTEP_Y, lcd_babystep_y);
#endif
#if ENABLED(BABYSTEP_ZPROBE_OFFSET)
MENU_ITEM(submenu, MSG_ZPROBE_ZOFFSET, lcd_babystep_zoffset);
#else
MENU_ITEM(submenu, MSG_BABYSTEP_Z, lcd_babystep_z);
#endif
#endif
2016-06-11 21:12:00 +00:00
//
// Change filament
//
#if ENABLED(FILAMENT_CHANGE_FEATURE)
2017-02-10 06:13:58 +00:00
if (!thermalManager.tooColdToExtrude(active_extruder))
MENU_ITEM(function, MSG_FILAMENTCHANGE, lcd_enqueue_filament_change);
#endif
2016-06-11 21:12:00 +00:00
END_MENU();
}
2016-10-03 22:15:29 +00:00
/**
*
* "Driver current control" submenu items
*
*/
#if ENABLED(DAC_STEPPER_CURRENT)
void dac_driver_getValues() { LOOP_XYZE(i) driverPercent[i] = dac_current_get_percent((AxisEnum)i); }
2016-10-07 20:57:24 +00:00
void dac_driver_commit() { dac_current_set_percents(driverPercent); }
2016-10-07 20:57:24 +00:00
void dac_driver_eeprom_write() { dac_commit_eeprom(); }
2016-10-07 20:57:24 +00:00
void lcd_dac_menu() {
2016-10-03 22:15:29 +00:00
dac_driver_getValues();
2016-11-19 10:17:39 +00:00
START_MENU();
MENU_BACK(MSG_CONTROL);
2016-10-03 22:15:29 +00:00
MENU_ITEM_EDIT_CALLBACK(int3, MSG_X " " MSG_DAC_PERCENT, &driverPercent[X_AXIS], 0, 100, dac_driver_commit);
MENU_ITEM_EDIT_CALLBACK(int3, MSG_Y " " MSG_DAC_PERCENT, &driverPercent[Y_AXIS], 0, 100, dac_driver_commit);
MENU_ITEM_EDIT_CALLBACK(int3, MSG_Z " " MSG_DAC_PERCENT, &driverPercent[Z_AXIS], 0, 100, dac_driver_commit);
MENU_ITEM_EDIT_CALLBACK(int3, MSG_E " " MSG_DAC_PERCENT, &driverPercent[E_AXIS], 0, 100, dac_driver_commit);
MENU_ITEM(function, MSG_DAC_EEPROM_WRITE, dac_driver_eeprom_write);
END_MENU();
}
#endif
constexpr int16_t heater_maxtemp[HOTENDS] = ARRAY_BY_HOTENDS(HEATER_0_MAXTEMP, HEATER_1_MAXTEMP, HEATER_2_MAXTEMP, HEATER_3_MAXTEMP, HEATER_4_MAXTEMP);
2016-06-11 21:12:00 +00:00
/**
*
* "Prepare" submenu items
*
*/
void _lcd_preheat(const int endnum, const int16_t temph, const int16_t tempb, const int16_t fan) {
if (temph > 0) thermalManager.setTargetHotend(min(heater_maxtemp[endnum], temph), endnum);
2016-06-11 21:12:00 +00:00
#if TEMP_SENSOR_BED != 0
2017-03-06 04:10:19 +00:00
if (tempb >= 0) thermalManager.setTargetBed(tempb);
#else
2016-06-11 21:12:00 +00:00
UNUSED(tempb);
#endif
2016-06-11 21:12:00 +00:00
#if FAN_COUNT > 0
#if FAN_COUNT > 1
fanSpeeds[active_extruder < FAN_COUNT ? active_extruder : 0] = fan;
#else
fanSpeeds[0] = fan;
#endif
#else
UNUSED(fan);
#endif
2016-06-11 21:12:00 +00:00
lcd_return_to_status();
}
2016-06-11 21:12:00 +00:00
#if TEMP_SENSOR_0 != 0
2017-03-06 04:10:19 +00:00
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]); }
#if TEMP_SENSOR_BED != 0
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]); }
#endif
2016-03-06 02:27:45 +00:00
#endif
2016-06-11 21:12:00 +00:00
#if HOTENDS > 1
2017-03-06 04:10:19 +00:00
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]); }
#if TEMP_SENSOR_BED != 0
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]); }
#endif
2016-06-11 21:12:00 +00:00
#if HOTENDS > 2
2017-03-06 04:10:19 +00:00
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]); }
#if TEMP_SENSOR_BED != 0
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]); }
#endif
2016-06-11 21:12:00 +00:00
#if HOTENDS > 3
2017-03-06 04:10:19 +00:00
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]); }
#if TEMP_SENSOR_BED != 0
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]); }
#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]); }
#if TEMP_SENSOR_BED != 0
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]); }
#endif
#endif // HOTENDS > 4
#endif // HOTENDS > 3
#endif // HOTENDS > 2
2017-03-06 04:10:19 +00:00
void lcd_preheat_m1_all() {
2016-06-11 21:12:00 +00:00
#if HOTENDS > 1
thermalManager.setTargetHotend(lcd_preheat_hotend_temp[0], 1);
2016-06-11 21:12:00 +00:00
#if HOTENDS > 2
thermalManager.setTargetHotend(lcd_preheat_hotend_temp[0], 2);
2016-06-11 21:12:00 +00:00
#if HOTENDS > 3
thermalManager.setTargetHotend(lcd_preheat_hotend_temp[0], 3);
#if HOTENDS > 4
thermalManager.setTargetHotend(lcd_preheat_hotend_temp[0], 4);
#endif // HOTENDS > 4
#endif // HOTENDS > 3
#endif // HOTENDS > 2
#endif // HOTENDS > 1
2017-03-06 04:10:19 +00:00
#if TEMP_SENSOR_BED != 0
lcd_preheat_m1_e0();
#else
lcd_preheat_m1_e0_only();
#endif
2016-06-11 21:12:00 +00:00
}
2017-03-06 04:10:19 +00:00
void lcd_preheat_m2_all() {
2016-06-11 21:12:00 +00:00
#if HOTENDS > 1
thermalManager.setTargetHotend(lcd_preheat_hotend_temp[1], 1);
2016-06-11 21:12:00 +00:00
#if HOTENDS > 2
thermalManager.setTargetHotend(lcd_preheat_hotend_temp[1], 2);
2016-06-11 21:12:00 +00:00
#if HOTENDS > 3
thermalManager.setTargetHotend(lcd_preheat_hotend_temp[1], 3);
#if HOTENDS > 4
thermalManager.setTargetHotend(lcd_preheat_hotend_temp[1], 4);
#endif // HOTENDS > 4
#endif // HOTENDS > 3
#endif // HOTENDS > 2
#endif // HOTENDS > 1
2017-03-06 04:10:19 +00:00
#if TEMP_SENSOR_BED != 0
2017-04-02 14:24:39 +00:00
lcd_preheat_m2_e0();
2017-03-06 04:10:19 +00:00
#else
2017-04-02 14:24:39 +00:00
lcd_preheat_m2_e0_only();
2017-03-06 04:10:19 +00:00
#endif
2016-06-11 21:12:00 +00:00
}
2016-06-11 21:12:00 +00:00
#endif // HOTENDS > 1
2016-04-03 05:46:15 +00:00
2016-06-11 21:12:00 +00:00
#if TEMP_SENSOR_BED != 0
2017-03-06 04:10:19 +00:00
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]); }
2016-06-11 21:12:00 +00:00
#endif
2016-04-03 05:46:15 +00:00
2016-06-11 21:12:00 +00:00
#if TEMP_SENSOR_0 != 0 && (TEMP_SENSOR_1 != 0 || TEMP_SENSOR_2 != 0 || TEMP_SENSOR_3 != 0 || TEMP_SENSOR_BED != 0)
2016-04-03 05:46:15 +00:00
2017-03-06 04:10:19 +00:00
void lcd_preheat_m1_menu() {
2016-06-11 21:12:00 +00:00
START_MENU();
MENU_BACK(MSG_PREPARE);
2016-06-11 21:12:00 +00:00
#if HOTENDS == 1
2017-03-06 04:10:19 +00:00
#if TEMP_SENSOR_BED != 0
MENU_ITEM(function, MSG_PREHEAT_1, lcd_preheat_m1_e0);
2017-03-06 08:06:51 +00:00
MENU_ITEM(function, MSG_PREHEAT_1_END, lcd_preheat_m1_e0_only);
2017-03-06 04:10:19 +00:00
#else
MENU_ITEM(function, MSG_PREHEAT_1, lcd_preheat_m1_e0_only);
#endif
2016-06-11 21:12:00 +00:00
#else
2017-03-06 04:10:19 +00:00
#if TEMP_SENSOR_BED != 0
MENU_ITEM(function, MSG_PREHEAT_1_N MSG_H1, lcd_preheat_m1_e0);
2017-03-06 08:06:51 +00:00
MENU_ITEM(function, MSG_PREHEAT_1_END " " MSG_E1, lcd_preheat_m1_e0_only);
2017-03-06 04:10:19 +00:00
MENU_ITEM(function, MSG_PREHEAT_1_N MSG_H2, lcd_preheat_m1_e1);
2017-03-06 08:06:51 +00:00
MENU_ITEM(function, MSG_PREHEAT_1_END " " MSG_E2, lcd_preheat_m1_e1_only);
2017-03-06 04:10:19 +00:00
#else
MENU_ITEM(function, MSG_PREHEAT_1_N MSG_H1, lcd_preheat_m1_e0_only);
MENU_ITEM(function, MSG_PREHEAT_1_N MSG_H2, lcd_preheat_m1_e1_only);
#endif
2016-06-11 21:12:00 +00:00
#if HOTENDS > 2
2017-03-06 04:10:19 +00:00
#if TEMP_SENSOR_BED != 0
MENU_ITEM(function, MSG_PREHEAT_1_N MSG_H3, lcd_preheat_m1_e2);
2017-03-06 08:06:51 +00:00
MENU_ITEM(function, MSG_PREHEAT_1_END " " MSG_E3, lcd_preheat_m1_e2_only);
2017-03-06 04:10:19 +00:00
#else
MENU_ITEM(function, MSG_PREHEAT_1_N MSG_H3, lcd_preheat_m1_e2_only);
#endif
2016-06-11 21:12:00 +00:00
#if HOTENDS > 3
2017-03-06 04:10:19 +00:00
#if TEMP_SENSOR_BED != 0
MENU_ITEM(function, MSG_PREHEAT_1_N MSG_H4, lcd_preheat_m1_e3);
2017-03-06 08:06:51 +00:00
MENU_ITEM(function, MSG_PREHEAT_1_END " " MSG_E4, lcd_preheat_m1_e3_only);
2017-03-06 04:10:19 +00:00
#else
MENU_ITEM(function, MSG_PREHEAT_1_N MSG_H4, lcd_preheat_m1_e3_only);
#endif
#if HOTENDS > 4
#if TEMP_SENSOR_BED != 0
MENU_ITEM(function, MSG_PREHEAT_1_N MSG_H5, lcd_preheat_m1_e4);
MENU_ITEM(function, MSG_PREHEAT_1_END " " MSG_E5, lcd_preheat_m1_e4_only);
#else
MENU_ITEM(function, MSG_PREHEAT_1_N MSG_H5, lcd_preheat_m1_e4_only);
#endif
#endif // HOTENDS > 4
#endif // HOTENDS > 3
#endif // HOTENDS > 2
2017-03-06 04:10:19 +00:00
MENU_ITEM(function, MSG_PREHEAT_1_ALL, lcd_preheat_m1_all);
#endif // HOTENDS > 1
2016-06-11 21:12:00 +00:00
#if TEMP_SENSOR_BED != 0
2017-03-06 04:10:19 +00:00
MENU_ITEM(function, MSG_PREHEAT_1_BEDONLY, lcd_preheat_m1_bedonly);
2016-06-11 21:12:00 +00:00
#endif
END_MENU();
}
2016-04-13 09:37:41 +00:00
2017-03-06 04:10:19 +00:00
void lcd_preheat_m2_menu() {
2016-06-11 21:12:00 +00:00
START_MENU();
MENU_BACK(MSG_PREPARE);
2016-06-11 21:12:00 +00:00
#if HOTENDS == 1
2017-03-06 04:10:19 +00:00
#if TEMP_SENSOR_BED != 0
MENU_ITEM(function, MSG_PREHEAT_2, lcd_preheat_m2_e0);
2017-03-06 08:06:51 +00:00
MENU_ITEM(function, MSG_PREHEAT_2_END, lcd_preheat_m2_e0_only);
2017-03-06 04:10:19 +00:00
#else
MENU_ITEM(function, MSG_PREHEAT_2, lcd_preheat_m2_e0_only);
#endif
2016-06-11 21:12:00 +00:00
#else
2017-03-06 04:10:19 +00:00
#if TEMP_SENSOR_BED != 0
MENU_ITEM(function, MSG_PREHEAT_2_N MSG_H1, lcd_preheat_m2_e0);
2017-03-06 08:06:51 +00:00
MENU_ITEM(function, MSG_PREHEAT_2_END " " MSG_E1, lcd_preheat_m2_e0_only);
2017-03-06 04:10:19 +00:00
MENU_ITEM(function, MSG_PREHEAT_2_N MSG_H2, lcd_preheat_m2_e1);
2017-03-06 08:06:51 +00:00
MENU_ITEM(function, MSG_PREHEAT_2_END " " MSG_E2, lcd_preheat_m2_e1_only);
2017-03-06 04:10:19 +00:00
#else
MENU_ITEM(function, MSG_PREHEAT_2_N MSG_H1, lcd_preheat_m2_e0_only);
MENU_ITEM(function, MSG_PREHEAT_2_N MSG_H2, lcd_preheat_m2_e1_only);
#endif
2016-06-11 21:12:00 +00:00
#if HOTENDS > 2
2017-03-06 04:10:19 +00:00
#if TEMP_SENSOR_BED != 0
MENU_ITEM(function, MSG_PREHEAT_2_N MSG_H3, lcd_preheat_m2_e2);
2017-03-06 08:06:51 +00:00
MENU_ITEM(function, MSG_PREHEAT_2_END " " MSG_E3, lcd_preheat_m2_e2_only);
2017-03-06 04:10:19 +00:00
#else
MENU_ITEM(function, MSG_PREHEAT_2_N MSG_H3, lcd_preheat_m2_e2_only);
#endif
2016-06-11 21:12:00 +00:00
#if HOTENDS > 3
2017-03-06 04:10:19 +00:00
#if TEMP_SENSOR_BED != 0
MENU_ITEM(function, MSG_PREHEAT_2_N MSG_H4, lcd_preheat_m2_e3);
2017-03-06 08:06:51 +00:00
MENU_ITEM(function, MSG_PREHEAT_2_END " " MSG_E4, lcd_preheat_m2_e3_only);
2017-03-06 04:10:19 +00:00
#else
MENU_ITEM(function, MSG_PREHEAT_2_N MSG_H4, lcd_preheat_m2_e3_only);
#endif
#if HOTENDS > 4
#if TEMP_SENSOR_BED != 0
MENU_ITEM(function, MSG_PREHEAT_2_N MSG_H5, lcd_preheat_m2_e4);
MENU_ITEM(function, MSG_PREHEAT_2_END " " MSG_E5, lcd_preheat_m2_e4_only);
#else
MENU_ITEM(function, MSG_PREHEAT_2_N MSG_H5, lcd_preheat_m2_e4_only);
#endif
#endif // HOTENDS > 4
#endif // HOTENDS > 3
#endif // HOTENDS > 2
2017-03-06 04:10:19 +00:00
MENU_ITEM(function, MSG_PREHEAT_2_ALL, lcd_preheat_m2_all);
#endif // HOTENDS > 1
2016-06-11 21:12:00 +00:00
#if TEMP_SENSOR_BED != 0
2017-03-06 04:10:19 +00:00
MENU_ITEM(function, MSG_PREHEAT_2_BEDONLY, lcd_preheat_m2_bedonly);
2016-06-11 21:12:00 +00:00
#endif
END_MENU();
}
#endif // TEMP_SENSOR_0 && (TEMP_SENSOR_1 || TEMP_SENSOR_2 || TEMP_SENSOR_3 || TEMP_SENSOR_BED)
void lcd_cooldown() {
#if FAN_COUNT > 0
for (uint8_t i = 0; i < FAN_COUNT; i++) fanSpeeds[i] = 0;
2016-04-13 09:37:41 +00:00
#endif
2016-06-11 21:12:00 +00:00
thermalManager.disable_all_heaters();
lcd_return_to_status();
}
2016-06-11 21:12:00 +00:00
#if ENABLED(SDSUPPORT) && ENABLED(MENU_ADDAUTOSTART)
void lcd_autostart_sd() {
2016-06-11 21:12:00 +00:00
card.autostart_index = 0;
card.setroot();
card.checkautostart(true);
}
2016-04-03 05:46:15 +00:00
2016-06-11 21:12:00 +00:00
#endif
2016-04-03 05:46:15 +00:00
2017-03-15 08:32:00 +00:00
#if ENABLED(LCD_BED_LEVELING)
2016-06-11 21:12:00 +00:00
/**
*
* "Prepare" > "Level Bed" handlers
2016-06-11 21:12:00 +00:00
*
*/
static uint8_t manual_probe_index;
2016-06-11 21:12:00 +00:00
// LCD probed points are from defaults
2017-05-12 04:22:35 +00:00
constexpr uint8_t total_probe_points = (
#if ENABLED(AUTO_BED_LEVELING_3POINT)
3
#elif ABL_GRID || ENABLED(AUTO_BED_LEVELING_UBL) || ENABLED(MESH_BED_LEVELING)
GRID_MAX_POINTS
2016-06-11 21:12:00 +00:00
#endif
2017-05-12 04:22:35 +00:00
);
#if ENABLED(MESH_BED_LEVELING)
2016-06-11 21:12:00 +00:00
// Utility to go to the next mesh point
inline void _manual_probe_goto_xy(float x, float y) {
#if MANUAL_PROBE_HEIGHT > 0
current_position[Z_AXIS] = LOGICAL_Z_POSITION(Z_MIN_POS) + MANUAL_PROBE_HEIGHT;
line_to_current(Z_AXIS);
#endif
current_position[X_AXIS] = LOGICAL_X_POSITION(x);
current_position[Y_AXIS] = LOGICAL_Y_POSITION(y);
planner.buffer_line_kinematic(current_position, MMM_TO_MMS(XY_PROBE_SPEED), active_extruder);
#if MANUAL_PROBE_HEIGHT > 0
current_position[Z_AXIS] = LOGICAL_Z_POSITION(Z_MIN_POS) + 0.2;
line_to_current(Z_AXIS);
#endif
lcd_synchronize();
}
#endif // MESH_BED_LEVELING
#if ENABLED(MESH_BED_LEVELING) || ENABLED(PROBE_MANUALLY)
void _lcd_level_goto_next_point();
#endif
2016-06-11 21:12:00 +00:00
void _lcd_level_bed_done() {
2016-06-11 21:12:00 +00:00
if (lcdDrawUpdate) lcd_implementation_drawedit(PSTR(MSG_LEVEL_BED_DONE));
2017-02-18 05:57:13 +00:00
lcdDrawUpdate = LCDVIEW_KEEP_REDRAWING;
2016-04-03 05:46:15 +00:00
}
2016-06-11 21:12:00 +00:00
/**
* Step 6: Display "Next point: 1 / 9" while waiting for move to finish
*/
void _lcd_level_bed_moving() {
if (lcdDrawUpdate) {
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);
}
lcdDrawUpdate = LCDVIEW_KEEP_REDRAWING;
}
/**
* Step 7: Get the Z coordinate, click goes to the next point or exits
2016-06-11 21:12:00 +00:00
*/
void _lcd_level_bed_get_z() {
2016-06-11 21:12:00 +00:00
ENCODER_DIRECTION_NORMAL();
// Encoder wheel adjusts the Z position
if (encoderPosition) {
refresh_cmd_timeout();
current_position[Z_AXIS] += float((int32_t)encoderPosition) * (MBL_Z_STEP);
2017-03-15 08:32:00 +00:00
NOLESS(current_position[Z_AXIS], -(LCD_PROBE_Z_RANGE) * 0.5);
NOMORE(current_position[Z_AXIS], (LCD_PROBE_Z_RANGE) * 0.5);
2016-06-11 21:12:00 +00:00
line_to_current(Z_AXIS);
2017-02-18 05:57:13 +00:00
lcdDrawUpdate = LCDVIEW_KEEP_REDRAWING;
2016-06-11 21:12:00 +00:00
encoderPosition = 0;
}
if (lcd_clicked) {
// Use a hook to set the probe point z
// (zigzag arranges in XY order)
#if ENABLED(AUTO_BED_LEVELING_UBL)
// UBL set-z handling goes here
#elif ENABLED(PROBE_MANUALLY)
// G29 helpfully records Z and goes to the next
// point (or beeps if done)
enqueue_and_echo_commands_P(PSTR("G29"));
manual_probe_index++;
#elif ENABLED(MESH_BED_LEVELING)
mbl.set_zigzag_z(manual_probe_index++, current_position[Z_AXIS]);
#endif
// If done...
if (manual_probe_index == total_probe_points) {
// Say "Done!"
2017-03-15 08:20:41 +00:00
lcd_goto_screen(_lcd_level_bed_done);
2016-06-11 21:12:00 +00:00
// Raise Z to the "manual probe height"
2017-03-15 08:20:41 +00:00
#if MANUAL_PROBE_HEIGHT > 0
current_position[Z_AXIS] = LOGICAL_Z_POSITION(Z_MIN_POS) + MANUAL_PROBE_HEIGHT;
2016-06-11 21:12:00 +00:00
line_to_current(Z_AXIS);
lcd_synchronize();
2017-03-15 08:20:41 +00:00
#endif
2016-06-11 21:12:00 +00:00
// Enable leveling, if needed
#if ENABLED(MESH_BED_LEVELING)
lcd_synchronize();
mbl.set_has_mesh(true);
mesh_probing_done();
#elif ENABLED(AUTO_BED_LEVELING_UBL)
// UBL enable goes here
#elif ENABLED(PROBE_MANUALLY)
// ABL will be enabled due to "G29".
#endif
2017-03-15 08:20:41 +00:00
lcd_return_to_status();
//LCD_MESSAGEPGM(MSG_LEVEL_BED_DONE);
lcd_completion_feedback();
2017-03-15 08:20:41 +00:00
}
else {
// Move to the next probe point, if needed
#if ENABLED(MESH_BED_LEVELING) || ENABLED(PROBE_MANUALLY)
_lcd_level_goto_next_point();
#elif ENABLED(AUTO_BED_LEVELING_UBL)
// UBL goto-next-point goes here
#endif
2016-04-03 05:46:15 +00:00
}
2016-06-11 21:12:00 +00:00
}
// Update on first display, then only on updates to Z position
// Show message above on clicks instead
if (lcdDrawUpdate) {
2017-03-15 08:20:41 +00:00
const float v = current_position[Z_AXIS];
2016-06-11 21:12:00 +00:00
lcd_implementation_drawedit(PSTR(MSG_MOVE_Z), ftostr43sign(v + (v < 0 ? -0.0001 : 0.0001), '+'));
}
}
#if ENABLED(MESH_BED_LEVELING) || ENABLED(PROBE_MANUALLY)
/**
* Step 5: Initiate a move to the next point
*/
void _lcd_level_goto_next_point() {
// Set the menu to display ahead of blocking call
lcd_goto_screen(_lcd_level_bed_moving);
2017-03-18 15:15:54 +00:00
#if ENABLED(MESH_BED_LEVELING)
int8_t px, py;
mbl.zigzag(manual_probe_index, px, py);
// Controls the loop until the move is done
_manual_probe_goto_xy(
LOGICAL_X_POSITION(mbl.index_to_xpos[px]),
LOGICAL_Y_POSITION(mbl.index_to_ypos[py])
);
2017-03-18 15:15:54 +00:00
#elif ENABLED(AUTO_BED_LEVELING_UBL)
// UBL may have its own methodology
#elif ENABLED(PROBE_MANUALLY)
2016-04-03 05:46:15 +00:00
// Just wait for the G29 move to complete
lcd_synchronize();
#endif
// After the blocking function returns, change menus
lcd_goto_screen(_lcd_level_bed_get_z);
}
#endif // MESH_BED_LEVELING
2016-06-11 21:12:00 +00:00
/**
* Step 4: Display "Click to Begin", wait for click
* Move to the first probe position
*/
void _lcd_level_bed_homing_done() {
2016-06-11 21:12:00 +00:00
if (lcdDrawUpdate) lcd_implementation_drawedit(PSTR(MSG_LEVEL_BED_WAITING));
if (lcd_clicked) {
manual_probe_index = 0;
#if ENABLED(MESH_BED_LEVELING)
_lcd_level_goto_next_point();
#elif ENABLED(AUTO_BED_LEVELING_UBL)
// UBL click handling should go here
#elif ENABLED(PROBE_MANUALLY)
enqueue_and_echo_commands_P(PSTR("G29"));
_lcd_level_goto_next_point();
#endif
2016-06-11 21:12:00 +00:00
}
}
2016-06-11 21:12:00 +00:00
/**
* Step 3: Display "Homing XYZ" - Wait for homing to finish
*/
void _lcd_level_bed_homing() {
2016-06-11 21:12:00 +00:00
if (lcdDrawUpdate) lcd_implementation_drawedit(PSTR(MSG_LEVEL_BED_HOMING), NULL);
if (axis_homed[X_AXIS] && axis_homed[Y_AXIS] && axis_homed[Z_AXIS])
lcd_goto_screen(_lcd_level_bed_homing_done);
2017-01-08 16:17:56 +00:00
lcdDrawUpdate = LCDVIEW_KEEP_REDRAWING;
2016-04-03 05:46:15 +00:00
}
#endif // LCD_BED_LEVELING
#if ENABLED(LCD_BED_LEVELING) || HAS_ABL
#if ENABLED(PROBE_MANUALLY)
extern bool g29_in_progress;
#endif
2016-06-11 21:12:00 +00:00
/**
* Step 2: Continue Bed Leveling...
*/
void _lcd_level_bed_continue() {
#if ENABLED(LCD_BED_LEVELING)
defer_return_to_status = true;
axis_homed[X_AXIS] = axis_homed[Y_AXIS] = axis_homed[Z_AXIS] = false;
lcd_goto_screen(_lcd_level_bed_homing);
enqueue_and_echo_commands_P(PSTR("G28"));
#else
lcd_return_to_status();
enqueue_and_echo_commands_P(axis_homed[X_AXIS] && axis_homed[Y_AXIS] ? PSTR("G29") : PSTR("G28\nG29"));
#endif
2016-06-11 21:12:00 +00:00
}
2016-04-03 05:46:15 +00:00
2016-06-11 21:12:00 +00:00
/**
* Step 1: Bed Level entry-point: "Cancel" or "Level Bed"
2016-06-11 21:12:00 +00:00
*/
void lcd_level_bed() {
2016-06-11 21:12:00 +00:00
START_MENU();
MENU_BACK(MSG_LEVEL_BED_CANCEL);
2016-06-11 21:12:00 +00:00
MENU_ITEM(submenu, MSG_LEVEL_BED, _lcd_level_bed_continue);
END_MENU();
}
#if ENABLED(AUTO_BED_LEVELING_UBL)
void _lcd_ubl_level_bed();
2017-05-12 11:48:15 +00:00
int UBL_STORAGE_SLOT = 0,
CUSTOM_BED_TEMP = 50,
CUSTOM_HOTEND_TEMP = 190,
SIDE_POINTS = 3,
UBL_FILLIN_AMOUNT = 5,
UBL_HEIGHT_AMOUNT,
map_type;
char UBL_LCD_GCODE [30];
/**
* UBL Build Custom Mesh Command
*/
void _lcd_ubl_build_custom_mesh() {
enqueue_and_echo_command("G28");
#if (WATCH_THE_BED)
sprintf_P(UBL_LCD_GCODE, PSTR("M190 S%i"), CUSTOM_BED_TEMP);
enqueue_and_echo_command(UBL_LCD_GCODE);
#endif
sprintf_P(UBL_LCD_GCODE, PSTR("M109 S%i"), CUSTOM_HOTEND_TEMP);
enqueue_and_echo_command(UBL_LCD_GCODE);
enqueue_and_echo_command("G29 P1");
}
/**
* UBL Custom Mesh submenu
*/
void _lcd_ubl_custom_mesh() {
START_MENU();
MENU_BACK(MSG_UBL_BUILD_MESH_MENU);
MENU_ITEM_EDIT(int3, MSG_UBL_CUSTOM_HOTEND_TEMP, &CUSTOM_HOTEND_TEMP, EXTRUDE_MINTEMP, (HEATER_0_MAXTEMP - 10));
#if (WATCH_THE_BED)
MENU_ITEM_EDIT(int3, MSG_UBL_CUSTOM_BED_TEMP, &CUSTOM_BED_TEMP, BED_MINTEMP, (BED_MAXTEMP - 5));
#endif
MENU_ITEM(function, MSG_UBL_BUILD_CUSTOM_MESH, _lcd_ubl_build_custom_mesh);
END_MENU();
}
/**
* UBL Adjust Mesh Height Command
*/
void _lcd_ubl_adjust_height_cmd() {
if (UBL_HEIGHT_AMOUNT < 0) {
// Convert to positive for the `sprintf_P` string.
UBL_HEIGHT_AMOUNT = (UBL_HEIGHT_AMOUNT - (UBL_HEIGHT_AMOUNT * 2)); // Convert to positive
sprintf_P(UBL_LCD_GCODE, PSTR("G29 P6-.%i"), UBL_HEIGHT_AMOUNT);
// Convert back to negative to preserve the user setting.
UBL_HEIGHT_AMOUNT = (UBL_HEIGHT_AMOUNT - (UBL_HEIGHT_AMOUNT * 2)); // Convert back to negative
}
else {
sprintf_P(UBL_LCD_GCODE, PSTR("G29 P6.%i"), UBL_HEIGHT_AMOUNT);
}
enqueue_and_echo_command(UBL_LCD_GCODE);
}
/**
* UBL Adjust Mesh Height submenu
*/
void _lcd_ubl_height_adjust_menu() {
START_MENU();
MENU_BACK(MSG_UBL_EDIT_MESH_MENU);
MENU_ITEM_EDIT(int3, MSG_UBL_MESH_HEIGHT_AMOUNT, &UBL_HEIGHT_AMOUNT, -9, 9);
MENU_ITEM(function, MSG_UBL_MESH_HEIGHT_ADJUST, _lcd_ubl_adjust_height_cmd);
MENU_ITEM(submenu, MSG_WATCH, lcd_status_screen);
END_MENU();
}
/**
* UBL Edit Mesh submenu
*/
void _lcd_ubl_edit_mesh() {
START_MENU();
MENU_BACK(MSG_UBL_TOOLS);
MENU_BACK(MSG_UBL_LEVEL_BED);
MENU_ITEM(gcode, MSG_UBL_FINE_TUNE_ALL, PSTR("G29 P4 R T"));
MENU_ITEM(gcode, MSG_UBL_FINE_TUNE_CLOSEST, PSTR("G29 P4 T"));
MENU_ITEM(submenu, MSG_UBL_MESH_HEIGHT_ADJUST, _lcd_ubl_height_adjust_menu);
MENU_ITEM(submenu, MSG_WATCH, lcd_status_screen);
END_MENU();
}
/**
* UBL Validate Custom Mesh Command
*/
void _lcd_ubl_validate_custom_mesh() {
enqueue_and_echo_command("G28");
#if (WATCH_THE_BED)
sprintf_P(UBL_LCD_GCODE, PSTR("G26 C B%i H%i P"), CUSTOM_BED_TEMP, CUSTOM_HOTEND_TEMP);
#else
sprintf_P(UBL_LCD_GCODE, PSTR("G26 C B0 H%i P"), CUSTOM_HOTEND_TEMP);
#endif
enqueue_and_echo_command(UBL_LCD_GCODE);
}
/**
* UBL Validate Mesh submenu
*/
void _lcd_ubl_validate_mesh() {
START_MENU();
MENU_BACK(MSG_UBL_TOOLS);
#if (WATCH_THE_BED)
MENU_ITEM(gcode, MSG_UBL_VALIDATE_PLA_MESH, PSTR("G28\nG26 C B" STRINGIFY(PREHEAT_1_TEMP_BED)
" H" STRINGIFY(PREHEAT_1_TEMP_HOTEND) " P"));
MENU_ITEM(gcode, MSG_UBL_VALIDATE_ABS_MESH, PSTR("G28\nG26 C B" STRINGIFY(PREHEAT_2_TEMP_BED)
" H" STRINGIFY(PREHEAT_2_TEMP_HOTEND) " P"));
#else
MENU_ITEM(gcode, MSG_UBL_VALIDATE_PLA_MESH, PSTR("G28\nG26 C B0 H" STRINGIFY(PREHEAT_1_TEMP_HOTEND) " P"));
MENU_ITEM(gcode, MSG_UBL_VALIDATE_ABS_MESH, 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(submenu, MSG_WATCH, lcd_status_screen);
END_MENU();
}
/**
* UBL Grid Leveling Command
*/
void _lcd_ubl_grid_level_cmd() {
sprintf_P(UBL_LCD_GCODE, PSTR("G29 J%i"), SIDE_POINTS);
enqueue_and_echo_command(UBL_LCD_GCODE);
}
/**
* UBL Grid Leveling submenu
*/
void _lcd_ubl_grid_level() {
START_MENU();
MENU_BACK(MSG_UBL_TOOLS);
MENU_ITEM_EDIT(int3, MSG_UBL_SIDE_POINTS, &SIDE_POINTS, 2, 6);
MENU_ITEM(function, MSG_UBL_MESH_LEVEL, _lcd_ubl_grid_level_cmd);
END_MENU();
}
/**
* UBL Mesh Leveling submenu
*/
void _lcd_ubl_mesh_leveling() {
START_MENU();
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(submenu, MSG_WATCH, lcd_status_screen);
END_MENU();
}
/**
* UBL Fill-in Amount Mesh Command
*/
void _lcd_ubl_fillin_amount_cmd() {
sprintf_P(UBL_LCD_GCODE, PSTR("G29 P3 R C.%i"), UBL_FILLIN_AMOUNT);
enqueue_and_echo_command(UBL_LCD_GCODE);
}
/**
* UBL Smart Fill-in Command
*/
void _lcd_ubl_smart_fillin_cmd() {
sprintf_P(UBL_LCD_GCODE, PSTR("G29 P3 T%i"), map_type);
enqueue_and_echo_command(UBL_LCD_GCODE);
}
/**
* UBL Fill-in Mesh submenu
*/
void _lcd_ubl_fillin_menu() {
START_MENU();
MENU_BACK(MSG_UBL_BUILD_MESH_MENU);
MENU_ITEM_EDIT(int3, MSG_UBL_FILLIN_AMOUNT, &UBL_FILLIN_AMOUNT, 0, 9);
MENU_ITEM(function, MSG_UBL_FILLIN_MESH, _lcd_ubl_fillin_amount_cmd);
MENU_ITEM(function, MSG_UBL_SMART_FILLIN, _lcd_ubl_smart_fillin_cmd);
MENU_ITEM(gcode, MSG_UBL_MANUAL_FILLIN, PSTR("G29 P2 B T0"));
MENU_ITEM(submenu, MSG_WATCH, lcd_status_screen);
END_MENU();
}
void _lcd_ubl_invalidate() {
ubl.invalidate();
SERIAL_PROTOCOLLNPGM("Mesh invalidated.");
}
/**
* UBL Build Mesh submenu
*/
void _lcd_ubl_build_mesh() {
START_MENU();
MENU_BACK(MSG_UBL_TOOLS);
#if (WATCH_THE_BED)
MENU_ITEM(gcode, MSG_UBL_BUILD_PLA_MESH, PSTR("G28\nM190 S" STRINGIFY(PREHEAT_1_TEMP_BED)
"\nM109 S" STRINGIFY(PREHEAT_1_TEMP_HOTEND) "\nG29 P1\nM104 S0\nM140 S0"));
MENU_ITEM(gcode, MSG_UBL_BUILD_ABS_MESH, PSTR("G28\nM190 S" STRINGIFY(PREHEAT_1_TEMP_BED)
"\nM109 S" STRINGIFY(PREHEAT_1_TEMP_HOTEND) "\nG29 P1\nM104 S0\nM140 S0"));
#else
MENU_ITEM(gcode, MSG_UBL_BUILD_PLA_MESH, PSTR("G28\nM109 S" STRINGIFY(PREHEAT_1_TEMP_HOTEND)
"\nG29 P1\nM104 S0"));
MENU_ITEM(gcode, MSG_UBL_BUILD_ABS_MESH, PSTR("G28\nM109 S" STRINGIFY(PREHEAT_1_TEMP_HOTEND)
"\nG29 P1\nM104 S0"));
#endif
MENU_ITEM(submenu, MSG_UBL_BUILD_CUSTOM_MESH, _lcd_ubl_custom_mesh);
MENU_ITEM(gcode, MSG_UBL_BUILD_COLD_MESH, PSTR("G28\nG29 P1"));
MENU_ITEM(submenu, MSG_UBL_FILLIN_MESH, _lcd_ubl_fillin_menu);
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(submenu, MSG_WATCH, lcd_status_screen);
END_MENU();
}
/**
* UBL Load Mesh Command
*/
void _lcd_ubl_load_mesh_cmd() {
sprintf_P(UBL_LCD_GCODE, PSTR("G29 L%i"), UBL_STORAGE_SLOT);
enqueue_and_echo_command(UBL_LCD_GCODE);
}
/**
* UBL Save Mesh Command
*/
void _lcd_ubl_save_mesh_cmd() {
sprintf_P(UBL_LCD_GCODE, PSTR("G29 S%i"), UBL_STORAGE_SLOT);
enqueue_and_echo_command(UBL_LCD_GCODE);
}
/**
* UBL Mesh Storage submenu
*/
void _lcd_ubl_storage_mesh() {
START_MENU();
MENU_BACK(MSG_UBL_LEVEL_BED);
MENU_ITEM_EDIT(int3, MSG_UBL_STORAGE_SLOT, &UBL_STORAGE_SLOT, 0, 9);
MENU_ITEM(function, MSG_UBL_LOAD_MESH, _lcd_ubl_load_mesh_cmd);
MENU_ITEM(function, MSG_UBL_SAVE_MESH, _lcd_ubl_save_mesh_cmd);
END_MENU();
}
/**
* UBL Output map Command
*/
void _lcd_ubl_output_map_cmd() {
sprintf_P(UBL_LCD_GCODE, PSTR("G29 T%i"), map_type);
enqueue_and_echo_command(UBL_LCD_GCODE);
}
/**
* UBL Output map submenu
*/
void _lcd_ubl_output_map() {
START_MENU();
MENU_BACK(MSG_UBL_LEVEL_BED);
MENU_ITEM_EDIT(int3, MSG_UBL_MAP_TYPE, &map_type, 0, 1);
if (map_type == 0) MENU_ITEM(function, MSG_UBL_OUTPUT_MAP_HOST, _lcd_ubl_output_map_cmd);
if (map_type == 1) MENU_ITEM(function, MSG_UBL_OUTPUT_MAP_CSV, _lcd_ubl_output_map_cmd);
END_MENU();
}
/**
* UBL Tools submenu
*/
void _lcd_ubl_tools_menu() {
START_MENU();
MENU_BACK(MSG_UBL_LEVEL_BED);
MENU_ITEM(submenu, MSG_UBL_BUILD_MESH_MENU, _lcd_ubl_build_mesh);
MENU_ITEM(submenu, MSG_UBL_VALIDATE_MESH_MENU, _lcd_ubl_validate_mesh);
MENU_ITEM(submenu, MSG_UBL_EDIT_MESH_MENU, _lcd_ubl_edit_mesh);
MENU_ITEM(submenu, MSG_UBL_MESH_LEVELING, _lcd_ubl_mesh_leveling);
END_MENU();
}
/**
* UBL System submenu
2017-05-15 23:46:07 +00:00
*
* Prepare
* - Unified Bed Leveling
* - Activate UBL
* - Deactivate UBL
* - Mesh Storage
* Memory Slot:
* Load Bed Mesh
* Save Bed Mesh
* - Output Map
* Map Type:
* Output Bed Mesh Host / Output Bed Mesh CSV
* - UBL Tools
* - Build Mesh
* Build PLA Mesh
* Build ABS Mesh
* - Build Custom Mesh
* Hotend Temp:
* Bed Temp:
* Build Custom Mesh
* Info Screen
* - Build Cold Mesh
* - Fill-in Mesh
* Fill-in Mesh
* Smart Fill-in
* Manual Fill-in
* Info Screen
* Continue Bed Mesh
* Invalidate All
* Invalidate Closest
* - Validate Mesh
* PLA Mesh Validation
* ABS Mesh Validation
* - Custom Mesh Validation
* Hotend Temp:
* Bed Temp:
* Validate Mesh
* Info Screen
* - Edit Mesh
* Fine Tune All
* Fine Tune Closest
* - Adjust Mesh Height
* Height Amount:
* Adjust Mesh Height
* Info Screen
* - Mesh Leveling
* 3-Point Mesh Leveling
* - Grid Mesh Leveling
* Side points:
* Level Mesh
* Info Screen
* - Output UBL Info
*/
void _lcd_ubl_level_bed() {
START_MENU();
MENU_BACK(MSG_PREPARE);
MENU_ITEM(gcode, MSG_UBL_ACTIVATE_MESH, PSTR("G29 A"));
MENU_ITEM(gcode, MSG_UBL_DEACTIVATE_MESH, PSTR("G29 D"));
MENU_ITEM(submenu, MSG_UBL_STORAGE_MESH_MENU, _lcd_ubl_storage_mesh);
MENU_ITEM(submenu, MSG_UBL_OUTPUT_MAP, _lcd_ubl_output_map);
MENU_ITEM(submenu, MSG_UBL_TOOLS, _lcd_ubl_tools_menu);
MENU_ITEM(gcode, MSG_UBL_INFO_UBL, PSTR("G29 W"));
END_MENU();
}
#endif
#endif // LCD_BED_LEVELING || HAS_ABL
2016-04-03 05:46:15 +00:00
/**
2016-06-11 21:12:00 +00:00
*
* "Prepare" submenu
*
2016-04-03 05:46:15 +00:00
*/
2016-06-11 21:12:00 +00:00
void lcd_prepare_menu() {
2016-04-03 05:46:15 +00:00
START_MENU();
2016-06-11 21:12:00 +00:00
//
// ^ Main
//
MENU_BACK(MSG_MAIN);
2016-04-03 05:46:15 +00:00
//
// Move Axis
//
#if ENABLED(DELTA)
if (axis_homed[Z_AXIS])
#endif
MENU_ITEM(submenu, MSG_MOVE_AXIS, lcd_move_menu);
2016-06-11 21:12:00 +00:00
//
// Auto Home
//
MENU_ITEM(gcode, MSG_AUTO_HOME, PSTR("G28"));
#if ENABLED(INDIVIDUAL_AXIS_HOMING_MENU)
MENU_ITEM(gcode, MSG_AUTO_HOME_X, PSTR("G28 X"));
MENU_ITEM(gcode, MSG_AUTO_HOME_Y, PSTR("G28 Y"));
MENU_ITEM(gcode, MSG_AUTO_HOME_Z, PSTR("G28 Z"));
#endif
2016-06-11 21:12:00 +00:00
//
// Level Bed
//
#if ENABLED(LCD_BED_LEVELING) || HAS_ABL
#if ENABLED(PROBE_MANUALLY)
if (!g29_in_progress)
#endif
#if ENABLED(AUTO_BED_LEVELING_UBL)
MENU_ITEM(submenu, MSG_UBL_LEVEL_BED, _lcd_ubl_level_bed);
#else
MENU_ITEM(submenu, MSG_LEVEL_BED, lcd_level_bed);
#endif
2016-06-11 21:12:00 +00:00
#endif
#if HAS_M206_COMMAND
2017-03-06 08:20:31 +00:00
//
// Set Home Offsets
//
MENU_ITEM(function, MSG_SET_HOME_OFFSETS, lcd_set_home_offsets);
//MENU_ITEM(gcode, MSG_SET_ORIGIN, PSTR("G92 X0 Y0 Z0"));
#endif
2016-06-11 21:12:00 +00:00
//
// Disable Steppers
//
MENU_ITEM(gcode, MSG_DISABLE_STEPPERS, PSTR("M84"));
2016-06-11 21:12:00 +00:00
//
// Preheat PLA
// Preheat ABS
//
#if TEMP_SENSOR_0 != 0
2017-02-18 05:57:13 +00:00
2017-03-06 04:08:26 +00:00
//
// Change filament
//
#if ENABLED(FILAMENT_CHANGE_FEATURE)
if (!thermalManager.tooColdToExtrude(active_extruder))
MENU_ITEM(function, MSG_FILAMENTCHANGE, lcd_enqueue_filament_change);
#endif
2017-03-06 04:06:44 +00:00
//
// Cooldown
//
bool has_heat = false;
HOTEND_LOOP() if (thermalManager.target_temperature[HOTEND_INDEX]) { has_heat = true; break; }
#if HAS_TEMP_BED
if (thermalManager.target_temperature_bed) has_heat = true;
#endif
if (has_heat) MENU_ITEM(function, MSG_COOLDOWN, lcd_cooldown);
//
// Preheat for Material 1 and 2
//
2016-06-11 21:12:00 +00:00
#if TEMP_SENSOR_1 != 0 || TEMP_SENSOR_2 != 0 || TEMP_SENSOR_3 != 0 || TEMP_SENSOR_BED != 0
2017-03-06 04:10:19 +00:00
MENU_ITEM(submenu, MSG_PREHEAT_1, lcd_preheat_m1_menu);
MENU_ITEM(submenu, MSG_PREHEAT_2, lcd_preheat_m2_menu);
2016-06-11 21:12:00 +00:00
#else
2017-03-06 04:10:19 +00:00
MENU_ITEM(function, MSG_PREHEAT_1, lcd_preheat_m1_e0_only);
MENU_ITEM(function, MSG_PREHEAT_2, lcd_preheat_m2_e0_only);
2016-06-11 21:12:00 +00:00
#endif
2017-02-18 05:57:13 +00:00
#endif // TEMP_SENSOR_0 != 0
2016-09-20 18:56:23 +00:00
//
// BLTouch Self-Test and Reset
//
#if ENABLED(BLTOUCH)
2016-09-21 06:33:30 +00:00
MENU_ITEM(gcode, MSG_BLTOUCH_SELFTEST, PSTR("M280 P" STRINGIFY(Z_ENDSTOP_SERVO_NR) " S" STRINGIFY(BLTOUCH_SELFTEST)));
2016-09-20 18:56:23 +00:00
if (!endstops.z_probe_enabled && TEST_BLTOUCH())
MENU_ITEM(gcode, MSG_BLTOUCH_RESET, PSTR("M280 P" STRINGIFY(Z_ENDSTOP_SERVO_NR) " S" STRINGIFY(BLTOUCH_RESET)));
#endif
2016-06-11 21:12:00 +00:00
//
// Switch power on/off
//
#if HAS_POWER_SWITCH
if (powersupply_on)
2016-06-11 21:12:00 +00:00
MENU_ITEM(gcode, MSG_SWITCH_PS_OFF, PSTR("M81"));
else
MENU_ITEM(gcode, MSG_SWITCH_PS_ON, PSTR("M80"));
#endif
2016-06-11 21:12:00 +00:00
//
// Autostart
//
#if ENABLED(SDSUPPORT) && ENABLED(MENU_ADDAUTOSTART)
MENU_ITEM(function, MSG_AUTOSTART, lcd_autostart_sd);
#endif
2016-06-11 21:12:00 +00:00
END_MENU();
}
2016-12-13 06:03:54 +00:00
float move_menu_scale;
2016-06-11 21:12:00 +00:00
#if ENABLED(DELTA_CALIBRATION_MENU)
2016-12-13 06:03:54 +00:00
void lcd_move_z();
void lcd_delta_calibrate_menu();
void _lcd_calibrate_homing() {
if (lcdDrawUpdate) lcd_implementation_drawmenu_static(LCD_HEIGHT >= 4 ? 1 : 0, PSTR(MSG_LEVEL_BED_HOMING));
2017-02-18 05:57:13 +00:00
lcdDrawUpdate = LCDVIEW_KEEP_REDRAWING;
2016-12-13 06:03:54 +00:00
if (axis_homed[X_AXIS] && axis_homed[Y_AXIS] && axis_homed[Z_AXIS])
lcd_goto_previous_menu();
}
void _lcd_delta_calibrate_home() {
enqueue_and_echo_commands_P(PSTR("G28"));
lcd_goto_screen(_lcd_calibrate_homing);
}
// Move directly to the tower position with uninterpolated moves
// If we used interpolated moves it would cause this to become re-entrant
void _goto_tower_pos(const float &a) {
2016-12-13 06:03:54 +00:00
current_position[Z_AXIS] = max(Z_HOMING_HEIGHT, Z_CLEARANCE_BETWEEN_PROBES) + (DELTA_PRINTABLE_RADIUS) / 5;
line_to_current(Z_AXIS);
current_position[X_AXIS] = a < 0 ? LOGICAL_X_POSITION(X_HOME_POS) : cos(RADIANS(a)) * delta_calibration_radius;
current_position[Y_AXIS] = a < 0 ? LOGICAL_Y_POSITION(Y_HOME_POS) : sin(RADIANS(a)) * delta_calibration_radius;
2016-12-13 06:03:54 +00:00
line_to_current(Z_AXIS);
current_position[Z_AXIS] = 4.0;
line_to_current(Z_AXIS);
lcd_synchronize();
move_menu_scale = 0.1;
lcd_goto_screen(lcd_move_z);
}
void _goto_tower_x() { _goto_tower_pos(210); }
void _goto_tower_y() { _goto_tower_pos(330); }
void _goto_tower_z() { _goto_tower_pos(90); }
void _goto_center() { _goto_tower_pos(-1); }
void lcd_delta_calibrate_menu() {
2016-06-11 21:12:00 +00:00
START_MENU();
MENU_BACK(MSG_MAIN);
#if ENABLED(DELTA_AUTO_CALIBRATION)
2017-04-28 22:17:01 +00:00
MENU_ITEM(gcode, MSG_DELTA_AUTO_CALIBRATE, PSTR("G33"));
MENU_ITEM(gcode, MSG_DELTA_HEIGHT_CALIBRATE, PSTR("G33 P1 A"));
#endif
2016-12-13 06:03:54 +00:00
MENU_ITEM(submenu, MSG_AUTO_HOME, _lcd_delta_calibrate_home);
if (axis_homed[Z_AXIS]) {
MENU_ITEM(submenu, MSG_DELTA_CALIBRATE_X, _goto_tower_x);
MENU_ITEM(submenu, MSG_DELTA_CALIBRATE_Y, _goto_tower_y);
MENU_ITEM(submenu, MSG_DELTA_CALIBRATE_Z, _goto_tower_z);
MENU_ITEM(submenu, MSG_DELTA_CALIBRATE_CENTER, _goto_center);
}
2016-06-11 21:12:00 +00:00
END_MENU();
}
2016-06-11 21:12:00 +00:00
#endif // DELTA_CALIBRATION_MENU
2016-06-11 21:12:00 +00:00
/**
* If the most recent manual move hasn't been fed to the planner yet,
* and the planner can accept one, send immediately
*/
inline void manage_manual_move() {
2016-07-13 00:13:56 +00:00
if (manual_move_axis != (int8_t)NO_AXIS && ELAPSED(millis(), manual_move_start_time) && !planner.is_full()) {
planner.buffer_line_kinematic(current_position, MMM_TO_MMS(manual_feedrate_mm_m[manual_move_axis]), manual_move_e_index);
2016-06-11 21:12:00 +00:00
manual_move_axis = (int8_t)NO_AXIS;
}
}
2016-06-11 21:12:00 +00:00
/**
* Set a flag that lcd_update() should start a move
* to "current_position" after a short delay.
*/
inline void manual_move_to_current(AxisEnum axis
#if E_MANUAL > 1
, int8_t eindex=-1
#endif
) {
#if E_MANUAL > 1
if (axis == E_AXIS) manual_move_e_index = eindex >= 0 ? eindex : active_extruder;
#endif
2016-07-13 00:13:56 +00:00
manual_move_start_time = millis() + (move_menu_scale < 0.99 ? 0UL : 250UL); // delay for bigger moves
2016-06-11 21:12:00 +00:00
manual_move_axis = (int8_t)axis;
}
2016-06-11 21:12:00 +00:00
/**
*
* "Prepare" > "Move Axis" submenu
*
*/
void _lcd_move_xyz(const char* name, AxisEnum axis) {
if (lcd_clicked) { return lcd_goto_previous_menu(); }
2016-06-11 21:12:00 +00:00
ENCODER_DIRECTION_NORMAL();
if (encoderPosition) {
refresh_cmd_timeout();
float min = current_position[axis] - 1000,
max = current_position[axis] + 1000;
#if HAS_SOFTWARE_ENDSTOPS
// Limit to software endstops, if enabled
if (soft_endstops_enabled) {
#if ENABLED(MIN_SOFTWARE_ENDSTOPS)
min = soft_endstop_min[axis];
#endif
#if ENABLED(MAX_SOFTWARE_ENDSTOPS)
max = soft_endstop_max[axis];
#endif
}
#endif
// Get the new position
2016-06-11 21:12:00 +00:00
current_position[axis] += float((int32_t)encoderPosition) * move_menu_scale;
// Delta limits XY based on the current offset from center
// This assumes the center is 0,0
#if ENABLED(DELTA)
if (axis != Z_AXIS) {
max = sqrt(sq((float)(DELTA_PRINTABLE_RADIUS)) - sq(current_position[Y_AXIS - axis]));
min = -max;
}
#endif
// Limit only when trying to move towards the limit
if ((int32_t)encoderPosition < 0) NOLESS(current_position[axis], min);
if ((int32_t)encoderPosition > 0) NOMORE(current_position[axis], max);
2016-06-11 21:12:00 +00:00
manual_move_to_current(axis);
encoderPosition = 0;
2016-06-11 21:12:00 +00:00
lcdDrawUpdate = LCDVIEW_REDRAW_NOW;
}
if (lcdDrawUpdate) lcd_implementation_drawedit(name, ftostr41sign(current_position[axis]));
2014-12-18 15:30:05 +00:00
}
void lcd_move_x() { _lcd_move_xyz(PSTR(MSG_MOVE_X), X_AXIS); }
void lcd_move_y() { _lcd_move_xyz(PSTR(MSG_MOVE_Y), Y_AXIS); }
void lcd_move_z() { _lcd_move_xyz(PSTR(MSG_MOVE_Z), Z_AXIS); }
void _lcd_move_e(
#if E_MANUAL > 1
2016-08-01 07:12:20 +00:00
int8_t eindex=-1
2016-06-11 21:12:00 +00:00
#endif
) {
if (lcd_clicked) { return lcd_goto_previous_menu(); }
2016-06-11 21:12:00 +00:00
ENCODER_DIRECTION_NORMAL();
if (encoderPosition) {
current_position[E_AXIS] += float((int32_t)encoderPosition) * move_menu_scale;
encoderPosition = 0;
manual_move_to_current(E_AXIS
#if E_MANUAL > 1
, eindex
#endif
);
2016-06-11 21:12:00 +00:00
lcdDrawUpdate = LCDVIEW_REDRAW_NOW;
}
if (lcdDrawUpdate) {
PGM_P pos_label;
#if E_MANUAL == 1
2016-06-11 21:12:00 +00:00
pos_label = PSTR(MSG_MOVE_E);
#else
switch (eindex) {
2016-07-17 00:59:01 +00:00
default: pos_label = PSTR(MSG_MOVE_E MSG_MOVE_E1); break;
2016-06-11 21:12:00 +00:00
case 1: pos_label = PSTR(MSG_MOVE_E MSG_MOVE_E2); break;
#if E_MANUAL > 2
2016-06-11 21:12:00 +00:00
case 2: pos_label = PSTR(MSG_MOVE_E MSG_MOVE_E3); break;
#if E_MANUAL > 3
2016-06-11 21:12:00 +00:00
case 3: pos_label = PSTR(MSG_MOVE_E MSG_MOVE_E4); break;
2017-04-09 08:23:05 +00:00
#if E_MANUAL > 4
case 4: pos_label = PSTR(MSG_MOVE_E MSG_MOVE_E5); break;
#endif // E_MANUAL > 4
#endif // E_MANUAL > 3
#endif // E_MANUAL > 2
2016-06-11 21:12:00 +00:00
}
2017-04-09 08:23:05 +00:00
#endif // E_MANUAL > 1
2016-06-11 21:12:00 +00:00
lcd_implementation_drawedit(pos_label, ftostr41sign(current_position[E_AXIS]));
}
2015-09-11 07:37:32 +00:00
}
2014-12-18 15:30:05 +00:00
void lcd_move_e() { _lcd_move_e(); }
#if E_MANUAL > 1
void lcd_move_e0() { _lcd_move_e(0); }
void lcd_move_e1() { _lcd_move_e(1); }
#if E_MANUAL > 2
void lcd_move_e2() { _lcd_move_e(2); }
#if E_MANUAL > 3
void lcd_move_e3() { _lcd_move_e(3); }
2017-04-09 08:23:05 +00:00
#if E_MANUAL > 4
void lcd_move_e4() { _lcd_move_e(4); }
#endif // E_MANUAL > 4
#endif // E_MANUAL > 3
#endif // E_MANUAL > 2
#endif // E_MANUAL > 1
2016-06-11 21:12:00 +00:00
/**
*
* "Prepare" > "Move Xmm" > "Move XYZ" submenu
*
*/
screenFunc_t _manual_move_func_ptr;
void lcd_move_menu_10mm() { move_menu_scale = 10.0; lcd_goto_screen(_manual_move_func_ptr); }
void lcd_move_menu_1mm() { move_menu_scale = 1.0; lcd_goto_screen(_manual_move_func_ptr); }
void lcd_move_menu_01mm() { move_menu_scale = 0.1; lcd_goto_screen(_manual_move_func_ptr); }
void _lcd_move_distance_menu(AxisEnum axis, screenFunc_t func) {
_manual_move_func_ptr = func;
START_MENU();
if (LCD_HEIGHT >= 4) {
switch(axis) {
case X_AXIS:
STATIC_ITEM(MSG_MOVE_X, true, true); break;
case Y_AXIS:
STATIC_ITEM(MSG_MOVE_Y, true, true); break;
case Z_AXIS:
STATIC_ITEM(MSG_MOVE_Z, true, true); break;
default:
STATIC_ITEM(MSG_MOVE_E, true, true); break;
}
2016-06-11 21:12:00 +00:00
}
MENU_BACK(MSG_MOVE_AXIS);
MENU_ITEM(submenu, MSG_MOVE_10MM, lcd_move_menu_10mm);
MENU_ITEM(submenu, MSG_MOVE_1MM, lcd_move_menu_1mm);
MENU_ITEM(submenu, MSG_MOVE_01MM, lcd_move_menu_01mm);
2016-06-11 21:12:00 +00:00
END_MENU();
}
void lcd_move_get_x_amount() { _lcd_move_distance_menu(X_AXIS, lcd_move_x); }
void lcd_move_get_y_amount() { _lcd_move_distance_menu(Y_AXIS, lcd_move_y); }
void lcd_move_get_z_amount() { _lcd_move_distance_menu(Z_AXIS, lcd_move_z); }
void lcd_move_get_e_amount() { _lcd_move_distance_menu(E_AXIS, lcd_move_e); }
#if E_MANUAL > 1
void lcd_move_get_e0_amount() { _lcd_move_distance_menu(E_AXIS, lcd_move_e0); }
void lcd_move_get_e1_amount() { _lcd_move_distance_menu(E_AXIS, lcd_move_e1); }
#if E_MANUAL > 2
void lcd_move_get_e2_amount() { _lcd_move_distance_menu(E_AXIS, lcd_move_e2); }
#if E_MANUAL > 3
void lcd_move_get_e3_amount() { _lcd_move_distance_menu(E_AXIS, lcd_move_e3); }
2017-04-09 08:23:05 +00:00
#if E_MANUAL > 4
void lcd_move_get_e4_amount() { _lcd_move_distance_menu(E_AXIS, lcd_move_e4); }
#endif // E_MANUAL > 4
#endif // E_MANUAL > 3
#endif // E_MANUAL > 2
#endif // E_MANUAL > 1
2016-06-11 21:12:00 +00:00
/**
*
* "Prepare" > "Move Axis" submenu
*
*/
#if IS_KINEMATIC
#define _MOVE_XYZ_ALLOWED (axis_homed[X_AXIS] && axis_homed[Y_AXIS] && axis_homed[Z_AXIS])
#if ENABLED(DELTA)
#define _MOVE_XY_ALLOWED (current_position[Z_AXIS] <= delta_clip_start_height)
void lcd_lower_z_to_clip_height() {
2017-04-11 00:17:14 +00:00
current_position[Z_AXIS] = delta_clip_start_height;
line_to_current(Z_AXIS);
lcd_synchronize();
}
#else
#define _MOVE_XY_ALLOWED true
#endif
#else
#define _MOVE_XYZ_ALLOWED true
#define _MOVE_XY_ALLOWED true
#endif
void lcd_move_menu() {
2016-06-11 21:12:00 +00:00
START_MENU();
MENU_BACK(MSG_PREPARE);
if (_MOVE_XYZ_ALLOWED) {
if (_MOVE_XY_ALLOWED) {
MENU_ITEM(submenu, MSG_MOVE_X, lcd_move_get_x_amount);
MENU_ITEM(submenu, MSG_MOVE_Y, lcd_move_get_y_amount);
}
#if ENABLED(DELTA)
else
MENU_ITEM(function, MSG_FREE_XY, lcd_lower_z_to_clip_height);
#endif
MENU_ITEM(submenu, MSG_MOVE_Z, lcd_move_get_z_amount);
}
else
MENU_ITEM(gcode, MSG_AUTO_HOME, PSTR("G28"));
#if ENABLED(SWITCHING_EXTRUDER)
if (active_extruder)
MENU_ITEM(gcode, MSG_SELECT " " MSG_E1, PSTR("T0"));
else
MENU_ITEM(gcode, MSG_SELECT " " MSG_E2, PSTR("T1"));
#endif
MENU_ITEM(submenu, MSG_MOVE_E, lcd_move_get_e_amount);
#if E_MANUAL > 1
MENU_ITEM(submenu, MSG_MOVE_E MSG_MOVE_E1, lcd_move_get_e0_amount);
MENU_ITEM(submenu, MSG_MOVE_E MSG_MOVE_E2, lcd_move_get_e1_amount);
#if E_MANUAL > 2
MENU_ITEM(submenu, MSG_MOVE_E MSG_MOVE_E3, lcd_move_get_e2_amount);
#if E_MANUAL > 3
MENU_ITEM(submenu, MSG_MOVE_E MSG_MOVE_E4, lcd_move_get_e3_amount);
2017-04-09 08:23:05 +00:00
#if E_MANUAL > 4
MENU_ITEM(submenu, MSG_MOVE_E MSG_MOVE_E5, lcd_move_get_e4_amount);
#endif // E_MANUAL > 4
#endif // E_MANUAL > 3
#endif // E_MANUAL > 2
#endif // E_MANUAL > 1
2016-06-11 21:12:00 +00:00
END_MENU();
}
2016-06-11 21:12:00 +00:00
/**
*
* "Control" submenu
*
*/
#if ENABLED(EEPROM_SETTINGS)
2017-04-10 02:47:49 +00:00
static void lcd_store_settings() { lcd_completion_feedback(settings.save()); }
static void lcd_load_settings() { lcd_completion_feedback(settings.load()); }
#endif
static void lcd_factory_settings() {
2017-04-10 02:47:49 +00:00
settings.reset();
lcd_completion_feedback();
}
void lcd_control_menu() {
2016-06-11 21:12:00 +00:00
START_MENU();
MENU_BACK(MSG_MAIN);
2016-06-11 21:12:00 +00:00
MENU_ITEM(submenu, MSG_TEMPERATURE, lcd_control_temperature_menu);
MENU_ITEM(submenu, MSG_MOTION, lcd_control_motion_menu);
2017-04-17 04:00:08 +00:00
MENU_ITEM(submenu, MSG_FILAMENT, lcd_control_filament_menu);
2016-06-11 21:12:00 +00:00
#if HAS_LCD_CONTRAST
//MENU_ITEM_EDIT(int3, MSG_CONTRAST, &lcd_contrast, 0, 63);
MENU_ITEM(submenu, MSG_CONTRAST, lcd_set_contrast);
2016-04-02 21:28:17 +00:00
#endif
2016-06-11 21:12:00 +00:00
#if ENABLED(FWRETRACT)
MENU_ITEM(submenu, MSG_RETRACT, lcd_control_retract_menu);
#endif
2016-10-03 22:15:29 +00:00
#if ENABLED(DAC_STEPPER_CURRENT)
2016-11-19 10:17:39 +00:00
MENU_ITEM(submenu, MSG_DRIVE_STRENGTH, lcd_dac_menu);
2016-10-03 22:15:29 +00:00
#endif
#if ENABLED(BLTOUCH)
MENU_ITEM(submenu, MSG_BLTOUCH, bltouch_menu);
#endif
2016-06-11 21:12:00 +00:00
#if ENABLED(EEPROM_SETTINGS)
MENU_ITEM(function, MSG_STORE_EEPROM, lcd_store_settings);
MENU_ITEM(function, MSG_LOAD_EEPROM, lcd_load_settings);
MENU_ITEM(function, MSG_RESTORE_FAILSAFE, lcd_factory_settings);
MENU_ITEM(gcode, MSG_INIT_EEPROM, PSTR("M502\nM500\nM501"));
2016-04-02 21:28:17 +00:00
#endif
END_MENU();
}
2016-06-11 21:12:00 +00:00
/**
*
* "Temperature" submenu
*
*/
2016-06-11 21:12:00 +00:00
#if ENABLED(PID_AUTOTUNE_MENU)
2016-06-11 21:12:00 +00:00
#if ENABLED(PIDTEMP)
int autotune_temp[HOTENDS] = ARRAY_BY_HOTENDS1(150);
#endif
2016-06-11 21:12:00 +00:00
#if ENABLED(PIDTEMPBED)
int autotune_temp_bed = 70;
#endif
void _lcd_autotune(int e) {
2016-06-11 21:12:00 +00:00
char cmd[30];
sprintf_P(cmd, PSTR("M303 U1 E%i S%i"), e,
#if HAS_PID_FOR_BOTH
e < 0 ? autotune_temp_bed : autotune_temp[e]
#elif ENABLED(PIDTEMPBED)
autotune_temp_bed
#else
autotune_temp[e]
#endif
);
enqueue_and_echo_command(cmd);
}
2017-05-09 17:35:43 +00:00
#endif // PID_AUTOTUNE_MENU
#if ENABLED(PIDTEMP)
2016-06-11 21:12:00 +00:00
// Helpers for editing PID Ki & Kd values
// grab the PID value out of the temp variable; scale it; then update the PID driver
void copy_and_scalePID_i(int e) {
2016-07-17 00:59:01 +00:00
#if DISABLED(PID_PARAMS_PER_HOTEND) || HOTENDS == 1
2016-06-11 21:12:00 +00:00
UNUSED(e);
#endif
PID_PARAM(Ki, e) = scalePID_i(raw_Ki);
thermalManager.updatePID();
}
void copy_and_scalePID_d(int e) {
2016-07-17 00:59:01 +00:00
#if DISABLED(PID_PARAMS_PER_HOTEND) || HOTENDS == 1
2016-06-11 21:12:00 +00:00
UNUSED(e);
#endif
PID_PARAM(Kd, e) = scalePID_d(raw_Kd);
thermalManager.updatePID();
}
2017-04-17 02:32:52 +00:00
#define _DEFINE_PIDTEMP_BASE_FUNCS(N) \
void copy_and_scalePID_i_E ## N() { copy_and_scalePID_i(N); } \
void copy_and_scalePID_d_E ## N() { copy_and_scalePID_d(N); }
#if ENABLED(PID_AUTOTUNE_MENU)
2017-04-17 02:32:52 +00:00
#define DEFINE_PIDTEMP_FUNCS(N) \
_DEFINE_PIDTEMP_BASE_FUNCS(N); \
void lcd_autotune_callback_E ## N() { _lcd_autotune(N); } typedef void _pid_##N##_void
#else
2017-04-17 02:32:52 +00:00
#define DEFINE_PIDTEMP_FUNCS(N) _DEFINE_PIDTEMP_BASE_FUNCS(N) typedef void _pid_##N##_void
#endif
2017-04-17 02:32:52 +00:00
DEFINE_PIDTEMP_FUNCS(0);
2016-06-11 21:12:00 +00:00
#if ENABLED(PID_PARAMS_PER_HOTEND)
#if HOTENDS > 1
2017-04-17 02:32:52 +00:00
DEFINE_PIDTEMP_FUNCS(1);
2016-06-11 21:12:00 +00:00
#if HOTENDS > 2
2017-04-17 02:32:52 +00:00
DEFINE_PIDTEMP_FUNCS(2);
2016-06-11 21:12:00 +00:00
#if HOTENDS > 3
2017-04-17 02:32:52 +00:00
DEFINE_PIDTEMP_FUNCS(3);
#if HOTENDS > 4
2017-04-17 02:32:52 +00:00
DEFINE_PIDTEMP_FUNCS(4);
#endif // HOTENDS > 4
#endif // HOTENDS > 3
#endif // HOTENDS > 2
#endif // HOTENDS > 1
#endif // PID_PARAMS_PER_HOTEND
#endif // PIDTEMP
2016-06-11 21:12:00 +00:00
/**
*
* "Control" > "Temperature" submenu
*
*/
void lcd_control_temperature_menu() {
2016-06-11 21:12:00 +00:00
START_MENU();
2016-06-11 21:12:00 +00:00
//
// ^ Control
//
MENU_BACK(MSG_CONTROL);
2016-06-11 21:12:00 +00:00
//
// Nozzle:
// Nozzle [1-5]:
2016-06-11 21:12:00 +00:00
//
#if HOTENDS == 1
MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_NOZZLE, &thermalManager.target_temperature[0], 0, HEATER_0_MAXTEMP - 15, watch_temp_callback_E0);
#else // HOTENDS > 1
MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_NOZZLE MSG_N1, &thermalManager.target_temperature[0], 0, HEATER_0_MAXTEMP - 15, watch_temp_callback_E0);
MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_NOZZLE MSG_N2, &thermalManager.target_temperature[1], 0, HEATER_1_MAXTEMP - 15, watch_temp_callback_E1);
2016-06-11 21:12:00 +00:00
#if HOTENDS > 2
MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_NOZZLE MSG_N3, &thermalManager.target_temperature[2], 0, HEATER_2_MAXTEMP - 15, watch_temp_callback_E2);
2016-06-11 21:12:00 +00:00
#if HOTENDS > 3
MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_NOZZLE MSG_N4, &thermalManager.target_temperature[3], 0, HEATER_3_MAXTEMP - 15, watch_temp_callback_E3);
#if HOTENDS > 4
MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_NOZZLE MSG_N5, &thermalManager.target_temperature[4], 0, HEATER_4_MAXTEMP - 15, watch_temp_callback_E4);
#endif // HOTENDS > 4
2016-06-11 21:12:00 +00:00
#endif // HOTENDS > 3
#endif // HOTENDS > 2
#endif // HOTENDS > 1
2016-06-11 21:12:00 +00:00
//
// Bed:
//
#if WATCH_THE_BED
MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_BED, &thermalManager.target_temperature_bed, 0, BED_MAXTEMP - 15, watch_temp_callback_bed);
2016-06-11 21:12:00 +00:00
#endif
2016-04-28 01:06:32 +00:00
2016-06-11 21:12:00 +00:00
//
// Fan Speed:
//
#if FAN_COUNT > 0
#if HAS_FAN0
#if FAN_COUNT > 1
#define MSG_1ST_FAN_SPEED MSG_FAN_SPEED " 1"
#else
#define MSG_1ST_FAN_SPEED MSG_FAN_SPEED
#endif
MENU_MULTIPLIER_ITEM_EDIT(int3, MSG_1ST_FAN_SPEED, &fanSpeeds[0], 0, 255);
#endif
#if HAS_FAN1
MENU_MULTIPLIER_ITEM_EDIT(int3, MSG_FAN_SPEED " 2", &fanSpeeds[1], 0, 255);
#endif
#if HAS_FAN2
MENU_MULTIPLIER_ITEM_EDIT(int3, MSG_FAN_SPEED " 3", &fanSpeeds[2], 0, 255);
#endif
#endif // FAN_COUNT > 0
//
// Autotemp, Min, Max, Fact
//
#if ENABLED(AUTOTEMP) && (TEMP_SENSOR_0 != 0)
MENU_ITEM_EDIT(bool, MSG_AUTOTEMP, &planner.autotemp_enabled);
MENU_ITEM_EDIT(float3, MSG_MIN, &planner.autotemp_min, 0, HEATER_0_MAXTEMP - 15);
MENU_ITEM_EDIT(float3, MSG_MAX, &planner.autotemp_max, 0, HEATER_0_MAXTEMP - 15);
MENU_ITEM_EDIT(float32, MSG_FACTOR, &planner.autotemp_factor, 0.0, 1.0);
#endif
2016-06-11 21:12:00 +00:00
//
// PID-P, PID-I, PID-D, PID-C, PID Autotune
// PID-P E1, PID-I E1, PID-D E1, PID-C E1, PID Autotune E1
// PID-P E2, PID-I E2, PID-D E2, PID-C E2, PID Autotune E2
// PID-P E3, PID-I E3, PID-D E3, PID-C E3, PID Autotune E3
// PID-P E4, PID-I E4, PID-D E4, PID-C E4, PID Autotune E4
2017-04-09 08:23:05 +00:00
// PID-P E5, PID-I E5, PID-D E5, PID-C E5, PID Autotune E5
2016-06-11 21:12:00 +00:00
//
#if ENABLED(PIDTEMP)
#define _PID_BASE_MENU_ITEMS(ELABEL, eindex) \
raw_Ki = unscalePID_i(PID_PARAM(Ki, eindex)); \
raw_Kd = unscalePID_d(PID_PARAM(Kd, eindex)); \
MENU_ITEM_EDIT(float52, MSG_PID_P ELABEL, &PID_PARAM(Kp, eindex), 1, 9990); \
MENU_ITEM_EDIT_CALLBACK(float52, MSG_PID_I ELABEL, &raw_Ki, 0.01, 9990, copy_and_scalePID_i_E ## eindex); \
MENU_ITEM_EDIT_CALLBACK(float52, MSG_PID_D ELABEL, &raw_Kd, 1, 9990, copy_and_scalePID_d_E ## eindex)
#if ENABLED(PID_EXTRUSION_SCALING)
2016-06-11 21:12:00 +00:00
#define _PID_MENU_ITEMS(ELABEL, eindex) \
_PID_BASE_MENU_ITEMS(ELABEL, eindex); \
MENU_ITEM_EDIT(float3, MSG_PID_C ELABEL, &PID_PARAM(Kc, eindex), 1, 9990)
#else
#define _PID_MENU_ITEMS(ELABEL, eindex) _PID_BASE_MENU_ITEMS(ELABEL, eindex)
#endif
2016-06-11 21:12:00 +00:00
#if ENABLED(PID_AUTOTUNE_MENU)
#define PID_MENU_ITEMS(ELABEL, eindex) \
_PID_MENU_ITEMS(ELABEL, eindex); \
MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_PID_AUTOTUNE ELABEL, &autotune_temp[eindex], 150, heater_maxtemp[eindex] - 15, lcd_autotune_callback_E ## eindex)
#else
#define PID_MENU_ITEMS(ELABEL, eindex) _PID_MENU_ITEMS(ELABEL, eindex)
#endif
2016-06-11 21:12:00 +00:00
#if ENABLED(PID_PARAMS_PER_HOTEND) && HOTENDS > 1
2016-12-08 10:57:41 +00:00
PID_MENU_ITEMS(" " MSG_E1, 0);
PID_MENU_ITEMS(" " MSG_E2, 1);
2016-06-11 21:12:00 +00:00
#if HOTENDS > 2
2016-12-08 10:57:41 +00:00
PID_MENU_ITEMS(" " MSG_E3, 2);
2016-06-11 21:12:00 +00:00
#if HOTENDS > 3
2016-12-08 10:57:41 +00:00
PID_MENU_ITEMS(" " MSG_E4, 3);
#if HOTENDS > 4
PID_MENU_ITEMS(" " MSG_E5, 4);
#endif // HOTENDS > 4
#endif // HOTENDS > 3
#endif // HOTENDS > 2
#else // !PID_PARAMS_PER_HOTEND || HOTENDS == 1
2016-06-11 21:12:00 +00:00
PID_MENU_ITEMS("", 0);
#endif // !PID_PARAMS_PER_HOTEND || HOTENDS == 1
2016-06-11 21:12:00 +00:00
2017-05-09 17:35:43 +00:00
#endif // PIDTEMP
2016-06-11 21:12:00 +00:00
//
2016-11-28 06:39:06 +00:00
// Preheat Material 1 conf
2016-06-11 21:12:00 +00:00
//
2016-11-28 06:39:06 +00:00
MENU_ITEM(submenu, MSG_PREHEAT_1_SETTINGS, lcd_control_temperature_preheat_material1_settings_menu);
2016-06-11 21:12:00 +00:00
//
2016-11-28 06:39:06 +00:00
// Preheat Material 2 conf
2016-06-11 21:12:00 +00:00
//
2016-11-28 06:39:06 +00:00
MENU_ITEM(submenu, MSG_PREHEAT_2_SETTINGS, lcd_control_temperature_preheat_material2_settings_menu);
2016-06-11 21:12:00 +00:00
END_MENU();
}
void _lcd_control_temperature_preheat_settings_menu(uint8_t material) {
#if HOTENDS > 4
#define MINTEMP_ALL MIN5(HEATER_0_MINTEMP, HEATER_1_MINTEMP, HEATER_2_MINTEMP, HEATER_3_MINTEMP, HEATER_4_MINTEMP)
#define MAXTEMP_ALL MAX5(HEATER_0_MAXTEMP, HEATER_1_MAXTEMP, HEATER_2_MAXTEMP, HEATER_3_MAXTEMP, HEATER_4_MAXTEMP)
#elif HOTENDS > 3
#define MINTEMP_ALL MIN4(HEATER_0_MINTEMP, HEATER_1_MINTEMP, HEATER_2_MINTEMP, HEATER_3_MINTEMP)
#define MAXTEMP_ALL MAX4(HEATER_0_MAXTEMP, HEATER_1_MAXTEMP, HEATER_2_MAXTEMP, HEATER_3_MAXTEMP)
#elif HOTENDS > 2
#define MINTEMP_ALL MIN3(HEATER_0_MINTEMP, HEATER_1_MINTEMP, HEATER_2_MINTEMP)
#define MAXTEMP_ALL MAX3(HEATER_0_MAXTEMP, HEATER_1_MAXTEMP, HEATER_2_MAXTEMP)
#elif HOTENDS > 1
#define MINTEMP_ALL min(HEATER_0_MINTEMP, HEATER_1_MINTEMP)
#define MAXTEMP_ALL max(HEATER_0_MAXTEMP, HEATER_1_MAXTEMP)
#else
#define MINTEMP_ALL HEATER_0_MINTEMP
#define MAXTEMP_ALL HEATER_0_MAXTEMP
#endif
2016-06-11 21:12:00 +00:00
START_MENU();
MENU_BACK(MSG_TEMPERATURE);
MENU_ITEM_EDIT(int3, MSG_FAN_SPEED, &lcd_preheat_fan_speed[material], 0, 255);
2016-06-11 21:12:00 +00:00
#if TEMP_SENSOR_0 != 0
MENU_ITEM_EDIT(int3, MSG_NOZZLE, &lcd_preheat_hotend_temp[material], MINTEMP_ALL, MAXTEMP_ALL - 15);
2016-06-11 21:12:00 +00:00
#endif
#if TEMP_SENSOR_BED != 0
MENU_ITEM_EDIT(int3, MSG_BED, &lcd_preheat_bed_temp[material], BED_MINTEMP, BED_MAXTEMP - 15);
2016-06-11 21:12:00 +00:00
#endif
#if ENABLED(EEPROM_SETTINGS)
MENU_ITEM(function, MSG_STORE_EEPROM, lcd_store_settings);
2016-06-11 21:12:00 +00:00
#endif
END_MENU();
}
/**
*
2016-11-28 06:39:06 +00:00
* "Temperature" > "Preheat Material 1 conf" submenu
*
*/
2016-11-28 06:39:06 +00:00
void lcd_control_temperature_preheat_material1_settings_menu() { _lcd_control_temperature_preheat_settings_menu(0); }
2016-06-11 21:12:00 +00:00
/**
*
2016-11-28 06:39:06 +00:00
* "Temperature" > "Preheat Material 2 conf" submenu
2016-06-11 21:12:00 +00:00
*
*/
2016-11-28 06:39:06 +00:00
void lcd_control_temperature_preheat_material2_settings_menu() { _lcd_control_temperature_preheat_settings_menu(1); }
void _reset_acceleration_rates() { planner.reset_acceleration_rates(); }
#if ENABLED(DISTINCT_E_FACTORS)
void _reset_e_acceleration_rate(const uint8_t e) { if (e == active_extruder) _reset_acceleration_rates(); }
void _reset_e0_acceleration_rate() { _reset_e_acceleration_rate(0); }
void _reset_e1_acceleration_rate() { _reset_e_acceleration_rate(1); }
#if E_STEPPERS > 2
void _reset_e2_acceleration_rate() { _reset_e_acceleration_rate(2); }
#if E_STEPPERS > 3
void _reset_e3_acceleration_rate() { _reset_e_acceleration_rate(3); }
2017-04-09 08:23:05 +00:00
#if E_STEPPERS > 4
void _reset_e4_acceleration_rate() { _reset_e_acceleration_rate(4); }
#endif // E_STEPPERS > 4
#endif // E_STEPPERS > 3
#endif // E_STEPPERS > 2
#endif
void _planner_refresh_positioning() { planner.refresh_positioning(); }
#if ENABLED(DISTINCT_E_FACTORS)
void _planner_refresh_e_positioning(const uint8_t e) {
if (e == active_extruder)
_planner_refresh_positioning();
else
2016-12-07 08:26:24 +00:00
planner.steps_to_mm[e] = 1.0 / planner.axis_steps_per_mm[e];
}
void _planner_refresh_e0_positioning() { _reset_e_acceleration_rate(0); }
void _planner_refresh_e1_positioning() { _reset_e_acceleration_rate(1); }
#if E_STEPPERS > 2
void _planner_refresh_e2_positioning() { _reset_e_acceleration_rate(2); }
#if E_STEPPERS > 3
void _planner_refresh_e3_positioning() { _reset_e_acceleration_rate(3); }
2017-04-09 08:23:05 +00:00
#if E_STEPPERS > 4
void _planner_refresh_e4_positioning() { _reset_e_acceleration_rate(4); }
#endif // E_STEPPERS > 4
#endif // E_STEPPERS > 3
#endif // E_STEPPERS > 2
#endif
2016-06-11 21:12:00 +00:00
/**
*
* "Control" > "Motion" submenu
*
*/
#if HAS_BED_PROBE && DISABLED(BABYSTEP_ZPROBE_OFFSET)
static void lcd_refresh_zprobe_zoffset() { refresh_zprobe_zoffset(); }
#endif
void lcd_control_motion_menu() {
2015-04-08 04:11:03 +00:00
START_MENU();
MENU_BACK(MSG_CONTROL);
#if ENABLED(BABYSTEP_ZPROBE_OFFSET)
MENU_ITEM(submenu, MSG_ZPROBE_ZOFFSET, lcd_babystep_zoffset);
#elif HAS_BED_PROBE
MENU_ITEM_EDIT_CALLBACK(float32, MSG_ZPROBE_ZOFFSET, &zprobe_zoffset, Z_PROBE_OFFSET_RANGE_MIN, Z_PROBE_OFFSET_RANGE_MAX, lcd_refresh_zprobe_zoffset);
2015-04-08 04:11:03 +00:00
#endif
2016-06-11 21:12:00 +00:00
// Manual bed leveling, Bed Z:
#if ENABLED(MESH_BED_LEVELING) && ENABLED(LCD_BED_LEVELING)
2016-06-11 21:12:00 +00:00
MENU_ITEM_EDIT(float43, MSG_BED_Z, &mbl.z_offset, -1, 1);
#endif
MENU_ITEM_EDIT(float5, MSG_ACC, &planner.acceleration, 10, 99000);
MENU_ITEM_EDIT(float3, MSG_VX_JERK, &planner.max_jerk[X_AXIS], 1, 990);
MENU_ITEM_EDIT(float3, MSG_VY_JERK, &planner.max_jerk[Y_AXIS], 1, 990);
2016-06-11 21:12:00 +00:00
#if ENABLED(DELTA)
2016-10-02 15:12:47 +00:00
MENU_ITEM_EDIT(float3, MSG_VZ_JERK, &planner.max_jerk[Z_AXIS], 1, 990);
2016-06-11 21:12:00 +00:00
#else
MENU_ITEM_EDIT(float52, MSG_VZ_JERK, &planner.max_jerk[Z_AXIS], 0.1, 990);
2016-06-11 21:12:00 +00:00
#endif
MENU_ITEM_EDIT(float3, MSG_VE_JERK, &planner.max_jerk[E_AXIS], 1, 990);
//
// M203 Settings
//
2016-07-16 01:49:34 +00:00
MENU_ITEM_EDIT(float3, MSG_VMAX MSG_X, &planner.max_feedrate_mm_s[X_AXIS], 1, 999);
MENU_ITEM_EDIT(float3, MSG_VMAX MSG_Y, &planner.max_feedrate_mm_s[Y_AXIS], 1, 999);
MENU_ITEM_EDIT(float3, MSG_VMAX MSG_Z, &planner.max_feedrate_mm_s[Z_AXIS], 1, 999);
#if ENABLED(DISTINCT_E_FACTORS)
MENU_ITEM_EDIT(float3, MSG_VMAX MSG_E, &planner.max_feedrate_mm_s[E_AXIS + active_extruder], 1, 999);
MENU_ITEM_EDIT(float3, MSG_VMAX MSG_E1, &planner.max_feedrate_mm_s[E_AXIS], 1, 999);
MENU_ITEM_EDIT(float3, MSG_VMAX MSG_E2, &planner.max_feedrate_mm_s[E_AXIS + 1], 1, 999);
#if E_STEPPERS > 2
MENU_ITEM_EDIT(float3, MSG_VMAX MSG_E3, &planner.max_feedrate_mm_s[E_AXIS + 2], 1, 999);
#if E_STEPPERS > 3
2017-04-09 08:23:05 +00:00
MENU_ITEM_EDIT(float3, MSG_VMAX MSG_E4, &planner.max_feedrate_mm_s[E_AXIS + 3], 1, 999);
#if E_STEPPERS > 4
MENU_ITEM_EDIT(float3, MSG_VMAX MSG_E5, &planner.max_feedrate_mm_s[E_AXIS + 4], 1, 999);
#endif // E_STEPPERS > 4
#endif // E_STEPPERS > 3
#endif // E_STEPPERS > 2
#else
MENU_ITEM_EDIT(float3, MSG_VMAX MSG_E, &planner.max_feedrate_mm_s[E_AXIS], 1, 999);
#endif
2016-07-16 01:49:34 +00:00
MENU_ITEM_EDIT(float3, MSG_VMIN, &planner.min_feedrate_mm_s, 0, 999);
MENU_ITEM_EDIT(float3, MSG_VTRAV_MIN, &planner.min_travel_feedrate_mm_s, 0, 999);
//
// M201 Settings
//
2016-06-11 21:12:00 +00:00
MENU_ITEM_EDIT_CALLBACK(long5, MSG_AMAX MSG_X, &planner.max_acceleration_mm_per_s2[X_AXIS], 100, 99000, _reset_acceleration_rates);
MENU_ITEM_EDIT_CALLBACK(long5, MSG_AMAX MSG_Y, &planner.max_acceleration_mm_per_s2[Y_AXIS], 100, 99000, _reset_acceleration_rates);
MENU_ITEM_EDIT_CALLBACK(long5, MSG_AMAX MSG_Z, &planner.max_acceleration_mm_per_s2[Z_AXIS], 10, 99000, _reset_acceleration_rates);
#if ENABLED(DISTINCT_E_FACTORS)
MENU_ITEM_EDIT_CALLBACK(long5, MSG_AMAX MSG_E, &planner.max_acceleration_mm_per_s2[E_AXIS + active_extruder], 100, 99000, _reset_acceleration_rates);
MENU_ITEM_EDIT_CALLBACK(long5, MSG_AMAX MSG_E1, &planner.max_acceleration_mm_per_s2[E_AXIS], 100, 99000, _reset_e0_acceleration_rate);
MENU_ITEM_EDIT_CALLBACK(long5, MSG_AMAX MSG_E2, &planner.max_acceleration_mm_per_s2[E_AXIS + 1], 100, 99000, _reset_e1_acceleration_rate);
#if E_STEPPERS > 2
MENU_ITEM_EDIT_CALLBACK(long5, MSG_AMAX MSG_E3, &planner.max_acceleration_mm_per_s2[E_AXIS + 2], 100, 99000, _reset_e2_acceleration_rate);
#if E_STEPPERS > 3
MENU_ITEM_EDIT_CALLBACK(long5, MSG_AMAX MSG_E4, &planner.max_acceleration_mm_per_s2[E_AXIS + 3], 100, 99000, _reset_e3_acceleration_rate);
2017-04-09 08:23:05 +00:00
#if E_STEPPERS > 4
MENU_ITEM_EDIT_CALLBACK(long5, MSG_AMAX MSG_E5, &planner.max_acceleration_mm_per_s2[E_AXIS + 4], 100, 99000, _reset_e4_acceleration_rate);
#endif // E_STEPPERS > 4
#endif // E_STEPPERS > 3
#endif // E_STEPPERS > 2
#else
MENU_ITEM_EDIT_CALLBACK(long5, MSG_AMAX MSG_E, &planner.max_acceleration_mm_per_s2[E_AXIS], 100, 99000, _reset_acceleration_rates);
#endif
2016-06-11 21:12:00 +00:00
MENU_ITEM_EDIT(float5, MSG_A_RETRACT, &planner.retract_acceleration, 100, 99000);
MENU_ITEM_EDIT(float5, MSG_A_TRAVEL, &planner.travel_acceleration, 100, 99000);
//
// M92 Settings
//
MENU_ITEM_EDIT_CALLBACK(float62, MSG_XSTEPS, &planner.axis_steps_per_mm[X_AXIS], 5, 9999, _planner_refresh_positioning);
MENU_ITEM_EDIT_CALLBACK(float62, MSG_YSTEPS, &planner.axis_steps_per_mm[Y_AXIS], 5, 9999, _planner_refresh_positioning);
MENU_ITEM_EDIT_CALLBACK(float62, MSG_ZSTEPS, &planner.axis_steps_per_mm[Z_AXIS], 5, 9999, _planner_refresh_positioning);
#if ENABLED(DISTINCT_E_FACTORS)
MENU_ITEM_EDIT_CALLBACK(float62, MSG_ESTEPS, &planner.axis_steps_per_mm[E_AXIS + active_extruder], 5, 9999, _planner_refresh_positioning);
2016-12-08 10:57:41 +00:00
MENU_ITEM_EDIT_CALLBACK(float62, MSG_E1STEPS, &planner.axis_steps_per_mm[E_AXIS], 5, 9999, _planner_refresh_e0_positioning);
MENU_ITEM_EDIT_CALLBACK(float62, MSG_E2STEPS, &planner.axis_steps_per_mm[E_AXIS + 1], 5, 9999, _planner_refresh_e1_positioning);
#if E_STEPPERS > 2
2016-12-08 10:57:41 +00:00
MENU_ITEM_EDIT_CALLBACK(float62, MSG_E3STEPS, &planner.axis_steps_per_mm[E_AXIS + 2], 5, 9999, _planner_refresh_e2_positioning);
#if E_STEPPERS > 3
2016-12-08 10:57:41 +00:00
MENU_ITEM_EDIT_CALLBACK(float62, MSG_E4STEPS, &planner.axis_steps_per_mm[E_AXIS + 3], 5, 9999, _planner_refresh_e3_positioning);
2017-04-09 08:23:05 +00:00
#if E_STEPPERS > 4
MENU_ITEM_EDIT_CALLBACK(float62, MSG_E5STEPS, &planner.axis_steps_per_mm[E_AXIS + 4], 5, 9999, _planner_refresh_e4_positioning);
#endif // E_STEPPERS > 4
#endif // E_STEPPERS > 3
#endif // E_STEPPERS > 2
#else
MENU_ITEM_EDIT_CALLBACK(float62, MSG_ESTEPS, &planner.axis_steps_per_mm[E_AXIS], 5, 9999, _planner_refresh_positioning);
#endif
2016-06-11 21:12:00 +00:00
#if ENABLED(ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED)
MENU_ITEM_EDIT(bool, MSG_ENDSTOP_ABORT, &stepper.abort_on_endstop_hit);
#endif
2015-04-08 04:11:03 +00:00
END_MENU();
}
2016-06-11 21:12:00 +00:00
/**
*
* "Control" > "Filament" submenu
*
*/
void lcd_control_filament_menu() {
2016-06-11 21:12:00 +00:00
START_MENU();
MENU_BACK(MSG_CONTROL);
#if ENABLED(LIN_ADVANCE)
MENU_ITEM_EDIT(float3, MSG_ADVANCE_K, &planner.extruder_advance_k, 0, 999);
#endif
2016-06-11 21:12:00 +00:00
MENU_ITEM_EDIT_CALLBACK(bool, MSG_VOLUMETRIC_ENABLED, &volumetric_enabled, calculate_volumetric_multipliers);
if (volumetric_enabled) {
#if EXTRUDERS == 1
MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float43, MSG_FILAMENT_DIAM, &filament_size[0], 1.5, 3.25, calculate_volumetric_multipliers);
#else // EXTRUDERS > 1
2016-06-11 21:12:00 +00:00
MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float43, MSG_FILAMENT_DIAM MSG_DIAM_E1, &filament_size[0], 1.5, 3.25, calculate_volumetric_multipliers);
MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float43, MSG_FILAMENT_DIAM MSG_DIAM_E2, &filament_size[1], 1.5, 3.25, calculate_volumetric_multipliers);
#if EXTRUDERS > 2
MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float43, MSG_FILAMENT_DIAM MSG_DIAM_E3, &filament_size[2], 1.5, 3.25, calculate_volumetric_multipliers);
#if EXTRUDERS > 3
MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float43, MSG_FILAMENT_DIAM MSG_DIAM_E4, &filament_size[3], 1.5, 3.25, calculate_volumetric_multipliers);
#if EXTRUDERS > 4
MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float43, MSG_FILAMENT_DIAM MSG_DIAM_E5, &filament_size[4], 1.5, 3.25, calculate_volumetric_multipliers);
#endif // EXTRUDERS > 4
#endif // EXTRUDERS > 3
#endif // EXTRUDERS > 2
#endif // EXTRUDERS > 1
}
2016-06-11 21:12:00 +00:00
END_MENU();
}
/**
*
2016-06-11 21:12:00 +00:00
* "Control" > "Contrast" submenu
*
*/
2016-06-11 21:12:00 +00:00
#if HAS_LCD_CONTRAST
void lcd_set_contrast() {
if (lcd_clicked) { return lcd_goto_previous_menu(); }
2016-06-11 21:12:00 +00:00
ENCODER_DIRECTION_NORMAL();
if (encoderPosition) {
set_lcd_contrast(lcd_contrast + encoderPosition);
encoderPosition = 0;
lcdDrawUpdate = LCDVIEW_REDRAW_NOW;
}
if (lcdDrawUpdate) {
lcd_implementation_drawedit(PSTR(MSG_CONTRAST),
#if LCD_CONTRAST_MAX >= 100
itostr3(lcd_contrast)
#else
itostr2(lcd_contrast)
#endif
);
}
}
2016-06-11 21:12:00 +00:00
#endif // HAS_LCD_CONTRAST
/**
*
* "Control" > "Retract" submenu
*
*/
#if ENABLED(FWRETRACT)
void lcd_control_retract_menu() {
2016-06-11 21:12:00 +00:00
START_MENU();
MENU_BACK(MSG_CONTROL);
2016-06-11 21:12:00 +00:00
MENU_ITEM_EDIT(bool, MSG_AUTORETRACT, &autoretract_enabled);
MENU_ITEM_EDIT(float52, MSG_CONTROL_RETRACT, &retract_length, 0, 100);
#if EXTRUDERS > 1
MENU_ITEM_EDIT(float52, MSG_CONTROL_RETRACT_SWAP, &retract_length_swap, 0, 100);
#endif
2016-06-22 10:27:31 +00:00
MENU_ITEM_EDIT(float3, MSG_CONTROL_RETRACTF, &retract_feedrate_mm_s, 1, 999);
2016-06-11 21:12:00 +00:00
MENU_ITEM_EDIT(float52, MSG_CONTROL_RETRACT_ZLIFT, &retract_zlift, 0, 999);
MENU_ITEM_EDIT(float52, MSG_CONTROL_RETRACT_RECOVER, &retract_recover_length, -100, 100);
2016-06-11 21:12:00 +00:00
#if EXTRUDERS > 1
MENU_ITEM_EDIT(float52, MSG_CONTROL_RETRACT_RECOVER_SWAP, &retract_recover_length_swap, -100, 100);
2016-06-11 21:12:00 +00:00
#endif
2016-07-16 01:49:34 +00:00
MENU_ITEM_EDIT(float3, MSG_CONTROL_RETRACT_RECOVERF, &retract_recover_feedrate_mm_s, 1, 999);
2016-06-11 21:12:00 +00:00
END_MENU();
}
2016-06-11 21:12:00 +00:00
#endif // FWRETRACT
2016-06-11 21:12:00 +00:00
#if ENABLED(SDSUPPORT)
2016-06-11 21:12:00 +00:00
#if !PIN_EXISTS(SD_DETECT)
void lcd_sd_refresh() {
2016-06-11 21:12:00 +00:00
card.initsd();
2016-07-08 22:08:56 +00:00
encoderTopLine = 0;
2016-06-11 21:12:00 +00:00
}
#endif
void lcd_sd_updir() {
2016-06-11 21:12:00 +00:00
card.updir();
2016-07-08 22:08:56 +00:00
encoderTopLine = 0;
2016-12-02 00:15:58 +00:00
screen_changed = true;
lcdDrawUpdate = LCDVIEW_CLEAR_CALL_REDRAW;
2016-06-11 21:12:00 +00:00
}
/**
*
* "Print from SD" submenu
*
*/
void lcd_sdcard_menu() {
ENCODER_DIRECTION_MENUS();
if (!lcdDrawUpdate && !lcd_clicked) return; // nothing to do (so don't thrash the SD card)
2017-04-17 02:32:52 +00:00
const uint16_t fileCnt = card.getnrfilenames();
2016-06-11 21:12:00 +00:00
START_MENU();
MENU_BACK(MSG_MAIN);
2016-06-11 21:12:00 +00:00
card.getWorkDirName();
if (card.filename[0] == '/') {
#if !PIN_EXISTS(SD_DETECT)
MENU_ITEM(function, LCD_STR_REFRESH MSG_REFRESH, lcd_sd_refresh);
#endif
}
else {
2016-06-11 21:12:00 +00:00
MENU_ITEM(function, LCD_STR_FOLDER "..", lcd_sd_updir);
}
2016-06-11 21:12:00 +00:00
for (uint16_t i = 0; i < fileCnt; i++) {
if (_menuLineNr == _thisItemNr) {
2017-04-17 02:32:52 +00:00
const uint16_t nr =
#if ENABLED(SDCARD_RATHERRECENTFIRST) && DISABLED(SDCARD_SORT_ALPHA)
fileCnt - 1 -
#endif
i;
2017-02-09 13:02:25 +00:00
#if ENABLED(SDCARD_SORT_ALPHA)
card.getfilename_sorted(nr);
#else
card.getfilename(nr);
#endif
2016-06-11 21:12:00 +00:00
if (card.filenameIsDir)
MENU_ITEM(sddirectory, MSG_CARD_MENU, card.filename, card.longFilename);
else
MENU_ITEM(sdfile, MSG_CARD_MENU, card.filename, card.longFilename);
}
else {
MENU_ITEM_DUMMY();
}
}
END_MENU();
}
2017-05-09 17:35:43 +00:00
#endif // SDSUPPORT
#if ENABLED(LCD_INFO_MENU)
2016-07-02 21:04:18 +00:00
#if ENABLED(PRINTCOUNTER)
/**
*
* About Printer > Statistics submenu
*
*/
void lcd_info_stats_menu() {
if (lcd_clicked) { return lcd_goto_previous_menu(); }
char buffer[21];
2016-07-23 00:42:21 +00:00
printStatistics stats = print_job_timer.getStats();
START_SCREEN(); // 12345678901234567890
STATIC_ITEM(MSG_INFO_PRINT_COUNT ": ", false, false, itostr3left(stats.totalPrints)); // Print Count: 999
2017-04-26 07:43:11 +00:00
STATIC_ITEM(MSG_INFO_COMPLETED_PRINTS": ", false, false, itostr3left(stats.finishedPrints)); // Completed : 666
2016-07-24 02:13:35 +00:00
duration_t elapsed = stats.printTime;
elapsed.toString(buffer);
STATIC_ITEM(MSG_INFO_PRINT_TIME ": ", false, false); // Total print Time:
STATIC_ITEM("", false, false, buffer); // 99y 364d 23h 59m 59s
2016-07-24 02:13:35 +00:00
elapsed = stats.longestPrint;
elapsed.toString(buffer);
STATIC_ITEM(MSG_INFO_PRINT_LONGEST ": ", false, false); // Longest job time:
STATIC_ITEM("", false, false, buffer); // 99y 364d 23h 59m 59s
sprintf_P(buffer, PSTR("%ld.%im"), long(stats.filamentUsed / 1000), int(stats.filamentUsed / 100) % 10);
STATIC_ITEM(MSG_INFO_PRINT_FILAMENT ": ", false, false); // Extruded total:
STATIC_ITEM("", false, false, buffer); // 125m
END_SCREEN();
}
2016-07-02 21:04:18 +00:00
#endif // PRINTCOUNTER
/**
*
2016-07-02 21:04:18 +00:00
* About Printer > Thermistors
*
*/
void lcd_info_thermistors_menu() {
if (lcd_clicked) { return lcd_goto_previous_menu(); }
START_SCREEN();
#define THERMISTOR_ID TEMP_SENSOR_0
#include "thermistornames.h"
2016-07-09 01:20:15 +00:00
STATIC_ITEM("T0: " THERMISTOR_NAME, false, true);
STATIC_ITEM(MSG_INFO_MIN_TEMP ": " STRINGIFY(HEATER_0_MINTEMP), false);
STATIC_ITEM(MSG_INFO_MAX_TEMP ": " STRINGIFY(HEATER_0_MAXTEMP), false);
#if TEMP_SENSOR_1 != 0
#undef THERMISTOR_ID
#define THERMISTOR_ID TEMP_SENSOR_1
#include "thermistornames.h"
2016-07-09 01:20:15 +00:00
STATIC_ITEM("T1: " THERMISTOR_NAME, false, true);
STATIC_ITEM(MSG_INFO_MIN_TEMP ": " STRINGIFY(HEATER_1_MINTEMP), false);
STATIC_ITEM(MSG_INFO_MAX_TEMP ": " STRINGIFY(HEATER_1_MAXTEMP), false);
#endif
#if TEMP_SENSOR_2 != 0
#undef THERMISTOR_ID
#define THERMISTOR_ID TEMP_SENSOR_2
#include "thermistornames.h"
2016-07-09 01:20:15 +00:00
STATIC_ITEM("T2: " THERMISTOR_NAME, false, true);
STATIC_ITEM(MSG_INFO_MIN_TEMP ": " STRINGIFY(HEATER_2_MINTEMP), false);
STATIC_ITEM(MSG_INFO_MAX_TEMP ": " STRINGIFY(HEATER_2_MAXTEMP), false);
#endif
#if TEMP_SENSOR_3 != 0
#undef THERMISTOR_ID
#define THERMISTOR_ID TEMP_SENSOR_3
#include "thermistornames.h"
2016-07-09 01:20:15 +00:00
STATIC_ITEM("T3: " THERMISTOR_NAME, false, true);
STATIC_ITEM(MSG_INFO_MIN_TEMP ": " STRINGIFY(HEATER_3_MINTEMP), false);
STATIC_ITEM(MSG_INFO_MAX_TEMP ": " STRINGIFY(HEATER_3_MAXTEMP), false);
#endif
2016-07-02 21:04:18 +00:00
#if TEMP_SENSOR_BED != 0
#undef THERMISTOR_ID
#define THERMISTOR_ID TEMP_SENSOR_BED
#include "thermistornames.h"
2016-07-09 01:20:15 +00:00
STATIC_ITEM("TBed:" THERMISTOR_NAME, false, true);
STATIC_ITEM(MSG_INFO_MIN_TEMP ": " STRINGIFY(BED_MINTEMP), false);
STATIC_ITEM(MSG_INFO_MAX_TEMP ": " STRINGIFY(BED_MAXTEMP), false);
#endif
END_SCREEN();
}
/**
*
2016-07-02 21:04:18 +00:00
* About Printer > Board Info
*
*/
void lcd_info_board_menu() {
if (lcd_clicked) { return lcd_goto_previous_menu(); }
START_SCREEN();
STATIC_ITEM(BOARD_NAME, true, true); // MyPrinterController
STATIC_ITEM(MSG_INFO_BAUDRATE ": " STRINGIFY(BAUDRATE), true); // Baud: 250000
STATIC_ITEM(MSG_INFO_PROTOCOL ": " PROTOCOL_VERSION, true); // Protocol: 1.0
2017-04-02 06:33:41 +00:00
#if POWER_SUPPLY == 0
STATIC_ITEM(MSG_INFO_PSU ": Generic", true);
#elif POWER_SUPPLY == 1
STATIC_ITEM(MSG_INFO_PSU ": ATX", true); // Power Supply: ATX
#elif POWER_SUPPLY == 2
STATIC_ITEM(MSG_INFO_PSU ": XBox", true); // Power Supply: XBox
#endif
END_SCREEN();
}
/**
*
2016-07-02 21:04:18 +00:00
* About Printer > Printer Info
*
*/
void lcd_info_printer_menu() {
if (lcd_clicked) { return lcd_goto_previous_menu(); }
START_SCREEN();
STATIC_ITEM(MSG_MARLIN, true, true); // Marlin
STATIC_ITEM(SHORT_BUILD_VERSION, true); // x.x.x-Branch
STATIC_ITEM(STRING_DISTRIBUTION_DATE, true); // YYYY-MM-DD HH:MM
STATIC_ITEM(MACHINE_NAME, true); // My3DPrinter
STATIC_ITEM(WEBSITE_URL, true); // www.my3dprinter.com
STATIC_ITEM(MSG_INFO_EXTRUDERS ": " STRINGIFY(EXTRUDERS), true); // Extruders: 2
END_SCREEN();
2016-07-02 21:04:18 +00:00
}
2016-07-02 21:04:18 +00:00
/**
*
* "About Printer" submenu
*
*/
void lcd_info_menu() {
2016-07-02 21:04:18 +00:00
START_MENU();
MENU_BACK(MSG_MAIN);
2016-07-02 21:04:18 +00:00
MENU_ITEM(submenu, MSG_INFO_PRINTER_MENU, lcd_info_printer_menu); // Printer Info >
MENU_ITEM(submenu, MSG_INFO_BOARD_MENU, lcd_info_board_menu); // Board Info >
MENU_ITEM(submenu, MSG_INFO_THERMISTOR_MENU, lcd_info_thermistors_menu); // Thermistors >
#if ENABLED(PRINTCOUNTER)
2016-07-02 21:04:18 +00:00
MENU_ITEM(submenu, MSG_INFO_STATS_MENU, lcd_info_stats_menu); // Printer Statistics >
#endif
END_MENU();
}
#endif // LCD_INFO_MENU
2017-02-10 06:13:58 +00:00
/**
*
* Filament Change Feature Screens
*
*/
#if ENABLED(FILAMENT_CHANGE_FEATURE)
2017-02-18 05:57:13 +00:00
// Portions from STATIC_ITEM...
#define HOTEND_STATUS_ITEM() do { \
if (_menuLineNr == _thisItemNr) { \
if (lcdDrawUpdate) { \
2017-02-18 05:57:13 +00:00
lcd_implementation_drawmenu_static(_lcdLineNr, PSTR(MSG_FILAMENT_CHANGE_NOZZLE), false, true); \
lcd_implementation_hotend_status(_lcdLineNr); \
} \
2017-02-18 05:57:13 +00:00
if (_skipStatic && encoderLine <= _thisItemNr) { \
encoderPosition += ENCODER_STEPS_PER_MENU_ITEM; \
++encoderLine; \
2017-02-18 05:57:13 +00:00
} \
lcdDrawUpdate = LCDVIEW_KEEP_REDRAWING; \
2017-02-18 05:57:13 +00:00
} \
++_thisItemNr; \
} while(0)
2016-12-20 07:47:46 +00:00
void lcd_filament_change_toocold_menu() {
START_MENU();
STATIC_ITEM(MSG_HEATING_FAILED_LCD, true, true);
2017-02-10 06:13:58 +00:00
STATIC_ITEM(MSG_FILAMENT_CHANGE_MINTEMP STRINGIFY(EXTRUDE_MINTEMP) ".", false, false);
MENU_BACK(MSG_BACK);
2017-02-18 05:57:13 +00:00
#if LCD_HEIGHT > 4
STATIC_ITEM(" ");
#endif
HOTEND_STATUS_ITEM();
2016-12-20 07:47:46 +00:00
END_MENU();
}
void lcd_filament_change_resume_print() {
filament_change_menu_response = FILAMENT_CHANGE_RESPONSE_RESUME_PRINT;
}
void lcd_filament_change_extrude_more() {
filament_change_menu_response = FILAMENT_CHANGE_RESPONSE_EXTRUDE_MORE;
}
void lcd_filament_change_option_menu() {
START_MENU();
#if LCD_HEIGHT > 2
2016-07-09 01:18:40 +00:00
STATIC_ITEM(MSG_FILAMENT_CHANGE_OPTION_HEADER, true, false);
#endif
MENU_ITEM(function, MSG_FILAMENT_CHANGE_OPTION_RESUME, lcd_filament_change_resume_print);
MENU_ITEM(function, MSG_FILAMENT_CHANGE_OPTION_EXTRUDE, lcd_filament_change_extrude_more);
END_MENU();
}
void lcd_filament_change_init_message() {
START_SCREEN();
2016-07-09 01:18:40 +00:00
STATIC_ITEM(MSG_FILAMENT_CHANGE_HEADER, true, true);
STATIC_ITEM(MSG_FILAMENT_CHANGE_INIT_1);
#ifdef MSG_FILAMENT_CHANGE_INIT_2
STATIC_ITEM(MSG_FILAMENT_CHANGE_INIT_2);
2017-02-18 05:57:13 +00:00
#define __FC_LINES_A 3
#else
#define __FC_LINES_A 2
#endif
#ifdef MSG_FILAMENT_CHANGE_INIT_3
STATIC_ITEM(MSG_FILAMENT_CHANGE_INIT_3);
2017-02-18 05:57:13 +00:00
#define _FC_LINES_A (__FC_LINES_A + 1)
#else
#define _FC_LINES_A __FC_LINES_A
#endif
#if LCD_HEIGHT > _FC_LINES_A + 1
STATIC_ITEM(" ");
#endif
2017-02-18 05:57:13 +00:00
HOTEND_STATUS_ITEM();
END_SCREEN();
}
void lcd_filament_change_unload_message() {
START_SCREEN();
2016-07-09 01:18:40 +00:00
STATIC_ITEM(MSG_FILAMENT_CHANGE_HEADER, true, true);
STATIC_ITEM(MSG_FILAMENT_CHANGE_UNLOAD_1);
#ifdef MSG_FILAMENT_CHANGE_UNLOAD_2
STATIC_ITEM(MSG_FILAMENT_CHANGE_UNLOAD_2);
2017-02-18 05:57:13 +00:00
#define __FC_LINES_B 3
#else
#define __FC_LINES_B 2
#endif
#ifdef MSG_FILAMENT_CHANGE_UNLOAD_3
STATIC_ITEM(MSG_FILAMENT_CHANGE_UNLOAD_3);
2017-02-18 05:57:13 +00:00
#define _FC_LINES_B (__FC_LINES_B + 1)
#else
#define _FC_LINES_B __FC_LINES_B
#endif
#if LCD_HEIGHT > _FC_LINES_B + 1
STATIC_ITEM(" ");
#endif
2017-02-18 05:57:13 +00:00
HOTEND_STATUS_ITEM();
END_SCREEN();
}
void lcd_filament_change_wait_for_nozzles_to_heat() {
START_SCREEN();
STATIC_ITEM(MSG_FILAMENT_CHANGE_HEADER, true, true);
STATIC_ITEM(MSG_FILAMENT_CHANGE_HEATING_1);
#ifdef MSG_FILAMENT_CHANGE_HEATING_2
STATIC_ITEM(MSG_FILAMENT_CHANGE_HEATING_2);
2017-02-18 05:57:13 +00:00
#define _FC_LINES_C 3
#else
#define _FC_LINES_C 2
#endif
2017-02-18 05:57:13 +00:00
#if LCD_HEIGHT > _FC_LINES_C + 1
STATIC_ITEM(" ");
#endif
HOTEND_STATUS_ITEM();
END_SCREEN();
}
void lcd_filament_change_heat_nozzle() {
START_SCREEN();
STATIC_ITEM(MSG_FILAMENT_CHANGE_HEADER, true, true);
STATIC_ITEM(MSG_FILAMENT_CHANGE_HEAT_1);
#ifdef MSG_FILAMENT_CHANGE_INSERT_2
STATIC_ITEM(MSG_FILAMENT_CHANGE_HEAT_2);
2017-02-18 05:57:13 +00:00
#define _FC_LINES_D 3
#else
#define _FC_LINES_D 2
#endif
#if LCD_HEIGHT > _FC_LINES_D + 1
STATIC_ITEM(" ");
#endif
2017-02-18 05:57:13 +00:00
HOTEND_STATUS_ITEM();
END_SCREEN();
}
void lcd_filament_change_insert_message() {
START_SCREEN();
2016-07-09 01:18:40 +00:00
STATIC_ITEM(MSG_FILAMENT_CHANGE_HEADER, true, true);
STATIC_ITEM(MSG_FILAMENT_CHANGE_INSERT_1);
#ifdef MSG_FILAMENT_CHANGE_INSERT_2
STATIC_ITEM(MSG_FILAMENT_CHANGE_INSERT_2);
2017-02-18 05:57:13 +00:00
#define __FC_LINES_E 3
#else
#define __FC_LINES_E 2
#endif
#ifdef MSG_FILAMENT_CHANGE_INSERT_3
STATIC_ITEM(MSG_FILAMENT_CHANGE_INSERT_3);
2017-02-18 05:57:13 +00:00
#define _FC_LINES_E (__FC_LINES_E + 1)
#else
#define _FC_LINES_E __FC_LINES_E
#endif
#if LCD_HEIGHT > _FC_LINES_E + 1
STATIC_ITEM(" ");
#endif
2017-02-18 05:57:13 +00:00
HOTEND_STATUS_ITEM();
END_SCREEN();
}
void lcd_filament_change_load_message() {
START_SCREEN();
2016-07-09 01:18:40 +00:00
STATIC_ITEM(MSG_FILAMENT_CHANGE_HEADER, true, true);
STATIC_ITEM(MSG_FILAMENT_CHANGE_LOAD_1);
#ifdef MSG_FILAMENT_CHANGE_LOAD_2
STATIC_ITEM(MSG_FILAMENT_CHANGE_LOAD_2);
2017-02-18 05:57:13 +00:00
#define __FC_LINES_F 3
#else
#define __FC_LINES_F 2
#endif
#ifdef MSG_FILAMENT_CHANGE_LOAD_3
STATIC_ITEM(MSG_FILAMENT_CHANGE_LOAD_3);
2017-02-18 05:57:13 +00:00
#define _FC_LINES_F (__FC_LINES_F + 1)
#else
#define _FC_LINES_F __FC_LINES_F
#endif
#if LCD_HEIGHT > _FC_LINES_F + 1
STATIC_ITEM(" ");
#endif
2017-02-18 05:57:13 +00:00
HOTEND_STATUS_ITEM();
END_SCREEN();
}
void lcd_filament_change_extrude_message() {
START_SCREEN();
2016-07-09 01:18:40 +00:00
STATIC_ITEM(MSG_FILAMENT_CHANGE_HEADER, true, true);
STATIC_ITEM(MSG_FILAMENT_CHANGE_EXTRUDE_1);
#ifdef MSG_FILAMENT_CHANGE_EXTRUDE_2
STATIC_ITEM(MSG_FILAMENT_CHANGE_EXTRUDE_2);
2017-02-18 05:57:13 +00:00
#define __FC_LINES_G 3
#else
#define __FC_LINES_G 2
#endif
#ifdef MSG_FILAMENT_CHANGE_EXTRUDE_3
STATIC_ITEM(MSG_FILAMENT_CHANGE_EXTRUDE_3);
2017-02-18 05:57:13 +00:00
#define _FC_LINES_G (__FC_LINES_G + 1)
#else
#define _FC_LINES_G __FC_LINES_G
#endif
#if LCD_HEIGHT > _FC_LINES_G + 1
STATIC_ITEM(" ");
#endif
2017-02-18 05:57:13 +00:00
HOTEND_STATUS_ITEM();
END_SCREEN();
}
void lcd_filament_change_resume_message() {
START_SCREEN();
2016-07-09 01:18:40 +00:00
STATIC_ITEM(MSG_FILAMENT_CHANGE_HEADER, true, true);
STATIC_ITEM(MSG_FILAMENT_CHANGE_RESUME_1);
#ifdef MSG_FILAMENT_CHANGE_RESUME_2
STATIC_ITEM(MSG_FILAMENT_CHANGE_RESUME_2);
#endif
#ifdef MSG_FILAMENT_CHANGE_RESUME_3
STATIC_ITEM(MSG_FILAMENT_CHANGE_RESUME_3);
#endif
END_SCREEN();
}
void lcd_filament_change_show_message(const FilamentChangeMessage message) {
switch (message) {
case FILAMENT_CHANGE_MESSAGE_INIT:
defer_return_to_status = true;
lcd_goto_screen(lcd_filament_change_init_message);
break;
case FILAMENT_CHANGE_MESSAGE_UNLOAD:
lcd_goto_screen(lcd_filament_change_unload_message);
break;
case FILAMENT_CHANGE_MESSAGE_INSERT:
lcd_goto_screen(lcd_filament_change_insert_message);
break;
case FILAMENT_CHANGE_MESSAGE_LOAD:
lcd_goto_screen(lcd_filament_change_load_message);
break;
case FILAMENT_CHANGE_MESSAGE_EXTRUDE:
lcd_goto_screen(lcd_filament_change_extrude_message);
break;
case FILAMENT_CHANGE_MESSAGE_CLICK_TO_HEAT_NOZZLE:
lcd_goto_screen(lcd_filament_change_heat_nozzle);
break;
case FILAMENT_CHANGE_MESSAGE_WAIT_FOR_NOZZLES_TO_HEAT:
lcd_goto_screen(lcd_filament_change_wait_for_nozzles_to_heat);
break;
case FILAMENT_CHANGE_MESSAGE_OPTION:
filament_change_menu_response = FILAMENT_CHANGE_RESPONSE_WAIT_FOR;
lcd_goto_screen(lcd_filament_change_option_menu);
break;
case FILAMENT_CHANGE_MESSAGE_RESUME:
lcd_goto_screen(lcd_filament_change_resume_message);
break;
case FILAMENT_CHANGE_MESSAGE_STATUS:
lcd_return_to_status();
break;
}
}
#endif // FILAMENT_CHANGE_FEATURE
2016-06-11 21:12:00 +00:00
/**
*
* Functions for editing single values
*
2017-04-17 02:32:52 +00:00
* The "DEFINE_MENU_EDIT_TYPE" macro generates the functions needed to edit a numerical value.
2016-06-11 21:12:00 +00:00
*
2017-04-17 02:32:52 +00:00
* For example, DEFINE_MENU_EDIT_TYPE(int, int3, itostr3, 1) expands into these functions:
2016-06-11 21:12:00 +00:00
*
* bool _menu_edit_int3();
* void menu_edit_int3(); // edit int (interactively)
* void menu_edit_callback_int3(); // edit int (interactively) with callback on completion
2016-12-04 09:51:10 +00:00
* void _menu_action_setting_edit_int3(const char * const pstr, int * const ptr, const int minValue, const int maxValue);
* void menu_action_setting_edit_int3(const char * const pstr, int * const ptr, const int minValue, const int maxValue);
* void menu_action_setting_edit_callback_int3(const char * const pstr, int * const ptr, const int minValue, const int maxValue, const screenFunc_t callback); // edit int with callback
2016-06-11 21:12:00 +00:00
*
* You can then use one of the menu macros to present the edit interface:
2016-07-16 01:49:34 +00:00
* MENU_ITEM_EDIT(int3, MSG_SPEED, &feedrate_percentage, 10, 999)
2016-06-11 21:12:00 +00:00
*
* This expands into a more primitive menu item:
2016-07-16 01:49:34 +00:00
* MENU_ITEM(setting_edit_int3, MSG_SPEED, PSTR(MSG_SPEED), &feedrate_percentage, 10, 999)
2016-06-11 21:12:00 +00:00
*
*
* Also: MENU_MULTIPLIER_ITEM_EDIT, MENU_ITEM_EDIT_CALLBACK, and MENU_MULTIPLIER_ITEM_EDIT_CALLBACK
*
2016-07-16 01:49:34 +00:00
* menu_action_setting_edit_int3(PSTR(MSG_SPEED), &feedrate_percentage, 10, 999)
2016-06-11 21:12:00 +00:00
*/
2017-04-17 02:32:52 +00:00
#define DEFINE_MENU_EDIT_TYPE(_type, _name, _strFunc, _scale) \
2016-06-11 21:12:00 +00:00
bool _menu_edit_ ## _name () { \
ENCODER_DIRECTION_NORMAL(); \
if ((int32_t)encoderPosition < 0) encoderPosition = 0; \
if ((int32_t)encoderPosition > maxEditValue) encoderPosition = maxEditValue; \
if (lcdDrawUpdate) \
2016-12-04 09:51:10 +00:00
lcd_implementation_drawedit(editLabel, _strFunc(((_type)((int32_t)encoderPosition + minEditValue)) * (1.0 / _scale))); \
if (lcd_clicked) { \
_type value = ((_type)((int32_t)encoderPosition + minEditValue)) * (1.0 / _scale); \
if (editValue != NULL) \
*((_type*)editValue) = value; \
lcd_goto_previous_menu(); \
2016-06-11 21:12:00 +00:00
} \
return lcd_clicked; \
} \
2016-06-11 21:12:00 +00:00
void menu_edit_ ## _name () { _menu_edit_ ## _name(); } \
void menu_edit_callback_ ## _name () { if (_menu_edit_ ## _name ()) (*callbackFunc)(); } \
2016-12-04 09:51:10 +00:00
void _menu_action_setting_edit_ ## _name (const char * const pstr, _type* const ptr, const _type minValue, const _type maxValue) { \
lcd_save_previous_screen(); \
2016-06-11 21:12:00 +00:00
\
lcdDrawUpdate = LCDVIEW_CLEAR_CALL_REDRAW; \
\
editLabel = pstr; \
editValue = ptr; \
2016-12-04 09:51:10 +00:00
minEditValue = minValue * _scale; \
maxEditValue = maxValue * _scale - minEditValue; \
encoderPosition = (*ptr) * _scale - minEditValue; \
2016-06-11 21:12:00 +00:00
} \
2016-12-04 09:51:10 +00:00
void menu_action_setting_edit_ ## _name (const char * const pstr, _type * const ptr, const _type minValue, const _type maxValue) { \
2016-06-11 21:12:00 +00:00
_menu_action_setting_edit_ ## _name(pstr, ptr, minValue, maxValue); \
2016-06-11 21:19:17 +00:00
currentScreen = menu_edit_ ## _name; \
} \
2016-12-04 09:51:10 +00:00
void menu_action_setting_edit_callback_ ## _name (const char * const pstr, _type * const ptr, const _type minValue, const _type maxValue, const screenFunc_t callback) { \
2016-06-11 21:12:00 +00:00
_menu_action_setting_edit_ ## _name(pstr, ptr, minValue, maxValue); \
2016-06-11 21:19:17 +00:00
currentScreen = menu_edit_callback_ ## _name; \
2016-06-11 21:12:00 +00:00
callbackFunc = callback; \
2016-12-04 09:51:10 +00:00
} \
typedef void _name
2017-04-17 02:32:52 +00:00
DEFINE_MENU_EDIT_TYPE(int, int3, itostr3, 1);
DEFINE_MENU_EDIT_TYPE(float, float3, ftostr3, 1.0);
DEFINE_MENU_EDIT_TYPE(float, float32, ftostr32, 100.0);
DEFINE_MENU_EDIT_TYPE(float, float43, ftostr43sign, 1000.0);
DEFINE_MENU_EDIT_TYPE(float, float5, ftostr5rj, 0.01);
DEFINE_MENU_EDIT_TYPE(float, float51, ftostr51sign, 10.0);
DEFINE_MENU_EDIT_TYPE(float, float52, ftostr52sign, 100.0);
DEFINE_MENU_EDIT_TYPE(float, float62, ftostr62rj, 100.0);
DEFINE_MENU_EDIT_TYPE(unsigned long, long5, ftostr5rj, 0.01);
2016-06-11 21:12:00 +00:00
/**
*
* Handlers for RepRap World Keypad input
*
*/
#if ENABLED(REPRAPWORLD_KEYPAD)
void _reprapworld_keypad_move(AxisEnum axis, int dir) {
2016-06-11 21:12:00 +00:00
move_menu_scale = REPRAPWORLD_KEYPAD_MOVE_STEP;
encoderPosition = dir;
switch (axis) {
case X_AXIS: lcd_move_x(); break;
case Y_AXIS: lcd_move_y(); break;
case Z_AXIS: lcd_move_z();
2016-10-23 01:08:29 +00:00
default: break;
}
2016-06-11 21:12:00 +00:00
}
void reprapworld_keypad_move_z_up() { _reprapworld_keypad_move(Z_AXIS, 1); }
void reprapworld_keypad_move_z_down() { _reprapworld_keypad_move(Z_AXIS, -1); }
void reprapworld_keypad_move_x_left() { _reprapworld_keypad_move(X_AXIS, -1); }
void reprapworld_keypad_move_x_right() { _reprapworld_keypad_move(X_AXIS, 1); }
void reprapworld_keypad_move_y_up() { _reprapworld_keypad_move(Y_AXIS, -1); }
void reprapworld_keypad_move_y_down() { _reprapworld_keypad_move(Y_AXIS, 1); }
void reprapworld_keypad_move_home() { enqueue_and_echo_commands_P(PSTR("G28")); } // move all axes home and wait
void reprapworld_keypad_move_menu() { lcd_goto_screen(lcd_move_menu); }
inline void handle_reprapworld_keypad() {
static uint8_t keypad_debounce = 0;
if (!REPRAPWORLD_KEYPAD_PRESSED) {
if (keypad_debounce > 0) keypad_debounce--;
}
else if (!keypad_debounce) {
keypad_debounce = 2;
if (REPRAPWORLD_KEYPAD_MOVE_MENU) reprapworld_keypad_move_menu();
#if DISABLED(DELTA) && Z_HOME_DIR == -1
if (REPRAPWORLD_KEYPAD_MOVE_Z_UP) reprapworld_keypad_move_z_up();
#endif
if (axis_homed[X_AXIS] && axis_homed[Y_AXIS] && axis_homed[Z_AXIS]) {
#if ENABLED(DELTA) || Z_HOME_DIR != -1
if (REPRAPWORLD_KEYPAD_MOVE_Z_UP) reprapworld_keypad_move_z_up();
#endif
if (REPRAPWORLD_KEYPAD_MOVE_Z_DOWN) reprapworld_keypad_move_z_down();
if (REPRAPWORLD_KEYPAD_MOVE_X_LEFT) reprapworld_keypad_move_x_left();
if (REPRAPWORLD_KEYPAD_MOVE_X_RIGHT) reprapworld_keypad_move_x_right();
if (REPRAPWORLD_KEYPAD_MOVE_Y_DOWN) reprapworld_keypad_move_y_down();
if (REPRAPWORLD_KEYPAD_MOVE_Y_UP) reprapworld_keypad_move_y_up();
}
else {
if (REPRAPWORLD_KEYPAD_MOVE_HOME) reprapworld_keypad_move_home();
}
}
}
2016-06-11 21:12:00 +00:00
#endif // REPRAPWORLD_KEYPAD
2016-06-11 21:12:00 +00:00
/**
*
* Menu actions
*
*/
void _menu_action_back() { lcd_goto_previous_menu(); }
void menu_action_submenu(screenFunc_t func) { lcd_save_previous_screen(); lcd_goto_screen(func); }
void menu_action_gcode(const char* pgcode) { enqueue_and_echo_commands_P(pgcode); }
void menu_action_function(screenFunc_t func) { (*func)(); }
2016-06-11 21:12:00 +00:00
#if ENABLED(SDSUPPORT)
void menu_action_sdfile(const char* filename, char* longFilename) {
2016-06-11 21:12:00 +00:00
UNUSED(longFilename);
card.openAndPrintFile(filename);
lcd_return_to_status();
}
void menu_action_sddirectory(const char* filename, char* longFilename) {
2016-06-11 21:12:00 +00:00
UNUSED(longFilename);
card.chdir(filename);
encoderPosition = 0;
2016-12-02 00:15:58 +00:00
screen_changed = true;
lcdDrawUpdate = LCDVIEW_CLEAR_CALL_REDRAW;
2016-06-11 21:12:00 +00:00
}
2017-05-09 17:35:43 +00:00
#endif // SDSUPPORT
2016-06-11 21:12:00 +00:00
2017-04-09 12:58:47 +00:00
void menu_action_setting_edit_bool(const char* pstr, bool* ptr) {UNUSED(pstr); *ptr ^= true; lcdDrawUpdate = LCDVIEW_CLEAR_CALL_REDRAW; }
void menu_action_setting_edit_callback_bool(const char* pstr, bool* ptr, screenFunc_t callback) {
2016-06-11 21:12:00 +00:00
menu_action_setting_edit_bool(pstr, ptr);
(*callback)();
}
#endif // ULTIPANEL
void lcd_init() {
lcd_implementation_init(
#if ENABLED(LCD_PROGRESS_BAR)
true
#endif
);
#if ENABLED(NEWPANEL)
#if BUTTON_EXISTS(EN1)
2017-03-08 05:43:33 +00:00
SET_INPUT_PULLUP(BTN_EN1);
2015-12-13 01:57:36 +00:00
#endif
#if BUTTON_EXISTS(EN2)
2017-03-08 05:43:33 +00:00
SET_INPUT_PULLUP(BTN_EN2);
2015-12-13 01:57:36 +00:00
#endif
#if BUTTON_EXISTS(ENC)
2017-03-08 05:43:33 +00:00
SET_INPUT_PULLUP(BTN_ENC);
#endif
#if ENABLED(REPRAPWORLD_KEYPAD)
2016-10-24 10:26:30 +00:00
SET_OUTPUT(SHIFT_CLK);
OUT_WRITE(SHIFT_LD, HIGH);
SET_INPUT_PULLUP(SHIFT_OUT);
#endif
2016-05-03 19:50:49 +00:00
#if BUTTON_EXISTS(UP)
2015-12-24 17:12:25 +00:00
SET_INPUT(BTN_UP);
2016-05-03 19:50:49 +00:00
#endif
#if BUTTON_EXISTS(DWN)
2015-12-24 17:12:25 +00:00
SET_INPUT(BTN_DWN);
2016-05-03 19:50:49 +00:00
#endif
#if BUTTON_EXISTS(LFT)
2015-12-24 17:12:25 +00:00
SET_INPUT(BTN_LFT);
2016-05-03 19:50:49 +00:00
#endif
#if BUTTON_EXISTS(RT)
2015-12-24 17:12:25 +00:00
SET_INPUT(BTN_RT);
2015-12-13 01:57:36 +00:00
#endif
#else // !NEWPANEL
#if ENABLED(SR_LCD_2W_NL) // Non latching 2 wire shift register
2016-10-24 10:26:30 +00:00
SET_OUTPUT(SR_DATA_PIN);
SET_OUTPUT(SR_CLK_PIN);
#elif defined(SHIFT_CLK)
2016-10-24 10:26:30 +00:00
SET_OUTPUT(SHIFT_CLK);
OUT_WRITE(SHIFT_LD, HIGH);
OUT_WRITE(SHIFT_EN, LOW);
SET_INPUT_PULLUP(SHIFT_OUT);
#endif // SR_LCD_2W_NL
#endif // !NEWPANEL
#if ENABLED(SDSUPPORT) && PIN_EXISTS(SD_DETECT)
2017-03-08 05:43:33 +00:00
SET_INPUT_PULLUP(SD_DETECT_PIN);
lcd_sd_status = 2; // UNKNOWN
#endif
#if ENABLED(LCD_HAS_SLOW_BUTTONS)
2013-11-17 16:41:30 +00:00
slow_buttons = 0;
#endif
lcd_buttons_update();
#if ENABLED(ULTIPANEL)
encoderDiff = 0;
#endif
}
int lcd_strlen(const char* s) {
int i = 0, j = 0;
while (s[i]) {
2016-07-18 19:42:41 +00:00
#if ENABLED(MAPPER_NON)
j++;
#else
2016-07-18 19:42:41 +00:00
if ((s[i] & 0xC0u) != 0x80u) j++;
#endif
i++;
}
return j;
}
int lcd_strlen_P(const char* s) {
int j = 0;
while (pgm_read_byte(s)) {
2016-07-18 19:42:41 +00:00
#if ENABLED(MAPPER_NON)
j++;
#else
2016-07-18 19:42:41 +00:00
if ((pgm_read_byte(s) & 0xC0u) != 0x80u) j++;
#endif
s++;
}
return j;
}
bool lcd_blink() {
static uint8_t blink = 0;
static millis_t next_blink_ms = 0;
millis_t ms = millis();
2016-04-10 22:55:12 +00:00
if (ELAPSED(ms, next_blink_ms)) {
blink ^= 0xFF;
next_blink_ms = ms + 1000 - LCD_UPDATE_INTERVAL / 2;
}
return blink != 0;
}
/**
* Update the LCD, read encoder buttons, etc.
* - Read button states
* - Check the SD Card slot state
* - Act on RepRap World keypad input
* - Update the encoder position
* - Apply acceleration to the encoder position
* - Set lcdDrawUpdate = LCDVIEW_CALL_REDRAW_NOW on controller events
* - Reset the Info Screen timeout if there's any input
* - Update status indicators, if any
*
2016-04-02 23:09:56 +00:00
* Run the current LCD menu handler callback function:
* - Call the handler only if lcdDrawUpdate != LCDVIEW_NONE
* - Before calling the handler, LCDVIEW_CALL_NO_REDRAW => LCDVIEW_NONE
2016-04-02 23:09:56 +00:00
* - Call the menu handler. Menu handlers should do the following:
* - If a value changes, set lcdDrawUpdate to LCDVIEW_REDRAW_NOW and draw the value
* (Encoder events automatically set lcdDrawUpdate for you.)
2016-04-02 23:09:56 +00:00
* - if (lcdDrawUpdate) { redraw }
* - Before exiting the handler set lcdDrawUpdate to:
* - LCDVIEW_CLEAR_CALL_REDRAW to clear screen and set LCDVIEW_CALL_REDRAW_NEXT.
2017-02-18 05:57:13 +00:00
* - LCDVIEW_REDRAW_NOW or LCDVIEW_NONE to keep drawing, but only in this loop.
2016-12-20 06:51:07 +00:00
* - LCDVIEW_CALL_REDRAW_NEXT to keep drawing and draw on the next loop also.
* - LCDVIEW_CALL_NO_REDRAW to keep drawing (or start drawing) with no redraw on the next loop.
* - NOTE: For graphical displays menu handlers may be called 2 or more times per loop,
* so don't change lcdDrawUpdate without considering this.
2016-04-02 23:09:56 +00:00
*
* After the menu handler callback runs (or not):
* - Clear the LCD if lcdDrawUpdate == LCDVIEW_CLEAR_CALL_REDRAW
* - Update lcdDrawUpdate for the next loop (i.e., move one state down, usually)
2016-04-02 23:09:56 +00:00
*
* No worries. This function is only called from the main thread.
*/
void lcd_update() {
2016-06-11 21:12:00 +00:00
#if ENABLED(ULTIPANEL)
2015-04-13 01:07:08 +00:00
static millis_t return_to_status_ms = 0;
manage_manual_move();
lcd_buttons_update();
2017-03-18 15:15:54 +00:00
#if ENABLED(AUTO_BED_LEVELING_UBL)
const bool UBL_CONDITION = !ubl.has_control_of_lcd_panel;
2017-03-18 15:15:54 +00:00
#else
constexpr bool UBL_CONDITION = true;
#endif
// If the action button is pressed...
2017-03-18 15:15:54 +00:00
if (UBL_CONDITION && LCD_CLICKED) {
if (!wait_for_unclick) { // If not waiting for a debounce release:
wait_for_unclick = true; // Set debounce flag to ignore continous clicks
lcd_clicked = !wait_for_user; // Keep the click if not waiting for a user-click
wait_for_user = false; // Any click clears wait for user
lcd_quick_feedback(); // Always make a click sound
}
}
else wait_for_unclick = false;
#endif
#if ENABLED(SDSUPPORT) && PIN_EXISTS(SD_DETECT)
2017-04-17 02:32:52 +00:00
const bool sd_status = IS_SD_INSERTED;
if (sd_status != lcd_sd_status && lcd_detected()) {
if (sd_status) {
card.initsd();
if (lcd_sd_status != 2) LCD_MESSAGEPGM(MSG_SD_INSERTED);
}
else {
card.release();
if (lcd_sd_status != 2) LCD_MESSAGEPGM(MSG_SD_REMOVED);
}
2016-08-09 03:53:18 +00:00
lcd_sd_status = sd_status;
lcdDrawUpdate = LCDVIEW_CLEAR_CALL_REDRAW;
lcd_implementation_init( // to maybe revive the LCD if static electricity killed it.
#if ENABLED(LCD_PROGRESS_BAR)
currentScreen == lcd_status_screen
#endif
);
}
2017-05-09 17:35:43 +00:00
#endif // SDSUPPORT && SD_DETECT_PIN
2017-04-17 02:32:52 +00:00
const millis_t ms = millis();
if (ELAPSED(ms, next_lcd_update_ms)
#if ENABLED(DOGLCD)
|| drawing_screen
#endif
) {
next_lcd_update_ms = ms + LCD_UPDATE_INTERVAL;
#if ENABLED(LCD_HAS_STATUS_INDICATORS)
lcd_implementation_update_indicators();
#endif
#if ENABLED(ULTIPANEL)
2016-08-20 23:12:57 +00:00
#if ENABLED(LCD_HAS_SLOW_BUTTONS)
slow_buttons = lcd_implementation_read_slow_buttons(); // buttons which take too long to read in interrupt context
#endif
#if ENABLED(REPRAPWORLD_KEYPAD)
handle_reprapworld_keypad();
#endif
bool encoderPastThreshold = (abs(encoderDiff) >= ENCODER_PULSES_PER_STEP);
if (encoderPastThreshold || lcd_clicked) {
if (encoderPastThreshold) {
2015-02-22 04:18:49 +00:00
int32_t encoderMultiplier = 1;
#if ENABLED(ENCODER_RATE_MULTIPLIER)
2015-02-22 04:18:49 +00:00
if (encoderRateMultiplierEnabled) {
int32_t encoderMovementSteps = abs(encoderDiff) / ENCODER_PULSES_PER_STEP;
if (lastEncoderMovementMillis != 0) {
// Note that the rate is always calculated between to passes through the
2015-02-22 04:18:49 +00:00
// loop and that the abs of the encoderDiff value is tracked.
float encoderStepRate = (float)(encoderMovementSteps) / ((float)(ms - lastEncoderMovementMillis)) * 1000.0;
if (encoderStepRate >= ENCODER_100X_STEPS_PER_SEC) encoderMultiplier = 100;
else if (encoderStepRate >= ENCODER_10X_STEPS_PER_SEC) encoderMultiplier = 10;
#if ENABLED(ENCODER_RATE_MULTIPLIER_DEBUG)
2015-02-22 04:18:49 +00:00
SERIAL_ECHO_START;
SERIAL_ECHOPAIR("Enc Step Rate: ", encoderStepRate);
SERIAL_ECHOPAIR(" Multiplier: ", encoderMultiplier);
SERIAL_ECHOPAIR(" ENCODER_10X_STEPS_PER_SEC: ", ENCODER_10X_STEPS_PER_SEC);
SERIAL_ECHOPAIR(" ENCODER_100X_STEPS_PER_SEC: ", ENCODER_100X_STEPS_PER_SEC);
SERIAL_EOL;
2017-05-09 17:35:43 +00:00
#endif // ENCODER_RATE_MULTIPLIER_DEBUG
2015-02-22 04:18:49 +00:00
}
lastEncoderMovementMillis = ms;
} // encoderRateMultiplierEnabled
2017-05-09 17:35:43 +00:00
#endif // ENCODER_RATE_MULTIPLIER
2015-02-22 04:18:49 +00:00
encoderPosition += (encoderDiff * encoderMultiplier) / ENCODER_PULSES_PER_STEP;
encoderDiff = 0;
}
2015-04-13 01:07:08 +00:00
return_to_status_ms = ms + LCD_TIMEOUT_TO_STATUS;
2017-02-18 05:57:13 +00:00
lcdDrawUpdate = LCDVIEW_KEEP_REDRAWING;
}
#endif // ULTIPANEL
// We arrive here every ~100ms when idling often enough.
// Instead of tracking the changes simply redraw the Info Screen ~1 time a second.
static int8_t lcd_status_update_delay = 1; // first update one loop delayed
if (
#if ENABLED(ULTIPANEL)
currentScreen == lcd_status_screen &&
#endif
!lcd_status_update_delay--
) {
lcd_status_update_delay = 9
2016-12-14 12:20:33 +00:00
#if ENABLED(DOGLCD)
+ 3
#endif
;
max_display_update_time--;
lcdDrawUpdate = LCDVIEW_REDRAW_NOW;
}
2015-04-13 01:07:08 +00:00
// then we want to use 1/2 of the time only.
uint16_t bbr2 = planner.block_buffer_runtime() >> 1;
#if ENABLED(DOGLCD)
if ((lcdDrawUpdate || drawing_screen) && (!bbr2 || (bbr2 > max_display_update_time)))
#else
if (lcdDrawUpdate && (!bbr2 || (bbr2 > max_display_update_time)))
#endif
{
Distribute GLCD screen updates in time Currently we draw and send the screens for a graphical LCD all at once. We draw in two or four parts but draw them directly behind each other. For the tested status screen this takes 59-62ms in a single block. During this time nothing else (except the interrupts) can be done. When printing a sequence of very short moves the buffer drains - sometimes until it's empty. This PR splits the screen update into parts. Currently we have 10 time slots. During the first one the complete screen is drawn. (60,0,0,0,0,0,0,0,0,0,0) Here i introduce pauses for doing other things. (30,30,0,0,0,0,0,0) or (15,15,15,15,0,0,0,0,0,0) Drawing in consecutive time slots prevents from lagging too much. Even with a 4 stripe display all the drawing is done after 400ms. Previous experiments with a even better distribution of the time slots like (30,0,0,0,0,30,0,0,0,0) and (15,0,15,0,15,0,15,0,0,0) did not feel good when using the menu, because of too much lag. Because of the previous PRs to speed up the display updates and especially reducing the difference between drawing 2 or 4 stripes, it now makes sense for the REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER to go from 2 to 4 stripes. This costs about 1-2ms per complete screen update, but is payed back by having partial updates lasting only the half time and two additional brakes. Also ~256 byte of framebuffer are saved in RAM. 13:45:59.213 : echo: #:17 >:13 s:30; #:16 >:13 s:29; S#:33 S>:26 S:59 13:46:00.213 : echo: #:16 >:14 s:30; #:17 >:13 s:30; S#:33 S>:27 S:60 13:46:01.215 : echo: #:17 >:13 s:30; #:16 >:13 s:29; S#:33 S>:26 S:59 13:46:02.215 : echo: #:16 >:13 s:29; #:16 >:14 s:30; S#:32 S>:27 S:59 13:46:03.214 : echo: #:17 >:13 s:30; #:17 >:13 s:30; S#:34 S>:26 S:60 13:46:04.214 : echo: #:16 >:13 s:29; #:16 >:14 s:30; S#:32 S>:27 S:59 13:46:05.212 : echo: #:16 >:14 s:30; #:17 >:13 s:30; S#:33 S>:27 S:60 13:46:06.212 : echo: #:17 >:13 s:30; #:16 >:13 s:29; S#:33 S>:26 S:59 03:30:36.779 : echo: #:8 >:7 s:15; #:10 >:7 s:17; #:8 >:6 s:14; #:8 >:7 s:15; S#:34 S>:27 S:61 03:30:37.778 : echo: #:8 >:6 s:14; #:10 >:7 s:17; #:9 >:7 s:16; #:8 >:6 s:14; S#:35 S>:26 S:61 03:30:38.778 : echo: #:8 >:6 s:14; #:11 >:7 s:18; #:8 >:6 s:14; #:8 >:7 s:15; S#:35 S>:26 S:61 03:30:39.777 : echo: #:8 >:6 s:14; #:10 >:7 s:17; #:8 >:8 s:16; #:8 >:6 s:14; S#:34 S>:27 S:61 03:30:40.780 : echo: #:8 >:6 s:14; #:11 >:7 s:18; #:8 >:6 s:14; #:8 >:6 s:14; S#:35 S>:25 S:60 03:30:41.780 : echo: #:9 >:6 s:15; #:10 >:7 s:17; #:8 >:6 s:14; #:9 >:6 s:15; S#:36 S>:25 S:61 03:30:42.779 : echo: #:8 >:6 s:14; #:10 >:8 s:18; #:8 >:6 s:14; #:8 >:6 s:14; S#:34 S>:26 S:60 03:30:43.778 : echo: #:9 >:6 s:15; #:10 >:7 s:17; #:8 >:7 s:15; #:9 >:6 s:15; S#:36 S>:26 S:62 #: draw a stripe >: transfer a stripe s: sum of of draw and transfer for one stripe S#: sum of draws for a complete screen S>: sum of transfers for a complete screen S: time to draw and transfer a complete screen
2016-11-24 20:17:25 +00:00
#if ENABLED(DOGLCD)
if (!drawing_screen)
#endif
{
switch (lcdDrawUpdate) {
case LCDVIEW_CALL_NO_REDRAW:
Distribute GLCD screen updates in time Currently we draw and send the screens for a graphical LCD all at once. We draw in two or four parts but draw them directly behind each other. For the tested status screen this takes 59-62ms in a single block. During this time nothing else (except the interrupts) can be done. When printing a sequence of very short moves the buffer drains - sometimes until it's empty. This PR splits the screen update into parts. Currently we have 10 time slots. During the first one the complete screen is drawn. (60,0,0,0,0,0,0,0,0,0,0) Here i introduce pauses for doing other things. (30,30,0,0,0,0,0,0) or (15,15,15,15,0,0,0,0,0,0) Drawing in consecutive time slots prevents from lagging too much. Even with a 4 stripe display all the drawing is done after 400ms. Previous experiments with a even better distribution of the time slots like (30,0,0,0,0,30,0,0,0,0) and (15,0,15,0,15,0,15,0,0,0) did not feel good when using the menu, because of too much lag. Because of the previous PRs to speed up the display updates and especially reducing the difference between drawing 2 or 4 stripes, it now makes sense for the REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER to go from 2 to 4 stripes. This costs about 1-2ms per complete screen update, but is payed back by having partial updates lasting only the half time and two additional brakes. Also ~256 byte of framebuffer are saved in RAM. 13:45:59.213 : echo: #:17 >:13 s:30; #:16 >:13 s:29; S#:33 S>:26 S:59 13:46:00.213 : echo: #:16 >:14 s:30; #:17 >:13 s:30; S#:33 S>:27 S:60 13:46:01.215 : echo: #:17 >:13 s:30; #:16 >:13 s:29; S#:33 S>:26 S:59 13:46:02.215 : echo: #:16 >:13 s:29; #:16 >:14 s:30; S#:32 S>:27 S:59 13:46:03.214 : echo: #:17 >:13 s:30; #:17 >:13 s:30; S#:34 S>:26 S:60 13:46:04.214 : echo: #:16 >:13 s:29; #:16 >:14 s:30; S#:32 S>:27 S:59 13:46:05.212 : echo: #:16 >:14 s:30; #:17 >:13 s:30; S#:33 S>:27 S:60 13:46:06.212 : echo: #:17 >:13 s:30; #:16 >:13 s:29; S#:33 S>:26 S:59 03:30:36.779 : echo: #:8 >:7 s:15; #:10 >:7 s:17; #:8 >:6 s:14; #:8 >:7 s:15; S#:34 S>:27 S:61 03:30:37.778 : echo: #:8 >:6 s:14; #:10 >:7 s:17; #:9 >:7 s:16; #:8 >:6 s:14; S#:35 S>:26 S:61 03:30:38.778 : echo: #:8 >:6 s:14; #:11 >:7 s:18; #:8 >:6 s:14; #:8 >:7 s:15; S#:35 S>:26 S:61 03:30:39.777 : echo: #:8 >:6 s:14; #:10 >:7 s:17; #:8 >:8 s:16; #:8 >:6 s:14; S#:34 S>:27 S:61 03:30:40.780 : echo: #:8 >:6 s:14; #:11 >:7 s:18; #:8 >:6 s:14; #:8 >:6 s:14; S#:35 S>:25 S:60 03:30:41.780 : echo: #:9 >:6 s:15; #:10 >:7 s:17; #:8 >:6 s:14; #:9 >:6 s:15; S#:36 S>:25 S:61 03:30:42.779 : echo: #:8 >:6 s:14; #:10 >:8 s:18; #:8 >:6 s:14; #:8 >:6 s:14; S#:34 S>:26 S:60 03:30:43.778 : echo: #:9 >:6 s:15; #:10 >:7 s:17; #:8 >:7 s:15; #:9 >:6 s:15; S#:36 S>:26 S:62 #: draw a stripe >: transfer a stripe s: sum of of draw and transfer for one stripe S#: sum of draws for a complete screen S>: sum of transfers for a complete screen S: time to draw and transfer a complete screen
2016-11-24 20:17:25 +00:00
lcdDrawUpdate = LCDVIEW_NONE;
break;
case LCDVIEW_CLEAR_CALL_REDRAW: // set by handlers, then altered after (rarely occurs here)
case LCDVIEW_CALL_REDRAW_NEXT: // set by handlers, then altered after (never occurs here?)
lcdDrawUpdate = LCDVIEW_REDRAW_NOW;
case LCDVIEW_REDRAW_NOW: // set above, or by a handler through LCDVIEW_CALL_REDRAW_NEXT
Distribute GLCD screen updates in time Currently we draw and send the screens for a graphical LCD all at once. We draw in two or four parts but draw them directly behind each other. For the tested status screen this takes 59-62ms in a single block. During this time nothing else (except the interrupts) can be done. When printing a sequence of very short moves the buffer drains - sometimes until it's empty. This PR splits the screen update into parts. Currently we have 10 time slots. During the first one the complete screen is drawn. (60,0,0,0,0,0,0,0,0,0,0) Here i introduce pauses for doing other things. (30,30,0,0,0,0,0,0) or (15,15,15,15,0,0,0,0,0,0) Drawing in consecutive time slots prevents from lagging too much. Even with a 4 stripe display all the drawing is done after 400ms. Previous experiments with a even better distribution of the time slots like (30,0,0,0,0,30,0,0,0,0) and (15,0,15,0,15,0,15,0,0,0) did not feel good when using the menu, because of too much lag. Because of the previous PRs to speed up the display updates and especially reducing the difference between drawing 2 or 4 stripes, it now makes sense for the REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER to go from 2 to 4 stripes. This costs about 1-2ms per complete screen update, but is payed back by having partial updates lasting only the half time and two additional brakes. Also ~256 byte of framebuffer are saved in RAM. 13:45:59.213 : echo: #:17 >:13 s:30; #:16 >:13 s:29; S#:33 S>:26 S:59 13:46:00.213 : echo: #:16 >:14 s:30; #:17 >:13 s:30; S#:33 S>:27 S:60 13:46:01.215 : echo: #:17 >:13 s:30; #:16 >:13 s:29; S#:33 S>:26 S:59 13:46:02.215 : echo: #:16 >:13 s:29; #:16 >:14 s:30; S#:32 S>:27 S:59 13:46:03.214 : echo: #:17 >:13 s:30; #:17 >:13 s:30; S#:34 S>:26 S:60 13:46:04.214 : echo: #:16 >:13 s:29; #:16 >:14 s:30; S#:32 S>:27 S:59 13:46:05.212 : echo: #:16 >:14 s:30; #:17 >:13 s:30; S#:33 S>:27 S:60 13:46:06.212 : echo: #:17 >:13 s:30; #:16 >:13 s:29; S#:33 S>:26 S:59 03:30:36.779 : echo: #:8 >:7 s:15; #:10 >:7 s:17; #:8 >:6 s:14; #:8 >:7 s:15; S#:34 S>:27 S:61 03:30:37.778 : echo: #:8 >:6 s:14; #:10 >:7 s:17; #:9 >:7 s:16; #:8 >:6 s:14; S#:35 S>:26 S:61 03:30:38.778 : echo: #:8 >:6 s:14; #:11 >:7 s:18; #:8 >:6 s:14; #:8 >:7 s:15; S#:35 S>:26 S:61 03:30:39.777 : echo: #:8 >:6 s:14; #:10 >:7 s:17; #:8 >:8 s:16; #:8 >:6 s:14; S#:34 S>:27 S:61 03:30:40.780 : echo: #:8 >:6 s:14; #:11 >:7 s:18; #:8 >:6 s:14; #:8 >:6 s:14; S#:35 S>:25 S:60 03:30:41.780 : echo: #:9 >:6 s:15; #:10 >:7 s:17; #:8 >:6 s:14; #:9 >:6 s:15; S#:36 S>:25 S:61 03:30:42.779 : echo: #:8 >:6 s:14; #:10 >:8 s:18; #:8 >:6 s:14; #:8 >:6 s:14; S#:34 S>:26 S:60 03:30:43.778 : echo: #:9 >:6 s:15; #:10 >:7 s:17; #:8 >:7 s:15; #:9 >:6 s:15; S#:36 S>:26 S:62 #: draw a stripe >: transfer a stripe s: sum of of draw and transfer for one stripe S#: sum of draws for a complete screen S>: sum of transfers for a complete screen S: time to draw and transfer a complete screen
2016-11-24 20:17:25 +00:00
case LCDVIEW_NONE:
break;
} // switch
}
#if ENABLED(ULTIPANEL)
#define CURRENTSCREEN() (*currentScreen)(), lcd_clicked = false
#else
#define CURRENTSCREEN() lcd_status_screen()
#endif
#if ENABLED(DOGLCD) // Changes due to different driver architecture of the DOGM display
if (!drawing_screen) {
u8g.firstPage();
drawing_screen = 1;
}
lcd_setFont(FONT_MENU);
u8g.setColorIndex(1);
CURRENTSCREEN();
if (drawing_screen && (drawing_screen = u8g.nextPage())) {
2016-12-14 12:20:33 +00:00
NOLESS(max_display_update_time, millis() - ms);
return;
}
#else
CURRENTSCREEN();
#endif
2016-12-14 12:20:33 +00:00
NOLESS(max_display_update_time, millis() - ms);
}
#if ENABLED(ULTIPANEL)
// Return to Status Screen after a timeout
if (currentScreen == lcd_status_screen || defer_return_to_status)
return_to_status_ms = ms + LCD_TIMEOUT_TO_STATUS;
else if (ELAPSED(ms, return_to_status_ms))
lcd_return_to_status();
#endif // ULTIPANEL
#if ENABLED(DOGLCD)
if (!drawing_screen)
#endif
{
switch (lcdDrawUpdate) {
case LCDVIEW_CLEAR_CALL_REDRAW:
lcd_implementation_clear();
case LCDVIEW_CALL_REDRAW_NEXT:
lcdDrawUpdate = LCDVIEW_REDRAW_NOW;
break;
case LCDVIEW_REDRAW_NOW:
lcdDrawUpdate = LCDVIEW_NONE;
break;
case LCDVIEW_NONE:
break;
} // switch
}
Distribute GLCD screen updates in time Currently we draw and send the screens for a graphical LCD all at once. We draw in two or four parts but draw them directly behind each other. For the tested status screen this takes 59-62ms in a single block. During this time nothing else (except the interrupts) can be done. When printing a sequence of very short moves the buffer drains - sometimes until it's empty. This PR splits the screen update into parts. Currently we have 10 time slots. During the first one the complete screen is drawn. (60,0,0,0,0,0,0,0,0,0,0) Here i introduce pauses for doing other things. (30,30,0,0,0,0,0,0) or (15,15,15,15,0,0,0,0,0,0) Drawing in consecutive time slots prevents from lagging too much. Even with a 4 stripe display all the drawing is done after 400ms. Previous experiments with a even better distribution of the time slots like (30,0,0,0,0,30,0,0,0,0) and (15,0,15,0,15,0,15,0,0,0) did not feel good when using the menu, because of too much lag. Because of the previous PRs to speed up the display updates and especially reducing the difference between drawing 2 or 4 stripes, it now makes sense for the REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER to go from 2 to 4 stripes. This costs about 1-2ms per complete screen update, but is payed back by having partial updates lasting only the half time and two additional brakes. Also ~256 byte of framebuffer are saved in RAM. 13:45:59.213 : echo: #:17 >:13 s:30; #:16 >:13 s:29; S#:33 S>:26 S:59 13:46:00.213 : echo: #:16 >:14 s:30; #:17 >:13 s:30; S#:33 S>:27 S:60 13:46:01.215 : echo: #:17 >:13 s:30; #:16 >:13 s:29; S#:33 S>:26 S:59 13:46:02.215 : echo: #:16 >:13 s:29; #:16 >:14 s:30; S#:32 S>:27 S:59 13:46:03.214 : echo: #:17 >:13 s:30; #:17 >:13 s:30; S#:34 S>:26 S:60 13:46:04.214 : echo: #:16 >:13 s:29; #:16 >:14 s:30; S#:32 S>:27 S:59 13:46:05.212 : echo: #:16 >:14 s:30; #:17 >:13 s:30; S#:33 S>:27 S:60 13:46:06.212 : echo: #:17 >:13 s:30; #:16 >:13 s:29; S#:33 S>:26 S:59 03:30:36.779 : echo: #:8 >:7 s:15; #:10 >:7 s:17; #:8 >:6 s:14; #:8 >:7 s:15; S#:34 S>:27 S:61 03:30:37.778 : echo: #:8 >:6 s:14; #:10 >:7 s:17; #:9 >:7 s:16; #:8 >:6 s:14; S#:35 S>:26 S:61 03:30:38.778 : echo: #:8 >:6 s:14; #:11 >:7 s:18; #:8 >:6 s:14; #:8 >:7 s:15; S#:35 S>:26 S:61 03:30:39.777 : echo: #:8 >:6 s:14; #:10 >:7 s:17; #:8 >:8 s:16; #:8 >:6 s:14; S#:34 S>:27 S:61 03:30:40.780 : echo: #:8 >:6 s:14; #:11 >:7 s:18; #:8 >:6 s:14; #:8 >:6 s:14; S#:35 S>:25 S:60 03:30:41.780 : echo: #:9 >:6 s:15; #:10 >:7 s:17; #:8 >:6 s:14; #:9 >:6 s:15; S#:36 S>:25 S:61 03:30:42.779 : echo: #:8 >:6 s:14; #:10 >:8 s:18; #:8 >:6 s:14; #:8 >:6 s:14; S#:34 S>:26 S:60 03:30:43.778 : echo: #:9 >:6 s:15; #:10 >:7 s:17; #:8 >:7 s:15; #:9 >:6 s:15; S#:36 S>:26 S:62 #: draw a stripe >: transfer a stripe s: sum of of draw and transfer for one stripe S#: sum of draws for a complete screen S>: sum of transfers for a complete screen S: time to draw and transfer a complete screen
2016-11-24 20:17:25 +00:00
} // ELAPSED(ms, next_lcd_update_ms)
}
2016-07-17 18:33:01 +00:00
void set_utf_strlen(char* s, uint8_t n) {
uint8_t i = 0, j = 0;
while (s[i] && (j < n)) {
#if ENABLED(MAPPER_NON)
j++;
#else
if ((s[i] & 0xC0u) != 0x80u) j++;
#endif
2016-07-17 18:33:01 +00:00
i++;
}
while (j++ < n) s[i++] = ' ';
s[i] = '\0';
}
void lcd_finishstatus(bool persist=false) {
2016-07-17 18:33:01 +00:00
set_utf_strlen(lcd_status_message, LCD_WIDTH);
2016-04-02 21:28:17 +00:00
#if !(ENABLED(LCD_PROGRESS_BAR) && (PROGRESS_MSG_EXPIRE > 0))
UNUSED(persist);
#endif
#if ENABLED(LCD_PROGRESS_BAR)
progress_bar_ms = millis();
2014-12-28 06:26:14 +00:00
#if PROGRESS_MSG_EXPIRE > 0
expire_status_ms = persist ? 0 : progress_bar_ms + PROGRESS_MSG_EXPIRE;
2014-12-28 06:26:14 +00:00
#endif
#endif
lcdDrawUpdate = LCDVIEW_CLEAR_CALL_REDRAW;
2014-12-28 06:26:14 +00:00
#if ENABLED(FILAMENT_LCD_DISPLAY) && ENABLED(SDSUPPORT)
2015-04-13 01:07:08 +00:00
previous_lcd_status_ms = millis(); //get status message to show up for a while
2014-12-28 06:26:14 +00:00
#endif
}
#if ENABLED(LCD_PROGRESS_BAR) && PROGRESS_MSG_EXPIRE > 0
void dontExpireStatus() { expire_status_ms = 0; }
#endif
bool lcd_hasstatus() { return (lcd_status_message[0] != '\0'); }
void lcd_setstatus(const char * const message, const bool persist) {
if (lcd_status_message_level > 0) return;
2016-03-13 06:38:55 +00:00
strncpy(lcd_status_message, message, 3 * (LCD_WIDTH));
lcd_finishstatus(persist);
}
void lcd_setstatuspgm(const char * const message, const uint8_t level) {
2016-07-17 18:33:01 +00:00
if (level < lcd_status_message_level) return;
lcd_status_message_level = level;
strncpy_P(lcd_status_message, message, 3 * (LCD_WIDTH));
lcd_finishstatus(level > 0);
}
2017-04-02 05:46:37 +00:00
void lcd_status_printf_P(const uint8_t level, const char * const fmt, ...) {
if (level < lcd_status_message_level) return;
lcd_status_message_level = level;
va_list args;
2017-04-02 05:46:37 +00:00
va_start(args, fmt);
vsnprintf_P(lcd_status_message, 3 * (LCD_WIDTH), fmt, args);
va_end(args);
lcd_finishstatus(level > 0);
}
void lcd_setalertstatuspgm(const char * const message) {
lcd_setstatuspgm(message, 1);
#if ENABLED(ULTIPANEL)
lcd_return_to_status();
#endif
}
void lcd_reset_alert_level() { lcd_status_message_level = 0; }
2016-05-31 18:47:02 +00:00
#if HAS_LCD_CONTRAST
void set_lcd_contrast(const int value) {
lcd_contrast = constrain(value, LCD_CONTRAST_MIN, LCD_CONTRAST_MAX);
u8g.setContrast(lcd_contrast);
}
#endif
#if ENABLED(ULTIPANEL)
/**
* Setup Rotary Encoder Bit Values (for two pin encoders to indicate movement)
* These values are independent of which pins are used for EN_A and EN_B indications
* The rotary encoder part is also independent to the chipset used for the LCD
*/
#if defined(EN_A) && defined(EN_B)
#define encrot0 0
#define encrot1 2
#define encrot2 3
#define encrot3 1
#endif
#define GET_BUTTON_STATES(DST) \
uint8_t new_##DST = 0; \
WRITE(SHIFT_LD, LOW); \
WRITE(SHIFT_LD, HIGH); \
for (int8_t i = 0; i < 8; i++) { \
new_##DST >>= 1; \
if (READ(SHIFT_OUT)) SBI(new_##DST, 7); \
WRITE(SHIFT_CLK, HIGH); \
WRITE(SHIFT_CLK, LOW); \
} \
DST = ~new_##DST; //invert it, because a pressed switch produces a logical 0
/**
* Read encoder buttons from the hardware registers
* Warning: This function is called from interrupt context!
*/
void lcd_buttons_update() {
2017-04-17 02:32:52 +00:00
static uint8_t lastEncoderBits;
millis_t now = millis();
if (ELAPSED(now, next_button_update_ms)) {
#if ENABLED(NEWPANEL)
uint8_t newbutton = 0;
#if BUTTON_EXISTS(EN1)
if (BUTTON_PRESSED(EN1)) newbutton |= EN_A;
#endif
#if BUTTON_EXISTS(EN2)
if (BUTTON_PRESSED(EN2)) newbutton |= EN_B;
#endif
#if BUTTON_EXISTS(ENC)
if (BUTTON_PRESSED(ENC)) newbutton |= EN_C;
#endif
#if LCD_HAS_DIRECTIONAL_BUTTONS
2016-05-03 19:50:49 +00:00
// Manage directional buttons
#if ENABLED(REVERSE_MENU_DIRECTION)
#define _ENCODER_UD_STEPS (ENCODER_STEPS_PER_MENU_ITEM * encoderDirection)
#else
#define _ENCODER_UD_STEPS ENCODER_STEPS_PER_MENU_ITEM
#endif
#if ENABLED(REVERSE_ENCODER_DIRECTION)
#define ENCODER_UD_STEPS _ENCODER_UD_STEPS
#define ENCODER_LR_PULSES ENCODER_PULSES_PER_STEP
#else
#define ENCODER_UD_STEPS -(_ENCODER_UD_STEPS)
#define ENCODER_LR_PULSES -(ENCODER_PULSES_PER_STEP)
#endif
2016-05-03 19:50:49 +00:00
if (false) {
// for the else-ifs below
}
2016-05-03 19:50:49 +00:00
#if BUTTON_EXISTS(UP)
else if (BUTTON_PRESSED(UP)) {
encoderDiff = -(ENCODER_UD_STEPS);
2016-05-03 19:50:49 +00:00
next_button_update_ms = now + 300;
}
#endif
#if BUTTON_EXISTS(DWN)
else if (BUTTON_PRESSED(DWN)) {
encoderDiff = ENCODER_UD_STEPS;
2016-05-03 19:50:49 +00:00
next_button_update_ms = now + 300;
}
#endif
#if BUTTON_EXISTS(LFT)
else if (BUTTON_PRESSED(LFT)) {
encoderDiff = -(ENCODER_LR_PULSES);
2016-05-03 19:50:49 +00:00
next_button_update_ms = now + 300;
}
#endif
#if BUTTON_EXISTS(RT)
else if (BUTTON_PRESSED(RT)) {
encoderDiff = ENCODER_LR_PULSES;
2016-05-03 19:50:49 +00:00
next_button_update_ms = now + 300;
}
#endif
#endif // LCD_HAS_DIRECTIONAL_BUTTONS
2016-05-03 19:50:49 +00:00
buttons = newbutton;
#if ENABLED(LCD_HAS_SLOW_BUTTONS)
buttons |= slow_buttons;
#endif
#if ENABLED(REPRAPWORLD_KEYPAD)
GET_BUTTON_STATES(buttons_reprapworld_keypad);
#endif
#else
GET_BUTTON_STATES(buttons);
2017-05-09 17:35:43 +00:00
#endif // !NEWPANEL
} // next_button_update_ms
// Manage encoder rotation
2016-05-11 22:39:28 +00:00
#if ENABLED(REVERSE_MENU_DIRECTION) && ENABLED(REVERSE_ENCODER_DIRECTION)
#define ENCODER_DIFF_CW (encoderDiff -= encoderDirection)
#define ENCODER_DIFF_CCW (encoderDiff += encoderDirection)
#elif ENABLED(REVERSE_MENU_DIRECTION)
#define ENCODER_DIFF_CW (encoderDiff += encoderDirection)
#define ENCODER_DIFF_CCW (encoderDiff -= encoderDirection)
2016-05-11 22:39:28 +00:00
#elif ENABLED(REVERSE_ENCODER_DIRECTION)
#define ENCODER_DIFF_CW (encoderDiff--)
#define ENCODER_DIFF_CCW (encoderDiff++)
#else
#define ENCODER_DIFF_CW (encoderDiff++)
#define ENCODER_DIFF_CCW (encoderDiff--)
#endif
#define ENCODER_SPIN(_E1, _E2) switch (lastEncoderBits) { case _E1: ENCODER_DIFF_CW; break; case _E2: ENCODER_DIFF_CCW; }
uint8_t enc = 0;
if (buttons & EN_A) enc |= B01;
if (buttons & EN_B) enc |= B10;
if (enc != lastEncoderBits) {
switch (enc) {
case encrot0: ENCODER_SPIN(encrot3, encrot1); break;
case encrot1: ENCODER_SPIN(encrot0, encrot2); break;
case encrot2: ENCODER_SPIN(encrot1, encrot3); break;
case encrot3: ENCODER_SPIN(encrot2, encrot0); break;
}
2017-03-18 15:15:54 +00:00
#if ENABLED(AUTO_BED_LEVELING_UBL)
if (ubl.has_control_of_lcd_panel) {
ubl.encoder_diff = encoderDiff; // Make the encoder's rotation available to G29's Mesh Editor
2017-03-18 15:15:54 +00:00
encoderDiff = 0; // We are going to lie to the LCD Panel and claim the encoder
// wheel has not turned.
}
#endif
lastEncoderBits = enc;
}
}
2016-11-03 23:03:02 +00:00
#if (ENABLED(LCD_I2C_TYPE_MCP23017) || ENABLED(LCD_I2C_TYPE_MCP23008)) && ENABLED(DETECT_DEVICE)
bool lcd_detected() { return lcd.LcdDetected() == 1; }
2016-12-08 05:29:06 +00:00
#else
bool lcd_detected() { return true; }
2016-11-03 23:03:02 +00:00
#endif
2017-03-18 15:15:54 +00:00
#if ENABLED(AUTO_BED_LEVELING_UBL)
2017-03-20 06:42:41 +00:00
2017-03-18 15:15:54 +00:00
void chirp_at_user() {
#if ENABLED(LCD_USE_I2C_BUZZER)
lcd.buzz(LCD_FEEDBACK_FREQUENCY_DURATION_MS, LCD_FEEDBACK_FREQUENCY_HZ);
#elif PIN_EXISTS(BEEPER)
buzzer.tone(LCD_FEEDBACK_FREQUENCY_DURATION_MS, LCD_FEEDBACK_FREQUENCY_HZ);
#endif
}
2017-03-20 06:42:41 +00:00
bool ubl_lcd_clicked() { return LCD_CLICKED; }
2017-03-18 15:15:54 +00:00
#endif
#endif // ULTIPANEL
#endif // ULTRA_LCD