dbe2ed4150
Remove the conflicting and mostly useless card.paused flag (the printing is either paused, or not) and switch to isPrintPaused only which accounts for both cases (SD/USB) correctly. Fix M27/getStatus to show the current real status of the SD print. Synchronize the queue on M601, as required to precisely pause the print at the correct instruction. Alias M25 to M601, which when combined with PR #1899 fixes issue #1614. Guard against incorrect usage in M601, M602 and M603.
9045 lines
260 KiB
C++
Executable File
9045 lines
260 KiB
C++
Executable File
//! @file
|
|
//! @date Aug 28, 2019
|
|
//! @author mkbel
|
|
//! @brief LCD
|
|
|
|
#include "temperature.h"
|
|
#include "ultralcd.h"
|
|
#include "fsensor.h"
|
|
#include "Marlin.h"
|
|
#include "language.h"
|
|
#include "cardreader.h"
|
|
#include "temperature.h"
|
|
#include "stepper.h"
|
|
#include "ConfigurationStore.h"
|
|
#include "printers.h"
|
|
#include <string.h>
|
|
|
|
|
|
#include "lcd.h"
|
|
#include "menu.h"
|
|
|
|
#include "util.h"
|
|
#include "mesh_bed_leveling.h"
|
|
#include "mesh_bed_calibration.h"
|
|
|
|
//#include "Configuration.h"
|
|
#include "cmdqueue.h"
|
|
|
|
#include "SdFatUtil.h"
|
|
|
|
#ifdef FILAMENT_SENSOR
|
|
#include "pat9125.h"
|
|
#include "fsensor.h"
|
|
#endif //FILAMENT_SENSOR
|
|
|
|
#ifdef TMC2130
|
|
#include "tmc2130.h"
|
|
#endif //TMC2130
|
|
|
|
#include "sound.h"
|
|
|
|
#include "mmu.h"
|
|
|
|
#include "static_assert.h"
|
|
#include "io_atmega2560.h"
|
|
#include "first_lay_cal.h"
|
|
|
|
#include "fsensor.h"
|
|
#include "adc.h"
|
|
#include "config.h"
|
|
|
|
|
|
int scrollstuff = 0;
|
|
char longFilenameOLD[LONG_FILENAME_LENGTH];
|
|
|
|
|
|
static void lcd_sd_updir();
|
|
static void lcd_mesh_bed_leveling_settings();
|
|
|
|
int8_t ReInitLCD = 0;
|
|
|
|
|
|
int8_t SilentModeMenu = SILENT_MODE_OFF;
|
|
uint8_t SilentModeMenu_MMU = 1; //activate mmu unit stealth mode
|
|
|
|
int8_t FSensorStateMenu = 1;
|
|
|
|
|
|
#ifdef SDCARD_SORT_ALPHA
|
|
bool presort_flag = false;
|
|
#endif
|
|
|
|
LcdCommands lcd_commands_type = LcdCommands::Idle;
|
|
static uint8_t lcd_commands_step = 0;
|
|
|
|
CustomMsg custom_message_type = CustomMsg::Status;
|
|
unsigned int custom_message_state = 0;
|
|
|
|
|
|
bool isPrintPaused = false;
|
|
uint8_t farm_mode = 0;
|
|
int farm_no = 0;
|
|
int farm_timer = 8;
|
|
uint8_t farm_status = 0;
|
|
bool printer_connected = true;
|
|
|
|
unsigned long display_time; //just timer for showing pid finished message on lcd;
|
|
float pid_temp = DEFAULT_PID_TEMP;
|
|
|
|
static bool forceMenuExpire = false;
|
|
static bool lcd_autoDeplete;
|
|
|
|
|
|
static float manual_feedrate[] = MANUAL_FEEDRATE;
|
|
|
|
/* !Configuration settings */
|
|
|
|
uint8_t lcd_status_message_level;
|
|
char lcd_status_message[LCD_WIDTH + 1] = ""; //////WELCOME!
|
|
unsigned char firstrun = 1;
|
|
|
|
static uint8_t lay1cal_filament = 0;
|
|
|
|
|
|
static const char separator[] PROGMEM = "--------------------";
|
|
|
|
/** forward declarations **/
|
|
|
|
static const char* lcd_display_message_fullscreen_nonBlocking_P(const char *msg, uint8_t &nlines);
|
|
// void copy_and_scalePID_i();
|
|
// void copy_and_scalePID_d();
|
|
|
|
/* Different menus */
|
|
static void lcd_status_screen();
|
|
static void lcd_language_menu();
|
|
static void lcd_main_menu();
|
|
static void lcd_tune_menu();
|
|
//static void lcd_move_menu();
|
|
static void lcd_settings_menu();
|
|
static void lcd_calibration_menu();
|
|
static void lcd_control_temperature_menu();
|
|
static void lcd_settings_linearity_correction_menu_save();
|
|
static void prusa_stat_printerstatus(int _status);
|
|
static void prusa_stat_farm_number();
|
|
static void prusa_stat_diameter();
|
|
static void prusa_stat_temperatures();
|
|
static void prusa_stat_printinfo();
|
|
static void lcd_farm_no();
|
|
static void lcd_menu_xyz_y_min();
|
|
static void lcd_menu_xyz_skew();
|
|
static void lcd_menu_xyz_offset();
|
|
static void lcd_menu_fails_stats_mmu();
|
|
static void lcd_menu_fails_stats_mmu_print();
|
|
static void lcd_menu_fails_stats_mmu_total();
|
|
static void mmu_unload_filament();
|
|
static void lcd_v2_calibration();
|
|
//static void lcd_menu_show_sensors_state(); // NOT static due to using inside "Marlin_main" module ("manage_inactivity()")
|
|
|
|
static void mmu_fil_eject_menu();
|
|
static void mmu_load_to_nozzle_menu();
|
|
static void preheat_or_continue();
|
|
|
|
#ifdef MMU_HAS_CUTTER
|
|
static void mmu_cut_filament_menu();
|
|
#endif //MMU_HAS_CUTTER
|
|
|
|
#if defined(TMC2130) || defined(FILAMENT_SENSOR)
|
|
static void lcd_menu_fails_stats();
|
|
#endif //TMC2130 or FILAMENT_SENSOR
|
|
|
|
#ifdef TMC2130
|
|
static void lcd_belttest_v();
|
|
#endif //TMC2130
|
|
|
|
static void lcd_selftest_v();
|
|
|
|
#ifdef TMC2130
|
|
static void reset_crash_det(unsigned char axis);
|
|
static bool lcd_selfcheck_axis_sg(unsigned char axis);
|
|
static bool lcd_selfcheck_axis(int _axis, int _travel);
|
|
#else
|
|
static bool lcd_selfcheck_endstops();
|
|
static bool lcd_selfcheck_axis(int _axis, int _travel);
|
|
static bool lcd_selfcheck_pulleys(int axis);
|
|
#endif //TMC2130
|
|
|
|
static bool lcd_selfcheck_check_heater(bool _isbed);
|
|
enum class TestScreen : uint_least8_t
|
|
{
|
|
ExtruderFan,
|
|
PrintFan,
|
|
FansOk,
|
|
EndStops,
|
|
AxisX,
|
|
AxisY,
|
|
AxisZ,
|
|
Bed,
|
|
Hotend,
|
|
HotendOk,
|
|
Fsensor,
|
|
FsensorOk,
|
|
AllCorrect,
|
|
Failed,
|
|
Home,
|
|
};
|
|
|
|
enum class TestError : uint_least8_t
|
|
{
|
|
Heater,
|
|
Bed,
|
|
Endstops,
|
|
Motor,
|
|
Endstop,
|
|
PrintFan,
|
|
ExtruderFan,
|
|
Pulley,
|
|
Axis,
|
|
SwappedFan,
|
|
WiringFsensor,
|
|
TriggeringFsensor,
|
|
FsensorLevel
|
|
};
|
|
|
|
static int lcd_selftest_screen(TestScreen screen, int _progress, int _progress_scale, bool _clear, int _delay);
|
|
static void lcd_selftest_screen_step(int _row, int _col, int _state, const char *_name, const char *_indicator);
|
|
static bool lcd_selftest_manual_fan_check(int _fan, bool check_opposite,
|
|
bool _default=false);
|
|
|
|
#ifdef FANCHECK
|
|
/** Enumerate for lcd_selftest_fan_auto function.
|
|
*/
|
|
enum class FanCheck : uint_least8_t {
|
|
Success,
|
|
PrintFan,
|
|
ExtruderFan,
|
|
SwappedFan,
|
|
};
|
|
|
|
/**
|
|
* Try to check fan working and wiring.
|
|
*
|
|
* @param _fan i fan number 0 means extruder fan, 1 means print fan.
|
|
*
|
|
* @returns a TestError noerror, extruderFan, printFan or swappedFan.
|
|
*/
|
|
static FanCheck lcd_selftest_fan_auto(int _fan);
|
|
#endif //FANCHECK
|
|
|
|
#ifdef PAT9125
|
|
static bool lcd_selftest_fsensor();
|
|
#endif //PAT9125
|
|
static bool selftest_irsensor();
|
|
#if IR_SENSOR_ANALOG
|
|
static bool lcd_selftest_IRsensor();
|
|
#endif //IR_SENSOR_ANALOG
|
|
static void lcd_selftest_error(TestError error, const char *_error_1, const char *_error_2);
|
|
static void lcd_colorprint_change();
|
|
#ifdef SNMM
|
|
static int get_ext_nr();
|
|
#endif //SNMM
|
|
#if defined (SNMM) || defined(SNMM_V2)
|
|
static void fil_load_menu();
|
|
static void fil_unload_menu();
|
|
#endif // SNMM || SNMM_V2
|
|
static void lcd_disable_farm_mode();
|
|
static void lcd_set_fan_check();
|
|
static void lcd_cutter_enabled();
|
|
static char snmm_stop_print_menu();
|
|
#ifdef SDCARD_SORT_ALPHA
|
|
static void lcd_sort_type_set();
|
|
#endif
|
|
static void lcd_babystep_z();
|
|
static void lcd_send_status();
|
|
#ifdef FARM_CONNECT_MESSAGE
|
|
static void lcd_connect_printer();
|
|
#endif //FARM_CONNECT_MESSAGE
|
|
|
|
//! Beware: has side effects - forces lcd_draw_update to 2, which means clear the display
|
|
void lcd_finishstatus();
|
|
|
|
static void lcd_sdcard_menu();
|
|
static void lcd_sheet_menu();
|
|
|
|
#ifdef DELTA_CALIBRATION_MENU
|
|
static void lcd_delta_calibrate_menu();
|
|
#endif // DELTA_CALIBRATION_MENU
|
|
|
|
|
|
/* Different types of actions that can be used in menu items. */
|
|
static void menu_action_sdfile(const char* filename);
|
|
static void menu_action_sddirectory(const char* filename);
|
|
|
|
#define ENCODER_FEEDRATE_DEADZONE 10
|
|
|
|
#define STATE_NA 255
|
|
#define STATE_OFF 0
|
|
#define STATE_ON 1
|
|
|
|
/*
|
|
#define MENU_ITEM(type, label, args...) do { \
|
|
if (menu_item == menu_line) { \
|
|
if (lcd_draw_update) { \
|
|
const char* _label_pstr = (label); \
|
|
if (lcd_encoder == menu_item) { \
|
|
lcd_implementation_drawmenu_ ## type ## _selected (menu_row, _label_pstr , ## args ); \
|
|
}else{\
|
|
lcd_implementation_drawmenu_ ## type (menu_row, _label_pstr , ## args ); \
|
|
}\
|
|
}\
|
|
if (menu_clicked && (lcd_encoder == menu_item)) {\
|
|
lcd_quick_feedback(); \
|
|
menu_action_ ## type ( args ); \
|
|
return;\
|
|
}\
|
|
}\
|
|
menu_item++;\
|
|
} while(0)
|
|
*/
|
|
|
|
#if (SDCARDDETECT > 0)
|
|
bool lcd_oldcardstatus;
|
|
#endif
|
|
|
|
uint8_t selected_sheet = 0;
|
|
|
|
bool ignore_click = false;
|
|
bool wait_for_unclick;
|
|
|
|
// place-holders for Ki and Kd edits
|
|
#ifdef PIDTEMP
|
|
// float raw_Ki, raw_Kd;
|
|
#endif
|
|
|
|
bool bMain; // flag (i.e. 'fake parameter') for 'lcd_sdcard_menu()' function
|
|
bool bSettings; // flag (i.e. 'fake parameter') for 'lcd_hw_setup_menu()' function
|
|
|
|
|
|
|
|
const char STR_SEPARATOR[] PROGMEM = "------------";
|
|
|
|
|
|
static void lcd_implementation_drawmenu_sdfile_selected(uint8_t row, const char* filename, char* longFilename)
|
|
{
|
|
char c;
|
|
int enc_dif = lcd_encoder_diff / ENCODER_PULSES_PER_STEP;
|
|
uint8_t n = LCD_WIDTH - 1;
|
|
|
|
for(uint_least8_t g = 0; g<4;g++){
|
|
lcd_set_cursor(0, g);
|
|
lcd_print(' ');
|
|
}
|
|
lcd_set_cursor(0, row);
|
|
lcd_print('>');
|
|
|
|
if (longFilename[0] == '\0')
|
|
{
|
|
longFilename = filename;
|
|
}
|
|
|
|
int i = 1;
|
|
int j = 0;
|
|
char* longFilenameTMP = longFilename;
|
|
|
|
while((c = *longFilenameTMP) != '\0')
|
|
{
|
|
lcd_set_cursor(i, row);
|
|
lcd_print(c);
|
|
i++;
|
|
longFilenameTMP++;
|
|
if(i==LCD_WIDTH){
|
|
i=1;
|
|
j++;
|
|
longFilenameTMP = longFilename + j;
|
|
n = LCD_WIDTH - 1;
|
|
for(int g = 0; g<300 ;g++){
|
|
manage_heater();
|
|
if(LCD_CLICKED || ( enc_dif != (lcd_encoder_diff / ENCODER_PULSES_PER_STEP))){
|
|
longFilenameTMP = longFilename;
|
|
*(longFilenameTMP + LCD_WIDTH - 2) = '\0';
|
|
i = 1;
|
|
j = 0;
|
|
break;
|
|
}else{
|
|
if (j == 1) _delay_ms(3); //wait around 1.2 s to start scrolling text
|
|
_delay_ms(1); //then scroll with redrawing every 300 ms
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
if(c!='\0'){
|
|
lcd_set_cursor(i, row);
|
|
lcd_print(c);
|
|
i++;
|
|
}
|
|
n=n-i+1;
|
|
while(n--)
|
|
lcd_print(' ');
|
|
}
|
|
static void lcd_implementation_drawmenu_sdfile(uint8_t row, const char* filename, char* longFilename)
|
|
{
|
|
char c;
|
|
uint8_t n = LCD_WIDTH - 1;
|
|
lcd_set_cursor(0, row);
|
|
lcd_print(' ');
|
|
if (longFilename[0] != '\0')
|
|
{
|
|
filename = longFilename;
|
|
longFilename[LCD_WIDTH-1] = '\0';
|
|
}
|
|
while( ((c = *filename) != '\0') && (n>0) )
|
|
{
|
|
lcd_print(c);
|
|
filename++;
|
|
n--;
|
|
}
|
|
while(n--)
|
|
lcd_print(' ');
|
|
}
|
|
static void lcd_implementation_drawmenu_sddirectory_selected(uint8_t row, const char* filename, char* longFilename)
|
|
{
|
|
char c;
|
|
uint8_t n = LCD_WIDTH - 2;
|
|
lcd_set_cursor(0, row);
|
|
lcd_print('>');
|
|
lcd_print(LCD_STR_FOLDER[0]);
|
|
if (longFilename[0] != '\0')
|
|
{
|
|
filename = longFilename;
|
|
longFilename[LCD_WIDTH-2] = '\0';
|
|
}
|
|
while( ((c = *filename) != '\0') && (n>0) )
|
|
{
|
|
lcd_print(c);
|
|
filename++;
|
|
n--;
|
|
}
|
|
while(n--)
|
|
lcd_print(' ');
|
|
}
|
|
static void lcd_implementation_drawmenu_sddirectory(uint8_t row, const char* filename, char* longFilename)
|
|
{
|
|
char c;
|
|
uint8_t n = LCD_WIDTH - 2;
|
|
lcd_set_cursor(0, row);
|
|
lcd_print(' ');
|
|
lcd_print(LCD_STR_FOLDER[0]);
|
|
if (longFilename[0] != '\0')
|
|
{
|
|
filename = longFilename;
|
|
longFilename[LCD_WIDTH-2] = '\0';
|
|
}
|
|
while( ((c = *filename) != '\0') && (n>0) )
|
|
{
|
|
lcd_print(c);
|
|
filename++;
|
|
n--;
|
|
}
|
|
while(n--)
|
|
lcd_print(' ');
|
|
}
|
|
|
|
|
|
|
|
#define MENU_ITEM_SDDIR(str_fn, str_fnl) do { if (menu_item_sddir(str_fn, str_fnl)) return; } while (0)
|
|
//#define MENU_ITEM_SDDIR(str, str_fn, str_fnl) MENU_ITEM(sddirectory, str, str_fn, str_fnl)
|
|
//extern uint8_t menu_item_sddir(const char* str, const char* str_fn, char* str_fnl);
|
|
|
|
#define MENU_ITEM_SDFILE(str, str_fn, str_fnl) do { if (menu_item_sdfile(str, str_fn, str_fnl)) return; } while (0)
|
|
//#define MENU_ITEM_SDFILE(str, str_fn, str_fnl) MENU_ITEM(sdfile, str, str_fn, str_fnl)
|
|
//extern uint8_t menu_item_sdfile(const char* str, const char* str_fn, char* str_fnl);
|
|
|
|
|
|
uint8_t menu_item_sddir(const char* str_fn, char* str_fnl)
|
|
{
|
|
#ifdef NEW_SD_MENU
|
|
// str_fnl[18] = 0;
|
|
// printf_P(PSTR("menu dir %d '%s' '%s'\n"), menu_row, str_fn, str_fnl);
|
|
if (menu_item == menu_line)
|
|
{
|
|
if (lcd_draw_update)
|
|
{
|
|
lcd_set_cursor(0, menu_row);
|
|
int cnt = lcd_printf_P(PSTR("%c%c%-18s"), (lcd_encoder == menu_item)?'>':' ', LCD_STR_FOLDER[0], str_fnl[0]?str_fnl:str_fn);
|
|
// int cnt = lcd_printf_P(PSTR("%c%c%-18s"), (lcd_encoder == menu_item)?'>':' ', LCD_STR_FOLDER[0], str_fn);
|
|
}
|
|
if (menu_clicked && (lcd_encoder == menu_item))
|
|
{
|
|
uint8_t depth = (uint8_t)card.getWorkDirDepth();
|
|
strcpy(dir_names[depth], str_fn);
|
|
// printf_P(PSTR("%s\n"), dir_names[depth]);
|
|
card.chdir(str_fn);
|
|
lcd_encoder = 0;
|
|
return menu_item_ret();
|
|
}
|
|
}
|
|
menu_item++;
|
|
return 0;
|
|
#else //NEW_SD_MENU
|
|
if (menu_item == menu_line)
|
|
{
|
|
if (lcd_draw_update)
|
|
{
|
|
if (lcd_encoder == menu_item)
|
|
lcd_implementation_drawmenu_sddirectory_selected(menu_row, str_fn, str_fnl);
|
|
else
|
|
lcd_implementation_drawmenu_sddirectory(menu_row, str_fn, str_fnl);
|
|
}
|
|
if (menu_clicked && (lcd_encoder == menu_item))
|
|
{
|
|
menu_clicked = false;
|
|
lcd_update_enabled = 0;
|
|
menu_action_sddirectory(str_fn);
|
|
lcd_update_enabled = 1;
|
|
return menu_item_ret();
|
|
}
|
|
}
|
|
menu_item++;
|
|
return 0;
|
|
|
|
#endif //NEW_SD_MENU
|
|
}
|
|
|
|
static uint8_t menu_item_sdfile(const char*
|
|
#ifdef NEW_SD_MENU
|
|
str
|
|
#endif //NEW_SD_MENU
|
|
,const char* str_fn, char* str_fnl)
|
|
{
|
|
#ifdef NEW_SD_MENU
|
|
// printf_P(PSTR("menu sdfile\n"));
|
|
// str_fnl[19] = 0;
|
|
// printf_P(PSTR("menu file %d '%s' '%s'\n"), menu_row, str_fn, str_fnl);
|
|
if (menu_item == menu_line)
|
|
{
|
|
if (lcd_draw_update)
|
|
{
|
|
// printf_P(PSTR("menu file %d %d '%s'\n"), menu_row, menuData.sdcard_menu.viewState, str_fnl[0]?str_fnl:str_fn);
|
|
lcd_set_cursor(0, menu_row);
|
|
/* if (lcd_encoder == menu_item)
|
|
{
|
|
lcd_printf_P(PSTR("%c%-19s"), (lcd_encoder == menu_item)?'>':' ', (str_fnl[0]?str_fnl:str_fn) + 1);
|
|
if (menuData.sdcard_menu.viewState == 0)
|
|
{
|
|
menuData.sdcard_menu.viewState++;
|
|
lcd_printf_P(PSTR("%c%-19s"), (lcd_encoder == menu_item)?'>':' ', (str_fnl[0]?str_fnl:str_fn) + 1);
|
|
}
|
|
else if (menuData.sdcard_menu.viewState == 1)
|
|
{
|
|
lcd_printf_P(PSTR("%c%-19s"), (lcd_encoder == menu_item)?'>':' ', (str_fnl[0]?str_fnl:str_fn) + 2);
|
|
}
|
|
}
|
|
else*/
|
|
{
|
|
str_fnl[19] = 0;
|
|
lcd_printf_P(PSTR("%c%-19s"), (lcd_encoder == menu_item)?'>':' ', str_fnl[0]?str_fnl:str_fn);
|
|
}
|
|
|
|
// int cnt = lcd_printf_P(PSTR("%c%-19s"), (lcd_encoder == menu_item)?'>':' ', str_fnl);
|
|
// int cnt = lcd_printf_P(PSTR("%cTESTIK.gcode"), (lcd_encoder == menu_item)?'>':' ');
|
|
}
|
|
if (menu_clicked && (lcd_encoder == menu_item))
|
|
{
|
|
return menu_item_ret();
|
|
}
|
|
}
|
|
menu_item++;
|
|
return 0;
|
|
#else //NEW_SD_MENU
|
|
if (menu_item == menu_line)
|
|
{
|
|
if (lcd_draw_update)
|
|
{
|
|
if (lcd_encoder == menu_item)
|
|
lcd_implementation_drawmenu_sdfile_selected(menu_row, str_fn, str_fnl);
|
|
else
|
|
lcd_implementation_drawmenu_sdfile(menu_row, str_fn, str_fnl);
|
|
}
|
|
if (menu_clicked && (lcd_encoder == menu_item))
|
|
{
|
|
lcd_consume_click();
|
|
menu_action_sdfile(str_fn);
|
|
return menu_item_ret();
|
|
}
|
|
}
|
|
menu_item++;
|
|
return 0;
|
|
#endif //NEW_SD_MENU
|
|
}
|
|
|
|
// Print temperature (nozzle/bed) (9 chars total)
|
|
void lcdui_print_temp(char type, int val_current, int val_target)
|
|
{
|
|
int chars = lcd_printf_P(_N("%c%3d/%d%c"), type, val_current, val_target, LCD_STR_DEGREE[0]);
|
|
lcd_space(9 - chars);
|
|
}
|
|
|
|
// Print Z-coordinate (8 chars total)
|
|
void lcdui_print_Z_coord(void)
|
|
{
|
|
if (custom_message_type == CustomMsg::MeshBedLeveling)
|
|
lcd_puts_P(_N("Z --- "));
|
|
else
|
|
lcd_printf_P(_N("Z%6.2f "), current_position[Z_AXIS]);
|
|
}
|
|
|
|
#ifdef PLANNER_DIAGNOSTICS
|
|
// Print planner diagnostics (8 chars total)
|
|
void lcdui_print_planner_diag(void)
|
|
{
|
|
lcd_set_cursor(LCD_WIDTH - 8-2, 1);
|
|
lcd_print(LCD_STR_FEEDRATE[0]);
|
|
lcd_print(itostr3(feedmultiply));
|
|
lcd_puts_P(PSTR("% Q"));
|
|
{
|
|
uint8_t queue = planner_queue_min();
|
|
if (queue < (BLOCK_BUFFER_SIZE >> 1))
|
|
lcd_putc('!');
|
|
else
|
|
{
|
|
lcd_putc((char)(queue / 10) + '0');
|
|
queue %= 10;
|
|
}
|
|
lcd_putc((char)queue + '0');
|
|
planner_queue_min_reset();
|
|
}
|
|
}
|
|
#endif // PLANNER_DIAGNOSTICS
|
|
|
|
// Print feedrate (8 chars total)
|
|
void lcdui_print_feedrate(void)
|
|
{
|
|
int chars = lcd_printf_P(_N("%c%3d%%"), LCD_STR_FEEDRATE[0], feedmultiply);
|
|
lcd_space(8 - chars);
|
|
}
|
|
|
|
// Print percent done in form "USB---%", " SD---%", " ---%" (7 chars total)
|
|
void lcdui_print_percent_done(void)
|
|
{
|
|
char sheet[8];
|
|
const char* src = is_usb_printing?_N("USB"):(IS_SD_PRINTING?_N(" SD"):_N(" "));
|
|
char per[4];
|
|
bool num = IS_SD_PRINTING || (PRINTER_ACTIVE && (print_percent_done_normal != PRINT_PERCENT_DONE_INIT));
|
|
if (!num || heating_status) // either not printing or heating
|
|
{
|
|
eeprom_read_block(sheet, EEPROM_Sheets_base->s[eeprom_read_byte(&(EEPROM_Sheets_base->active_sheet))].name, 7);
|
|
sheet[7] = '\0';
|
|
lcd_printf_P(PSTR("%s"),sheet);
|
|
}
|
|
else
|
|
{
|
|
sprintf_P(per, num?_N("%3hhd"):_N("---"), calc_percent_done());
|
|
lcd_printf_P(_N("%3S%3s%%"), src, per);
|
|
}
|
|
}
|
|
|
|
// Print extruder status (5 chars total)
|
|
void lcdui_print_extruder(void)
|
|
{
|
|
int chars = 0;
|
|
if (mmu_extruder == tmp_extruder) {
|
|
if (mmu_extruder == MMU_FILAMENT_UNKNOWN) chars = lcd_printf_P(_N(" F?"));
|
|
else chars = lcd_printf_P(_N(" F%u"), mmu_extruder + 1);
|
|
}
|
|
else
|
|
{
|
|
if (mmu_extruder == MMU_FILAMENT_UNKNOWN) chars = lcd_printf_P(_N(" ?>%u"), tmp_extruder + 1);
|
|
else chars = lcd_printf_P(_N(" %u>%u"), mmu_extruder + 1, tmp_extruder + 1);
|
|
}
|
|
lcd_space(5 - chars);
|
|
}
|
|
|
|
// Print farm number (5 chars total)
|
|
void lcdui_print_farm(void)
|
|
{
|
|
int chars = lcd_printf_P(_N(" F0 "));
|
|
// lcd_space(5 - chars);
|
|
/*
|
|
// Farm number display
|
|
if (farm_mode)
|
|
{
|
|
lcd_set_cursor(6, 2);
|
|
lcd_puts_P(PSTR(" F"));
|
|
lcd_print(farm_no);
|
|
lcd_puts_P(PSTR(" "));
|
|
|
|
// Beat display
|
|
lcd_set_cursor(LCD_WIDTH - 1, 0);
|
|
if ( (_millis() - kicktime) < 60000 ) {
|
|
|
|
lcd_puts_P(PSTR("L"));
|
|
|
|
}else{
|
|
lcd_puts_P(PSTR(" "));
|
|
}
|
|
|
|
}
|
|
else {
|
|
#ifdef SNMM
|
|
lcd_puts_P(PSTR(" E"));
|
|
lcd_print(get_ext_nr() + 1);
|
|
|
|
#else
|
|
lcd_set_cursor(LCD_WIDTH - 8 - 2, 2);
|
|
lcd_puts_P(PSTR(" "));
|
|
#endif
|
|
}
|
|
*/
|
|
}
|
|
|
|
#ifdef CMD_DIAGNOSTICS
|
|
// Print CMD queue diagnostic (8 chars total)
|
|
void lcdui_print_cmd_diag(void)
|
|
{
|
|
lcd_set_cursor(LCD_WIDTH - 8 -1, 2);
|
|
lcd_puts_P(PSTR(" C"));
|
|
lcd_print(buflen); // number of commands in cmd buffer
|
|
if (buflen < 9) lcd_puts_P(" ");
|
|
}
|
|
#endif //CMD_DIAGNOSTICS
|
|
|
|
// Print time (8 chars total)
|
|
void lcdui_print_time(void)
|
|
{
|
|
//if remaining print time estimation is available print it else print elapsed time
|
|
uint16_t print_t = 0;
|
|
if (print_time_remaining_normal != PRINT_TIME_REMAINING_INIT)
|
|
print_t = print_time_remaining();
|
|
else if(starttime != 0)
|
|
print_t = _millis() / 60000 - starttime / 60000;
|
|
int chars = 0;
|
|
if ((PRINTER_ACTIVE) && ((print_time_remaining_normal != PRINT_TIME_REMAINING_INIT) || (starttime != 0)))
|
|
{
|
|
char suff = ' ';
|
|
char suff_doubt = ' ';
|
|
if (print_time_remaining_normal != PRINT_TIME_REMAINING_INIT)
|
|
{
|
|
suff = 'R';
|
|
if (feedmultiply != 100)
|
|
suff_doubt = '?';
|
|
}
|
|
if (print_t < 6000) //time<100h
|
|
chars = lcd_printf_P(_N("%c%02u:%02u%c%c"), LCD_STR_CLOCK[0], print_t / 60, print_t % 60, suff, suff_doubt);
|
|
else //time>=100h
|
|
chars = lcd_printf_P(_N("%c%3uh %c%c"), LCD_STR_CLOCK[0], print_t / 60, suff, suff_doubt);
|
|
}
|
|
else
|
|
chars = lcd_printf_P(_N("%c--:-- "), LCD_STR_CLOCK[0]);
|
|
lcd_space(8 - chars);
|
|
}
|
|
|
|
//Print status line on status screen
|
|
void lcdui_print_status_line(void)
|
|
{
|
|
if (IS_SD_PRINTING)
|
|
{
|
|
if (strcmp(longFilenameOLD, (card.longFilename[0] ? card.longFilename : card.filename)) != 0)
|
|
{
|
|
memset(longFilenameOLD, '\0', strlen(longFilenameOLD));
|
|
sprintf_P(longFilenameOLD, PSTR("%s"), (card.longFilename[0] ? card.longFilename : card.filename));
|
|
scrollstuff = 0;
|
|
}
|
|
}
|
|
|
|
if (heating_status)
|
|
{ // If heating flag, show progress of heating
|
|
heating_status_counter++;
|
|
if (heating_status_counter > 13)
|
|
{
|
|
heating_status_counter = 0;
|
|
}
|
|
lcd_set_cursor(7, 3);
|
|
lcd_puts_P(PSTR(" "));
|
|
|
|
for (unsigned int dots = 0; dots < heating_status_counter; dots++)
|
|
{
|
|
lcd_set_cursor(7 + dots, 3);
|
|
lcd_print('.');
|
|
}
|
|
switch (heating_status)
|
|
{
|
|
case 1:
|
|
lcd_set_cursor(0, 3);
|
|
lcd_puts_P(_T(MSG_HEATING));
|
|
break;
|
|
case 2:
|
|
lcd_set_cursor(0, 3);
|
|
lcd_puts_P(_T(MSG_HEATING_COMPLETE));
|
|
heating_status = 0;
|
|
heating_status_counter = 0;
|
|
break;
|
|
case 3:
|
|
lcd_set_cursor(0, 3);
|
|
lcd_puts_P(_T(MSG_BED_HEATING));
|
|
break;
|
|
case 4:
|
|
lcd_set_cursor(0, 3);
|
|
lcd_puts_P(_T(MSG_BED_DONE));
|
|
heating_status = 0;
|
|
heating_status_counter = 0;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
else if ((IS_SD_PRINTING) && (custom_message_type == CustomMsg::Status))
|
|
{ // If printing from SD, show what we are printing
|
|
if(strlen(longFilenameOLD) > LCD_WIDTH)
|
|
{
|
|
int inters = 0;
|
|
int gh = scrollstuff;
|
|
while (((gh - scrollstuff) < LCD_WIDTH) && (inters == 0))
|
|
{
|
|
if (longFilenameOLD[gh] == '\0')
|
|
{
|
|
lcd_set_cursor(gh - scrollstuff, 3);
|
|
lcd_print(longFilenameOLD[gh - 1]);
|
|
scrollstuff = 0;
|
|
gh = scrollstuff;
|
|
inters = 1;
|
|
}
|
|
else
|
|
{
|
|
lcd_set_cursor(gh - scrollstuff, 3);
|
|
lcd_print(longFilenameOLD[gh - 1]);
|
|
gh++;
|
|
}
|
|
}
|
|
scrollstuff++;
|
|
}
|
|
else
|
|
{
|
|
lcd_printf_P(PSTR("%-20s"), longFilenameOLD);
|
|
}
|
|
}
|
|
else
|
|
{ // Otherwise check for other special events
|
|
switch (custom_message_type)
|
|
{
|
|
case CustomMsg::Status: // Nothing special, print status message normally
|
|
lcd_print(lcd_status_message);
|
|
break;
|
|
case CustomMsg::MeshBedLeveling: // If mesh bed leveling in progress, show the status
|
|
if (custom_message_state > 10)
|
|
{
|
|
lcd_set_cursor(0, 3);
|
|
lcd_puts_P(PSTR(" "));
|
|
lcd_set_cursor(0, 3);
|
|
lcd_puts_P(_T(MSG_CALIBRATE_Z_AUTO));
|
|
lcd_puts_P(PSTR(" : "));
|
|
lcd_print(custom_message_state-10);
|
|
}
|
|
else
|
|
{
|
|
if (custom_message_state == 3)
|
|
{
|
|
lcd_puts_P(_T(WELCOME_MSG));
|
|
lcd_setstatuspgm(_T(WELCOME_MSG));
|
|
custom_message_type = CustomMsg::Status;
|
|
}
|
|
if (custom_message_state > 3 && custom_message_state <= 10 )
|
|
{
|
|
lcd_set_cursor(0, 3);
|
|
lcd_puts_P(PSTR(" "));
|
|
lcd_set_cursor(0, 3);
|
|
lcd_puts_P(_i("Calibration done"));////MSG_HOMEYZ_DONE
|
|
custom_message_state--;
|
|
}
|
|
}
|
|
break;
|
|
case CustomMsg::FilamentLoading: // If loading filament, print status
|
|
lcd_print(lcd_status_message);
|
|
break;
|
|
case CustomMsg::PidCal: // PID tuning in progress
|
|
lcd_print(lcd_status_message);
|
|
if (pid_cycle <= pid_number_of_cycles && custom_message_state > 0)
|
|
{
|
|
lcd_set_cursor(10, 3);
|
|
lcd_print(itostr3(pid_cycle));
|
|
lcd_print('/');
|
|
lcd_print(itostr3left(pid_number_of_cycles));
|
|
}
|
|
break;
|
|
case CustomMsg::TempCal: // PINDA temp calibration in progress
|
|
{
|
|
char statusLine[LCD_WIDTH + 1];
|
|
sprintf_P(statusLine, PSTR("%-20S"), _T(MSG_TEMP_CALIBRATION));
|
|
char progress[4];
|
|
sprintf_P(progress, PSTR("%d/6"), custom_message_state);
|
|
memcpy(statusLine + 12, progress, sizeof(progress) - 1);
|
|
lcd_set_cursor(0, 3);
|
|
lcd_print(statusLine);
|
|
}
|
|
break;
|
|
case CustomMsg::TempCompPreheat: // temp compensation preheat
|
|
lcd_set_cursor(0, 3);
|
|
lcd_puts_P(_i("PINDA Heating"));////MSG_PINDA_PREHEAT c=20 r=1
|
|
if (custom_message_state <= PINDA_HEAT_T)
|
|
{
|
|
lcd_puts_P(PSTR(": "));
|
|
lcd_print(custom_message_state); //seconds
|
|
lcd_print(' ');
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Fill the rest of line to have nice and clean output
|
|
for(int fillspace = 0; fillspace < 20; fillspace++)
|
|
if ((lcd_status_message[fillspace] <= 31 ))
|
|
lcd_print(' ');
|
|
}
|
|
|
|
//! @brief Show Status Screen
|
|
//!
|
|
//! @code{.unparsed}
|
|
//! |01234567890123456789|
|
|
//! |N 000/000D Z000.0 |
|
|
//! |B 000/000D F100% |
|
|
//! |USB100% T0 t--:-- |
|
|
//! |Status line.........|
|
|
//! ----------------------
|
|
//! N - nozzle temp symbol LCD_STR_THERMOMETER
|
|
//! D - Degree sysmbol LCD_STR_DEGREE
|
|
//! B - bed temp symbol LCD_STR_BEDTEMP
|
|
//! F - feedrate symbol LCD_STR_FEEDRATE
|
|
//! t - clock symbol LCD_STR_THERMOMETER
|
|
//! @endcode
|
|
void lcdui_print_status_screen(void)
|
|
{
|
|
|
|
lcd_set_cursor(0, 0); //line 0
|
|
|
|
//Print the hotend temperature (9 chars total)
|
|
lcdui_print_temp(LCD_STR_THERMOMETER[0], (int)(degHotend(0) + 0.5), (int)(degTargetHotend(0) + 0.5));
|
|
|
|
lcd_space(3); //3 spaces
|
|
|
|
//Print Z-coordinate (8 chars total)
|
|
lcdui_print_Z_coord();
|
|
|
|
lcd_set_cursor(0, 1); //line 1
|
|
|
|
//Print the Bed temperature (9 chars total)
|
|
lcdui_print_temp(LCD_STR_BEDTEMP[0], (int)(degBed() + 0.5), (int)(degTargetBed() + 0.5));
|
|
|
|
lcd_space(3); //3 spaces
|
|
|
|
#ifdef PLANNER_DIAGNOSTICS
|
|
//Print planner diagnostics (8 chars)
|
|
lcdui_print_planner_diag();
|
|
#else // PLANNER_DIAGNOSTICS
|
|
//Print Feedrate (8 chars)
|
|
lcdui_print_feedrate();
|
|
#endif // PLANNER_DIAGNOSTICS
|
|
|
|
lcd_set_cursor(0, 2); //line 2
|
|
|
|
//Print SD status (7 chars)
|
|
lcdui_print_percent_done();
|
|
|
|
if (mmu_enabled)
|
|
//Print extruder status (5 chars)
|
|
lcdui_print_extruder();
|
|
else if (farm_mode)
|
|
//Print farm number (5 chars)
|
|
lcdui_print_farm();
|
|
else
|
|
lcd_space(5); //5 spaces
|
|
|
|
#ifdef CMD_DIAGNOSTICS
|
|
//Print cmd queue diagnostics (8chars)
|
|
lcdui_print_cmd_diag();
|
|
#else
|
|
//Print time (8chars)
|
|
lcdui_print_time();
|
|
#endif //CMD_DIAGNOSTICS
|
|
|
|
lcd_set_cursor(0, 3); //line 3
|
|
|
|
#ifndef DEBUG_DISABLE_LCD_STATUS_LINE
|
|
lcdui_print_status_line();
|
|
#endif //DEBUG_DISABLE_LCD_STATUS_LINE
|
|
|
|
}
|
|
|
|
// Main status screen. It's up to the implementation specific part to show what is needed. As this is very display dependent
|
|
static void lcd_status_screen()
|
|
{
|
|
if (firstrun == 1)
|
|
{
|
|
firstrun = 0;
|
|
if(lcd_status_message_level == 0)
|
|
{
|
|
strncpy_P(lcd_status_message, _T(WELCOME_MSG), LCD_WIDTH);
|
|
lcd_finishstatus();
|
|
}
|
|
if (eeprom_read_byte((uint8_t *)EEPROM_TOTALTIME) == 255 && eeprom_read_byte((uint8_t *)EEPROM_TOTALTIME + 1) == 255 && eeprom_read_byte((uint8_t *)EEPROM_TOTALTIME + 2) == 255 && eeprom_read_byte((uint8_t *)EEPROM_TOTALTIME + 3) == 255)
|
|
{
|
|
eeprom_update_dword((uint32_t *)EEPROM_TOTALTIME, 0);
|
|
eeprom_update_dword((uint32_t *)EEPROM_FILAMENTUSED, 0);
|
|
}
|
|
}
|
|
|
|
if (lcd_status_update_delay)
|
|
lcd_status_update_delay--;
|
|
else
|
|
lcd_draw_update = 1;
|
|
|
|
|
|
if (lcd_draw_update)
|
|
{
|
|
ReInitLCD++;
|
|
if (ReInitLCD == 30)
|
|
{
|
|
lcd_refresh(); // to maybe revive the LCD if static electricity killed it.
|
|
ReInitLCD = 0 ;
|
|
}
|
|
else
|
|
{
|
|
if ((ReInitLCD % 10) == 0)
|
|
lcd_refresh_noclear(); //to maybe revive the LCD if static electricity killed it.
|
|
}
|
|
|
|
lcdui_print_status_screen();
|
|
|
|
if (farm_mode)
|
|
{
|
|
farm_timer--;
|
|
if (farm_timer < 1)
|
|
{
|
|
farm_timer = 10;
|
|
prusa_statistics(0);
|
|
}
|
|
switch (farm_timer)
|
|
{
|
|
case 8:
|
|
prusa_statistics(21);
|
|
if(loading_flag)
|
|
prusa_statistics(22);
|
|
break;
|
|
case 5:
|
|
if (IS_SD_PRINTING)
|
|
prusa_statistics(20);
|
|
break;
|
|
}
|
|
} // end of farm_mode
|
|
|
|
lcd_status_update_delay = 10; /* redraw the main screen every second. This is easier then trying keep track of all things that change on the screen */
|
|
if (lcd_commands_type != LcdCommands::Idle)
|
|
lcd_commands();
|
|
} // end of lcd_draw_update
|
|
|
|
bool current_click = LCD_CLICKED;
|
|
|
|
if (ignore_click)
|
|
{
|
|
if (wait_for_unclick)
|
|
{
|
|
if (!current_click)
|
|
ignore_click = wait_for_unclick = false;
|
|
else
|
|
current_click = false;
|
|
}
|
|
else if (current_click)
|
|
{
|
|
lcd_quick_feedback();
|
|
wait_for_unclick = true;
|
|
current_click = false;
|
|
}
|
|
}
|
|
|
|
if (current_click
|
|
&& (lcd_commands_type != LcdCommands::StopPrint) //click is aborted unless stop print finishes
|
|
&& ( menu_block_entering_on_serious_errors == SERIOUS_ERR_NONE ) // or a serious error blocks entering the menu
|
|
)
|
|
{
|
|
menu_depth = 0; //redundant, as already done in lcd_return_to_status(), just to be sure
|
|
menu_submenu(lcd_main_menu);
|
|
lcd_refresh(); // to maybe revive the LCD if static electricity killed it.
|
|
}
|
|
|
|
#ifdef ULTIPANEL_FEEDMULTIPLY
|
|
// Dead zone at 100% feedrate
|
|
if ((feedmultiply < 100 && (feedmultiply + int(lcd_encoder)) > 100) ||
|
|
(feedmultiply > 100 && (feedmultiply + int(lcd_encoder)) < 100))
|
|
{
|
|
lcd_encoder = 0;
|
|
feedmultiply = 100;
|
|
}
|
|
if (feedmultiply == 100 && int(lcd_encoder) > ENCODER_FEEDRATE_DEADZONE)
|
|
{
|
|
feedmultiply += int(lcd_encoder) - ENCODER_FEEDRATE_DEADZONE;
|
|
lcd_encoder = 0;
|
|
}
|
|
else if (feedmultiply == 100 && int(lcd_encoder) < -ENCODER_FEEDRATE_DEADZONE)
|
|
{
|
|
feedmultiply += int(lcd_encoder) + ENCODER_FEEDRATE_DEADZONE;
|
|
lcd_encoder = 0;
|
|
}
|
|
else if (feedmultiply != 100)
|
|
{
|
|
feedmultiply += int(lcd_encoder);
|
|
lcd_encoder = 0;
|
|
}
|
|
#endif //ULTIPANEL_FEEDMULTIPLY
|
|
|
|
if (feedmultiply < 10)
|
|
feedmultiply = 10;
|
|
else if (feedmultiply > 999)
|
|
feedmultiply = 999;
|
|
}
|
|
|
|
void lcd_commands()
|
|
{
|
|
if (lcd_commands_type == LcdCommands::LongPause)
|
|
{
|
|
if (!blocks_queued() && !homing_flag)
|
|
{
|
|
lcd_setstatuspgm(_i("Print paused"));////MSG_PRINT_PAUSED c=20 r=1
|
|
lcd_commands_type = LcdCommands::Idle;
|
|
lcd_commands_step = 0;
|
|
}
|
|
}
|
|
|
|
|
|
#ifdef SNMM
|
|
if (lcd_commands_type == LcdCommands::Layer1Cal)
|
|
{
|
|
char cmd1[30];
|
|
float width = 0.4;
|
|
float length = 20 - width;
|
|
float extr = count_e(0.2, width, length);
|
|
float extr_short_segment = count_e(0.2, width, width);
|
|
|
|
if (lcd_commands_step>1) lcd_timeoutToStatus.start(); //if user dont confirm live adjust Z value by pressing the knob, we are saving last value by timeout to status screen
|
|
if (lcd_commands_step == 0)
|
|
{
|
|
lcd_commands_step = 10;
|
|
}
|
|
if (lcd_commands_step == 10 && !blocks_queued() && cmd_buffer_empty())
|
|
{
|
|
enquecommand_P(PSTR("M107"));
|
|
enquecommand_P(PSTR("M104 S" STRINGIFY(PLA_PREHEAT_HOTEND_TEMP)));
|
|
enquecommand_P(PSTR("M140 S" STRINGIFY(PLA_PREHEAT_HPB_TEMP)));
|
|
enquecommand_P(PSTR("M190 S" STRINGIFY(PLA_PREHEAT_HPB_TEMP)));
|
|
enquecommand_P(PSTR("M109 S" STRINGIFY(PLA_PREHEAT_HOTEND_TEMP)));
|
|
enquecommand_P(PSTR("T0"));
|
|
enquecommand_P(_T(MSG_M117_V2_CALIBRATION));
|
|
enquecommand_P(PSTR("G87")); //sets calibration status
|
|
enquecommand_P(PSTR("G28"));
|
|
enquecommand_P(PSTR("G21")); //set units to millimeters
|
|
enquecommand_P(PSTR("G90")); //use absolute coordinates
|
|
enquecommand_P(PSTR("M83")); //use relative distances for extrusion
|
|
enquecommand_P(PSTR("G92 E0"));
|
|
enquecommand_P(PSTR("M203 E100"));
|
|
enquecommand_P(PSTR("M92 E140"));
|
|
lcd_commands_step = 9;
|
|
}
|
|
if (lcd_commands_step == 9 && !blocks_queued() && cmd_buffer_empty())
|
|
{
|
|
lcd_timeoutToStatus.start();
|
|
enquecommand_P(PSTR("G1 Z0.250 F7200.000"));
|
|
enquecommand_P(PSTR("G1 X50.0 E80.0 F1000.0"));
|
|
enquecommand_P(PSTR("G1 X160.0 E20.0 F1000.0"));
|
|
enquecommand_P(PSTR("G1 Z0.200 F7200.000"));
|
|
enquecommand_P(PSTR("G1 X220.0 E13 F1000.0"));
|
|
enquecommand_P(PSTR("G1 X240.0 E0 F1000.0"));
|
|
enquecommand_P(PSTR("G92 E0.0"));
|
|
enquecommand_P(PSTR("G21"));
|
|
enquecommand_P(PSTR("G90"));
|
|
enquecommand_P(PSTR("M83"));
|
|
enquecommand_P(PSTR("G1 E-4 F2100.00000"));
|
|
enquecommand_P(PSTR("G1 Z0.150 F7200.000"));
|
|
enquecommand_P(PSTR("M204 S1000"));
|
|
enquecommand_P(PSTR("G1 F4000"));
|
|
|
|
lcd_clear();
|
|
menu_goto(lcd_babystep_z, 0, false, true);
|
|
|
|
|
|
lcd_commands_step = 8;
|
|
}
|
|
if (lcd_commands_step == 8 && !blocks_queued() && cmd_buffer_empty()) //draw meander
|
|
{
|
|
lcd_timeoutToStatus.start();
|
|
|
|
|
|
enquecommand_P(PSTR("G1 X50 Y155"));
|
|
enquecommand_P(PSTR("G1 X60 Y155 E4"));
|
|
enquecommand_P(PSTR("G1 F1080"));
|
|
enquecommand_P(PSTR("G1 X75 Y155 E2.5"));
|
|
enquecommand_P(PSTR("G1 X100 Y155 E2"));
|
|
enquecommand_P(PSTR("G1 X200 Y155 E2.62773"));
|
|
enquecommand_P(PSTR("G1 X200 Y135 E0.66174"));
|
|
enquecommand_P(PSTR("G1 X50 Y135 E3.62773"));
|
|
enquecommand_P(PSTR("G1 X50 Y115 E0.49386"));
|
|
enquecommand_P(PSTR("G1 X200 Y115 E3.62773"));
|
|
enquecommand_P(PSTR("G1 X200 Y95 E0.49386"));
|
|
enquecommand_P(PSTR("G1 X50 Y95 E3.62773"));
|
|
enquecommand_P(PSTR("G1 X50 Y75 E0.49386"));
|
|
enquecommand_P(PSTR("G1 X200 Y75 E3.62773"));
|
|
enquecommand_P(PSTR("G1 X200 Y55 E0.49386"));
|
|
enquecommand_P(PSTR("G1 X50 Y55 E3.62773"));
|
|
|
|
lcd_commands_step = 7;
|
|
}
|
|
|
|
if (lcd_commands_step == 7 && !blocks_queued() && cmd_buffer_empty())
|
|
{
|
|
lcd_timeoutToStatus.start();
|
|
strcpy(cmd1, "G1 X50 Y35 E");
|
|
strcat(cmd1, ftostr43(extr));
|
|
enquecommand(cmd1);
|
|
|
|
for (int i = 0; i < 4; i++) {
|
|
strcpy(cmd1, "G1 X70 Y");
|
|
strcat(cmd1, ftostr32(35 - i*width * 2));
|
|
strcat(cmd1, " E");
|
|
strcat(cmd1, ftostr43(extr));
|
|
enquecommand(cmd1);
|
|
strcpy(cmd1, "G1 Y");
|
|
strcat(cmd1, ftostr32(35 - (2 * i + 1)*width));
|
|
strcat(cmd1, " E");
|
|
strcat(cmd1, ftostr43(extr_short_segment));
|
|
enquecommand(cmd1);
|
|
strcpy(cmd1, "G1 X50 Y");
|
|
strcat(cmd1, ftostr32(35 - (2 * i + 1)*width));
|
|
strcat(cmd1, " E");
|
|
strcat(cmd1, ftostr43(extr));
|
|
enquecommand(cmd1);
|
|
strcpy(cmd1, "G1 Y");
|
|
strcat(cmd1, ftostr32(35 - (i + 1)*width * 2));
|
|
strcat(cmd1, " E");
|
|
strcat(cmd1, ftostr43(extr_short_segment));
|
|
enquecommand(cmd1);
|
|
}
|
|
|
|
lcd_commands_step = 6;
|
|
}
|
|
|
|
if (lcd_commands_step == 6 && !blocks_queued() && cmd_buffer_empty())
|
|
{
|
|
lcd_timeoutToStatus.start();
|
|
for (int i = 4; i < 8; i++) {
|
|
strcpy(cmd1, "G1 X70 Y");
|
|
strcat(cmd1, ftostr32(35 - i*width * 2));
|
|
strcat(cmd1, " E");
|
|
strcat(cmd1, ftostr43(extr));
|
|
enquecommand(cmd1);
|
|
strcpy(cmd1, "G1 Y");
|
|
strcat(cmd1, ftostr32(35 - (2 * i + 1)*width));
|
|
strcat(cmd1, " E");
|
|
strcat(cmd1, ftostr43(extr_short_segment));
|
|
enquecommand(cmd1);
|
|
strcpy(cmd1, "G1 X50 Y");
|
|
strcat(cmd1, ftostr32(35 - (2 * i + 1)*width));
|
|
strcat(cmd1, " E");
|
|
strcat(cmd1, ftostr43(extr));
|
|
enquecommand(cmd1);
|
|
strcpy(cmd1, "G1 Y");
|
|
strcat(cmd1, ftostr32(35 - (i + 1)*width * 2));
|
|
strcat(cmd1, " E");
|
|
strcat(cmd1, ftostr43(extr_short_segment));
|
|
enquecommand(cmd1);
|
|
}
|
|
|
|
lcd_commands_step = 5;
|
|
}
|
|
|
|
if (lcd_commands_step == 5 && !blocks_queued() && cmd_buffer_empty())
|
|
{
|
|
lcd_timeoutToStatus.start();
|
|
for (int i = 8; i < 12; i++) {
|
|
strcpy(cmd1, "G1 X70 Y");
|
|
strcat(cmd1, ftostr32(35 - i*width * 2));
|
|
strcat(cmd1, " E");
|
|
strcat(cmd1, ftostr43(extr));
|
|
enquecommand(cmd1);
|
|
strcpy(cmd1, "G1 Y");
|
|
strcat(cmd1, ftostr32(35 - (2 * i + 1)*width));
|
|
strcat(cmd1, " E");
|
|
strcat(cmd1, ftostr43(extr_short_segment));
|
|
enquecommand(cmd1);
|
|
strcpy(cmd1, "G1 X50 Y");
|
|
strcat(cmd1, ftostr32(35 - (2 * i + 1)*width));
|
|
strcat(cmd1, " E");
|
|
strcat(cmd1, ftostr43(extr));
|
|
enquecommand(cmd1);
|
|
strcpy(cmd1, "G1 Y");
|
|
strcat(cmd1, ftostr32(35 - (i + 1)*width * 2));
|
|
strcat(cmd1, " E");
|
|
strcat(cmd1, ftostr43(extr_short_segment));
|
|
enquecommand(cmd1);
|
|
}
|
|
|
|
lcd_commands_step = 4;
|
|
}
|
|
|
|
if (lcd_commands_step == 4 && !blocks_queued() && cmd_buffer_empty())
|
|
{
|
|
lcd_timeoutToStatus.start();
|
|
for (int i = 12; i < 16; i++) {
|
|
strcpy(cmd1, "G1 X70 Y");
|
|
strcat(cmd1, ftostr32(35 - i*width * 2));
|
|
strcat(cmd1, " E");
|
|
strcat(cmd1, ftostr43(extr));
|
|
enquecommand(cmd1);
|
|
strcpy(cmd1, "G1 Y");
|
|
strcat(cmd1, ftostr32(35 - (2 * i + 1)*width));
|
|
strcat(cmd1, " E");
|
|
strcat(cmd1, ftostr43(extr_short_segment));
|
|
enquecommand(cmd1);
|
|
strcpy(cmd1, "G1 X50 Y");
|
|
strcat(cmd1, ftostr32(35 - (2 * i + 1)*width));
|
|
strcat(cmd1, " E");
|
|
strcat(cmd1, ftostr43(extr));
|
|
enquecommand(cmd1);
|
|
strcpy(cmd1, "G1 Y");
|
|
strcat(cmd1, ftostr32(35 - (i + 1)*width * 2));
|
|
strcat(cmd1, " E");
|
|
strcat(cmd1, ftostr43(extr_short_segment));
|
|
enquecommand(cmd1);
|
|
}
|
|
|
|
lcd_commands_step = 3;
|
|
}
|
|
|
|
if (lcd_commands_step == 3 && !blocks_queued() && cmd_buffer_empty())
|
|
{
|
|
lcd_timeoutToStatus.start();
|
|
enquecommand_P(PSTR("G1 E-0.07500 F2100.00000"));
|
|
enquecommand_P(PSTR("G4 S0"));
|
|
enquecommand_P(PSTR("G1 E-4 F2100.00000"));
|
|
enquecommand_P(PSTR("G1 Z0.5 F7200.000"));
|
|
enquecommand_P(PSTR("G1 X245 Y1"));
|
|
enquecommand_P(PSTR("G1 X240 E4"));
|
|
enquecommand_P(PSTR("G1 F4000"));
|
|
enquecommand_P(PSTR("G1 X190 E2.7"));
|
|
enquecommand_P(PSTR("G1 F4600"));
|
|
enquecommand_P(PSTR("G1 X110 E2.8"));
|
|
enquecommand_P(PSTR("G1 F5200"));
|
|
enquecommand_P(PSTR("G1 X40 E3"));
|
|
enquecommand_P(PSTR("G1 E-15.0000 F5000"));
|
|
enquecommand_P(PSTR("G1 E-50.0000 F5400"));
|
|
enquecommand_P(PSTR("G1 E-15.0000 F3000"));
|
|
enquecommand_P(PSTR("G1 E-12.0000 F2000"));
|
|
enquecommand_P(PSTR("G1 F1600"));
|
|
|
|
lcd_commands_step = 2;
|
|
}
|
|
if (lcd_commands_step == 2 && !blocks_queued() && cmd_buffer_empty())
|
|
{
|
|
lcd_timeoutToStatus.start();
|
|
|
|
enquecommand_P(PSTR("G1 X0 Y1 E3.0000"));
|
|
enquecommand_P(PSTR("G1 X50 Y1 E-5.0000"));
|
|
enquecommand_P(PSTR("G1 F2000"));
|
|
enquecommand_P(PSTR("G1 X0 Y1 E5.0000"));
|
|
enquecommand_P(PSTR("G1 X50 Y1 E-5.0000"));
|
|
enquecommand_P(PSTR("G1 F2400"));
|
|
enquecommand_P(PSTR("G1 X0 Y1 E5.0000"));
|
|
enquecommand_P(PSTR("G1 X50 Y1 E-5.0000"));
|
|
enquecommand_P(PSTR("G1 F2400"));
|
|
enquecommand_P(PSTR("G1 X0 Y1 E5.0000"));
|
|
enquecommand_P(PSTR("G1 X50 Y1 E-3.0000"));
|
|
enquecommand_P(PSTR("G4 S0"));
|
|
enquecommand_P(PSTR("M107"));
|
|
enquecommand_P(PSTR("M104 S0"));
|
|
enquecommand_P(PSTR("M140 S0"));
|
|
enquecommand_P(PSTR("G1 X10 Y180 F4000"));
|
|
enquecommand_P(PSTR("G1 Z10 F1300.000"));
|
|
enquecommand_P(PSTR("M84"));
|
|
|
|
lcd_commands_step = 1;
|
|
|
|
}
|
|
|
|
if (lcd_commands_step == 1 && !blocks_queued() && cmd_buffer_empty())
|
|
{
|
|
lcd_setstatuspgm(_T(WELCOME_MSG));
|
|
lcd_commands_step = 0;
|
|
lcd_commands_type = 0;
|
|
if (eeprom_read_byte((uint8_t*)EEPROM_WIZARD_ACTIVE) == 1) {
|
|
lcd_wizard(WizState::RepeatLay1Cal);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
#else //if not SNMM
|
|
|
|
if (lcd_commands_type == LcdCommands::Layer1Cal)
|
|
{
|
|
char cmd1[30];
|
|
|
|
if(lcd_commands_step>1) lcd_timeoutToStatus.start(); //if user dont confirm live adjust Z value by pressing the knob, we are saving last value by timeout to status screen
|
|
|
|
if (!blocks_queued() && cmd_buffer_empty() && !saved_printing)
|
|
{
|
|
switch(lcd_commands_step)
|
|
{
|
|
case 0:
|
|
lcd_commands_step = 11;
|
|
break;
|
|
case 11:
|
|
lay1cal_wait_preheat();
|
|
lcd_commands_step = 10;
|
|
break;
|
|
case 10:
|
|
lay1cal_load_filament(cmd1, lay1cal_filament);
|
|
lcd_commands_step = 9;
|
|
break;
|
|
case 9:
|
|
lcd_clear();
|
|
menu_depth = 0;
|
|
menu_submenu(lcd_babystep_z);
|
|
lay1cal_intro_line();
|
|
lcd_commands_step = 8;
|
|
break;
|
|
case 8:
|
|
lay1cal_before_meander();
|
|
lcd_commands_step = 7;
|
|
break;
|
|
case 7:
|
|
lay1cal_meander(cmd1);
|
|
lcd_commands_step = 6;
|
|
break;
|
|
case 6:
|
|
for (uint8_t i = 0; i < 4; i++)
|
|
{
|
|
lay1cal_square(cmd1, i);
|
|
}
|
|
lcd_commands_step = 5;
|
|
break;
|
|
case 5:
|
|
for (uint8_t i = 4; i < 8; i++)
|
|
{
|
|
lay1cal_square(cmd1, i);
|
|
}
|
|
lcd_commands_step = 4;
|
|
break;
|
|
case 4:
|
|
for (uint8_t i = 8; i < 12; i++)
|
|
{
|
|
lay1cal_square(cmd1, i);
|
|
}
|
|
lcd_commands_step = 3;
|
|
break;
|
|
case 3:
|
|
for (uint8_t i = 12; i < 16; i++)
|
|
{
|
|
lay1cal_square(cmd1, i);
|
|
}
|
|
lcd_commands_step = 2;
|
|
break;
|
|
case 2:
|
|
enquecommand_P(PSTR("M107")); //turn off printer fan
|
|
enquecommand_P(PSTR("G1 E-0.07500 F2100.00000")); //retract
|
|
enquecommand_P(PSTR("M104 S0")); // turn off temperature
|
|
enquecommand_P(PSTR("M140 S0")); // turn off heatbed
|
|
enquecommand_P(PSTR("G1 Z10 F1300.000")); //lift Z
|
|
enquecommand_P(PSTR("G1 X10 Y180 F4000")); //Go to parking position
|
|
if (mmu_enabled) enquecommand_P(PSTR("M702 C")); //unload from nozzle
|
|
enquecommand_P(PSTR("M84"));// disable motors
|
|
forceMenuExpire = true; //if user dont confirm live adjust Z value by pressing the knob, we are saving last value by timeout to status screen
|
|
lcd_commands_step = 1;
|
|
break;
|
|
case 1:
|
|
lcd_setstatuspgm(_T(WELCOME_MSG));
|
|
lcd_commands_step = 0;
|
|
lcd_commands_type = LcdCommands::Idle;
|
|
if (eeprom_read_byte((uint8_t*)EEPROM_WIZARD_ACTIVE) == 1)
|
|
{
|
|
lcd_wizard(WizState::RepeatLay1Cal);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif // not SNMM
|
|
|
|
if (lcd_commands_type == LcdCommands::StopPrint) /// stop print
|
|
{
|
|
|
|
|
|
if (lcd_commands_step == 0)
|
|
{
|
|
lcd_commands_step = 6;
|
|
}
|
|
|
|
if (lcd_commands_step == 1 && !blocks_queued())
|
|
{
|
|
lcd_commands_step = 0;
|
|
lcd_commands_type = LcdCommands::Idle;
|
|
lcd_setstatuspgm(_T(WELCOME_MSG));
|
|
custom_message_type = CustomMsg::Status;
|
|
isPrintPaused = false;
|
|
}
|
|
if (lcd_commands_step == 2 && !blocks_queued())
|
|
{
|
|
setTargetBed(0);
|
|
enquecommand_P(PSTR("M104 S0")); //set hotend temp to 0
|
|
|
|
manage_heater();
|
|
lcd_setstatuspgm(_T(WELCOME_MSG));
|
|
cancel_heatup = false;
|
|
lcd_commands_step = 1;
|
|
}
|
|
if (lcd_commands_step == 3 && !blocks_queued())
|
|
{
|
|
// M84: Disable steppers.
|
|
enquecommand_P(PSTR("M84"));
|
|
autotempShutdown();
|
|
lcd_commands_step = 2;
|
|
}
|
|
if (lcd_commands_step == 4 && !blocks_queued())
|
|
{
|
|
lcd_setstatuspgm(_T(MSG_PLEASE_WAIT));
|
|
// G90: Absolute positioning.
|
|
enquecommand_P(PSTR("G90"));
|
|
// M83: Set extruder to relative mode.
|
|
enquecommand_P(PSTR("M83"));
|
|
#ifdef X_CANCEL_POS
|
|
enquecommand_P(PSTR("G1 X" STRINGIFY(X_CANCEL_POS) " Y" STRINGIFY(Y_CANCEL_POS) " E0 F7000"));
|
|
#else
|
|
enquecommand_P(PSTR("G1 X50 Y" STRINGIFY(Y_MAX_POS) " E0 F7000"));
|
|
#endif
|
|
lcd_ignore_click(false);
|
|
if (mmu_enabled)
|
|
lcd_commands_step = 8;
|
|
else
|
|
lcd_commands_step = 3;
|
|
}
|
|
if (lcd_commands_step == 5 && !blocks_queued())
|
|
{
|
|
lcd_setstatuspgm(_T(MSG_PRINT_ABORTED));
|
|
// G91: Set to relative positioning.
|
|
enquecommand_P(PSTR("G91"));
|
|
// Lift up.
|
|
enquecommand_P(PSTR("G1 Z15 F1500"));
|
|
if (axis_known_position[X_AXIS] && axis_known_position[Y_AXIS]) lcd_commands_step = 4;
|
|
else lcd_commands_step = 3;
|
|
}
|
|
if (lcd_commands_step == 6 && !blocks_queued())
|
|
{
|
|
lcd_setstatuspgm(_T(MSG_PRINT_ABORTED));
|
|
cancel_heatup = true;
|
|
setTargetBed(0);
|
|
if (mmu_enabled)
|
|
setAllTargetHotends(0);
|
|
manage_heater();
|
|
custom_message_type = CustomMsg::FilamentLoading;
|
|
lcd_commands_step = 5;
|
|
}
|
|
if (lcd_commands_step == 7 && !blocks_queued())
|
|
{
|
|
if (mmu_enabled)
|
|
enquecommand_P(PSTR("M702 C")); //current
|
|
else
|
|
switch(snmm_stop_print_menu())
|
|
{
|
|
case 0: enquecommand_P(PSTR("M702")); break;//all
|
|
case 1: enquecommand_P(PSTR("M702 U")); break; //used
|
|
case 2: enquecommand_P(PSTR("M702 C")); break; //current
|
|
default: enquecommand_P(PSTR("M702")); break;
|
|
}
|
|
lcd_commands_step = 3;
|
|
}
|
|
if (lcd_commands_step == 8 && !blocks_queued()) { //step 8 is here for delay (going to next step after execution of all gcodes from step 4)
|
|
lcd_commands_step = 7;
|
|
}
|
|
}
|
|
|
|
if (lcd_commands_type == LcdCommands::FarmModeConfirm) /// farm mode confirm
|
|
{
|
|
|
|
if (lcd_commands_step == 0) { lcd_commands_step = 6; }
|
|
|
|
if (lcd_commands_step == 1 && !blocks_queued())
|
|
{
|
|
lcd_confirm_print();
|
|
lcd_commands_step = 0;
|
|
lcd_commands_type = LcdCommands::Idle;
|
|
}
|
|
if (lcd_commands_step == 2 && !blocks_queued())
|
|
{
|
|
lcd_commands_step = 1;
|
|
}
|
|
if (lcd_commands_step == 3 && !blocks_queued())
|
|
{
|
|
lcd_commands_step = 2;
|
|
}
|
|
if (lcd_commands_step == 4 && !blocks_queued())
|
|
{
|
|
enquecommand_P(PSTR("G90"));
|
|
enquecommand_P(PSTR("G1 X" STRINGIFY(X_CANCEL_POS) " Y" STRINGIFY(Y_CANCEL_POS) " E0 F7000"));
|
|
lcd_commands_step = 3;
|
|
}
|
|
if (lcd_commands_step == 5 && !blocks_queued())
|
|
{
|
|
lcd_commands_step = 4;
|
|
}
|
|
if (lcd_commands_step == 6 && !blocks_queued())
|
|
{
|
|
enquecommand_P(PSTR("G91"));
|
|
enquecommand_P(PSTR("G1 Z15 F1500"));
|
|
st_synchronize();
|
|
#ifdef SNMM
|
|
lcd_commands_step = 7;
|
|
#else
|
|
lcd_commands_step = 5;
|
|
#endif
|
|
}
|
|
|
|
}
|
|
if (lcd_commands_type == LcdCommands::PidExtruder) {
|
|
char cmd1[30];
|
|
|
|
if (lcd_commands_step == 0) {
|
|
custom_message_type = CustomMsg::PidCal;
|
|
custom_message_state = 1;
|
|
lcd_draw_update = 3;
|
|
lcd_commands_step = 3;
|
|
}
|
|
if (lcd_commands_step == 3 && !blocks_queued()) { //PID calibration
|
|
strcpy(cmd1, "M303 E0 S");
|
|
strcat(cmd1, ftostr3(pid_temp));
|
|
// setting the correct target temperature (for visualization) is done in PID_autotune
|
|
enquecommand(cmd1);
|
|
lcd_setstatuspgm(_i("PID cal. "));////MSG_PID_RUNNING c=20 r=1
|
|
lcd_commands_step = 2;
|
|
}
|
|
if (lcd_commands_step == 2 && pid_tuning_finished) { //saving to eeprom
|
|
pid_tuning_finished = false;
|
|
custom_message_state = 0;
|
|
lcd_setstatuspgm(_i("PID cal. finished"));////MSG_PID_FINISHED c=20 r=1
|
|
setAllTargetHotends(0); // reset all hotends temperature including the number displayed on the main screen
|
|
if (_Kp != 0 || _Ki != 0 || _Kd != 0) {
|
|
strcpy(cmd1, "M301 P");
|
|
strcat(cmd1, ftostr32(_Kp));
|
|
strcat(cmd1, " I");
|
|
strcat(cmd1, ftostr32(_Ki));
|
|
strcat(cmd1, " D");
|
|
strcat(cmd1, ftostr32(_Kd));
|
|
enquecommand(cmd1);
|
|
enquecommand_P(PSTR("M500"));
|
|
}
|
|
else {
|
|
SERIAL_ECHOPGM("Invalid PID cal. results. Not stored to EEPROM.");
|
|
}
|
|
display_time = _millis();
|
|
lcd_commands_step = 1;
|
|
}
|
|
if ((lcd_commands_step == 1) && ((_millis()- display_time)>2000)) { //calibration finished message
|
|
lcd_setstatuspgm(_T(WELCOME_MSG));
|
|
custom_message_type = CustomMsg::Status;
|
|
pid_temp = DEFAULT_PID_TEMP;
|
|
lcd_commands_step = 0;
|
|
lcd_commands_type = LcdCommands::Idle;
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|
|
void lcd_return_to_status()
|
|
{
|
|
lcd_refresh(); // to maybe revive the LCD if static electricity killed it.
|
|
menu_goto(lcd_status_screen, 0, false, true);
|
|
menu_depth = 0;
|
|
eFilamentAction = FilamentAction::None; // i.e. non-autoLoad
|
|
}
|
|
|
|
//! @brief Pause print, disable nozzle heater, move to park position
|
|
void lcd_pause_print()
|
|
{
|
|
lcd_return_to_status();
|
|
stop_and_save_print_to_ram(0.0,0.0);
|
|
long_pause();
|
|
isPrintPaused = true;
|
|
if (LcdCommands::Idle == lcd_commands_type)
|
|
{
|
|
lcd_commands_type = LcdCommands::LongPause;
|
|
}
|
|
SERIAL_PROTOCOLLNRPGM(MSG_OCTOPRINT_PAUSED); //pause for octoprint
|
|
}
|
|
|
|
|
|
float move_menu_scale;
|
|
static void lcd_move_menu_axis();
|
|
|
|
|
|
|
|
/* Menu implementation */
|
|
|
|
static void lcd_cooldown()
|
|
{
|
|
setAllTargetHotends(0);
|
|
setTargetBed(0);
|
|
fanSpeed = 0;
|
|
eFilamentAction = FilamentAction::None;
|
|
lcd_return_to_status();
|
|
}
|
|
|
|
//! @brief append text label with a colon and format it into a fixed size output buffer
|
|
//! It would have been much easier if there was a ':' in the labels.
|
|
//! But since the texts like Bed, Nozzle and PINDA are used in other places
|
|
//! it is better to reuse these texts even though it requires some extra formatting code.
|
|
//! @param [in] ipgmLabel pointer to string in PROGMEM
|
|
//! @param [out] pointer to string in RAM which will receive the formatted text. Must be allocated to appropriate size
|
|
//! @param [in] dstSize allocated length of dst
|
|
static void pgmtext_with_colon(const char *ipgmLabel, char *dst, uint8_t dstSize){
|
|
uint8_t i = 0;
|
|
for(; i < dstSize - 2; ++i){ // 2 byte less than buffer, we'd be adding a ':' to the end
|
|
uint8_t b = pgm_read_byte(ipgmLabel + i);
|
|
if( ! b )
|
|
break;
|
|
dst[i] = b;
|
|
}
|
|
dst[i] = ':'; // append the colon
|
|
++i;
|
|
for(; i < dstSize - 1; ++i) // fill the rest with spaces
|
|
dst[i] = ' ';
|
|
dst[dstSize-1] = '\0'; // terminate the string properly
|
|
}
|
|
|
|
//! @brief Show Extruder Info
|
|
//!
|
|
//! @code{.unparsed}
|
|
//! |01234567890123456789|
|
|
//! |Nozzle FAN: 0000 RPM| FAN c=10 r=1 SPEED c=3 r=1
|
|
//! |Print FAN: 0000 RPM| FAN c=10 r=1 SPEED c=3 r=1
|
|
//! |Fil. Xd:000 Yd:000 | Fil. c=4 r=1
|
|
//! |Int: 000 Shut: 000 | Int: c=4 r=1 Shut: c=4 r=1
|
|
//! ----------------------
|
|
//! @endcode
|
|
//! @todo Positioning of the messages and values on LCD aren't fixed to their exact place. This causes issues with translations.
|
|
void lcd_menu_extruder_info() // NOT static due to using inside "Marlin_main" module ("manage_inactivity()")
|
|
{
|
|
|
|
// Display Nozzle fan RPM
|
|
lcd_timeoutToStatus.stop(); //infinite timeout
|
|
lcd_home();
|
|
static const size_t maxChars = 12;
|
|
char nozzle[maxChars], print[maxChars];
|
|
pgmtext_with_colon(_i("Nozzle FAN"), nozzle, maxChars); ////c=10 r=1
|
|
pgmtext_with_colon(_i("Print FAN"), print, maxChars); ////c=10 r=1
|
|
lcd_printf_P(_N("%s %4d RPM\n" "%s %4d RPM\n"), nozzle, 60*fan_speed[0], print, 60*fan_speed[1] );
|
|
|
|
#ifdef PAT9125
|
|
// Display X and Y difference from Filament sensor
|
|
// Display Light intensity from Filament sensor
|
|
// Frame_Avg register represents the average brightness of all pixels within a frame (324 pixels). This
|
|
// value ranges from 0(darkest) to 255(brightest).
|
|
// Display LASER shutter time from Filament sensor
|
|
// Shutter register is an index of LASER shutter time. It is automatically controlled by the chip's internal
|
|
// auto-exposure algorithm. When the chip is tracking on a good reflection surface, the Shutter is small.
|
|
// When the chip is tracking on a poor reflection surface, the Shutter is large. Value ranges from 0 to 46.
|
|
if (mmu_enabled == false)
|
|
{
|
|
if (!fsensor_enabled)
|
|
lcd_puts_P(_N("Filament sensor\n" "is disabled."));
|
|
else
|
|
{
|
|
if (!moves_planned() && !IS_SD_PRINTING && !is_usb_printing && (lcd_commands_type != LcdCommands::Layer1Cal))
|
|
pat9125_update();
|
|
lcd_printf_P(_N(
|
|
"Fil. Xd:%3d Yd:%3d\n" ////c=4 r=1
|
|
"Int: %3d " ////c=4 r=1
|
|
"Shut: %3d" ////c=4 r=1
|
|
),
|
|
pat9125_x, pat9125_y,
|
|
pat9125_b, pat9125_s
|
|
);
|
|
}
|
|
}
|
|
#endif //PAT9125
|
|
|
|
menu_back_if_clicked();
|
|
}
|
|
|
|
//! @brief Show Fails Statistics MMU
|
|
//!
|
|
//! @code{.unparsed}
|
|
//! |01234567890123456789|
|
|
//! | Main | c=18 r=1
|
|
//! | Last print | c=18 r=1
|
|
//! | Total | c=18 r=1
|
|
//! | |
|
|
//! ----------------------
|
|
//! @endcode
|
|
static void lcd_menu_fails_stats_mmu()
|
|
{
|
|
MENU_BEGIN();
|
|
MENU_ITEM_BACK_P(_T(MSG_MAIN));
|
|
MENU_ITEM_SUBMENU_P(_i("Last print"), lcd_menu_fails_stats_mmu_print); ////c=18 r=1
|
|
MENU_ITEM_SUBMENU_P(_i("Total"), lcd_menu_fails_stats_mmu_total); ////c=18 r=1
|
|
MENU_END();
|
|
}
|
|
|
|
//! @brief Show Last Print Failures Statistics MMU
|
|
//!
|
|
//! @code{.unparsed}
|
|
//! |01234567890123456789|
|
|
//! |Last print failures | c=20 r=1
|
|
//! | MMU fails: 000| c=14 r=1
|
|
//! | MMU load fails: 000| c=14 r=1
|
|
//! | |
|
|
//! ----------------------
|
|
//! @endcode
|
|
//! @todo Positioning of the messages and values on LCD aren't fixed to their exact place. This causes issues with translations.
|
|
static void lcd_menu_fails_stats_mmu_print()
|
|
{
|
|
lcd_timeoutToStatus.stop(); //infinite timeout
|
|
uint8_t fails = eeprom_read_byte((uint8_t*)EEPROM_MMU_FAIL);
|
|
uint16_t load_fails = eeprom_read_byte((uint8_t*)EEPROM_MMU_LOAD_FAIL);
|
|
lcd_home();
|
|
lcd_printf_P(PSTR("%S\n" " %-16.16S%-3d\n" " %-16.16S%-3d"),
|
|
_i("Last print failures"), ////c=20 r=1
|
|
_i("MMU fails"), fails, ////c=14 r=1
|
|
_i("MMU load fails"), load_fails); ////c=14 r=1
|
|
menu_back_if_clicked_fb();
|
|
}
|
|
|
|
//! @brief Show Total Failures Statistics MMU
|
|
//!
|
|
//! @code{.unparsed}
|
|
//! |01234567890123456789|
|
|
//! |Total failures | c=20 r=1
|
|
//! | MMU fails: 000| c=14 r=1
|
|
//! | MMU load fails: 000| c=14 r=1
|
|
//! | MMU power fails:000| c=14 r=1
|
|
//! ----------------------
|
|
//! @endcode
|
|
//! @todo Positioning of the messages and values on LCD aren't fixed to their exact place. This causes issues with translations.
|
|
static void lcd_menu_fails_stats_mmu_total()
|
|
{
|
|
mmu_command(MmuCmd::S3);
|
|
lcd_timeoutToStatus.stop(); //infinite timeout
|
|
uint8_t fails = eeprom_read_byte((uint8_t*)EEPROM_MMU_FAIL_TOT);
|
|
uint16_t load_fails = eeprom_read_byte((uint8_t*)EEPROM_MMU_LOAD_FAIL_TOT);
|
|
lcd_home();
|
|
lcd_printf_P(PSTR("%S\n" " %-16.16S%-3d\n" " %-16.16S%-3d\n" " %-16.16S%-3d"),
|
|
_i("Total failures"), ////c=20 r=1
|
|
_i("MMU fails"), fails, ////c=14 r=1
|
|
_i("MMU load fails"), load_fails, ////c=14 r=1
|
|
_i("MMU power fails"), mmu_power_failures); ////c=14 r=1
|
|
menu_back_if_clicked_fb();
|
|
}
|
|
|
|
#if defined(TMC2130) && defined(FILAMENT_SENSOR)
|
|
static const char failStatsFmt[] PROGMEM = "%S\n" " %-16.16S%-3d\n" " %-16.16S%-3d\n" " %-7.7SX %-3d Y %-3d";
|
|
|
|
//! @brief Show Total Failures Statistics MMU
|
|
//!
|
|
//! @code{.unparsed}
|
|
//! |01234567890123456789|
|
|
//! |Total failures | c=20 r=1
|
|
//! | Power failures: 000| c=14 r=1
|
|
//! | Filam. runouts: 000| c=14 r=1
|
|
//! | Crash X:000 Y:000| c=7 r=1
|
|
//! ----------------------
|
|
//! @endcode
|
|
//! @todo Positioning of the messages and values on LCD aren't fixed to their exact place. This causes issues with translations.
|
|
static void lcd_menu_fails_stats_total()
|
|
{
|
|
lcd_timeoutToStatus.stop(); //infinite timeout
|
|
uint16_t power = eeprom_read_word((uint16_t*)EEPROM_POWER_COUNT_TOT);
|
|
uint16_t filam = eeprom_read_word((uint16_t*)EEPROM_FERROR_COUNT_TOT);
|
|
uint16_t crashX = eeprom_read_word((uint16_t*)EEPROM_CRASH_COUNT_X_TOT);
|
|
uint16_t crashY = eeprom_read_word((uint16_t*)EEPROM_CRASH_COUNT_Y_TOT);
|
|
lcd_home();
|
|
lcd_printf_P(failStatsFmt,
|
|
_i("Total failures"), ////c=20 r=1
|
|
_i("Power failures"), power, ////c=14 r=1
|
|
_i("Filam. runouts"), filam, ////c=14 r=1
|
|
_i("Crash"), crashX, crashY); ////c=7 r=1
|
|
menu_back_if_clicked_fb();
|
|
}
|
|
|
|
//! @brief Show Last Print Failures Statistics
|
|
//!
|
|
//! @code{.unparsed}
|
|
//! |01234567890123456789|
|
|
//! |Last print failures | c=20 r=1
|
|
//! | Power failures 000| c=14 r=1
|
|
//! | Filam. runouts 000| c=14 r=1
|
|
//! | Crash X:000 Y:000| c=7 r=1
|
|
//! ----------------------
|
|
//! @endcode
|
|
//! @todo Positioning of the messages and values on LCD aren't fixed to their exact place. This causes issues with translations.
|
|
static void lcd_menu_fails_stats_print()
|
|
{
|
|
lcd_timeoutToStatus.stop(); //infinite timeout
|
|
uint8_t power = eeprom_read_byte((uint8_t*)EEPROM_POWER_COUNT);
|
|
uint8_t filam = eeprom_read_byte((uint8_t*)EEPROM_FERROR_COUNT);
|
|
uint8_t crashX = eeprom_read_byte((uint8_t*)EEPROM_CRASH_COUNT_X);
|
|
uint8_t crashY = eeprom_read_byte((uint8_t*)EEPROM_CRASH_COUNT_Y);
|
|
lcd_home();
|
|
lcd_printf_P(failStatsFmt,
|
|
_i("Last print failures"), ////c=20 r=1
|
|
_i("Power failures"), power, ////c=14 r=1
|
|
_i("Filam. runouts"), filam, ////c=14 r=1
|
|
_i("Crash"), crashX, crashY); ////c=7 r=1
|
|
menu_back_if_clicked_fb();
|
|
}
|
|
|
|
//! @brief Open fail statistics menu
|
|
//!
|
|
//! This version of function is used, when there is filament sensor,
|
|
//! power failure and crash detection.
|
|
//! There are Last print and Total menu items.
|
|
//!
|
|
//! @code{.unparsed}
|
|
//! |01234567890123456789|
|
|
//! | Main | c=18 r=1
|
|
//! | Last print | c=18 r=1
|
|
//! | Total | c=18 r=1
|
|
//! | |
|
|
//! ----------------------
|
|
//! @endcode
|
|
|
|
static void lcd_menu_fails_stats()
|
|
{
|
|
MENU_BEGIN();
|
|
MENU_ITEM_BACK_P(_T(MSG_MAIN));
|
|
MENU_ITEM_SUBMENU_P(_i("Last print"), lcd_menu_fails_stats_print); ////c=18 r=1
|
|
MENU_ITEM_SUBMENU_P(_i("Total"), lcd_menu_fails_stats_total); ////c=18 r=1
|
|
MENU_END();
|
|
}
|
|
|
|
#elif defined(FILAMENT_SENSOR)
|
|
static const char failStatsFmt[] PROGMEM = "%S\n" " %-16.16S%-3d\n" "%S\n" " %-16.16S%-3d\n";
|
|
//!
|
|
//! @brief Print last print and total filament run outs
|
|
//!
|
|
//! This version of function is used, when there is filament sensor,
|
|
//! but no other sensors (e.g. power failure, crash detection).
|
|
//!
|
|
//! Example screen:
|
|
//! @code{.unparsed}
|
|
//! |01234567890123456789|
|
|
//! |Last print failures | c=20 r=1
|
|
//! | Filam. runouts 000| c=14 r=1
|
|
//! |Total failures | c=20 r=1
|
|
//! | Filam. runouts 000| c=14 r=1
|
|
//! ----------------------
|
|
//! @endcode
|
|
//! @todo Positioning of the messages and values on LCD aren't fixed to their exact place. This causes issues with translations.
|
|
static void lcd_menu_fails_stats()
|
|
{
|
|
lcd_timeoutToStatus.stop(); //infinite timeout
|
|
uint8_t filamentLast = eeprom_read_byte((uint8_t*)EEPROM_FERROR_COUNT);
|
|
uint16_t filamentTotal = eeprom_read_word((uint16_t*)EEPROM_FERROR_COUNT_TOT);
|
|
lcd_home();
|
|
lcd_printf_P(failStatsFmt,
|
|
_i("Last print failures"), ////c=20 r=1
|
|
_i("Filam. runouts"), filamentLast, ////c=14 r=1
|
|
_i("Total failures"), ////c=20 r=1
|
|
_i("Filam. runouts"), filamentTotal); ////c=14 r=1
|
|
|
|
menu_back_if_clicked();
|
|
}
|
|
#else
|
|
static void lcd_menu_fails_stats()
|
|
{
|
|
lcd_timeoutToStatus.stop(); //infinite timeout
|
|
MENU_BEGIN();
|
|
MENU_ITEM_BACK_P(_T(MSG_MAIN));
|
|
MENU_END();
|
|
}
|
|
#endif //TMC2130
|
|
|
|
|
|
#ifdef DEBUG_BUILD
|
|
#ifdef DEBUG_STACK_MONITOR
|
|
extern uint16_t SP_min;
|
|
extern char* __malloc_heap_start;
|
|
extern char* __malloc_heap_end;
|
|
#endif //DEBUG_STACK_MONITOR
|
|
|
|
//! @brief Show Debug Information
|
|
//!
|
|
//! @code{.unparsed}
|
|
//! |01234567890123456789|
|
|
//! |RAM statistics | c=20 r=1
|
|
//! | SP_min: 0000| c=14 r=1
|
|
//! | heap_start: 0000| c=14 r=1
|
|
//! | heap_end: 0000| c=14 r=1
|
|
//! ----------------------
|
|
//! @endcode
|
|
//! @todo Positioning of the messages and values on LCD aren't fixed to their exact place. This causes issues with translations.
|
|
static void lcd_menu_debug()
|
|
{
|
|
#ifdef DEBUG_STACK_MONITOR
|
|
lcd_home();
|
|
lcd_printf_P(PSTR("RAM statistics\n" ////c=20 r=1
|
|
" SP_min: 0x%04x\n" ////c=14 r=1
|
|
" heap_start: 0x%04x\n" ////c=14 r=1
|
|
" heap_end: 0x%04x"), SP_min, __malloc_heap_start, __malloc_heap_end); ////c=14 r=1
|
|
#endif //DEBUG_STACK_MONITOR
|
|
|
|
menu_back_if_clicked_fb();
|
|
}
|
|
#endif /* DEBUG_BUILD */
|
|
|
|
//! @brief common line print for lcd_menu_temperatures
|
|
//! @param [in] ipgmLabel pointer to string in PROGMEM
|
|
//! @param [in] value to be printed behind the label
|
|
static void lcd_menu_temperatures_line(const char *ipgmLabel, int value){
|
|
static const size_t maxChars = 15;
|
|
char tmp[maxChars];
|
|
pgmtext_with_colon(ipgmLabel, tmp, maxChars);
|
|
lcd_printf_P(PSTR(" %s%3d\x01 \n"), tmp, value); // no need to add -14.14 to string alignment
|
|
}
|
|
|
|
//! @brief Show Temperatures
|
|
//!
|
|
//! @code{.unparsed}
|
|
//! |01234567890123456789|
|
|
//! | Nozzle: 000D| c=14 r=1
|
|
//! | Bed: 000D| c=14 r=1
|
|
//! | Ambient: 000D| c=14 r=1
|
|
//! | PINDA: 000D| c=14 r=1
|
|
//! ----------------------
|
|
//! D - Degree sysmbol LCD_STR_DEGREE
|
|
//! @endcode
|
|
//! @todo Positioning of the messages and values on LCD aren't fixed to their exact place. This causes issues with translations.
|
|
static void lcd_menu_temperatures()
|
|
{
|
|
lcd_timeoutToStatus.stop(); //infinite timeout
|
|
lcd_home();
|
|
lcd_menu_temperatures_line( _T(MSG_NOZZLE), (int)current_temperature[0] ); ////c=14 r=1
|
|
lcd_menu_temperatures_line( _T(MSG_BED), (int)current_temperature_bed ); ////c=14 r=1
|
|
#ifdef AMBIENT_THERMISTOR
|
|
lcd_menu_temperatures_line( _i("Ambient"), (int)current_temperature_ambient ); ////c=14 r=1
|
|
#endif //AMBIENT_THERMISTOR
|
|
#ifdef PINDA_THERMISTOR
|
|
lcd_menu_temperatures_line( _i("PINDA"), (int)current_temperature_pinda ); ////c=14 r=1
|
|
#endif //PINDA_THERMISTOR
|
|
menu_back_if_clicked();
|
|
}
|
|
|
|
#if defined (VOLT_BED_PIN) || defined (VOLT_PWR_PIN) || IR_SENSOR_ANALOG
|
|
#define VOLT_DIV_R1 10000
|
|
#define VOLT_DIV_R2 2370
|
|
#define VOLT_DIV_FAC ((float)VOLT_DIV_R2 / (VOLT_DIV_R2 + VOLT_DIV_R1))
|
|
|
|
//! @brief Show Voltages
|
|
//!
|
|
//! @code{.unparsed}
|
|
//! |01234567890123456789|
|
|
//! | |
|
|
//! | PWR: 00.0V | c=12 r=1
|
|
//! | Bed: 00.0V | c=12 r=1
|
|
//! | |
|
|
//! ----------------------
|
|
//! @endcode
|
|
//! @todo Positioning of the messages and values on LCD aren't fixed to their exact place. This causes issues with translations.
|
|
static void lcd_menu_voltages()
|
|
{
|
|
lcd_timeoutToStatus.stop(); //infinite timeout
|
|
float volt_pwr = VOLT_DIV_REF * ((float)current_voltage_raw_pwr / (1023 * OVERSAMPLENR)) / VOLT_DIV_FAC;
|
|
float volt_bed = VOLT_DIV_REF * ((float)current_voltage_raw_bed / (1023 * OVERSAMPLENR)) / VOLT_DIV_FAC;
|
|
lcd_home();
|
|
#if !IR_SENSOR_ANALOG
|
|
lcd_printf_P(PSTR("\n"));
|
|
#endif //!IR_SENSOR_ANALOG
|
|
lcd_printf_P(PSTR(" PWR: %4.1fV\n" " BED: %4.1fV"), volt_pwr, volt_bed);
|
|
#if IR_SENSOR_ANALOG
|
|
float volt_IR = VOLT_DIV_REF * ((float)current_voltage_raw_IR / (1023 * OVERSAMPLENR));
|
|
lcd_printf_P(PSTR("\n IR : %3.1fV"),volt_IR);
|
|
#endif //IR_SENSOR_ANALOG
|
|
menu_back_if_clicked();
|
|
}
|
|
#endif //defined (VOLT_BED_PIN) || defined (VOLT_PWR_PIN) || IR_SENSOR_ANALOG
|
|
|
|
#ifdef TMC2130
|
|
//! @brief Show Belt Status
|
|
//!
|
|
//! @code{.unparsed}
|
|
//! |01234567890123456789|
|
|
//! | Belt status | c=18 r=1
|
|
//! | X: 000 |
|
|
//! | Y: 000 |
|
|
//! | |
|
|
//! ----------------------
|
|
//! @endcode
|
|
//! @todo Positioning of the messages and values on LCD aren't fixed to their exact place. This causes issues with translations.
|
|
static void lcd_menu_belt_status()
|
|
{
|
|
lcd_home();
|
|
lcd_printf_P(PSTR("%S\n" " X %d\n" " Y %d"), _i("Belt status"), eeprom_read_word((uint16_t*)(EEPROM_BELTSTATUS_X)), eeprom_read_word((uint16_t*)(EEPROM_BELTSTATUS_Y)));
|
|
menu_back_if_clicked();
|
|
}
|
|
#endif //TMC2130
|
|
|
|
#ifdef RESUME_DEBUG
|
|
extern void stop_and_save_print_to_ram(float z_move, float e_move);
|
|
extern void restore_print_from_ram_and_continue(float e_move);
|
|
|
|
static void lcd_menu_test_save()
|
|
{
|
|
stop_and_save_print_to_ram(10, -0.8);
|
|
}
|
|
|
|
static void lcd_menu_test_restore()
|
|
{
|
|
restore_print_from_ram_and_continue(0.8);
|
|
}
|
|
#endif //RESUME_DEBUG
|
|
|
|
//! @brief Show Preheat Menu
|
|
static void lcd_preheat_menu()
|
|
{
|
|
eFilamentAction = FilamentAction::Preheat;
|
|
lcd_generic_preheat_menu();
|
|
}
|
|
|
|
//! @brief Show Support Menu
|
|
//!
|
|
//! @code{.unparsed}
|
|
//! |01234567890123456789|
|
|
//! | Main |
|
|
//! | Firmware: | c=18 r=1
|
|
//! | 3.7.2.-2363 | c=16 r=1
|
|
//! | prusa3d.com | MSG_PRUSA3D
|
|
//! | forum.prusa3d.com | MSG_PRUSA3D_FORUM
|
|
//! | howto.prusa3d.com | MSG_PRUSA3D_HOWTO
|
|
//! | -------------- | STR_SEPARATOR
|
|
//! | 1_75mm_MK3 | FILAMENT_SIZE
|
|
//! | howto.prusa3d.com | ELECTRONICS
|
|
//! | howto.prusa3d.com | NOZZLE_TYPE
|
|
//! | -------------- | STR_SEPARATOR
|
|
//! | Date: | c=17 r=1
|
|
//! | MMM DD YYYY | __DATE__
|
|
//! | -------------- | STR_SEPARATOR
|
|
//! @endcode
|
|
//!
|
|
//! If MMU is connected
|
|
//!
|
|
//! @code{.unparsed}
|
|
//! | MMU2 connected | c=18 r=1
|
|
//! | FW: 1.0.6-7064523 |
|
|
//! @endcode
|
|
//!
|
|
//! If MMU is not connected
|
|
//!
|
|
//! @code{.unparsed}
|
|
//! | MMU2 N/A | c=18 r=1
|
|
//! @endcode
|
|
//!
|
|
//! If Flash Air is connected
|
|
//!
|
|
//! @code{.unparsed}
|
|
//! | -------------- | STR_SEPARATOR
|
|
//! | FlashAir IP Addr: | c=18 r=1
|
|
//! | 192.168.1.100 |
|
|
//! @endcode
|
|
//!
|
|
//! @code{.unparsed}
|
|
//! | -------------- | STR_SEPARATOR
|
|
//! | XYZ cal. details | MSG_XYZ_DETAILS
|
|
//! | Extruder info | MSG_INFO_EXTRUDER
|
|
//! | XYZ cal. details | MSG_INFO_SENSORS
|
|
//! @endcode
|
|
//!
|
|
//! If TMC2130 defined
|
|
//!
|
|
//! @code{.unparsed}
|
|
//! | Belt status | MSG_MENU_BELT_STATUS
|
|
//! @endcode
|
|
//!
|
|
//! @code{.unparsed}
|
|
//! | Temperatures | MSG_MENU_TEMPERATURES
|
|
//! @endcode
|
|
//!
|
|
//! If Voltage Bed and PWR Pin are defined
|
|
//!
|
|
//! @code{.unparsed}
|
|
//! | Voltages | MSG_MENU_VOLTAGES
|
|
//! @endcode
|
|
//!
|
|
//!
|
|
//! If DEBUG_BUILD is defined
|
|
//!
|
|
//! @code{.unparsed}
|
|
//! | Debug | c=18 r=1
|
|
//! @endcode
|
|
//! ----------------------
|
|
//! @endcode
|
|
static void lcd_support_menu()
|
|
{
|
|
typedef struct
|
|
{ // 22bytes total
|
|
int8_t status; // 1byte
|
|
bool is_flash_air; // 1byte
|
|
uint8_t ip[4]; // 4bytes
|
|
char ip_str[3*4+3+1]; // 16bytes
|
|
} _menu_data_t;
|
|
static_assert(sizeof(menu_data)>= sizeof(_menu_data_t),"_menu_data_t doesn't fit into menu_data");
|
|
_menu_data_t* _md = (_menu_data_t*)&(menu_data[0]);
|
|
if (_md->status == 0 || lcd_draw_update == 2)
|
|
{
|
|
// Menu was entered or SD card status has changed (plugged in or removed).
|
|
// Initialize its status.
|
|
_md->status = 1;
|
|
_md->is_flash_air = card.ToshibaFlashAir_isEnabled() && card.ToshibaFlashAir_GetIP(_md->ip);
|
|
if (_md->is_flash_air)
|
|
sprintf_P(_md->ip_str, PSTR("%d.%d.%d.%d"),
|
|
_md->ip[0], _md->ip[1],
|
|
_md->ip[2], _md->ip[3]);
|
|
} else if (_md->is_flash_air &&
|
|
_md->ip[0] == 0 && _md->ip[1] == 0 &&
|
|
_md->ip[2] == 0 && _md->ip[3] == 0 &&
|
|
++ _md->status == 16)
|
|
{
|
|
// Waiting for the FlashAir card to get an IP address from a router. Force an update.
|
|
_md->status = 0;
|
|
}
|
|
|
|
MENU_BEGIN();
|
|
|
|
MENU_ITEM_BACK_P(_T(MSG_MAIN));
|
|
|
|
MENU_ITEM_BACK_P(PSTR("Firmware:"));
|
|
MENU_ITEM_BACK_P(PSTR(" " FW_VERSION_FULL));
|
|
#if (FW_DEV_VERSION != FW_VERSION_GOLD) && (FW_DEV_VERSION != FW_VERSION_RC)
|
|
MENU_ITEM_BACK_P(PSTR(" repo " FW_REPOSITORY));
|
|
#endif
|
|
// Ideally this block would be optimized out by the compiler.
|
|
/* const uint8_t fw_string_len = strlen_P(FW_VERSION_STR_P());
|
|
if (fw_string_len < 6) {
|
|
MENU_ITEM_BACK_P(PSTR(MSG_FW_VERSION " - " FW_version));
|
|
} else {
|
|
MENU_ITEM_BACK_P(PSTR("FW - " FW_version));
|
|
}*/
|
|
|
|
MENU_ITEM_BACK_P(_i("prusa3d.com"));////MSG_PRUSA3D
|
|
MENU_ITEM_BACK_P(_i("forum.prusa3d.com"));////MSG_PRUSA3D_FORUM
|
|
MENU_ITEM_BACK_P(_i("howto.prusa3d.com"));////MSG_PRUSA3D_HOWTO
|
|
MENU_ITEM_BACK_P(STR_SEPARATOR);
|
|
MENU_ITEM_BACK_P(PSTR(FILAMENT_SIZE));
|
|
MENU_ITEM_BACK_P(PSTR(ELECTRONICS));
|
|
MENU_ITEM_BACK_P(PSTR(NOZZLE_TYPE));
|
|
MENU_ITEM_BACK_P(STR_SEPARATOR);
|
|
MENU_ITEM_BACK_P(_i("Date:"));////MSG_DATE c=17 r=1
|
|
MENU_ITEM_BACK_P(PSTR(__DATE__));
|
|
|
|
MENU_ITEM_BACK_P(STR_SEPARATOR);
|
|
if (mmu_enabled)
|
|
{
|
|
MENU_ITEM_BACK_P(_i("MMU2 connected")); ////c=18 r=1
|
|
MENU_ITEM_BACK_P(PSTR(" FW:")); ////c=17 r=1
|
|
if (((menu_item - 1) == menu_line) && lcd_draw_update)
|
|
{
|
|
lcd_set_cursor(6, menu_row);
|
|
if ((mmu_version > 0) && (mmu_buildnr > 0))
|
|
lcd_printf_P(PSTR("%d.%d.%d-%d"), mmu_version/100, mmu_version%100/10, mmu_version%10, mmu_buildnr);
|
|
else
|
|
lcd_puts_P(_i("unknown"));
|
|
}
|
|
}
|
|
else
|
|
MENU_ITEM_BACK_P(PSTR("MMU2 N/A"));
|
|
|
|
|
|
// Show the FlashAir IP address, if the card is available.
|
|
if (_md->is_flash_air) {
|
|
MENU_ITEM_BACK_P(STR_SEPARATOR);
|
|
MENU_ITEM_BACK_P(PSTR("FlashAir IP Addr:")); //c=18 r=1
|
|
///! MENU_ITEM(back_RAM, _md->ip_str, 0);
|
|
}
|
|
|
|
#ifndef MK1BP
|
|
MENU_ITEM_BACK_P(STR_SEPARATOR);
|
|
MENU_ITEM_SUBMENU_P(_i("XYZ cal. details"), lcd_menu_xyz_y_min);////MSG_XYZ_DETAILS c=19 r=1
|
|
MENU_ITEM_SUBMENU_P(_i("Extruder info"), lcd_menu_extruder_info);////MSG_INFO_EXTRUDER c=18 r=1
|
|
MENU_ITEM_SUBMENU_P(_i("Sensor info"), lcd_menu_show_sensors_state);////MSG_INFO_SENSORS c=18 r=1
|
|
|
|
#ifdef TMC2130
|
|
MENU_ITEM_SUBMENU_P(_i("Belt status"), lcd_menu_belt_status);////MSG_MENU_BELT_STATUS c=18 r=1
|
|
#endif //TMC2130
|
|
|
|
MENU_ITEM_SUBMENU_P(_i("Temperatures"), lcd_menu_temperatures);////MSG_MENU_TEMPERATURES c=18 r=1
|
|
|
|
#if defined (VOLT_BED_PIN) || defined (VOLT_PWR_PIN)
|
|
MENU_ITEM_SUBMENU_P(_i("Voltages"), lcd_menu_voltages);////MSG_MENU_VOLTAGES c=18 r=1
|
|
#endif //defined VOLT_BED_PIN || defined VOLT_PWR_PIN
|
|
|
|
#ifdef DEBUG_BUILD
|
|
MENU_ITEM_SUBMENU_P(PSTR("Debug"), lcd_menu_debug);////c=18 r=1
|
|
#endif /* DEBUG_BUILD */
|
|
|
|
#endif //MK1BP
|
|
|
|
MENU_END();
|
|
}
|
|
|
|
void lcd_set_fan_check() {
|
|
fans_check_enabled = !fans_check_enabled;
|
|
eeprom_update_byte((unsigned char *)EEPROM_FAN_CHECK_ENABLED, fans_check_enabled);
|
|
}
|
|
|
|
#ifdef MMU_HAS_CUTTER
|
|
void lcd_cutter_enabled()
|
|
{
|
|
if (EEPROM_MMU_CUTTER_ENABLED_enabled == eeprom_read_byte((uint8_t*)EEPROM_MMU_CUTTER_ENABLED))
|
|
{
|
|
#ifndef MMU_ALWAYS_CUT
|
|
eeprom_update_byte((uint8_t*)EEPROM_MMU_CUTTER_ENABLED, 0);
|
|
}
|
|
#else //MMU_ALWAYS_CUT
|
|
eeprom_update_byte((uint8_t*)EEPROM_MMU_CUTTER_ENABLED, EEPROM_MMU_CUTTER_ENABLED_always);
|
|
}
|
|
else if (EEPROM_MMU_CUTTER_ENABLED_always == eeprom_read_byte((uint8_t*)EEPROM_MMU_CUTTER_ENABLED))
|
|
{
|
|
eeprom_update_byte((uint8_t*)EEPROM_MMU_CUTTER_ENABLED, 0);
|
|
}
|
|
#endif //MMU_ALWAYS_CUT
|
|
else
|
|
{
|
|
eeprom_update_byte((uint8_t*)EEPROM_MMU_CUTTER_ENABLED, EEPROM_MMU_CUTTER_ENABLED_enabled);
|
|
}
|
|
}
|
|
#endif //MMU_HAS_CUTTER
|
|
|
|
void lcd_set_filament_autoload() {
|
|
fsensor_autoload_set(!fsensor_autoload_enabled);
|
|
}
|
|
|
|
void lcd_set_filament_oq_meass()
|
|
{
|
|
fsensor_oq_meassure_set(!fsensor_oq_meassure_enabled);
|
|
}
|
|
|
|
|
|
FilamentAction eFilamentAction=FilamentAction::None; // must be initialized as 'non-autoLoad'
|
|
bool bFilamentFirstRun;
|
|
bool bFilamentPreheatState;
|
|
bool bFilamentAction=false;
|
|
static bool bFilamentWaitingFlag=false;
|
|
|
|
static void mFilamentPrompt()
|
|
{
|
|
uint8_t nLevel;
|
|
|
|
lcd_set_cursor(0,0);
|
|
lcdui_print_temp(LCD_STR_THERMOMETER[0],(int)degHotend(0),(int)degTargetHotend(0));
|
|
lcd_set_cursor(0,2);
|
|
lcd_puts_P(_i("Press the knob")); ////MSG_ c=20 r=1
|
|
lcd_set_cursor(0,3);
|
|
switch(eFilamentAction)
|
|
{
|
|
case FilamentAction::Load:
|
|
case FilamentAction::AutoLoad:
|
|
case FilamentAction::MmuLoad:
|
|
lcd_puts_P(_i("to load filament")); ////MSG_ c=20 r=1
|
|
break;
|
|
case FilamentAction::UnLoad:
|
|
case FilamentAction::MmuUnLoad:
|
|
lcd_puts_P(_i("to unload filament")); ////MSG_ c=20 r=1
|
|
break;
|
|
case FilamentAction::MmuEject:
|
|
case FilamentAction::MmuCut:
|
|
case FilamentAction::None:
|
|
case FilamentAction::Preheat:
|
|
case FilamentAction::Lay1Cal:
|
|
break;
|
|
}
|
|
if(lcd_clicked())
|
|
{
|
|
nLevel=2;
|
|
if(!bFilamentPreheatState)
|
|
{
|
|
nLevel++;
|
|
// setTargetHotend0(0.0); // uncoment if return to base-state is required
|
|
}
|
|
menu_back(nLevel);
|
|
switch(eFilamentAction)
|
|
{
|
|
case FilamentAction::AutoLoad:
|
|
eFilamentAction=FilamentAction::None; // i.e. non-autoLoad
|
|
// no break
|
|
case FilamentAction::Load:
|
|
loading_flag=true;
|
|
enquecommand_P(PSTR("M701")); // load filament
|
|
break;
|
|
case FilamentAction::UnLoad:
|
|
enquecommand_P(PSTR("M702")); // unload filament
|
|
break;
|
|
case FilamentAction::MmuLoad:
|
|
case FilamentAction::MmuUnLoad:
|
|
case FilamentAction::MmuEject:
|
|
case FilamentAction::MmuCut:
|
|
case FilamentAction::None:
|
|
case FilamentAction::Preheat:
|
|
case FilamentAction::Lay1Cal:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void mFilamentItem(uint16_t nTemp, uint16_t nTempBed)
|
|
{
|
|
static int nTargetOld;
|
|
static int nTargetBedOld;
|
|
uint8_t nLevel;
|
|
|
|
nTargetOld = target_temperature[0];
|
|
nTargetBedOld = target_temperature_bed;
|
|
setTargetHotend0((float )nTemp);
|
|
setTargetBed((float) nTempBed);
|
|
|
|
{
|
|
const FilamentAction action = eFilamentAction;
|
|
if (action == FilamentAction::Preheat || action == FilamentAction::Lay1Cal)
|
|
{
|
|
lcd_return_to_status();
|
|
if (action == FilamentAction::Lay1Cal)
|
|
{
|
|
lcd_commands_type = LcdCommands::Layer1Cal;
|
|
}
|
|
else
|
|
{
|
|
raise_z_above(MIN_Z_FOR_PREHEAT);
|
|
if (eeprom_read_byte((uint8_t*)EEPROM_WIZARD_ACTIVE))
|
|
lcd_wizard(WizState::LoadFilHot);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
lcd_timeoutToStatus.stop();
|
|
|
|
if (current_temperature[0] > (target_temperature[0] * 0.95))
|
|
{
|
|
switch (eFilamentAction)
|
|
{
|
|
case FilamentAction::Load:
|
|
case FilamentAction::AutoLoad:
|
|
case FilamentAction::UnLoad:
|
|
if (bFilamentWaitingFlag) menu_submenu(mFilamentPrompt);
|
|
else
|
|
{
|
|
nLevel = bFilamentPreheatState ? 1 : 2;
|
|
menu_back(nLevel);
|
|
if ((eFilamentAction == FilamentAction::Load) || (eFilamentAction == FilamentAction::AutoLoad))
|
|
{
|
|
loading_flag = true;
|
|
enquecommand_P(PSTR("M701")); // load filament
|
|
if (eFilamentAction == FilamentAction::AutoLoad) eFilamentAction = FilamentAction::None; // i.e. non-autoLoad
|
|
}
|
|
if (eFilamentAction == FilamentAction::UnLoad)
|
|
enquecommand_P(PSTR("M702")); // unload filament
|
|
}
|
|
break;
|
|
case FilamentAction::MmuLoad:
|
|
nLevel = bFilamentPreheatState ? 1 : 2;
|
|
bFilamentAction = true;
|
|
menu_back(nLevel);
|
|
menu_submenu(mmu_load_to_nozzle_menu);
|
|
break;
|
|
case FilamentAction::MmuUnLoad:
|
|
nLevel = bFilamentPreheatState ? 1 : 2;
|
|
bFilamentAction = true;
|
|
menu_back(nLevel);
|
|
extr_unload();
|
|
break;
|
|
case FilamentAction::MmuEject:
|
|
nLevel = bFilamentPreheatState ? 1 : 2;
|
|
bFilamentAction = true;
|
|
menu_back(nLevel);
|
|
menu_submenu(mmu_fil_eject_menu);
|
|
break;
|
|
case FilamentAction::MmuCut:
|
|
#ifdef MMU_HAS_CUTTER
|
|
nLevel=bFilamentPreheatState?1:2;
|
|
bFilamentAction=true;
|
|
menu_back(nLevel);
|
|
menu_submenu(mmu_cut_filament_menu);
|
|
#endif //MMU_HAS_CUTTER
|
|
break;
|
|
case FilamentAction::None:
|
|
case FilamentAction::Preheat:
|
|
case FilamentAction::Lay1Cal:
|
|
|
|
break;
|
|
}
|
|
if (bFilamentWaitingFlag) Sound_MakeSound(e_SOUND_TYPE_StandardPrompt);
|
|
bFilamentWaitingFlag = false;
|
|
}
|
|
else
|
|
{
|
|
bFilamentWaitingFlag = true;
|
|
lcd_set_cursor(0, 0);
|
|
lcdui_print_temp(LCD_STR_THERMOMETER[0], (int) degHotend(0), (int) degTargetHotend(0));
|
|
lcd_set_cursor(0, 1);
|
|
switch (eFilamentAction)
|
|
{
|
|
case FilamentAction::Load:
|
|
case FilamentAction::AutoLoad:
|
|
case FilamentAction::MmuLoad:
|
|
lcd_puts_P(_i("Preheating to load")); ////MSG_ c=20 r=1
|
|
break;
|
|
case FilamentAction::UnLoad:
|
|
case FilamentAction::MmuUnLoad:
|
|
lcd_puts_P(_i("Preheating to unload")); ////MSG_ c=20 r=1
|
|
break;
|
|
case FilamentAction::MmuEject:
|
|
lcd_puts_P(_i("Preheating to eject")); ////MSG_ c=20 r=1
|
|
break;
|
|
case FilamentAction::MmuCut:
|
|
lcd_puts_P(_i("Preheating to cut")); ////MSG_ c=20 r=1
|
|
break;
|
|
case FilamentAction::None:
|
|
case FilamentAction::Preheat:
|
|
case FilamentAction::Lay1Cal:
|
|
break;
|
|
}
|
|
lcd_set_cursor(0, 3);
|
|
lcd_puts_P(_i(">Cancel")); ////MSG_ c=20 r=1
|
|
if (lcd_clicked())
|
|
{
|
|
bFilamentWaitingFlag = false;
|
|
if (!bFilamentPreheatState)
|
|
{
|
|
setTargetHotend0(0.0);
|
|
setTargetBed(0.0);
|
|
menu_back();
|
|
}
|
|
else
|
|
{
|
|
setTargetHotend0((float )nTargetOld);
|
|
setTargetBed((float) nTargetBedOld);
|
|
}
|
|
menu_back();
|
|
if (eFilamentAction == FilamentAction::AutoLoad) eFilamentAction = FilamentAction::None; // i.e. non-autoLoad
|
|
}
|
|
}
|
|
}
|
|
|
|
static void mFilamentItem_farm()
|
|
{
|
|
bFilamentPreheatState = false;
|
|
mFilamentItem(FARM_PREHEAT_HOTEND_TEMP, FARM_PREHEAT_HPB_TEMP);
|
|
}
|
|
static void mFilamentItem_farm_nozzle()
|
|
{
|
|
bFilamentPreheatState = false;
|
|
mFilamentItem(FARM_PREHEAT_HOTEND_TEMP, 0);
|
|
}
|
|
|
|
static void mFilamentItem_PLA()
|
|
{
|
|
bFilamentPreheatState = false;
|
|
mFilamentItem(PLA_PREHEAT_HOTEND_TEMP, PLA_PREHEAT_HPB_TEMP);
|
|
}
|
|
|
|
static void mFilamentItem_PET()
|
|
{
|
|
bFilamentPreheatState = false;
|
|
mFilamentItem(PET_PREHEAT_HOTEND_TEMP, PET_PREHEAT_HPB_TEMP);
|
|
}
|
|
|
|
static void mFilamentItem_ASA()
|
|
{
|
|
bFilamentPreheatState = false;
|
|
mFilamentItem(ASA_PREHEAT_HOTEND_TEMP, ASA_PREHEAT_HPB_TEMP);
|
|
}
|
|
|
|
static void mFilamentItem_ABS()
|
|
{
|
|
bFilamentPreheatState = false;
|
|
mFilamentItem(ABS_PREHEAT_HOTEND_TEMP, ABS_PREHEAT_HPB_TEMP);
|
|
}
|
|
|
|
static void mFilamentItem_HIPS()
|
|
{
|
|
bFilamentPreheatState = false;
|
|
mFilamentItem(HIPS_PREHEAT_HOTEND_TEMP, HIPS_PREHEAT_HPB_TEMP);
|
|
}
|
|
|
|
static void mFilamentItem_PP()
|
|
{
|
|
bFilamentPreheatState = false;
|
|
mFilamentItem(PP_PREHEAT_HOTEND_TEMP, PP_PREHEAT_HPB_TEMP);
|
|
}
|
|
|
|
static void mFilamentItem_FLEX()
|
|
{
|
|
bFilamentPreheatState = false;
|
|
mFilamentItem(FLEX_PREHEAT_HOTEND_TEMP, FLEX_PREHEAT_HPB_TEMP);
|
|
}
|
|
|
|
void mFilamentBack()
|
|
{
|
|
menu_back();
|
|
if (eFilamentAction == FilamentAction::AutoLoad ||
|
|
eFilamentAction == FilamentAction::Preheat ||
|
|
eFilamentAction == FilamentAction::Lay1Cal)
|
|
{
|
|
eFilamentAction = FilamentAction::None; // i.e. non-autoLoad
|
|
}
|
|
}
|
|
|
|
void lcd_generic_preheat_menu()
|
|
{
|
|
MENU_BEGIN();
|
|
if (!eeprom_read_byte((uint8_t*)EEPROM_WIZARD_ACTIVE))
|
|
{
|
|
if (eFilamentAction == FilamentAction::Lay1Cal)
|
|
{
|
|
MENU_ITEM_FUNCTION_P(_T(MSG_BACK), mFilamentBack);
|
|
}
|
|
else
|
|
{
|
|
MENU_ITEM_FUNCTION_P(_T(MSG_MAIN), mFilamentBack);
|
|
}
|
|
}
|
|
if (farm_mode)
|
|
{
|
|
MENU_ITEM_FUNCTION_P(PSTR("farm - " STRINGIFY(FARM_PREHEAT_HOTEND_TEMP) "/" STRINGIFY(FARM_PREHEAT_HPB_TEMP)), mFilamentItem_farm);
|
|
MENU_ITEM_FUNCTION_P(PSTR("nozzle - " STRINGIFY(FARM_PREHEAT_HOTEND_TEMP) "/0"), mFilamentItem_farm_nozzle);
|
|
}
|
|
else
|
|
{
|
|
MENU_ITEM_SUBMENU_P(PSTR("PLA - " STRINGIFY(PLA_PREHEAT_HOTEND_TEMP) "/" STRINGIFY(PLA_PREHEAT_HPB_TEMP)),mFilamentItem_PLA);
|
|
MENU_ITEM_SUBMENU_P(PSTR("PET - " STRINGIFY(PET_PREHEAT_HOTEND_TEMP) "/" STRINGIFY(PET_PREHEAT_HPB_TEMP)),mFilamentItem_PET);
|
|
MENU_ITEM_SUBMENU_P(PSTR("ASA - " STRINGIFY(ASA_PREHEAT_HOTEND_TEMP) "/" STRINGIFY(ASA_PREHEAT_HPB_TEMP)),mFilamentItem_ASA);
|
|
MENU_ITEM_SUBMENU_P(PSTR("ABS - " STRINGIFY(ABS_PREHEAT_HOTEND_TEMP) "/" STRINGIFY(ABS_PREHEAT_HPB_TEMP)),mFilamentItem_ABS);
|
|
MENU_ITEM_SUBMENU_P(PSTR("HIPS - " STRINGIFY(HIPS_PREHEAT_HOTEND_TEMP) "/" STRINGIFY(HIPS_PREHEAT_HPB_TEMP)),mFilamentItem_HIPS);
|
|
MENU_ITEM_SUBMENU_P(PSTR("PP - " STRINGIFY(PP_PREHEAT_HOTEND_TEMP) "/" STRINGIFY(PP_PREHEAT_HPB_TEMP)),mFilamentItem_PP);
|
|
MENU_ITEM_SUBMENU_P(PSTR("FLEX - " STRINGIFY(FLEX_PREHEAT_HOTEND_TEMP) "/" STRINGIFY(FLEX_PREHEAT_HPB_TEMP)),mFilamentItem_FLEX);
|
|
}
|
|
if (!eeprom_read_byte((uint8_t*)EEPROM_WIZARD_ACTIVE) && eFilamentAction == FilamentAction::Preheat) MENU_ITEM_FUNCTION_P(_T(MSG_COOLDOWN), lcd_cooldown);
|
|
MENU_END();
|
|
}
|
|
|
|
void mFilamentItemForce()
|
|
{
|
|
mFilamentItem(target_temperature[0],target_temperature_bed);
|
|
}
|
|
|
|
|
|
void lcd_unLoadFilament()
|
|
{
|
|
eFilamentAction=FilamentAction::UnLoad;
|
|
preheat_or_continue();
|
|
}
|
|
|
|
static void mmu_unload_filament()
|
|
{
|
|
eFilamentAction = FilamentAction::MmuUnLoad;
|
|
preheat_or_continue();
|
|
}
|
|
|
|
|
|
void lcd_wait_interact() {
|
|
|
|
lcd_clear();
|
|
|
|
lcd_set_cursor(0, 1);
|
|
#ifdef SNMM
|
|
lcd_puts_P(_i("Prepare new filament"));////MSG_PREPARE_FILAMENT c=20 r=1
|
|
#else
|
|
lcd_puts_P(_i("Insert filament"));////MSG_INSERT_FILAMENT c=20
|
|
#endif
|
|
if (!fsensor_autoload_enabled) {
|
|
lcd_set_cursor(0, 2);
|
|
lcd_puts_P(_i("and press the knob"));////MSG_PRESS c=20
|
|
}
|
|
}
|
|
|
|
|
|
void lcd_change_success() {
|
|
|
|
lcd_clear();
|
|
|
|
lcd_set_cursor(0, 2);
|
|
|
|
lcd_puts_P(_i("Change success!"));////MSG_CHANGE_SUCCESS
|
|
|
|
|
|
}
|
|
|
|
static void lcd_loading_progress_bar(uint16_t loading_time_ms) {
|
|
|
|
for (uint_least8_t i = 0; i < 20; i++) {
|
|
lcd_set_cursor(i, 3);
|
|
lcd_print(".");
|
|
//loading_time_ms/20 delay
|
|
for (uint_least8_t j = 0; j < 5; j++) {
|
|
delay_keep_alive(loading_time_ms / 100);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void lcd_loading_color() {
|
|
//we are extruding 25mm with feedrate 200mm/min -> 7.5 seconds for whole action, 0.375 s for one character
|
|
|
|
lcd_clear();
|
|
|
|
lcd_set_cursor(0, 0);
|
|
|
|
lcd_puts_P(_i("Loading color"));////MSG_LOADING_COLOR
|
|
lcd_set_cursor(0, 2);
|
|
lcd_puts_P(_T(MSG_PLEASE_WAIT));
|
|
lcd_loading_progress_bar((FILAMENTCHANGE_FINALFEED * 1000ul) / FILAMENTCHANGE_EFEED_FINAL); //show progress bar during filament loading slow sequence
|
|
}
|
|
|
|
|
|
void lcd_loading_filament() {
|
|
|
|
|
|
lcd_clear();
|
|
|
|
lcd_set_cursor(0, 0);
|
|
|
|
lcd_puts_P(_T(MSG_LOADING_FILAMENT));
|
|
lcd_set_cursor(0, 2);
|
|
lcd_puts_P(_T(MSG_PLEASE_WAIT));
|
|
#ifdef SNMM
|
|
for (int i = 0; i < 20; i++) {
|
|
|
|
lcd_set_cursor(i, 3);
|
|
lcd_print(".");
|
|
for (int j = 0; j < 10 ; j++) {
|
|
manage_heater();
|
|
manage_inactivity(true);
|
|
|
|
_delay(153);
|
|
}
|
|
|
|
|
|
}
|
|
#else //SNMM
|
|
uint16_t slow_seq_time = (FILAMENTCHANGE_FINALFEED * 1000ul) / FILAMENTCHANGE_EFEED_FINAL;
|
|
uint16_t fast_seq_time = (FILAMENTCHANGE_FIRSTFEED * 1000ul) / FILAMENTCHANGE_EFEED_FIRST;
|
|
lcd_loading_progress_bar(slow_seq_time + fast_seq_time); //show progress bar for total time of filament loading fast + slow sequence
|
|
#endif //SNMM
|
|
}
|
|
|
|
|
|
|
|
|
|
void lcd_alright() {
|
|
int enc_dif = 0;
|
|
int cursor_pos = 1;
|
|
|
|
|
|
|
|
|
|
lcd_clear();
|
|
|
|
lcd_set_cursor(0, 0);
|
|
|
|
lcd_puts_P(_i("Changed correctly?"));////MSG_CORRECTLY c=20
|
|
|
|
lcd_set_cursor(1, 1);
|
|
|
|
lcd_puts_P(_T(MSG_YES));
|
|
|
|
lcd_set_cursor(1, 2);
|
|
|
|
lcd_puts_P(_i("Filament not loaded"));////MSG_NOT_LOADED c=19
|
|
|
|
|
|
lcd_set_cursor(1, 3);
|
|
lcd_puts_P(_i("Color not correct"));////MSG_NOT_COLOR
|
|
|
|
|
|
lcd_set_cursor(0, 1);
|
|
|
|
lcd_print(">");
|
|
|
|
|
|
enc_dif = lcd_encoder_diff;
|
|
lcd_consume_click();
|
|
while (lcd_change_fil_state == 0) {
|
|
|
|
manage_heater();
|
|
manage_inactivity(true);
|
|
|
|
if ( abs((enc_dif - lcd_encoder_diff)) > 4 ) {
|
|
|
|
if ( (abs(enc_dif - lcd_encoder_diff)) > 1 ) {
|
|
if (enc_dif > lcd_encoder_diff ) {
|
|
cursor_pos --;
|
|
}
|
|
|
|
if (enc_dif < lcd_encoder_diff ) {
|
|
cursor_pos ++;
|
|
}
|
|
|
|
if (cursor_pos > 3) {
|
|
cursor_pos = 3;
|
|
Sound_MakeSound(e_SOUND_TYPE_BlindAlert);
|
|
}
|
|
|
|
if (cursor_pos < 1) {
|
|
cursor_pos = 1;
|
|
Sound_MakeSound(e_SOUND_TYPE_BlindAlert);
|
|
}
|
|
lcd_set_cursor(0, 1);
|
|
lcd_print(" ");
|
|
lcd_set_cursor(0, 2);
|
|
lcd_print(" ");
|
|
lcd_set_cursor(0, 3);
|
|
lcd_print(" ");
|
|
lcd_set_cursor(0, cursor_pos);
|
|
lcd_print(">");
|
|
enc_dif = lcd_encoder_diff;
|
|
Sound_MakeSound(e_SOUND_TYPE_EncoderMove);
|
|
_delay(100);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
if (lcd_clicked()) {
|
|
Sound_MakeSound(e_SOUND_TYPE_ButtonEcho);
|
|
lcd_change_fil_state = cursor_pos;
|
|
_delay(500);
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
lcd_clear();
|
|
lcd_return_to_status();
|
|
|
|
}
|
|
|
|
void show_preheat_nozzle_warning()
|
|
{
|
|
lcd_clear();
|
|
lcd_set_cursor(0, 0);
|
|
lcd_puts_P(_T(MSG_ERROR));
|
|
lcd_set_cursor(0, 2);
|
|
lcd_puts_P(_T(MSG_PREHEAT_NOZZLE));
|
|
_delay(2000);
|
|
lcd_clear();
|
|
}
|
|
|
|
void lcd_load_filament_color_check()
|
|
{
|
|
bool clean = lcd_show_fullscreen_message_yes_no_and_wait_P(_T(MSG_FILAMENT_CLEAN), false, true);
|
|
while (!clean) {
|
|
lcd_update_enable(true);
|
|
lcd_update(2);
|
|
load_filament_final_feed();
|
|
st_synchronize();
|
|
clean = lcd_show_fullscreen_message_yes_no_and_wait_P(_T(MSG_FILAMENT_CLEAN), false, true);
|
|
}
|
|
}
|
|
|
|
#ifdef FILAMENT_SENSOR
|
|
static void lcd_menu_AutoLoadFilament()
|
|
{
|
|
uint8_t nlines;
|
|
lcd_display_message_fullscreen_nonBlocking_P(_i("Autoloading filament is active, just press the knob and insert filament..."),nlines);////MSG_AUTOLOADING_ENABLED c=20 r=4
|
|
menu_back_if_clicked();
|
|
}
|
|
#endif //FILAMENT_SENSOR
|
|
|
|
static void preheat_or_continue()
|
|
{
|
|
bFilamentFirstRun = false;
|
|
if (target_temperature[0] >= EXTRUDE_MINTEMP)
|
|
{
|
|
bFilamentPreheatState = true;
|
|
mFilamentItem(target_temperature[0], target_temperature_bed);
|
|
}
|
|
else lcd_generic_preheat_menu();
|
|
}
|
|
|
|
static void lcd_LoadFilament()
|
|
{
|
|
eFilamentAction = FilamentAction::Load;
|
|
preheat_or_continue();
|
|
}
|
|
|
|
|
|
//! @brief Show filament used a print time
|
|
//!
|
|
//! If printing current print statistics are shown
|
|
//!
|
|
//! @code{.unparsed}
|
|
//! |01234567890123456789|
|
|
//! |Filament used: | c=18 r=1
|
|
//! | 00.00m |
|
|
//! |Print time: | c=18 r=1
|
|
//! | 00h 00m 00s |
|
|
//! ----------------------
|
|
//! @endcode
|
|
//!
|
|
//! If not printing, total statistics are shown
|
|
//!
|
|
//! @code{.unparsed}
|
|
//! |01234567890123456789|
|
|
//! |Total filament : | c=18 r=1
|
|
//! | 000.00 m |
|
|
//! |Total print time : | c=18 r=1
|
|
//! | 00d :00h :00 m |
|
|
//! ----------------------
|
|
//! @endcode
|
|
//! @todo Positioning of the messages and values on LCD aren't fixed to their exact place. This causes issues with translations. Translations missing for "d"days, "h"ours, "m"inutes", "s"seconds".
|
|
void lcd_menu_statistics()
|
|
{
|
|
if (IS_SD_PRINTING)
|
|
{
|
|
const float _met = ((float)total_filament_used) / (100000.f);
|
|
const uint32_t _t = (_millis() - starttime) / 1000ul;
|
|
const int _h = _t / 3600;
|
|
const int _m = (_t - (_h * 3600ul)) / 60ul;
|
|
const int _s = _t - ((_h * 3600ul) + (_m * 60ul));
|
|
|
|
lcd_clear();
|
|
lcd_printf_P(_N(
|
|
"%S:\n"
|
|
"%17.2fm \n"
|
|
"%S:\n"
|
|
"%2dh %02dm %02ds"
|
|
),
|
|
_i("Filament used"), _met, ////c=18 r=1
|
|
_i("Print time"), _h, _m, _s); ////c=18 r=1
|
|
menu_back_if_clicked_fb();
|
|
}
|
|
else
|
|
{
|
|
unsigned long _filament = eeprom_read_dword((uint32_t *)EEPROM_FILAMENTUSED);
|
|
unsigned long _time = eeprom_read_dword((uint32_t *)EEPROM_TOTALTIME); //in minutes
|
|
uint8_t _hours, _minutes;
|
|
uint32_t _days;
|
|
float _filament_m = (float)_filament/100;
|
|
// int _filament_km = (_filament >= 100000) ? _filament / 100000 : 0;
|
|
// if (_filament_km > 0) _filament_m = _filament - (_filament_km * 100000);
|
|
_days = _time / 1440;
|
|
_hours = (_time - (_days * 1440)) / 60;
|
|
_minutes = _time - ((_days * 1440) + (_hours * 60));
|
|
|
|
lcd_clear();
|
|
lcd_printf_P(_N(
|
|
"%S:\n"
|
|
"%17.2fm \n"
|
|
"%S:\n"
|
|
"%7ldd :%2hhdh :%02hhdm"
|
|
), _i("Total filament"), _filament_m, _i("Total print time"), _days, _hours, _minutes);
|
|
KEEPALIVE_STATE(PAUSED_FOR_USER);
|
|
while (!lcd_clicked())
|
|
{
|
|
manage_heater();
|
|
manage_inactivity(true);
|
|
_delay(100);
|
|
}
|
|
KEEPALIVE_STATE(NOT_BUSY);
|
|
lcd_quick_feedback();
|
|
menu_back();
|
|
}
|
|
}
|
|
|
|
|
|
static void _lcd_move(const char *name, int axis, int min, int max)
|
|
{
|
|
typedef struct
|
|
{ // 2bytes total
|
|
bool initialized; // 1byte
|
|
bool endstopsEnabledPrevious; // 1byte
|
|
} _menu_data_t;
|
|
static_assert(sizeof(menu_data)>= sizeof(_menu_data_t),"_menu_data_t doesn't fit into menu_data");
|
|
_menu_data_t* _md = (_menu_data_t*)&(menu_data[0]);
|
|
if (!_md->initialized)
|
|
{
|
|
_md->endstopsEnabledPrevious = enable_endstops(false);
|
|
_md->initialized = true;
|
|
}
|
|
if (lcd_encoder != 0)
|
|
{
|
|
refresh_cmd_timeout();
|
|
if (! planner_queue_full())
|
|
{
|
|
current_position[axis] += float((int)lcd_encoder) * move_menu_scale;
|
|
if (min_software_endstops && current_position[axis] < min) current_position[axis] = min;
|
|
if (max_software_endstops && current_position[axis] > max) current_position[axis] = max;
|
|
lcd_encoder = 0;
|
|
world2machine_clamp(current_position[X_AXIS], current_position[Y_AXIS]);
|
|
plan_buffer_line_curposXYZE(manual_feedrate[axis] / 60, active_extruder);
|
|
lcd_draw_update = 1;
|
|
}
|
|
}
|
|
if (lcd_draw_update)
|
|
{
|
|
lcd_set_cursor(0, 1);
|
|
menu_draw_float31(name, current_position[axis]);
|
|
}
|
|
if (menu_leaving || LCD_CLICKED) (void)enable_endstops(_md->endstopsEnabledPrevious);
|
|
if (LCD_CLICKED) menu_back();
|
|
}
|
|
|
|
|
|
static void lcd_move_e()
|
|
{
|
|
if (degHotend0() > EXTRUDE_MINTEMP)
|
|
{
|
|
if (lcd_encoder != 0)
|
|
{
|
|
refresh_cmd_timeout();
|
|
if (! planner_queue_full())
|
|
{
|
|
current_position[E_AXIS] += float((int)lcd_encoder) * move_menu_scale;
|
|
lcd_encoder = 0;
|
|
plan_buffer_line_curposXYZE(manual_feedrate[E_AXIS] / 60, active_extruder);
|
|
lcd_draw_update = 1;
|
|
}
|
|
}
|
|
if (lcd_draw_update)
|
|
{
|
|
lcd_set_cursor(0, 1);
|
|
// Note: the colon behind the text is necessary to greatly shorten
|
|
// the implementation of menu_draw_float31
|
|
menu_draw_float31(PSTR("Extruder:"), current_position[E_AXIS]);
|
|
}
|
|
if (LCD_CLICKED) menu_back();
|
|
}
|
|
else
|
|
{
|
|
show_preheat_nozzle_warning();
|
|
lcd_return_to_status();
|
|
}
|
|
}
|
|
|
|
|
|
//! @brief Show measured Y distance of front calibration points from Y_MIN_POS
|
|
//! If those points are detected too close to edge of reachable area, their confidence is lowered.
|
|
//! This functionality is applied more often for MK2 printers.
|
|
//! @code{.unparsed}
|
|
//! |01234567890123456789|
|
|
//! |Y distance from min | c=19 r=1
|
|
//! | -------------- | STR_SEPARATOR
|
|
//! |Left: 00.00mm | c=11 r=1
|
|
//! |Right: 00.00mm | c=11 r=1
|
|
//! ----------------------
|
|
//! @endcode
|
|
//! @todo Positioning of the messages and values on LCD aren't fixed to their exact place. This causes issues with translations.
|
|
static void lcd_menu_xyz_y_min()
|
|
{
|
|
float distanceMin[2];
|
|
count_xyz_details(distanceMin);
|
|
lcd_home();
|
|
lcd_printf_P(_N(
|
|
"%S:\n"
|
|
"%S\n"
|
|
"%S:\n"
|
|
"%S:"
|
|
),
|
|
_i("Y distance from min"), ////c=19 r=1
|
|
separator,
|
|
_i("Left"), ////c=11 r=1
|
|
_i("Right") ////c=11 r=1
|
|
);
|
|
for (uint8_t i = 0; i < 2; i++)
|
|
{
|
|
lcd_set_cursor(11,2+i);
|
|
if (distanceMin[i] >= 200) lcd_puts_P(_T(MSG_NA)); ////c=3 r=1
|
|
else lcd_printf_P(_N("%6.2fmm"), distanceMin[i]);
|
|
}
|
|
if (lcd_clicked())
|
|
menu_goto(lcd_menu_xyz_skew, 0, true, true);
|
|
}
|
|
|
|
//@brief Show measured axis skewness
|
|
float _deg(float rad)
|
|
{
|
|
return rad * 180 / M_PI;
|
|
}
|
|
|
|
//! @brief Show Measured XYZ Skew
|
|
//!
|
|
//! @code{.unparsed}
|
|
//! |01234567890123456789|
|
|
//! |Measured skew: 0.00D| c=13 r=1
|
|
//! | -------------- | STR_SEPARATOR
|
|
//! |Slight skew: 0.12D| c=13 r=1 c=4 r=1
|
|
//! |Severe skew: 0.25D| c=13 r=1 c=4 r=1
|
|
//! ----------------------
|
|
//! D - Degree sysmbol LCD_STR_DEGREE
|
|
//! @endcode
|
|
//! @todo Positioning of the messages and values on LCD aren't fixed to their exact place. This causes issues with translations.
|
|
static void lcd_menu_xyz_skew()
|
|
{
|
|
float angleDiff = eeprom_read_float((float*)(EEPROM_XYZ_CAL_SKEW));
|
|
lcd_home();
|
|
lcd_printf_P(_N(
|
|
"%S:\n"
|
|
"%S\n"
|
|
"%-15.15S%3.2f\x01\n"
|
|
"%-15.15S%3.2f\x01"
|
|
),
|
|
_i("Measured skew"), ////c=13 r=1
|
|
separator,
|
|
_i("Slight skew:"), _deg(bed_skew_angle_mild), ////c=13 r=1 c=4 r=1
|
|
_i("Severe skew:"), _deg(bed_skew_angle_extreme) ////c=13 r=1 c=4 r=1
|
|
);
|
|
if (angleDiff < 100){
|
|
lcd_set_cursor(15,0);
|
|
lcd_printf_P(_N("%3.2f\x01"), _deg(angleDiff));
|
|
}
|
|
else{
|
|
lcd_set_cursor(15,0);
|
|
lcd_puts_P(_T(MSG_NA));
|
|
}
|
|
if (lcd_clicked())
|
|
menu_goto(lcd_menu_xyz_offset, 0, true, true);
|
|
}
|
|
//! @brief Show measured bed offset from expected position
|
|
//!
|
|
//! @code{.unparsed}
|
|
//! |01234567890123456789|
|
|
//! |[0;0] point offset | c=20 r=1
|
|
//! | -------------- | STR_SEPARATOR
|
|
//! |X: 000.00mm| c=10 r=1
|
|
//! |Y: 000.00mm| c=10 r=1
|
|
//! ----------------------
|
|
//! @endcode
|
|
//! @todo Positioning of the messages and values on LCD aren't fixed to their exact place. This causes issues with translations.
|
|
static void lcd_menu_xyz_offset()
|
|
{
|
|
lcd_set_cursor(0,0);
|
|
lcd_puts_P(_i("[0;0] point offset"));////MSG_MEASURED_OFFSET
|
|
lcd_puts_at_P(0, 1, separator);
|
|
lcd_puts_at_P(0, 2, PSTR("X")); ////c=10 r=1
|
|
lcd_puts_at_P(0, 3, PSTR("Y")); ////c=10 r=1
|
|
|
|
float vec_x[2];
|
|
float vec_y[2];
|
|
float cntr[2];
|
|
world2machine_read_valid(vec_x, vec_y, cntr);
|
|
|
|
for (uint_least8_t i = 0; i < 2; i++)
|
|
{
|
|
lcd_set_cursor((cntr[i] < 0) ? 10 : 11, i+2);
|
|
lcd_print(cntr[i]);
|
|
lcd_puts_at_P(16, i + 2, PSTR("mm"));
|
|
}
|
|
menu_back_if_clicked();
|
|
}
|
|
|
|
// Save a single axis babystep value.
|
|
void EEPROM_save_B(int pos, int* value)
|
|
{
|
|
eeprom_update_byte((unsigned char*)pos, (unsigned char)((*value) & 0xff));
|
|
eeprom_update_byte((unsigned char*)pos + 1, (unsigned char)((*value) >> 8));
|
|
}
|
|
|
|
// Read a single axis babystep value.
|
|
void EEPROM_read_B(int pos, int* value)
|
|
{
|
|
*value = (int)eeprom_read_byte((unsigned char*)pos) | (int)(eeprom_read_byte((unsigned char*)pos + 1) << 8);
|
|
}
|
|
|
|
|
|
// Note: the colon behind the text (X, Y, Z) is necessary to greatly shorten
|
|
// the implementation of menu_draw_float31
|
|
static void lcd_move_x() {
|
|
_lcd_move(PSTR("X:"), X_AXIS, X_MIN_POS, X_MAX_POS);
|
|
}
|
|
static void lcd_move_y() {
|
|
_lcd_move(PSTR("Y:"), Y_AXIS, Y_MIN_POS, Y_MAX_POS);
|
|
}
|
|
static void lcd_move_z() {
|
|
_lcd_move(PSTR("Z:"), Z_AXIS, Z_MIN_POS, Z_MAX_POS);
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief Adjust first layer offset from bed if axis is Z_AXIS
|
|
*
|
|
* If menu is left (button pushed or timed out), value is stored to EEPROM and
|
|
* if the axis is Z_AXIS, CALIBRATION_STATUS_CALIBRATED is also stored.
|
|
* Purpose of this function for other axis then Z is unknown.
|
|
*
|
|
* @param axis AxisEnum X_AXIS Y_AXIS Z_AXIS
|
|
* other value leads to storing Z_AXIS
|
|
* @param msg text to be displayed
|
|
*/
|
|
static void lcd_babystep_z()
|
|
{
|
|
typedef struct
|
|
{
|
|
int8_t status;
|
|
int16_t babystepMemZ;
|
|
float babystepMemMMZ;
|
|
} _menu_data_t;
|
|
static_assert(sizeof(menu_data)>= sizeof(_menu_data_t),"_menu_data_t doesn't fit into menu_data");
|
|
_menu_data_t* _md = (_menu_data_t*)&(menu_data[0]);
|
|
if (_md->status == 0)
|
|
{
|
|
// Menu was entered.
|
|
// Initialize its status.
|
|
_md->status = 1;
|
|
check_babystep();
|
|
|
|
if(!eeprom_is_sheet_initialized(eeprom_read_byte(&(EEPROM_Sheets_base->active_sheet)))){
|
|
_md->babystepMemZ = 0;
|
|
}
|
|
else{
|
|
_md->babystepMemZ = eeprom_read_word(reinterpret_cast<uint16_t *>(&(EEPROM_Sheets_base->
|
|
s[(eeprom_read_byte(&(EEPROM_Sheets_base->active_sheet)))].z_offset)));
|
|
}
|
|
|
|
// same logic as in babystep_load
|
|
if (calibration_status() >= CALIBRATION_STATUS_LIVE_ADJUST)
|
|
_md->babystepMemZ = 0;
|
|
|
|
_md->babystepMemMMZ = _md->babystepMemZ/cs.axis_steps_per_unit[Z_AXIS];
|
|
lcd_draw_update = 1;
|
|
//SERIAL_ECHO("Z baby step: ");
|
|
//SERIAL_ECHO(_md->babystepMem[2]);
|
|
// Wait 90 seconds before closing the live adjust dialog.
|
|
lcd_timeoutToStatus.start();
|
|
}
|
|
|
|
if (lcd_encoder != 0)
|
|
{
|
|
if (homing_flag) lcd_encoder = 0;
|
|
_md->babystepMemZ += (int)lcd_encoder;
|
|
|
|
if (_md->babystepMemZ < Z_BABYSTEP_MIN) _md->babystepMemZ = Z_BABYSTEP_MIN; //-3999 -> -9.99 mm
|
|
else if (_md->babystepMemZ > Z_BABYSTEP_MAX) _md->babystepMemZ = Z_BABYSTEP_MAX; //0
|
|
else
|
|
{
|
|
CRITICAL_SECTION_START
|
|
babystepsTodo[Z_AXIS] += (int)lcd_encoder;
|
|
CRITICAL_SECTION_END
|
|
}
|
|
|
|
_md->babystepMemMMZ = _md->babystepMemZ/cs.axis_steps_per_unit[Z_AXIS];
|
|
_delay(50);
|
|
lcd_encoder = 0;
|
|
lcd_draw_update = 1;
|
|
}
|
|
if (lcd_draw_update)
|
|
{
|
|
SheetFormatBuffer buffer;
|
|
menu_format_sheet_E(EEPROM_Sheets_base->s[(eeprom_read_byte(&(EEPROM_Sheets_base->active_sheet)))], buffer);
|
|
lcd_set_cursor(0, 0);
|
|
lcd_print(buffer.c);
|
|
lcd_set_cursor(0, 1);
|
|
menu_draw_float13(_i("Adjusting Z:"), _md->babystepMemMMZ); ////MSG_BABYSTEPPING_Z c=15 Beware: must include the ':' as its last character
|
|
}
|
|
if (LCD_CLICKED || menu_leaving)
|
|
{
|
|
// Only update the EEPROM when leaving the menu.
|
|
uint8_t active_sheet=eeprom_read_byte(&(EEPROM_Sheets_base->active_sheet));
|
|
eeprom_update_word(reinterpret_cast<uint16_t *>(&(EEPROM_Sheets_base->s[active_sheet].z_offset)),_md->babystepMemZ);
|
|
eeprom_update_byte(&(EEPROM_Sheets_base->s[active_sheet].bed_temp),target_temperature_bed);
|
|
#ifdef PINDA_THERMISTOR
|
|
eeprom_update_byte(&(EEPROM_Sheets_base->s[active_sheet].pinda_temp),current_temperature_pinda);
|
|
#endif //PINDA_THERMISTOR
|
|
calibration_status_store(CALIBRATION_STATUS_CALIBRATED);
|
|
}
|
|
if (LCD_CLICKED) menu_back();
|
|
}
|
|
|
|
|
|
typedef struct
|
|
{ // 12bytes + 9bytes = 21bytes total
|
|
menu_data_edit_t reserved; //12 bytes reserved for number editing functions
|
|
int8_t status; // 1byte
|
|
int16_t left; // 2byte
|
|
int16_t right; // 2byte
|
|
int16_t front; // 2byte
|
|
int16_t rear; // 2byte
|
|
} _menu_data_adjust_bed_t;
|
|
static_assert(sizeof(menu_data)>= sizeof(_menu_data_adjust_bed_t),"_menu_data_adjust_bed_t doesn't fit into menu_data");
|
|
|
|
void lcd_adjust_bed_reset(void)
|
|
{
|
|
eeprom_update_byte((unsigned char*)EEPROM_BED_CORRECTION_VALID, 1);
|
|
eeprom_update_byte((unsigned char*)EEPROM_BED_CORRECTION_LEFT , 0);
|
|
eeprom_update_byte((unsigned char*)EEPROM_BED_CORRECTION_RIGHT, 0);
|
|
eeprom_update_byte((unsigned char*)EEPROM_BED_CORRECTION_FRONT, 0);
|
|
eeprom_update_byte((unsigned char*)EEPROM_BED_CORRECTION_REAR , 0);
|
|
_menu_data_adjust_bed_t* _md = (_menu_data_adjust_bed_t*)&(menu_data[0]);
|
|
_md->status = 0;
|
|
}
|
|
|
|
//! @brief Show Bed level correct
|
|
//!
|
|
//! @code{.unparsed}
|
|
//! |01234567890123456789|
|
|
//! |Settings: | MSG_SETTINGS
|
|
//! |Left side [um]: | MSG_BED_CORRECTION_LEFT
|
|
//! |Right side[um]: | MSG_BED_CORRECTION_RIGHT
|
|
//! |Front side[um]: | MSG_BED_CORRECTION_FRONT
|
|
//! |Rear side [um]: | MSG_BED_CORRECTION_REAR
|
|
//! |Reset | MSG_BED_CORRECTION_RESET
|
|
//! ----------------------
|
|
//! @endcode
|
|
void lcd_adjust_bed(void)
|
|
{
|
|
_menu_data_adjust_bed_t* _md = (_menu_data_adjust_bed_t*)&(menu_data[0]);
|
|
if (_md->status == 0)
|
|
{
|
|
// Menu was entered.
|
|
_md->left = 0;
|
|
_md->right = 0;
|
|
_md->front = 0;
|
|
_md->rear = 0;
|
|
if (eeprom_read_byte((unsigned char*)EEPROM_BED_CORRECTION_VALID) == 1)
|
|
{
|
|
_md->left = eeprom_read_int8((unsigned char*)EEPROM_BED_CORRECTION_LEFT);
|
|
_md->right = eeprom_read_int8((unsigned char*)EEPROM_BED_CORRECTION_RIGHT);
|
|
_md->front = eeprom_read_int8((unsigned char*)EEPROM_BED_CORRECTION_FRONT);
|
|
_md->rear = eeprom_read_int8((unsigned char*)EEPROM_BED_CORRECTION_REAR);
|
|
}
|
|
_md->status = 1;
|
|
}
|
|
MENU_BEGIN();
|
|
// leaving menu - this condition must be immediately before MENU_ITEM_BACK_P
|
|
ON_MENU_LEAVE(
|
|
eeprom_update_int8((unsigned char*)EEPROM_BED_CORRECTION_LEFT, _md->left);
|
|
eeprom_update_int8((unsigned char*)EEPROM_BED_CORRECTION_RIGHT, _md->right);
|
|
eeprom_update_int8((unsigned char*)EEPROM_BED_CORRECTION_FRONT, _md->front);
|
|
eeprom_update_int8((unsigned char*)EEPROM_BED_CORRECTION_REAR, _md->rear);
|
|
eeprom_update_byte((unsigned char*)EEPROM_BED_CORRECTION_VALID, 1);
|
|
);
|
|
MENU_ITEM_BACK_P(_T(MSG_SETTINGS));
|
|
MENU_ITEM_EDIT_int3_P(_i("Left side [um]"), &_md->left, -BED_ADJUSTMENT_UM_MAX, BED_ADJUSTMENT_UM_MAX);////MSG_BED_CORRECTION_LEFT c=14 r=1
|
|
MENU_ITEM_EDIT_int3_P(_i("Right side[um]"), &_md->right, -BED_ADJUSTMENT_UM_MAX, BED_ADJUSTMENT_UM_MAX);////MSG_BED_CORRECTION_RIGHT c=14 r=1
|
|
MENU_ITEM_EDIT_int3_P(_i("Front side[um]"), &_md->front, -BED_ADJUSTMENT_UM_MAX, BED_ADJUSTMENT_UM_MAX);////MSG_BED_CORRECTION_FRONT c=14 r=1
|
|
MENU_ITEM_EDIT_int3_P(_i("Rear side [um]"), &_md->rear, -BED_ADJUSTMENT_UM_MAX, BED_ADJUSTMENT_UM_MAX);////MSG_BED_CORRECTION_REAR c=14 r=1
|
|
MENU_ITEM_FUNCTION_P(_i("Reset"), lcd_adjust_bed_reset);////MSG_BED_CORRECTION_RESET
|
|
MENU_END();
|
|
}
|
|
|
|
//! @brief Show PID Extruder
|
|
//!
|
|
//! @code{.unparsed}
|
|
//! |01234567890123456789|
|
|
//! | Set temperature: | MSG_SET_TEMPERATURE
|
|
//! | |
|
|
//! | 210 |
|
|
//! | |
|
|
//! ----------------------
|
|
//! @endcode
|
|
void pid_extruder()
|
|
{
|
|
lcd_clear();
|
|
lcd_set_cursor(1, 0);
|
|
lcd_puts_P(_i("Set temperature:"));////MSG_SET_TEMPERATURE c=19 r=1
|
|
pid_temp += int(lcd_encoder);
|
|
if (pid_temp > HEATER_0_MAXTEMP) pid_temp = HEATER_0_MAXTEMP;
|
|
if (pid_temp < HEATER_0_MINTEMP) pid_temp = HEATER_0_MINTEMP;
|
|
lcd_encoder = 0;
|
|
lcd_set_cursor(1, 2);
|
|
lcd_print(ftostr3(pid_temp));
|
|
if (lcd_clicked()) {
|
|
lcd_commands_type = LcdCommands::PidExtruder;
|
|
lcd_return_to_status();
|
|
lcd_update(2);
|
|
}
|
|
|
|
}
|
|
/*
|
|
void lcd_adjust_z() {
|
|
int enc_dif = 0;
|
|
int cursor_pos = 1;
|
|
int fsm = 0;
|
|
|
|
|
|
|
|
|
|
lcd_clear();
|
|
lcd_set_cursor(0, 0);
|
|
lcd_puts_P(_i("Auto adjust Z?"));////MSG_ADJUSTZ
|
|
lcd_set_cursor(1, 1);
|
|
lcd_puts_P(_T(MSG_YES));
|
|
|
|
lcd_set_cursor(1, 2);
|
|
|
|
lcd_puts_P(_T(MSG_NO));
|
|
|
|
lcd_set_cursor(0, 1);
|
|
|
|
lcd_print(">");
|
|
|
|
|
|
enc_dif = lcd_encoder_diff;
|
|
|
|
while (fsm == 0) {
|
|
|
|
manage_heater();
|
|
manage_inactivity(true);
|
|
|
|
if ( abs((enc_dif - lcd_encoder_diff)) > 4 ) {
|
|
|
|
if ( (abs(enc_dif - lcd_encoder_diff)) > 1 ) {
|
|
if (enc_dif > lcd_encoder_diff ) {
|
|
cursor_pos --;
|
|
}
|
|
|
|
if (enc_dif < lcd_encoder_diff ) {
|
|
cursor_pos ++;
|
|
}
|
|
|
|
if (cursor_pos > 2) {
|
|
cursor_pos = 2;
|
|
}
|
|
|
|
if (cursor_pos < 1) {
|
|
cursor_pos = 1;
|
|
}
|
|
lcd_set_cursor(0, 1);
|
|
lcd_print(" ");
|
|
lcd_set_cursor(0, 2);
|
|
lcd_print(" ");
|
|
lcd_set_cursor(0, cursor_pos);
|
|
lcd_print(">");
|
|
enc_dif = lcd_encoder_diff;
|
|
_delay(100);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
if (lcd_clicked()) {
|
|
fsm = cursor_pos;
|
|
if (fsm == 1) {
|
|
int babystepLoadZ = 0;
|
|
EEPROM_read_B(EEPROM_BABYSTEP_Z, &babystepLoadZ);
|
|
CRITICAL_SECTION_START
|
|
babystepsTodo[Z_AXIS] = babystepLoadZ;
|
|
CRITICAL_SECTION_END
|
|
} else {
|
|
int zero = 0;
|
|
EEPROM_save_B(EEPROM_BABYSTEP_X, &zero);
|
|
EEPROM_save_B(EEPROM_BABYSTEP_Y, &zero);
|
|
EEPROM_save_B(EEPROM_BABYSTEP_Z, &zero);
|
|
}
|
|
_delay(500);
|
|
}
|
|
};
|
|
|
|
lcd_clear();
|
|
lcd_return_to_status();
|
|
|
|
}*/
|
|
|
|
#ifdef PINDA_THERMISTOR
|
|
bool lcd_wait_for_pinda(float temp) {
|
|
lcd_set_custom_characters_degree();
|
|
setAllTargetHotends(0);
|
|
setTargetBed(0);
|
|
LongTimer pinda_timeout;
|
|
pinda_timeout.start();
|
|
bool target_temp_reached = true;
|
|
|
|
while (current_temperature_pinda > temp){
|
|
lcd_display_message_fullscreen_P(_i("Waiting for PINDA probe cooling"));////MSG_WAITING_TEMP_PINDA c=20 r=3
|
|
|
|
lcd_set_cursor(0, 4);
|
|
lcd_print(LCD_STR_THERMOMETER[0]);
|
|
lcd_print(ftostr3(current_temperature_pinda));
|
|
lcd_print("/");
|
|
lcd_print(ftostr3(temp));
|
|
lcd_print(LCD_STR_DEGREE);
|
|
delay_keep_alive(1000);
|
|
serialecho_temperatures();
|
|
if (pinda_timeout.expired(8 * 60 * 1000ul)) { //PINDA cooling from 60 C to 35 C takes about 7 minutes
|
|
target_temp_reached = false;
|
|
break;
|
|
}
|
|
}
|
|
lcd_set_custom_characters_arrows();
|
|
lcd_update_enable(true);
|
|
return target_temp_reached;
|
|
}
|
|
#endif //PINDA_THERMISTOR
|
|
|
|
void lcd_wait_for_heater() {
|
|
lcd_display_message_fullscreen_P(_T(MSG_WIZARD_HEATING));
|
|
lcd_set_degree();
|
|
lcd_set_cursor(0, 4);
|
|
lcd_print(LCD_STR_THERMOMETER[0]);
|
|
lcd_print(ftostr3(degHotend(active_extruder)));
|
|
lcd_print("/");
|
|
lcd_print(ftostr3(degTargetHotend(active_extruder)));
|
|
lcd_print(LCD_STR_DEGREE);
|
|
}
|
|
|
|
void lcd_wait_for_cool_down() {
|
|
lcd_set_custom_characters_degree();
|
|
setAllTargetHotends(0);
|
|
setTargetBed(0);
|
|
int fanSpeedBckp = fanSpeed;
|
|
fanSpeed = 255;
|
|
while ((degHotend(0)>MAX_HOTEND_TEMP_CALIBRATION) || (degBed() > MAX_BED_TEMP_CALIBRATION)) {
|
|
lcd_display_message_fullscreen_P(_i("Waiting for nozzle and bed cooling"));////MSG_WAITING_TEMP c=20 r=3
|
|
|
|
lcd_set_cursor(0, 4);
|
|
lcd_print(LCD_STR_THERMOMETER[0]);
|
|
lcd_print(ftostr3(degHotend(0)));
|
|
lcd_print("/0");
|
|
lcd_print(LCD_STR_DEGREE);
|
|
|
|
lcd_set_cursor(9, 4);
|
|
lcd_print(LCD_STR_BEDTEMP[0]);
|
|
lcd_print(ftostr3(degBed()));
|
|
lcd_print("/0");
|
|
lcd_print(LCD_STR_DEGREE);
|
|
lcd_set_custom_characters();
|
|
delay_keep_alive(1000);
|
|
serialecho_temperatures();
|
|
}
|
|
fanSpeed = fanSpeedBckp;
|
|
lcd_set_custom_characters_arrows();
|
|
lcd_update_enable(true);
|
|
}
|
|
|
|
// Lets the user move the Z carriage up to the end stoppers.
|
|
// When done, it sets the current Z to Z_MAX_POS and returns true.
|
|
// Otherwise the Z calibration is not changed and false is returned.
|
|
|
|
#ifndef TMC2130
|
|
bool lcd_calibrate_z_end_stop_manual(bool only_z)
|
|
{
|
|
// Don't know where we are. Let's claim we are Z=0, so the soft end stops will not be triggered when moving up.
|
|
current_position[Z_AXIS] = 0;
|
|
plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
|
|
|
|
// Until confirmed by the confirmation dialog.
|
|
for (;;) {
|
|
const char *msg = only_z ? _i("Calibrating Z. Rotate the knob to move the Z carriage up to the end stoppers. Click when done.") : _i("Calibrating XYZ. Rotate the knob to move the Z carriage up to the end stoppers. Click when done.");////MSG_MOVE_CARRIAGE_TO_THE_TOP c=20 r=8////MSG_MOVE_CARRIAGE_TO_THE_TOP_Z c=20 r=8
|
|
const char *msg_next = lcd_display_message_fullscreen_P(msg);
|
|
const bool multi_screen = msg_next != NULL;
|
|
unsigned long previous_millis_msg = _millis();
|
|
// Until the user finishes the z up movement.
|
|
lcd_encoder_diff = 0;
|
|
lcd_encoder = 0;
|
|
for (;;) {
|
|
manage_heater();
|
|
manage_inactivity(true);
|
|
if (abs(lcd_encoder_diff) >= ENCODER_PULSES_PER_STEP) {
|
|
_delay(50);
|
|
lcd_encoder += abs(lcd_encoder_diff / ENCODER_PULSES_PER_STEP);
|
|
lcd_encoder_diff = 0;
|
|
if (! planner_queue_full()) {
|
|
// Only move up, whatever direction the user rotates the encoder.
|
|
current_position[Z_AXIS] += fabs(lcd_encoder);
|
|
lcd_encoder = 0;
|
|
plan_buffer_line_curposXYZE(manual_feedrate[Z_AXIS] / 60, active_extruder);
|
|
}
|
|
}
|
|
if (lcd_clicked()) {
|
|
// Abort a move if in progress.
|
|
planner_abort_hard();
|
|
while (lcd_clicked()) ;
|
|
_delay(10);
|
|
while (lcd_clicked()) ;
|
|
break;
|
|
}
|
|
if (multi_screen && _millis() - previous_millis_msg > 5000) {
|
|
if (msg_next == NULL)
|
|
msg_next = msg;
|
|
msg_next = lcd_display_message_fullscreen_P(msg_next);
|
|
previous_millis_msg = _millis();
|
|
}
|
|
}
|
|
// Let the user confirm, that the Z carriage is at the top end stoppers.
|
|
int8_t result = lcd_show_fullscreen_message_yes_no_and_wait_P(_i("Are left and right Z~carriages all up?"), false);////MSG_CONFIRM_CARRIAGE_AT_THE_TOP c=20 r=2
|
|
if (result == -1)
|
|
goto canceled;
|
|
else if (result == 1)
|
|
goto calibrated;
|
|
// otherwise perform another round of the Z up dialog.
|
|
}
|
|
|
|
calibrated:
|
|
// Let the machine think the Z axis is a bit higher than it is, so it will not home into the bed
|
|
// during the search for the induction points.
|
|
if ((PRINTER_TYPE == PRINTER_MK25) || (PRINTER_TYPE == PRINTER_MK2) || (PRINTER_TYPE == PRINTER_MK2_SNMM)) {
|
|
current_position[Z_AXIS] = Z_MAX_POS-3.f;
|
|
}
|
|
else {
|
|
current_position[Z_AXIS] = Z_MAX_POS+4.f;
|
|
}
|
|
plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
|
|
return true;
|
|
|
|
canceled:
|
|
return false;
|
|
}
|
|
|
|
#endif // TMC2130
|
|
|
|
static inline bool pgm_is_whitespace(const char *c_addr)
|
|
{
|
|
const char c = pgm_read_byte(c_addr);
|
|
return c == ' ' || c == '\t' || c == '\r' || c == '\n';
|
|
}
|
|
|
|
static inline bool pgm_is_interpunction(const char *c_addr)
|
|
{
|
|
const char c = pgm_read_byte(c_addr);
|
|
return c == '.' || c == ',' || c == ':'|| c == ';' || c == '?' || c == '!' || c == '/';
|
|
}
|
|
|
|
/**
|
|
* @brief show full screen message
|
|
*
|
|
* This function is non-blocking
|
|
* @param msg message to be displayed from PROGMEM
|
|
* @param nlines
|
|
* @return rest of the text (to be displayed on next page)
|
|
*/
|
|
static const char* lcd_display_message_fullscreen_nonBlocking_P(const char *msg, uint8_t &nlines)
|
|
{
|
|
lcd_set_cursor(0, 0);
|
|
const char *msgend = msg;
|
|
uint8_t row = 0;
|
|
bool multi_screen = false;
|
|
for (; row < 4; ++ row) {
|
|
while (pgm_is_whitespace(msg))
|
|
++ msg;
|
|
if (pgm_read_byte(msg) == 0)
|
|
// End of the message.
|
|
break;
|
|
lcd_set_cursor(0, row);
|
|
uint8_t linelen = min(strlen_P(msg), 20);
|
|
const char *msgend2 = msg + linelen;
|
|
msgend = msgend2;
|
|
if (row == 3 && linelen == 20) {
|
|
// Last line of the display, full line shall be displayed.
|
|
// Find out, whether this message will be split into multiple screens.
|
|
while (pgm_is_whitespace(msgend))
|
|
++ msgend;
|
|
multi_screen = pgm_read_byte(msgend) != 0;
|
|
if (multi_screen)
|
|
msgend = (msgend2 -= 2);
|
|
}
|
|
if (pgm_read_byte(msgend) != 0 && ! pgm_is_whitespace(msgend) && ! pgm_is_interpunction(msgend)) {
|
|
// Splitting a word. Find the start of the current word.
|
|
while (msgend > msg && ! pgm_is_whitespace(msgend - 1))
|
|
-- msgend;
|
|
if (msgend == msg)
|
|
// Found a single long word, which cannot be split. Just cut it.
|
|
msgend = msgend2;
|
|
}
|
|
for (; msg < msgend; ++ msg) {
|
|
char c = char(pgm_read_byte(msg));
|
|
if (c == '~')
|
|
c = ' ';
|
|
lcd_print(c);
|
|
}
|
|
}
|
|
|
|
if (multi_screen) {
|
|
// Display the "next screen" indicator character.
|
|
// lcd_set_custom_characters_arrows();
|
|
lcd_set_custom_characters_nextpage();
|
|
lcd_set_cursor(19, 3);
|
|
// Display the down arrow.
|
|
lcd_print(char(1));
|
|
}
|
|
|
|
nlines = row;
|
|
return multi_screen ? msgend : NULL;
|
|
}
|
|
|
|
const char* lcd_display_message_fullscreen_P(const char *msg, uint8_t &nlines)
|
|
{
|
|
// Disable update of the screen by the usual lcd_update(0) routine.
|
|
lcd_update_enable(false);
|
|
lcd_clear();
|
|
// uint8_t nlines;
|
|
return lcd_display_message_fullscreen_nonBlocking_P(msg, nlines);
|
|
}
|
|
const char* lcd_display_message_fullscreen_P(const char *msg)
|
|
{
|
|
uint8_t nlines;
|
|
return lcd_display_message_fullscreen_P(msg, nlines);
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief show full screen message and wait
|
|
*
|
|
* This function is blocking.
|
|
* @param msg message to be displayed from PROGMEM
|
|
*/
|
|
void lcd_show_fullscreen_message_and_wait_P(const char *msg)
|
|
{
|
|
LcdUpdateDisabler lcdUpdateDisabler;
|
|
const char *msg_next = lcd_display_message_fullscreen_P(msg);
|
|
bool multi_screen = msg_next != NULL;
|
|
lcd_set_custom_characters_nextpage();
|
|
lcd_consume_click();
|
|
KEEPALIVE_STATE(PAUSED_FOR_USER);
|
|
// Until confirmed by a button click.
|
|
for (;;) {
|
|
if (!multi_screen) {
|
|
lcd_set_cursor(19, 3);
|
|
// Display the confirm char.
|
|
lcd_print(char(2));
|
|
}
|
|
// Wait for 5 seconds before displaying the next text.
|
|
for (uint8_t i = 0; i < 100; ++ i) {
|
|
delay_keep_alive(50);
|
|
if (lcd_clicked()) {
|
|
if (msg_next == NULL) {
|
|
KEEPALIVE_STATE(IN_HANDLER);
|
|
lcd_set_custom_characters();
|
|
lcd_update_enable(true);
|
|
lcd_update(2);
|
|
return;
|
|
}
|
|
else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (multi_screen) {
|
|
if (msg_next == NULL)
|
|
msg_next = msg;
|
|
msg_next = lcd_display_message_fullscreen_P(msg_next);
|
|
if (msg_next == NULL) {
|
|
|
|
lcd_set_cursor(19, 3);
|
|
// Display the confirm char.
|
|
lcd_print(char(2));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool lcd_wait_for_click_delay(uint16_t nDelay)
|
|
// nDelay :: timeout [s] (0 ~ no timeout)
|
|
// true ~ clicked, false ~ delayed
|
|
{
|
|
bool bDelayed;
|
|
long nTime0 = _millis()/1000;
|
|
lcd_consume_click();
|
|
KEEPALIVE_STATE(PAUSED_FOR_USER);
|
|
for (;;) {
|
|
manage_heater();
|
|
manage_inactivity(true);
|
|
bDelayed = ((_millis()/1000-nTime0) > nDelay);
|
|
bDelayed = (bDelayed && (nDelay != 0)); // 0 ~ no timeout, always waiting for click
|
|
if (lcd_clicked() || bDelayed) {
|
|
KEEPALIVE_STATE(IN_HANDLER);
|
|
return(!bDelayed);
|
|
}
|
|
}
|
|
}
|
|
|
|
void lcd_wait_for_click()
|
|
{
|
|
lcd_wait_for_click_delay(0);
|
|
}
|
|
|
|
//! @brief Show multiple screen message with yes and no possible choices and wait with possible timeout
|
|
//! @param msg Message to show
|
|
//! @param allow_timeouting if true, allows time outing of the screen
|
|
//! @param default_yes if true, yes choice is selected by default, otherwise no choice is preselected
|
|
//! @retval 1 yes choice selected by user
|
|
//! @retval 0 no choice selected by user
|
|
//! @retval -1 screen timed out
|
|
int8_t lcd_show_multiscreen_message_yes_no_and_wait_P(const char *msg, bool allow_timeouting, bool default_yes) //currently just max. n*4 + 3 lines supported (set in language header files)
|
|
{
|
|
return lcd_show_multiscreen_message_two_choices_and_wait_P(msg, allow_timeouting, default_yes, _T(MSG_YES), _T(MSG_NO));
|
|
}
|
|
//! @brief Show multiple screen message with two possible choices and wait with possible timeout
|
|
//! @param msg Message to show
|
|
//! @param allow_timeouting if true, allows time outing of the screen
|
|
//! @param default_first if true, fist choice is selected by default, otherwise second choice is preselected
|
|
//! @param first_choice text caption of first possible choice
|
|
//! @param second_choice text caption of second possible choice
|
|
//! @retval 1 first choice selected by user
|
|
//! @retval 0 second choice selected by user
|
|
//! @retval -1 screen timed out
|
|
int8_t lcd_show_multiscreen_message_two_choices_and_wait_P(const char *msg, bool allow_timeouting, bool default_first,
|
|
const char *first_choice, const char *second_choice)
|
|
{
|
|
const char *msg_next = lcd_display_message_fullscreen_P(msg);
|
|
bool multi_screen = msg_next != NULL;
|
|
bool yes = default_first ? true : false;
|
|
|
|
// Wait for user confirmation or a timeout.
|
|
unsigned long previous_millis_cmd = _millis();
|
|
int8_t enc_dif = lcd_encoder_diff;
|
|
lcd_consume_click();
|
|
//KEEPALIVE_STATE(PAUSED_FOR_USER);
|
|
for (;;) {
|
|
for (uint8_t i = 0; i < 100; ++i) {
|
|
delay_keep_alive(50);
|
|
if (allow_timeouting && _millis() - previous_millis_cmd > LCD_TIMEOUT_TO_STATUS)
|
|
return -1;
|
|
manage_heater();
|
|
manage_inactivity(true);
|
|
|
|
if (abs(enc_dif - lcd_encoder_diff) > 4) {
|
|
if (msg_next == NULL) {
|
|
lcd_set_cursor(0, 3);
|
|
if (enc_dif < lcd_encoder_diff && yes) {
|
|
lcd_puts_P((PSTR(" ")));
|
|
lcd_set_cursor(7, 3);
|
|
lcd_puts_P((PSTR(">")));
|
|
yes = false;
|
|
Sound_MakeSound(e_SOUND_TYPE_EncoderMove);
|
|
}
|
|
else if (enc_dif > lcd_encoder_diff && !yes) {
|
|
lcd_puts_P((PSTR(">")));
|
|
lcd_set_cursor(7, 3);
|
|
lcd_puts_P((PSTR(" ")));
|
|
yes = true;
|
|
Sound_MakeSound(e_SOUND_TYPE_EncoderMove);
|
|
}
|
|
enc_dif = lcd_encoder_diff;
|
|
}
|
|
else {
|
|
Sound_MakeSound(e_SOUND_TYPE_BlindAlert);
|
|
break; //turning knob skips waiting loop
|
|
}
|
|
}
|
|
if (lcd_clicked()) {
|
|
Sound_MakeSound(e_SOUND_TYPE_ButtonEcho);
|
|
if (msg_next == NULL) {
|
|
//KEEPALIVE_STATE(IN_HANDLER);
|
|
lcd_set_custom_characters();
|
|
return yes;
|
|
}
|
|
else break;
|
|
}
|
|
}
|
|
if (multi_screen) {
|
|
if (msg_next == NULL) {
|
|
msg_next = msg;
|
|
}
|
|
msg_next = lcd_display_message_fullscreen_P(msg_next);
|
|
}
|
|
if (msg_next == NULL) {
|
|
lcd_set_cursor(0, 3);
|
|
if (yes) lcd_puts_P(PSTR(">"));
|
|
lcd_set_cursor(1, 3);
|
|
lcd_puts_P(first_choice);
|
|
lcd_set_cursor(7, 3);
|
|
if (!yes) lcd_puts_P(PSTR(">"));
|
|
lcd_set_cursor(8, 3);
|
|
lcd_puts_P(second_choice);
|
|
}
|
|
}
|
|
}
|
|
|
|
//! @brief Show single screen message with yes and no possible choices and wait with possible timeout
|
|
//! @param msg Message to show
|
|
//! @param allow_timeouting if true, allows time outing of the screen
|
|
//! @param default_yes if true, yes choice is selected by default, otherwise no choice is preselected
|
|
//! @retval 1 yes choice selected by user
|
|
//! @retval 0 no choice selected by user
|
|
//! @retval -1 screen timed out
|
|
int8_t lcd_show_fullscreen_message_yes_no_and_wait_P(const char *msg, bool allow_timeouting, bool default_yes)
|
|
{
|
|
|
|
lcd_display_message_fullscreen_P(msg);
|
|
|
|
if (default_yes) {
|
|
lcd_set_cursor(0, 2);
|
|
lcd_puts_P(PSTR(">"));
|
|
lcd_puts_P(_T(MSG_YES));
|
|
lcd_set_cursor(1, 3);
|
|
lcd_puts_P(_T(MSG_NO));
|
|
}
|
|
else {
|
|
lcd_set_cursor(1, 2);
|
|
lcd_puts_P(_T(MSG_YES));
|
|
lcd_set_cursor(0, 3);
|
|
lcd_puts_P(PSTR(">"));
|
|
lcd_puts_P(_T(MSG_NO));
|
|
}
|
|
int8_t retval = default_yes ? true : false;
|
|
|
|
// Wait for user confirmation or a timeout.
|
|
unsigned long previous_millis_cmd = _millis();
|
|
int8_t enc_dif = lcd_encoder_diff;
|
|
lcd_consume_click();
|
|
KEEPALIVE_STATE(PAUSED_FOR_USER);
|
|
for (;;) {
|
|
if (allow_timeouting && _millis() - previous_millis_cmd > LCD_TIMEOUT_TO_STATUS)
|
|
{
|
|
retval = -1;
|
|
break;
|
|
}
|
|
manage_heater();
|
|
manage_inactivity(true);
|
|
if (abs(enc_dif - lcd_encoder_diff) > 4) {
|
|
lcd_set_cursor(0, 2);
|
|
if (enc_dif < lcd_encoder_diff && retval) {
|
|
lcd_puts_P((PSTR(" ")));
|
|
lcd_set_cursor(0, 3);
|
|
lcd_puts_P((PSTR(">")));
|
|
retval = 0;
|
|
Sound_MakeSound(e_SOUND_TYPE_EncoderMove);
|
|
|
|
}
|
|
else if (enc_dif > lcd_encoder_diff && !retval) {
|
|
lcd_puts_P((PSTR(">")));
|
|
lcd_set_cursor(0, 3);
|
|
lcd_puts_P((PSTR(" ")));
|
|
retval = 1;
|
|
Sound_MakeSound(e_SOUND_TYPE_EncoderMove);
|
|
}
|
|
enc_dif = lcd_encoder_diff;
|
|
}
|
|
if (lcd_clicked()) {
|
|
Sound_MakeSound(e_SOUND_TYPE_ButtonEcho);
|
|
KEEPALIVE_STATE(IN_HANDLER);
|
|
break;
|
|
}
|
|
}
|
|
lcd_encoder_diff = 0;
|
|
return retval;
|
|
}
|
|
|
|
void lcd_bed_calibration_show_result(BedSkewOffsetDetectionResultType result, uint8_t point_too_far_mask)
|
|
{
|
|
const char *msg = NULL;
|
|
if (result == BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND) {
|
|
lcd_show_fullscreen_message_and_wait_P(_i("XYZ calibration failed. Bed calibration point was not found."));////MSG_BED_SKEW_OFFSET_DETECTION_POINT_NOT_FOUND c=20 r=8
|
|
} else if (result == BED_SKEW_OFFSET_DETECTION_FITTING_FAILED) {
|
|
if (point_too_far_mask == 0)
|
|
msg = _T(MSG_BED_SKEW_OFFSET_DETECTION_FITTING_FAILED);
|
|
else if (point_too_far_mask == 2 || point_too_far_mask == 7)
|
|
// Only the center point or all the three front points.
|
|
msg = _i("XYZ calibration failed. Front calibration points not reachable.");////MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_BOTH_FAR c=20 r=8
|
|
else if ((point_too_far_mask & 1) == 0)
|
|
// The right and maybe the center point out of reach.
|
|
msg = _i("XYZ calibration failed. Right front calibration point not reachable.");////MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_RIGHT_FAR c=20 r=8
|
|
else
|
|
// The left and maybe the center point out of reach.
|
|
msg = _i("XYZ calibration failed. Left front calibration point not reachable.");////MSG_BED_SKEW_OFFSET_DETECTION_FAILED_FRONT_LEFT_FAR c=20 r=8
|
|
lcd_show_fullscreen_message_and_wait_P(msg);
|
|
} else {
|
|
if (point_too_far_mask != 0) {
|
|
if (point_too_far_mask == 2 || point_too_far_mask == 7)
|
|
// Only the center point or all the three front points.
|
|
msg = _i("XYZ calibration compromised. Front calibration points not reachable.");////MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_BOTH_FAR c=20 r=8
|
|
else if ((point_too_far_mask & 1) == 0)
|
|
// The right and maybe the center point out of reach.
|
|
msg = _i("XYZ calibration compromised. Right front calibration point not reachable.");////MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_RIGHT_FAR c=20 r=8
|
|
else
|
|
// The left and maybe the center point out of reach.
|
|
msg = _i("XYZ calibration compromised. Left front calibration point not reachable.");////MSG_BED_SKEW_OFFSET_DETECTION_WARNING_FRONT_LEFT_FAR c=20 r=8
|
|
lcd_show_fullscreen_message_and_wait_P(msg);
|
|
}
|
|
if (point_too_far_mask == 0 || result > 0) {
|
|
switch (result) {
|
|
default:
|
|
// should not happen
|
|
msg = _T(MSG_BED_SKEW_OFFSET_DETECTION_FITTING_FAILED);
|
|
break;
|
|
case BED_SKEW_OFFSET_DETECTION_PERFECT:
|
|
msg = _i("XYZ calibration ok. X/Y axes are perpendicular. Congratulations!");////MSG_BED_SKEW_OFFSET_DETECTION_PERFECT c=20 r=8
|
|
break;
|
|
case BED_SKEW_OFFSET_DETECTION_SKEW_MILD:
|
|
msg = _i("XYZ calibration all right. X/Y axes are slightly skewed. Good job!");////MSG_BED_SKEW_OFFSET_DETECTION_SKEW_MILD c=20 r=8
|
|
break;
|
|
case BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME:
|
|
msg = _i("XYZ calibration all right. Skew will be corrected automatically.");////MSG_BED_SKEW_OFFSET_DETECTION_SKEW_EXTREME c=20 r=8
|
|
break;
|
|
}
|
|
lcd_show_fullscreen_message_and_wait_P(msg);
|
|
}
|
|
}
|
|
}
|
|
|
|
void lcd_temp_cal_show_result(bool result) {
|
|
|
|
custom_message_type = CustomMsg::Status;
|
|
disable_x();
|
|
disable_y();
|
|
disable_z();
|
|
disable_e0();
|
|
disable_e1();
|
|
disable_e2();
|
|
setTargetBed(0); //set bed target temperature back to 0
|
|
|
|
if (result == true) {
|
|
eeprom_update_byte((uint8_t*)EEPROM_CALIBRATION_STATUS_PINDA, 1);
|
|
SERIAL_ECHOLNPGM("Temperature calibration done. Continue with pressing the knob.");
|
|
lcd_show_fullscreen_message_and_wait_P(_T(MSG_TEMP_CALIBRATION_DONE));
|
|
temp_cal_active = true;
|
|
eeprom_update_byte((unsigned char *)EEPROM_TEMP_CAL_ACTIVE, 1);
|
|
}
|
|
else {
|
|
eeprom_update_byte((uint8_t*)EEPROM_CALIBRATION_STATUS_PINDA, 0);
|
|
SERIAL_ECHOLNPGM("Temperature calibration failed. Continue with pressing the knob.");
|
|
lcd_show_fullscreen_message_and_wait_P(_i("Temperature calibration failed"));////MSG_TEMP_CAL_FAILED c=20 r=8
|
|
temp_cal_active = false;
|
|
eeprom_update_byte((unsigned char *)EEPROM_TEMP_CAL_ACTIVE, 0);
|
|
}
|
|
lcd_update_enable(true);
|
|
lcd_update(2);
|
|
}
|
|
|
|
static void lcd_show_end_stops() {
|
|
lcd_set_cursor(0, 0);
|
|
lcd_puts_P((PSTR("End stops diag")));
|
|
lcd_set_cursor(0, 1);
|
|
lcd_puts_P((READ(X_MIN_PIN) ^ (bool)X_MIN_ENDSTOP_INVERTING) ? (PSTR("X1")) : (PSTR("X0")));
|
|
lcd_set_cursor(0, 2);
|
|
lcd_puts_P((READ(Y_MIN_PIN) ^ (bool)Y_MIN_ENDSTOP_INVERTING) ? (PSTR("Y1")) : (PSTR("Y0")));
|
|
lcd_set_cursor(0, 3);
|
|
lcd_puts_P((READ(Z_MIN_PIN) ^ (bool)Z_MIN_ENDSTOP_INVERTING) ? (PSTR("Z1")) : (PSTR("Z0")));
|
|
}
|
|
|
|
#ifndef TMC2130
|
|
static void menu_show_end_stops() {
|
|
lcd_show_end_stops();
|
|
if (LCD_CLICKED) menu_back();
|
|
}
|
|
#endif // not defined TMC2130
|
|
|
|
// Lets the user move the Z carriage up to the end stoppers.
|
|
// When done, it sets the current Z to Z_MAX_POS and returns true.
|
|
// Otherwise the Z calibration is not changed and false is returned.
|
|
void lcd_diag_show_end_stops()
|
|
{
|
|
lcd_clear();
|
|
lcd_consume_click();
|
|
for (;;) {
|
|
manage_heater();
|
|
manage_inactivity(true);
|
|
lcd_show_end_stops();
|
|
if (lcd_clicked()) {
|
|
break;
|
|
}
|
|
}
|
|
lcd_clear();
|
|
lcd_return_to_status();
|
|
}
|
|
|
|
static void lcd_print_state(uint8_t state)
|
|
{
|
|
switch (state) {
|
|
case STATE_ON:
|
|
lcd_puts_P(_N(" 1"));
|
|
break;
|
|
case STATE_OFF:
|
|
lcd_puts_P(_N(" 0"));
|
|
break;
|
|
default:
|
|
lcd_puts_P(_T(MSG_NA));
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void lcd_show_sensors_state()
|
|
{
|
|
//0: N/A; 1: OFF; 2: ON
|
|
uint8_t pinda_state = STATE_NA;
|
|
uint8_t finda_state = STATE_NA;
|
|
uint8_t idler_state = STATE_NA;
|
|
|
|
pinda_state = READ(Z_MIN_PIN);
|
|
if (mmu_enabled && ((_millis() - mmu_last_finda_response) < 1000ul) )
|
|
{
|
|
finda_state = mmu_finda;
|
|
}
|
|
if (ir_sensor_detected) {
|
|
idler_state = !PIN_GET(IR_SENSOR_PIN);
|
|
}
|
|
lcd_puts_at_P(0, 0, _i("Sensor state"));
|
|
lcd_puts_at_P(1, 1, _i("PINDA:"));
|
|
lcd_set_cursor(LCD_WIDTH - 4, 1);
|
|
lcd_print_state(pinda_state);
|
|
|
|
lcd_puts_at_P(1, 2, _i("FINDA:"));
|
|
lcd_set_cursor(LCD_WIDTH - 4, 2);
|
|
lcd_print_state(finda_state);
|
|
|
|
lcd_puts_at_P(1, 3, _i("IR:"));
|
|
lcd_set_cursor(LCD_WIDTH - 4, 3);
|
|
lcd_print_state(idler_state);
|
|
}
|
|
|
|
void lcd_menu_show_sensors_state() // NOT static due to using inside "Marlin_main" module ("manage_inactivity()")
|
|
{
|
|
lcd_timeoutToStatus.stop();
|
|
lcd_show_sensors_state();
|
|
if(LCD_CLICKED)
|
|
{
|
|
lcd_timeoutToStatus.start();
|
|
menu_back();
|
|
}
|
|
}
|
|
|
|
void prusa_statistics_err(char c){
|
|
SERIAL_ECHO("{[ERR:");
|
|
SERIAL_ECHO(c);
|
|
SERIAL_ECHO(']');
|
|
prusa_stat_farm_number();
|
|
}
|
|
|
|
static void prusa_statistics_case0(uint8_t statnr){
|
|
SERIAL_ECHO("{");
|
|
prusa_stat_printerstatus(statnr);
|
|
prusa_stat_farm_number();
|
|
prusa_stat_printinfo();
|
|
}
|
|
|
|
void prusa_statistics(int _message, uint8_t _fil_nr) {
|
|
#ifdef DEBUG_DISABLE_PRUSA_STATISTICS
|
|
return;
|
|
#endif //DEBUG_DISABLE_PRUSA_STATISTICS
|
|
switch (_message)
|
|
{
|
|
|
|
case 0: // default message
|
|
if (busy_state == PAUSED_FOR_USER)
|
|
{
|
|
prusa_statistics_case0(15);
|
|
}
|
|
else if (isPrintPaused)
|
|
{
|
|
prusa_statistics_case0(14);
|
|
}
|
|
else if (IS_SD_PRINTING || loading_flag)
|
|
{
|
|
prusa_statistics_case0(4);
|
|
}
|
|
else
|
|
{
|
|
SERIAL_ECHO("{");
|
|
prusa_stat_printerstatus(1);
|
|
prusa_stat_farm_number();
|
|
prusa_stat_diameter();
|
|
status_number = 1;
|
|
}
|
|
break;
|
|
|
|
case 1: // 1 heating
|
|
farm_status = 2;
|
|
SERIAL_ECHO('{');
|
|
prusa_stat_printerstatus(2);
|
|
prusa_stat_farm_number();
|
|
status_number = 2;
|
|
farm_timer = 1;
|
|
break;
|
|
|
|
case 2: // heating done
|
|
farm_status = 3;
|
|
SERIAL_ECHO('{');
|
|
prusa_stat_printerstatus(3);
|
|
prusa_stat_farm_number();
|
|
SERIAL_ECHOLN('}');
|
|
status_number = 3;
|
|
farm_timer = 1;
|
|
|
|
if (IS_SD_PRINTING || loading_flag)
|
|
{
|
|
farm_status = 4;
|
|
SERIAL_ECHO('{');
|
|
prusa_stat_printerstatus(4);
|
|
prusa_stat_farm_number();
|
|
status_number = 4;
|
|
}
|
|
else
|
|
{
|
|
SERIAL_ECHO('{');
|
|
prusa_stat_printerstatus(3);
|
|
prusa_stat_farm_number();
|
|
status_number = 3;
|
|
}
|
|
farm_timer = 1;
|
|
break;
|
|
|
|
case 3: // filament change
|
|
// must do a return here to prevent doing SERIAL_ECHOLN("}") at the very end of this function
|
|
// saved a considerable amount of FLASH
|
|
return;
|
|
break;
|
|
case 4: // print succesfull
|
|
SERIAL_ECHO("{[RES:1][FIL:");
|
|
MYSERIAL.print(int(_fil_nr));
|
|
SERIAL_ECHO(']');
|
|
prusa_stat_printerstatus(status_number);
|
|
prusa_stat_farm_number();
|
|
farm_timer = 2;
|
|
break;
|
|
case 5: // print not succesfull
|
|
SERIAL_ECHO("{[RES:0][FIL:");
|
|
MYSERIAL.print(int(_fil_nr));
|
|
SERIAL_ECHO(']');
|
|
prusa_stat_printerstatus(status_number);
|
|
prusa_stat_farm_number();
|
|
farm_timer = 2;
|
|
break;
|
|
case 6: // print done
|
|
SERIAL_ECHO("{[PRN:8]");
|
|
prusa_stat_farm_number();
|
|
status_number = 8;
|
|
farm_timer = 2;
|
|
break;
|
|
case 7: // print done - stopped
|
|
SERIAL_ECHO("{[PRN:9]");
|
|
prusa_stat_farm_number();
|
|
status_number = 9;
|
|
farm_timer = 2;
|
|
break;
|
|
case 8: // printer started
|
|
SERIAL_ECHO("{[PRN:0][PFN:");
|
|
status_number = 0;
|
|
SERIAL_ECHO(farm_no);
|
|
SERIAL_ECHO(']');
|
|
farm_timer = 2;
|
|
break;
|
|
case 20: // echo farm no
|
|
SERIAL_ECHO('{');
|
|
prusa_stat_printerstatus(status_number);
|
|
prusa_stat_farm_number();
|
|
farm_timer = 4;
|
|
break;
|
|
case 21: // temperatures
|
|
SERIAL_ECHO('{');
|
|
prusa_stat_temperatures();
|
|
prusa_stat_farm_number();
|
|
prusa_stat_printerstatus(status_number);
|
|
break;
|
|
case 22: // waiting for filament change
|
|
SERIAL_ECHO("{[PRN:5]");
|
|
prusa_stat_farm_number();
|
|
status_number = 5;
|
|
break;
|
|
|
|
case 90: // Error - Thermal Runaway
|
|
prusa_statistics_err('1');
|
|
break;
|
|
case 91: // Error - Thermal Runaway Preheat
|
|
prusa_statistics_err('2');
|
|
break;
|
|
case 92: // Error - Min temp
|
|
prusa_statistics_err('3');
|
|
break;
|
|
case 93: // Error - Max temp
|
|
prusa_statistics_err('4');
|
|
break;
|
|
|
|
case 99: // heartbeat
|
|
SERIAL_ECHO("{[PRN:99]");
|
|
prusa_stat_temperatures();
|
|
SERIAL_ECHO("[PFN:");
|
|
SERIAL_ECHO(farm_no);
|
|
SERIAL_ECHO(']');
|
|
|
|
break;
|
|
}
|
|
SERIAL_ECHOLN('}');
|
|
|
|
}
|
|
|
|
static void prusa_stat_printerstatus(int _status)
|
|
{
|
|
SERIAL_ECHO("[PRN:");
|
|
SERIAL_ECHO(_status);
|
|
SERIAL_ECHO(']');
|
|
}
|
|
|
|
static void prusa_stat_farm_number() {
|
|
SERIAL_ECHO("[PFN:");
|
|
SERIAL_ECHO(farm_no);
|
|
SERIAL_ECHO(']');
|
|
}
|
|
|
|
static void prusa_stat_diameter() {
|
|
SERIAL_ECHO("[DIA:");
|
|
SERIAL_ECHO(eeprom_read_word((uint16_t*)EEPROM_NOZZLE_DIAMETER_uM));
|
|
SERIAL_ECHO(']');
|
|
}
|
|
|
|
static void prusa_stat_temperatures()
|
|
{
|
|
SERIAL_ECHO("[ST0:");
|
|
SERIAL_ECHO(target_temperature[0]);
|
|
SERIAL_ECHO("][STB:");
|
|
SERIAL_ECHO(target_temperature_bed);
|
|
SERIAL_ECHO("][AT0:");
|
|
SERIAL_ECHO(current_temperature[0]);
|
|
SERIAL_ECHO("][ATB:");
|
|
SERIAL_ECHO(current_temperature_bed);
|
|
SERIAL_ECHO(']');
|
|
}
|
|
|
|
static void prusa_stat_printinfo()
|
|
{
|
|
SERIAL_ECHO("[TFU:");
|
|
SERIAL_ECHO(total_filament_used);
|
|
SERIAL_ECHO("][PCD:");
|
|
SERIAL_ECHO(itostr3(card.percentDone()));
|
|
SERIAL_ECHO("][FEM:");
|
|
SERIAL_ECHO(itostr3(feedmultiply));
|
|
SERIAL_ECHO("][FNM:");
|
|
SERIAL_ECHO(longFilenameOLD);
|
|
SERIAL_ECHO("][TIM:");
|
|
if (starttime != 0)
|
|
{
|
|
SERIAL_ECHO(_millis() / 1000 - starttime / 1000);
|
|
}
|
|
else
|
|
{
|
|
SERIAL_ECHO(0);
|
|
}
|
|
SERIAL_ECHO("][FWR:");
|
|
SERIAL_ECHO(FW_VERSION);
|
|
SERIAL_ECHO(']');
|
|
prusa_stat_diameter();
|
|
}
|
|
|
|
/*
|
|
void lcd_pick_babystep(){
|
|
int enc_dif = 0;
|
|
int cursor_pos = 1;
|
|
int fsm = 0;
|
|
|
|
|
|
|
|
|
|
lcd_clear();
|
|
|
|
lcd_set_cursor(0, 0);
|
|
|
|
lcd_puts_P(_i("Pick print"));////MSG_PICK_Z
|
|
|
|
|
|
lcd_set_cursor(3, 2);
|
|
|
|
lcd_print("1");
|
|
|
|
lcd_set_cursor(3, 3);
|
|
|
|
lcd_print("2");
|
|
|
|
lcd_set_cursor(12, 2);
|
|
|
|
lcd_print("3");
|
|
|
|
lcd_set_cursor(12, 3);
|
|
|
|
lcd_print("4");
|
|
|
|
lcd_set_cursor(1, 2);
|
|
|
|
lcd_print(">");
|
|
|
|
|
|
enc_dif = lcd_encoder_diff;
|
|
|
|
while (fsm == 0) {
|
|
|
|
manage_heater();
|
|
manage_inactivity(true);
|
|
|
|
if ( abs((enc_dif - lcd_encoder_diff)) > 4 ) {
|
|
|
|
if ( (abs(enc_dif - lcd_encoder_diff)) > 1 ) {
|
|
if (enc_dif > lcd_encoder_diff ) {
|
|
cursor_pos --;
|
|
}
|
|
|
|
if (enc_dif < lcd_encoder_diff ) {
|
|
cursor_pos ++;
|
|
}
|
|
|
|
if (cursor_pos > 4) {
|
|
cursor_pos = 4;
|
|
}
|
|
|
|
if (cursor_pos < 1) {
|
|
cursor_pos = 1;
|
|
}
|
|
|
|
|
|
lcd_set_cursor(1, 2);
|
|
lcd_print(" ");
|
|
lcd_set_cursor(1, 3);
|
|
lcd_print(" ");
|
|
lcd_set_cursor(10, 2);
|
|
lcd_print(" ");
|
|
lcd_set_cursor(10, 3);
|
|
lcd_print(" ");
|
|
|
|
if (cursor_pos < 3) {
|
|
lcd_set_cursor(1, cursor_pos+1);
|
|
lcd_print(">");
|
|
}else{
|
|
lcd_set_cursor(10, cursor_pos-1);
|
|
lcd_print(">");
|
|
}
|
|
|
|
|
|
enc_dif = lcd_encoder_diff;
|
|
_delay(100);
|
|
}
|
|
|
|
}
|
|
|
|
if (lcd_clicked()) {
|
|
fsm = cursor_pos;
|
|
int babyStepZ;
|
|
EEPROM_read_B(EEPROM_BABYSTEP_Z0+((fsm-1)*2),&babyStepZ);
|
|
EEPROM_save_B(EEPROM_BABYSTEP_Z,&babyStepZ);
|
|
calibration_status_store(CALIBRATION_STATUS_CALIBRATED);
|
|
_delay(500);
|
|
|
|
}
|
|
};
|
|
|
|
lcd_clear();
|
|
lcd_return_to_status();
|
|
}
|
|
*/
|
|
void lcd_move_menu_axis()
|
|
{
|
|
MENU_BEGIN();
|
|
MENU_ITEM_BACK_P(_T(MSG_SETTINGS));
|
|
MENU_ITEM_SUBMENU_P(_i("Move X"), lcd_move_x);////MSG_MOVE_X
|
|
MENU_ITEM_SUBMENU_P(_i("Move Y"), lcd_move_y);////MSG_MOVE_Y
|
|
MENU_ITEM_SUBMENU_P(_i("Move Z"), lcd_move_z);////MSG_MOVE_Z
|
|
MENU_ITEM_SUBMENU_P(_i("Extruder"), lcd_move_e);////MSG_MOVE_E
|
|
MENU_END();
|
|
}
|
|
|
|
static void lcd_move_menu_1mm()
|
|
{
|
|
move_menu_scale = 1.0;
|
|
lcd_move_menu_axis();
|
|
}
|
|
|
|
|
|
void EEPROM_save(int pos, uint8_t* value, uint8_t size)
|
|
{
|
|
do
|
|
{
|
|
eeprom_write_byte((unsigned char*)pos, *value);
|
|
pos++;
|
|
value++;
|
|
} while (--size);
|
|
}
|
|
|
|
void EEPROM_read(int pos, uint8_t* value, uint8_t size)
|
|
{
|
|
do
|
|
{
|
|
*value = eeprom_read_byte((unsigned char*)pos);
|
|
pos++;
|
|
value++;
|
|
} while (--size);
|
|
}
|
|
|
|
#ifdef SDCARD_SORT_ALPHA
|
|
static void lcd_sort_type_set() {
|
|
uint8_t sdSort;
|
|
EEPROM_read(EEPROM_SD_SORT, (uint8_t*)&sdSort, sizeof(sdSort));
|
|
switch (sdSort) {
|
|
case SD_SORT_TIME: sdSort = SD_SORT_ALPHA; break;
|
|
case SD_SORT_ALPHA: sdSort = SD_SORT_NONE; break;
|
|
default: sdSort = SD_SORT_TIME;
|
|
}
|
|
eeprom_update_byte((unsigned char *)EEPROM_SD_SORT, sdSort);
|
|
presort_flag = true;
|
|
}
|
|
#endif //SDCARD_SORT_ALPHA
|
|
|
|
#ifdef TMC2130
|
|
static void lcd_crash_mode_info()
|
|
{
|
|
lcd_update_enable(true);
|
|
static uint32_t tim = 0;
|
|
if ((tim + 1000) < _millis())
|
|
{
|
|
lcd_clear();
|
|
fputs_P(_i("Crash detection can\nbe turned on only in\nNormal mode"), lcdout);////MSG_CRASH_DET_ONLY_IN_NORMAL c=20 r=4
|
|
tim = _millis();
|
|
}
|
|
menu_back_if_clicked();
|
|
}
|
|
|
|
static void lcd_crash_mode_info2()
|
|
{
|
|
lcd_update_enable(true);
|
|
static uint32_t tim = 0;
|
|
if ((tim + 1000) < _millis())
|
|
{
|
|
lcd_clear();
|
|
fputs_P(_i("WARNING:\nCrash detection\ndisabled in\nStealth mode"), lcdout);////MSG_CRASH_DET_STEALTH_FORCE_OFF c=20 r=4
|
|
tim = _millis();
|
|
}
|
|
menu_back_if_clicked();
|
|
}
|
|
#endif //TMC2130
|
|
|
|
#ifdef FILAMENT_SENSOR
|
|
static void lcd_filament_autoload_info()
|
|
{
|
|
uint8_t nlines;
|
|
lcd_update_enable(true);
|
|
static uint32_t tim = 0;
|
|
if ((tim + 1000) < _millis())
|
|
{
|
|
lcd_display_message_fullscreen_nonBlocking_P(_i("Autoloading filament available only when filament sensor is turned on..."), nlines); ////MSG_AUTOLOADING_ONLY_IF_FSENS_ON c=20 r=4
|
|
tim = _millis();
|
|
}
|
|
menu_back_if_clicked();
|
|
}
|
|
|
|
static void lcd_fsensor_fail()
|
|
{
|
|
uint8_t nlines;
|
|
lcd_update_enable(true);
|
|
static uint32_t tim = 0;
|
|
if ((tim + 1000) < _millis())
|
|
{
|
|
lcd_display_message_fullscreen_nonBlocking_P(_i("ERROR: Filament sensor is not responding, please check connection."), nlines);////MSG_FSENS_NOT_RESPONDING c=20 r=4
|
|
tim = _millis();
|
|
}
|
|
menu_back_if_clicked();
|
|
}
|
|
#endif //FILAMENT_SENSOR
|
|
|
|
//-//
|
|
static void lcd_sound_state_set(void)
|
|
{
|
|
Sound_CycleState();
|
|
}
|
|
|
|
#ifndef MMU_FORCE_STEALTH_MODE
|
|
static void lcd_silent_mode_mmu_set() {
|
|
if (SilentModeMenu_MMU == 1) SilentModeMenu_MMU = 0;
|
|
else SilentModeMenu_MMU = 1;
|
|
//saving to eeprom is done in mmu_loop() after mmu actually switches state and confirms with "ok"
|
|
}
|
|
#endif //MMU_FORCE_STEALTH_MODE
|
|
|
|
static void lcd_silent_mode_set() {
|
|
switch (SilentModeMenu) {
|
|
#ifdef TMC2130
|
|
case SILENT_MODE_NORMAL: SilentModeMenu = SILENT_MODE_STEALTH; break;
|
|
case SILENT_MODE_STEALTH: SilentModeMenu = SILENT_MODE_NORMAL; break;
|
|
default: SilentModeMenu = SILENT_MODE_NORMAL; break; // (probably) not needed
|
|
#else
|
|
case SILENT_MODE_POWER: SilentModeMenu = SILENT_MODE_SILENT; break;
|
|
case SILENT_MODE_SILENT: SilentModeMenu = SILENT_MODE_AUTO; break;
|
|
case SILENT_MODE_AUTO: SilentModeMenu = SILENT_MODE_POWER; break;
|
|
default: SilentModeMenu = SILENT_MODE_POWER; break; // (probably) not needed
|
|
#endif //TMC2130
|
|
}
|
|
eeprom_update_byte((unsigned char *)EEPROM_SILENT, SilentModeMenu);
|
|
#ifdef TMC2130
|
|
lcd_display_message_fullscreen_P(_i("Mode change in progress ..."));
|
|
// Wait until the planner queue is drained and the stepper routine achieves
|
|
// an idle state.
|
|
st_synchronize();
|
|
if (tmc2130_wait_standstill_xy(1000)) {}
|
|
// MYSERIAL.print("standstill OK");
|
|
// else
|
|
// MYSERIAL.print("standstill NG!");
|
|
cli();
|
|
tmc2130_mode = (SilentModeMenu != SILENT_MODE_NORMAL)?TMC2130_MODE_SILENT:TMC2130_MODE_NORMAL;
|
|
update_mode_profile();
|
|
tmc2130_init();
|
|
// We may have missed a stepper timer interrupt due to the time spent in tmc2130_init.
|
|
// Be safe than sorry, reset the stepper timer before re-enabling interrupts.
|
|
st_reset_timer();
|
|
sei();
|
|
#endif //TMC2130
|
|
st_current_init();
|
|
#ifdef TMC2130
|
|
if (lcd_crash_detect_enabled() && (SilentModeMenu != SILENT_MODE_NORMAL))
|
|
menu_submenu(lcd_crash_mode_info2);
|
|
lcd_encoder_diff=0; // reset 'encoder buffer'
|
|
#endif //TMC2130
|
|
}
|
|
|
|
#ifdef TMC2130
|
|
static void crash_mode_switch()
|
|
{
|
|
if (lcd_crash_detect_enabled())
|
|
{
|
|
lcd_crash_detect_disable();
|
|
}
|
|
else
|
|
{
|
|
lcd_crash_detect_enable();
|
|
}
|
|
if (IS_SD_PRINTING || is_usb_printing || (lcd_commands_type == LcdCommands::Layer1Cal)) menu_goto(lcd_tune_menu, 9, true, true);
|
|
else menu_goto(lcd_settings_menu, 9, true, true);
|
|
}
|
|
#endif //TMC2130
|
|
|
|
|
|
#ifdef FILAMENT_SENSOR
|
|
static void lcd_fsensor_state_set()
|
|
{
|
|
FSensorStateMenu = !FSensorStateMenu; //set also from fsensor_enable() and fsensor_disable()
|
|
if (!FSensorStateMenu) {
|
|
fsensor_disable();
|
|
if (fsensor_autoload_enabled && !mmu_enabled)
|
|
menu_submenu(lcd_filament_autoload_info);
|
|
}
|
|
else {
|
|
fsensor_enable();
|
|
if (fsensor_not_responding && !mmu_enabled)
|
|
menu_submenu(lcd_fsensor_fail);
|
|
}
|
|
}
|
|
#endif //FILAMENT_SENSOR
|
|
|
|
|
|
#if !SDSORT_USES_RAM
|
|
void lcd_set_degree() {
|
|
lcd_set_custom_characters_degree();
|
|
}
|
|
|
|
void lcd_set_progress() {
|
|
lcd_set_custom_characters_progress();
|
|
}
|
|
#endif
|
|
|
|
#if (LANG_MODE != 0)
|
|
|
|
void menu_setlang(unsigned char lang)
|
|
{
|
|
if (!lang_select(lang))
|
|
{
|
|
if (lcd_show_fullscreen_message_yes_no_and_wait_P(_i("Copy selected language?"), false, true))
|
|
lang_boot_update_start(lang);
|
|
lcd_update_enable(true);
|
|
lcd_clear();
|
|
menu_goto(lcd_language_menu, 0, true, true);
|
|
lcd_timeoutToStatus.stop(); //infinite timeout
|
|
lcd_draw_update = 2;
|
|
}
|
|
}
|
|
|
|
static void lcd_language_menu()
|
|
{
|
|
MENU_BEGIN();
|
|
if (lang_is_selected()) MENU_ITEM_BACK_P(_T(MSG_SETTINGS)); //
|
|
if (menu_item_text_P(lang_get_name_by_code(lang_get_code(0)))) //primary language
|
|
{
|
|
menu_setlang(0);
|
|
return;
|
|
}
|
|
uint8_t cnt = lang_get_count();
|
|
#ifdef W25X20CL
|
|
if (cnt == 2) //display secondary language in case of clear xflash
|
|
{
|
|
if (menu_item_text_P(lang_get_name_by_code(lang_get_code(1))))
|
|
{
|
|
menu_setlang(1);
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
for (int i = 2; i < cnt; i++) //skip seconday language - solved in lang_select (MK3)
|
|
#else //W25X20CL
|
|
for (int i = 1; i < cnt; i++) //all seconday languages (MK2/25)
|
|
#endif //W25X20CL
|
|
if (menu_item_text_P(lang_get_name_by_code(lang_get_code(i))))
|
|
{
|
|
menu_setlang(i);
|
|
return;
|
|
}
|
|
MENU_END();
|
|
}
|
|
#endif //(LANG_MODE != 0)
|
|
|
|
|
|
void lcd_mesh_bedleveling()
|
|
{
|
|
mesh_bed_run_from_menu = true;
|
|
enquecommand_P(PSTR("G80"));
|
|
lcd_return_to_status();
|
|
}
|
|
|
|
void lcd_mesh_calibration()
|
|
{
|
|
enquecommand_P(PSTR("M45"));
|
|
lcd_return_to_status();
|
|
}
|
|
|
|
void lcd_mesh_calibration_z()
|
|
{
|
|
enquecommand_P(PSTR("M45 Z"));
|
|
lcd_return_to_status();
|
|
}
|
|
|
|
void lcd_pinda_calibration_menu()
|
|
{
|
|
MENU_BEGIN();
|
|
MENU_ITEM_BACK_P(_T(MSG_MENU_CALIBRATION));
|
|
MENU_ITEM_SUBMENU_P(_i("Calibrate"), lcd_calibrate_pinda);////MSG_CALIBRATE_PINDA c=17 r=1
|
|
MENU_END();
|
|
}
|
|
|
|
void lcd_temp_calibration_set() {
|
|
temp_cal_active = !temp_cal_active;
|
|
eeprom_update_byte((unsigned char *)EEPROM_TEMP_CAL_ACTIVE, temp_cal_active);
|
|
st_current_init();
|
|
}
|
|
|
|
#ifdef HAS_SECOND_SERIAL_PORT
|
|
void lcd_second_serial_set() {
|
|
if(selectedSerialPort == 1) selectedSerialPort = 0;
|
|
else selectedSerialPort = 1;
|
|
eeprom_update_byte((unsigned char *)EEPROM_SECOND_SERIAL_ACTIVE, selectedSerialPort);
|
|
MYSERIAL.begin(BAUDRATE);
|
|
}
|
|
#endif //HAS_SECOND_SERIAL_PORT
|
|
|
|
void lcd_calibrate_pinda() {
|
|
enquecommand_P(PSTR("G76"));
|
|
lcd_return_to_status();
|
|
}
|
|
|
|
#ifndef SNMM
|
|
|
|
/*void lcd_calibrate_extruder() {
|
|
|
|
if (degHotend0() > EXTRUDE_MINTEMP)
|
|
{
|
|
current_position[E_AXIS] = 0; //set initial position to zero
|
|
plan_set_e_position(current_position[E_AXIS]);
|
|
|
|
//long steps_start = st_get_position(E_AXIS);
|
|
|
|
long steps_final;
|
|
float e_steps_per_unit;
|
|
float feedrate = (180 / axis_steps_per_unit[E_AXIS]) * 1; //3 //initial automatic extrusion feedrate (depends on current value of axis_steps_per_unit to avoid too fast extrusion)
|
|
float e_shift_calibration = (axis_steps_per_unit[E_AXIS] > 180 ) ? ((180 / axis_steps_per_unit[E_AXIS]) * 70): 70; //length of initial automatic extrusion sequence
|
|
const char *msg_e_cal_knob = _i("Rotate knob until mark reaches extruder body. Click when done.");////MSG_E_CAL_KNOB c=20 r=8
|
|
const char *msg_next_e_cal_knob = lcd_display_message_fullscreen_P(msg_e_cal_knob);
|
|
const bool multi_screen = msg_next_e_cal_knob != NULL;
|
|
unsigned long msg_millis;
|
|
|
|
lcd_show_fullscreen_message_and_wait_P(_i("Mark filament 100mm from extruder body. Click when done."));////MSG_MARK_FIL c=20 r=8
|
|
lcd_clear();
|
|
|
|
|
|
lcd_set_cursor(0, 1); lcd_puts_P(_T(MSG_PLEASE_WAIT));
|
|
current_position[E_AXIS] += e_shift_calibration;
|
|
plan_buffer_line_curposXYZE(feedrate, active_extruder);
|
|
st_synchronize();
|
|
|
|
lcd_display_message_fullscreen_P(msg_e_cal_knob);
|
|
msg_millis = _millis();
|
|
while (!LCD_CLICKED) {
|
|
if (multi_screen && _millis() - msg_millis > 5000) {
|
|
if (msg_next_e_cal_knob == NULL)
|
|
msg_next_e_cal_knob = msg_e_cal_knob;
|
|
msg_next_e_cal_knob = lcd_display_message_fullscreen_P(msg_next_e_cal_knob);
|
|
msg_millis = _millis();
|
|
}
|
|
|
|
//manage_inactivity(true);
|
|
manage_heater();
|
|
if (abs(lcd_encoder_diff) >= ENCODER_PULSES_PER_STEP) { //adjusting mark by knob rotation
|
|
delay_keep_alive(50);
|
|
//previous_millis_cmd = _millis();
|
|
lcd_encoder += (lcd_encoder_diff / ENCODER_PULSES_PER_STEP);
|
|
lcd_encoder_diff = 0;
|
|
if (!planner_queue_full()) {
|
|
current_position[E_AXIS] += float(abs((int)lcd_encoder)) * 0.01; //0.05
|
|
lcd_encoder = 0;
|
|
plan_buffer_line_curposXYZE(feedrate, active_extruder);
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
steps_final = current_position[E_AXIS] * axis_steps_per_unit[E_AXIS];
|
|
//steps_final = st_get_position(E_AXIS);
|
|
lcd_draw_update = 1;
|
|
e_steps_per_unit = ((float)(steps_final)) / 100.0f;
|
|
if (e_steps_per_unit < MIN_E_STEPS_PER_UNIT) e_steps_per_unit = MIN_E_STEPS_PER_UNIT;
|
|
if (e_steps_per_unit > MAX_E_STEPS_PER_UNIT) e_steps_per_unit = MAX_E_STEPS_PER_UNIT;
|
|
|
|
lcd_clear();
|
|
|
|
axis_steps_per_unit[E_AXIS] = e_steps_per_unit;
|
|
enquecommand_P(PSTR("M500")); //store settings to eeprom
|
|
|
|
//lcd_drawedit(PSTR("Result"), ftostr31(axis_steps_per_unit[E_AXIS]));
|
|
//delay_keep_alive(2000);
|
|
delay_keep_alive(500);
|
|
lcd_show_fullscreen_message_and_wait_P(_i("E calibration finished. Please clean the nozzle. Click when done."));////MSG_CLEAN_NOZZLE_E c=20 r=8
|
|
lcd_update_enable(true);
|
|
lcd_draw_update = 2;
|
|
|
|
}
|
|
else
|
|
{
|
|
show_preheat_nozzle_warning();
|
|
}
|
|
lcd_return_to_status();
|
|
}
|
|
|
|
void lcd_extr_cal_reset() {
|
|
float tmp1[] = DEFAULT_AXIS_STEPS_PER_UNIT;
|
|
axis_steps_per_unit[E_AXIS] = tmp1[3];
|
|
//extrudemultiply = 100;
|
|
enquecommand_P(PSTR("M500"));
|
|
}*/
|
|
|
|
#endif
|
|
|
|
void lcd_toshiba_flash_air_compatibility_toggle()
|
|
{
|
|
card.ToshibaFlashAir_enable(! card.ToshibaFlashAir_isEnabled());
|
|
eeprom_update_byte((uint8_t*)EEPROM_TOSHIBA_FLASH_AIR_COMPATIBLITY, card.ToshibaFlashAir_isEnabled());
|
|
}
|
|
|
|
//! @brief Continue first layer calibration with previous value or start from zero?
|
|
//!
|
|
//! @code{.unparsed}
|
|
//! |01234567890123456789|
|
|
//! |Sheet Smooth1 actual| c=a, c=b, a+b = 13
|
|
//! |Z offset: -1.480 mm | c=a, c=b, a+b = 14
|
|
//! |>Continue | c=19
|
|
//! | Start from zero | c=19
|
|
//! ----------------------
|
|
//! @endcode
|
|
void lcd_first_layer_calibration_reset()
|
|
{
|
|
typedef struct
|
|
{
|
|
bool reset;
|
|
} MenuData;
|
|
static_assert(sizeof(menu_data)>= sizeof(MenuData),"_menu_data_t doesn't fit into menu_data");
|
|
MenuData* menuData = (MenuData*)&(menu_data[0]);
|
|
|
|
if(LCD_CLICKED || !eeprom_is_sheet_initialized(eeprom_read_byte(&(EEPROM_Sheets_base->active_sheet))) ||
|
|
(calibration_status() >= CALIBRATION_STATUS_LIVE_ADJUST) ||
|
|
(0 == static_cast<int16_t>(eeprom_read_word(reinterpret_cast<uint16_t*>
|
|
(&EEPROM_Sheets_base->s[(eeprom_read_byte(&(EEPROM_Sheets_base->active_sheet)))].z_offset)))))
|
|
{
|
|
if (menuData->reset)
|
|
{
|
|
eeprom_update_word(reinterpret_cast<uint16_t*>(&EEPROM_Sheets_base->s[(eeprom_read_byte(&(EEPROM_Sheets_base->active_sheet)))].z_offset), 0xffff);
|
|
}
|
|
menu_goto(lcd_v2_calibration,0,true,true);
|
|
}
|
|
|
|
if (lcd_encoder > 0)
|
|
{
|
|
menuData->reset = true;
|
|
lcd_encoder = 1;
|
|
}
|
|
else if (lcd_encoder < 1)
|
|
{
|
|
menuData->reset = false;
|
|
lcd_encoder = 0;
|
|
}
|
|
|
|
char sheet_name[sizeof(Sheet::name)];
|
|
eeprom_read_block(sheet_name, &EEPROM_Sheets_base->s[(eeprom_read_byte(&(EEPROM_Sheets_base->active_sheet)))].name, sizeof(Sheet::name));
|
|
lcd_set_cursor(0, 0);
|
|
float offset = static_cast<int16_t>(eeprom_read_word(reinterpret_cast<uint16_t*>(&EEPROM_Sheets_base->s[(eeprom_read_byte(&(EEPROM_Sheets_base->active_sheet)))].z_offset)))/cs.axis_steps_per_unit[Z_AXIS];
|
|
lcd_printf_P(_i("Sheet %.7s\nZ offset: %+1.3f mm\n%cContinue\n%cStart from zero"), //// \n denotes line break, %.7s is replaced by 7 character long sheet name, %+1.3f is replaced by 6 character long floating point number, %c is replaced by > or white space (one character) based on whether first or second option is selected. % denoted place holders can not be reordered. r=4
|
|
sheet_name, offset, menuData->reset ? ' ' : '>', menuData->reset ? '>' : ' ');
|
|
|
|
}
|
|
|
|
void lcd_v2_calibration()
|
|
{
|
|
if (mmu_enabled)
|
|
{
|
|
const uint8_t filament = choose_menu_P(
|
|
_i("Select filament:"), ////c=20 r=1
|
|
_T(MSG_FILAMENT),_i("Cancel")); ////c=19 r=1
|
|
if (filament < 5)
|
|
{
|
|
lay1cal_filament = filament;
|
|
}
|
|
else
|
|
{
|
|
menu_back();
|
|
return;
|
|
}
|
|
}
|
|
else if (!eeprom_read_byte((uint8_t*)EEPROM_WIZARD_ACTIVE))
|
|
{
|
|
bool loaded = false;
|
|
if (fsensor_enabled && ir_sensor_detected)
|
|
{
|
|
loaded = (digitalRead(IR_SENSOR_PIN) == 0);
|
|
}
|
|
else
|
|
{
|
|
loaded = lcd_show_fullscreen_message_yes_no_and_wait_P(_i("Is filament loaded?"), false, true);////MSG_PLA_FILAMENT_LOADED c=20 r=2
|
|
lcd_update_enabled = true;
|
|
|
|
}
|
|
|
|
|
|
if (!loaded)
|
|
{
|
|
lcd_display_message_fullscreen_P(_i("Please load filament first."));////MSG_PLEASE_LOAD_PLA c=20 r=4
|
|
lcd_consume_click();
|
|
for (uint_least8_t i = 0; i < 20; i++) { //wait max. 2s
|
|
delay_keep_alive(100);
|
|
if (lcd_clicked()) {
|
|
break;
|
|
}
|
|
}
|
|
lcd_update_enabled = true;
|
|
menu_back();
|
|
return;
|
|
}
|
|
}
|
|
|
|
eFilamentAction = FilamentAction::Lay1Cal;
|
|
menu_goto(lcd_generic_preheat_menu, 0, true, true);
|
|
}
|
|
|
|
void lcd_wizard() {
|
|
bool result = true;
|
|
if (calibration_status() != CALIBRATION_STATUS_ASSEMBLED) {
|
|
result = lcd_show_multiscreen_message_yes_no_and_wait_P(_i("Running Wizard will delete current calibration results and start from the beginning. Continue?"), false, false);////MSG_WIZARD_RERUN c=20 r=7
|
|
}
|
|
if (result) {
|
|
calibration_status_store(CALIBRATION_STATUS_ASSEMBLED);
|
|
lcd_wizard(WizState::Run);
|
|
}
|
|
else {
|
|
lcd_return_to_status();
|
|
lcd_update_enable(true);
|
|
lcd_update(2);
|
|
}
|
|
}
|
|
|
|
void lcd_language()
|
|
{
|
|
lcd_update_enable(true);
|
|
lcd_clear();
|
|
menu_goto(lcd_language_menu, 0, true, true);
|
|
lcd_timeoutToStatus.stop(); //infinite timeout
|
|
lcd_draw_update = 2;
|
|
while ((menu_menu != lcd_status_screen) && (!lang_is_selected()))
|
|
{
|
|
_delay(50);
|
|
lcd_update(0);
|
|
manage_heater();
|
|
manage_inactivity(true);
|
|
}
|
|
if (lang_is_selected())
|
|
lcd_return_to_status();
|
|
else
|
|
lang_select(LANG_ID_PRI);
|
|
}
|
|
|
|
static void wait_preheat()
|
|
{
|
|
current_position[Z_AXIS] = 100; //move in z axis to make space for loading filament
|
|
plan_buffer_line_curposXYZE(homing_feedrate[Z_AXIS] / 60, active_extruder);
|
|
delay_keep_alive(2000);
|
|
lcd_display_message_fullscreen_P(_T(MSG_WIZARD_HEATING));
|
|
lcd_set_custom_characters();
|
|
while (abs(degHotend(0) - degTargetHotend(0)) > 3) {
|
|
lcd_display_message_fullscreen_P(_T(MSG_WIZARD_HEATING));
|
|
|
|
lcd_set_cursor(0, 4);
|
|
//Print the hotend temperature (9 chars total)
|
|
lcdui_print_temp(LCD_STR_THERMOMETER[0], (int)(degHotend(0) + 0.5), (int)(degTargetHotend(0) + 0.5));
|
|
delay_keep_alive(1000);
|
|
}
|
|
|
|
}
|
|
|
|
static void lcd_wizard_load()
|
|
{
|
|
if (mmu_enabled)
|
|
{
|
|
lcd_show_fullscreen_message_and_wait_P(_i("Please insert filament into the first tube of the MMU, then press the knob to load it."));////c=20 r=8
|
|
tmp_extruder = 0;
|
|
}
|
|
else
|
|
{
|
|
lcd_show_fullscreen_message_and_wait_P(_i("Please insert filament into the extruder, then press the knob to load it."));////MSG_WIZARD_LOAD_FILAMENT c=20 r=8
|
|
}
|
|
lcd_update_enable(false);
|
|
lcd_clear();
|
|
lcd_puts_at_P(0, 2, _T(MSG_LOADING_FILAMENT));
|
|
#ifdef SNMM
|
|
change_extr(0);
|
|
#endif
|
|
loading_flag = true;
|
|
gcode_M701();
|
|
}
|
|
|
|
bool lcd_autoDepleteEnabled()
|
|
{
|
|
return (lcd_autoDeplete && fsensor_enabled);
|
|
}
|
|
|
|
static void wizard_lay1cal_message(bool cold)
|
|
{
|
|
lcd_show_fullscreen_message_and_wait_P(
|
|
_i("Now I will calibrate distance between tip of the nozzle and heatbed surface.")); ////MSG_WIZARD_V2_CAL c=20 r=8
|
|
if (mmu_enabled)
|
|
{
|
|
lcd_show_fullscreen_message_and_wait_P(
|
|
_i("Choose a filament for the First Layer Calibration and select it in the on-screen menu."));
|
|
}
|
|
else if (cold)
|
|
{
|
|
lcd_show_fullscreen_message_and_wait_P(
|
|
_i("Select temperature which matches your material."));
|
|
}
|
|
lcd_show_fullscreen_message_and_wait_P(
|
|
_i("The printer will start printing a zig-zag line. Rotate the knob until you reach the optimal height. Check the pictures in the handbook (Calibration chapter).")); ////MSG_WIZARD_V2_CAL_2 c=20 r=12
|
|
}
|
|
|
|
//! @brief Printer first run wizard (Selftest and calibration)
|
|
//!
|
|
//!
|
|
//! First layer calibration with MMU state diagram
|
|
//!
|
|
//! @startuml
|
|
//! [*] --> IsFil
|
|
//! IsFil : Is any filament loaded?
|
|
//! LoadFilCold : Push the button to start loading Filament 1
|
|
//!
|
|
//! IsFil --> Lay1CalCold : yes
|
|
//! IsFil --> LoadFilCold : no
|
|
//! LoadFilCold --> Lay1CalCold : click
|
|
//! @enduml
|
|
//!
|
|
//! First layer calibration without MMU state diagram
|
|
//!
|
|
//! @startuml
|
|
//! [*] --> IsFil
|
|
//! IsFil : Is filament loaded?
|
|
//! Preheat : Select nozle temperature which matches your material.
|
|
//! LoadFilHot : Insert filament to extruder and press the knob.
|
|
//!
|
|
//! IsFil --> Lay1CalCold : yes
|
|
//! IsFil --> Preheat : no
|
|
//! Preheat --> LoadFilHot : select
|
|
//! LoadFilHot --> Lay1CalHot : click
|
|
//! @enduml
|
|
//!
|
|
//! @param state Entry point of the wizard
|
|
//!
|
|
//! state | description
|
|
//! ---------------------- | ----------------
|
|
//! WizState::Run | Main entry point
|
|
//! WizState::RepeatLay1Cal | Entry point after passing 1st layer calibration
|
|
//! WizState::LoadFilHot | Entry point after temporarily left for preheat before load filament
|
|
void lcd_wizard(WizState state)
|
|
{
|
|
using S = WizState;
|
|
bool end = false;
|
|
int wizard_event;
|
|
const char *msg = NULL;
|
|
// Make sure EEPROM_WIZARD_ACTIVE is true if entering using different entry point
|
|
// other than WizState::Run - it is useful for debugging wizard.
|
|
if (state != S::Run) eeprom_update_byte((uint8_t*)EEPROM_WIZARD_ACTIVE, 1);
|
|
|
|
while (!end) {
|
|
printf_P(PSTR("Wizard state: %d\n"), state);
|
|
switch (state) {
|
|
case S::Run: //Run wizard?
|
|
|
|
// 2019-08-07 brutal hack - solving the "viper" situation.
|
|
// It is caused by the fact, that tmc2130_st_isr makes a crash detection before the printers really starts.
|
|
// And thus it calles stop_and_save_print_to_ram which sets the saved_printing flag.
|
|
// Having this flag set during normal printing is lethal - mesh_plan_buffer_line exist in the middle of planning long travels
|
|
// which results in distorted print.
|
|
// This primarily happens when the printer is new and parked in 0,0
|
|
// So any new printer will fail the first layer calibration unless being reset or the Stop function gets called.
|
|
// We really must find a way to prevent the crash from happening before the printer is started - that would be the correct solution.
|
|
// Btw. the flag may even trigger the viper situation on normal start this way and the user won't be able to find out why.
|
|
saved_printing = false;
|
|
|
|
wizard_event = lcd_show_multiscreen_message_yes_no_and_wait_P(_i("Hi, I am your Original Prusa i3 printer. Would you like me to guide you through the setup process?"), false, true);////MSG_WIZARD_WELCOME c=20 r=7
|
|
if (wizard_event) {
|
|
state = S::Restore;
|
|
eeprom_update_byte((uint8_t*)EEPROM_WIZARD_ACTIVE, 1);
|
|
}
|
|
else {
|
|
eeprom_update_byte((uint8_t*)EEPROM_WIZARD_ACTIVE, 0);
|
|
end = true;
|
|
}
|
|
break;
|
|
case S::Restore:
|
|
switch (calibration_status()) {
|
|
case CALIBRATION_STATUS_ASSEMBLED: state = S::Selftest; break; //run selftest
|
|
case CALIBRATION_STATUS_XYZ_CALIBRATION: state = S::Xyz; break; //run xyz cal.
|
|
case CALIBRATION_STATUS_Z_CALIBRATION: state = S::Z; break; //run z cal.
|
|
case CALIBRATION_STATUS_LIVE_ADJUST: state = S::IsFil; break; //run live adjust
|
|
case CALIBRATION_STATUS_CALIBRATED: end = true; eeprom_update_byte((uint8_t*)EEPROM_WIZARD_ACTIVE, 0); break;
|
|
default: state = S::Selftest; break; //if calibration status is unknown, run wizard from the beginning
|
|
}
|
|
break;
|
|
case S::Selftest:
|
|
lcd_show_fullscreen_message_and_wait_P(_i("First, I will run the selftest to check most common assembly problems."));////MSG_WIZARD_SELFTEST c=20 r=8
|
|
wizard_event = lcd_selftest();
|
|
if (wizard_event) {
|
|
calibration_status_store(CALIBRATION_STATUS_XYZ_CALIBRATION);
|
|
state = S::Xyz;
|
|
}
|
|
else end = true;
|
|
break;
|
|
case S::Xyz:
|
|
lcd_show_fullscreen_message_and_wait_P(_i("I will run xyz calibration now. It will take approx. 12 mins."));////MSG_WIZARD_XYZ_CAL c=20 r=8
|
|
wizard_event = gcode_M45(false, 0);
|
|
if (wizard_event) state = S::IsFil;
|
|
else end = true;
|
|
break;
|
|
case S::Z:
|
|
lcd_show_fullscreen_message_and_wait_P(_i("Please remove shipping helpers first."));
|
|
lcd_show_fullscreen_message_and_wait_P(_i("Now remove the test print from steel sheet."));
|
|
lcd_show_fullscreen_message_and_wait_P(_i("I will run z calibration now."));////MSG_WIZARD_Z_CAL c=20 r=8
|
|
wizard_event = lcd_show_fullscreen_message_yes_no_and_wait_P(_T(MSG_STEEL_SHEET_CHECK), false, false);
|
|
if (!wizard_event) lcd_show_fullscreen_message_and_wait_P(_T(MSG_PLACE_STEEL_SHEET));
|
|
wizard_event = gcode_M45(true, 0);
|
|
if (wizard_event) {
|
|
//current filament needs to be unloaded and then new filament should be loaded
|
|
//start to preheat nozzle for unloading remaining PLA filament
|
|
setTargetHotend(PLA_PREHEAT_HOTEND_TEMP, 0);
|
|
lcd_display_message_fullscreen_P(_i("Now I will preheat nozzle for PLA."));
|
|
wait_preheat();
|
|
//unload current filament
|
|
unload_filament();
|
|
//load filament
|
|
lcd_wizard_load();
|
|
setTargetHotend(0, 0); //we are finished, cooldown nozzle
|
|
state = S::Finish; //shipped, no need to set first layer, go to final message directly
|
|
}
|
|
else end = true;
|
|
break;
|
|
case S::IsFil:
|
|
//start to preheat nozzle and bed to save some time later
|
|
setTargetHotend(PLA_PREHEAT_HOTEND_TEMP, 0);
|
|
setTargetBed(PLA_PREHEAT_HPB_TEMP);
|
|
if (mmu_enabled)
|
|
{
|
|
wizard_event = lcd_show_fullscreen_message_yes_no_and_wait_P(_i("Is filament loaded?"), true);////c=20 r=2
|
|
} else
|
|
{
|
|
wizard_event = lcd_show_fullscreen_message_yes_no_and_wait_P(_i("Is filament loaded?"), true);////MSG_WIZARD_FILAMENT_LOADED c=20 r=2
|
|
}
|
|
if (wizard_event) state = S::Lay1CalCold;
|
|
else
|
|
{
|
|
if(mmu_enabled) state = S::LoadFilCold;
|
|
else state = S::Preheat;
|
|
}
|
|
break;
|
|
case S::Preheat:
|
|
menu_goto(lcd_preheat_menu,0,false,true);
|
|
lcd_show_fullscreen_message_and_wait_P(_i("Select nozzle preheat temperature which matches your material."));
|
|
end = true; // Leave wizard temporarily for lcd_preheat_menu
|
|
break;
|
|
case S::LoadFilHot:
|
|
wait_preheat();
|
|
lcd_wizard_load();
|
|
state = S::Lay1CalHot;
|
|
break;
|
|
case S::LoadFilCold:
|
|
lcd_wizard_load();
|
|
state = S::Lay1CalCold;
|
|
break;
|
|
case S::Lay1CalCold:
|
|
wizard_lay1cal_message(true);
|
|
menu_goto(lcd_v2_calibration,0,false,true);
|
|
end = true; // Leave wizard temporarily for lcd_v2_calibration
|
|
break;
|
|
case S::Lay1CalHot:
|
|
wizard_lay1cal_message(false);
|
|
lcd_commands_type = LcdCommands::Layer1Cal;
|
|
end = true; // Leave wizard temporarily for lcd_v2_calibration
|
|
break;
|
|
case S::RepeatLay1Cal:
|
|
wizard_event = lcd_show_multiscreen_message_yes_no_and_wait_P(_i("Do you want to repeat last step to readjust distance between nozzle and heatbed?"), false);////MSG_WIZARD_REPEAT_V2_CAL c=20 r=7
|
|
if (wizard_event)
|
|
{
|
|
lcd_show_fullscreen_message_and_wait_P(_i("Please clean heatbed and then press the knob."));////MSG_WIZARD_CLEAN_HEATBED c=20 r=8
|
|
state = S::Lay1CalCold;
|
|
}
|
|
else
|
|
{
|
|
lcd_show_fullscreen_message_and_wait_P(_i("If you have additional steel sheets, calibrate their presets in Settings - HW Setup - Steel sheets."));
|
|
state = S::Finish;
|
|
}
|
|
break;
|
|
case S::Finish:
|
|
eeprom_update_byte((uint8_t*)EEPROM_WIZARD_ACTIVE, 0);
|
|
end = true;
|
|
break;
|
|
|
|
default: break;
|
|
}
|
|
}
|
|
|
|
printf_P(_N("Wizard end state: %d\n"), state);
|
|
switch (state) { //final message
|
|
case S::Restore: //printer was already calibrated
|
|
msg = _T(MSG_WIZARD_DONE);
|
|
break;
|
|
case S::Selftest: //selftest
|
|
case S::Xyz: //xyz cal.
|
|
case S::Z: //z cal.
|
|
msg = _T(MSG_WIZARD_CALIBRATION_FAILED);
|
|
break;
|
|
case S::Finish: //we are finished
|
|
|
|
msg = _T(MSG_WIZARD_DONE);
|
|
lcd_reset_alert_level();
|
|
lcd_setstatuspgm(_T(WELCOME_MSG));
|
|
lcd_return_to_status();
|
|
break;
|
|
|
|
default:
|
|
msg = _T(MSG_WIZARD_QUIT);
|
|
break;
|
|
|
|
}
|
|
if (!((S::Lay1CalCold == state) || (S::Lay1CalHot == state) || (S::Preheat == state)))
|
|
{
|
|
lcd_show_fullscreen_message_and_wait_P(msg);
|
|
}
|
|
lcd_update_enable(true);
|
|
lcd_update(2);
|
|
}
|
|
|
|
#ifdef TMC2130
|
|
void lcd_settings_linearity_correction_menu(void)
|
|
{
|
|
MENU_BEGIN();
|
|
ON_MENU_LEAVE(
|
|
lcd_settings_linearity_correction_menu_save();
|
|
);
|
|
MENU_ITEM_BACK_P(_T(MSG_SETTINGS));
|
|
#ifdef TMC2130_LINEARITY_CORRECTION_XYZ
|
|
//tmc2130_wave_fac[X_AXIS]
|
|
|
|
MENU_ITEM_EDIT_int3_P(_i("X-correct:"), &tmc2130_wave_fac[X_AXIS], TMC2130_WAVE_FAC1000_MIN-TMC2130_WAVE_FAC1000_STP, TMC2130_WAVE_FAC1000_MAX);////MSG_EXTRUDER_CORRECTION c=10
|
|
MENU_ITEM_EDIT_int3_P(_i("Y-correct:"), &tmc2130_wave_fac[Y_AXIS], TMC2130_WAVE_FAC1000_MIN-TMC2130_WAVE_FAC1000_STP, TMC2130_WAVE_FAC1000_MAX);////MSG_EXTRUDER_CORRECTION c=10
|
|
MENU_ITEM_EDIT_int3_P(_i("Z-correct:"), &tmc2130_wave_fac[Z_AXIS], TMC2130_WAVE_FAC1000_MIN-TMC2130_WAVE_FAC1000_STP, TMC2130_WAVE_FAC1000_MAX);////MSG_EXTRUDER_CORRECTION c=10
|
|
#endif //TMC2130_LINEARITY_CORRECTION_XYZ
|
|
MENU_ITEM_EDIT_int3_P(_i("E-correct:"), &tmc2130_wave_fac[E_AXIS], TMC2130_WAVE_FAC1000_MIN-TMC2130_WAVE_FAC1000_STP, TMC2130_WAVE_FAC1000_MAX);////MSG_EXTRUDER_CORRECTION c=10
|
|
MENU_END();
|
|
}
|
|
#endif // TMC2130
|
|
|
|
#ifdef FILAMENT_SENSOR
|
|
#define SETTINGS_FILAMENT_SENSOR \
|
|
do\
|
|
{\
|
|
if (FSensorStateMenu == 0)\
|
|
{\
|
|
if (fsensor_not_responding && (mmu_enabled == false))\
|
|
{\
|
|
/* Filament sensor not working*/\
|
|
MENU_ITEM_TOGGLE_P(_T(MSG_FSENSOR), _T(MSG_NA), lcd_fsensor_state_set);/*////MSG_FSENSOR_NA*/\
|
|
MENU_ITEM_TOGGLE_P(_T(MSG_FSENSOR_AUTOLOAD), NULL, lcd_fsensor_fail);\
|
|
}\
|
|
else\
|
|
{\
|
|
/* Filament sensor turned off, working, no problems*/\
|
|
MENU_ITEM_TOGGLE_P(_T(MSG_FSENSOR), _T(MSG_OFF), lcd_fsensor_state_set);\
|
|
if (mmu_enabled == false)\
|
|
{\
|
|
MENU_ITEM_TOGGLE_P(_T(MSG_FSENSOR_AUTOLOAD), NULL, lcd_filament_autoload_info);\
|
|
}\
|
|
}\
|
|
}\
|
|
else\
|
|
{\
|
|
/* Filament sensor turned on, working, no problems*/\
|
|
MENU_ITEM_TOGGLE_P(_T(MSG_FSENSOR), _T(MSG_ON), lcd_fsensor_state_set);\
|
|
if (mmu_enabled == false)\
|
|
{\
|
|
if (fsensor_autoload_enabled)\
|
|
MENU_ITEM_TOGGLE_P(_T(MSG_FSENSOR_AUTOLOAD), _T(MSG_ON), lcd_set_filament_autoload);/*////MSG_FSENS_AUTOLOAD_ON c=17 r=1*/\
|
|
else\
|
|
MENU_ITEM_TOGGLE_P(_T(MSG_FSENSOR_AUTOLOAD), _T(MSG_OFF), lcd_set_filament_autoload);/*////MSG_FSENS_AUTOLOAD_OFF c=17 r=1*/\
|
|
/*if (fsensor_oq_meassure_enabled)*/\
|
|
/*MENU_ITEM_FUNCTION_P(_i("F. OQ meass. [on]"), lcd_set_filament_oq_meass);*//*////MSG_FSENS_OQMEASS_ON c=17 r=1*/\
|
|
/*else*/\
|
|
/*MENU_ITEM_FUNCTION_P(_i("F. OQ meass.[off]"), lcd_set_filament_oq_meass);*//*////MSG_FSENS_OQMEASS_OFF c=17 r=1*/\
|
|
}\
|
|
}\
|
|
}\
|
|
while(0)
|
|
|
|
#else //FILAMENT_SENSOR
|
|
#define SETTINGS_FILAMENT_SENSOR do{}while(0)
|
|
#endif //FILAMENT_SENSOR
|
|
|
|
static void auto_deplete_switch()
|
|
{
|
|
lcd_autoDeplete = !lcd_autoDeplete;
|
|
eeprom_update_byte((unsigned char *)EEPROM_AUTO_DEPLETE, lcd_autoDeplete);
|
|
}
|
|
|
|
static void settingsAutoDeplete()
|
|
{
|
|
if (mmu_enabled)
|
|
{
|
|
if (!fsensor_enabled)
|
|
{
|
|
MENU_ITEM_TOGGLE_P(_T(MSG_AUTO_DEPLETE), _T(MSG_NA), NULL);
|
|
}
|
|
else if (lcd_autoDeplete)
|
|
{
|
|
MENU_ITEM_TOGGLE_P(_T(MSG_AUTO_DEPLETE), _T(MSG_ON), auto_deplete_switch);
|
|
}
|
|
else
|
|
{
|
|
MENU_ITEM_TOGGLE_P(_T(MSG_AUTO_DEPLETE), _T(MSG_OFF), auto_deplete_switch);
|
|
}
|
|
}
|
|
}
|
|
|
|
#define SETTINGS_AUTO_DEPLETE \
|
|
do\
|
|
{\
|
|
settingsAutoDeplete();\
|
|
}\
|
|
while(0)\
|
|
|
|
#ifdef MMU_HAS_CUTTER
|
|
static void settingsCutter()
|
|
{
|
|
if (mmu_enabled)
|
|
{
|
|
if (EEPROM_MMU_CUTTER_ENABLED_enabled == eeprom_read_byte((uint8_t*)EEPROM_MMU_CUTTER_ENABLED))
|
|
{
|
|
MENU_ITEM_TOGGLE_P(_T(MSG_CUTTER), _T(MSG_ON), lcd_cutter_enabled);
|
|
}
|
|
#ifdef MMU_ALWAYS_CUT
|
|
else if (EEPROM_MMU_CUTTER_ENABLED_always == eeprom_read_byte((uint8_t*)EEPROM_MMU_CUTTER_ENABLED))
|
|
{
|
|
MENU_ITEM_TOGGLE_P(_T(MSG_CUTTER), _i("Always"), lcd_cutter_enabled);
|
|
}
|
|
#endif
|
|
else
|
|
{
|
|
MENU_ITEM_TOGGLE_P(_T(MSG_CUTTER), _T(MSG_OFF), lcd_cutter_enabled);
|
|
}
|
|
}
|
|
}
|
|
|
|
#define SETTINGS_CUTTER \
|
|
do\
|
|
{\
|
|
settingsCutter();\
|
|
}\
|
|
while(0)
|
|
#else
|
|
#define SETTINGS_CUTTER
|
|
#endif //MMU_HAS_CUTTER
|
|
|
|
#ifdef TMC2130
|
|
#define SETTINGS_SILENT_MODE \
|
|
do\
|
|
{\
|
|
if(!farm_mode)\
|
|
{\
|
|
if (SilentModeMenu == SILENT_MODE_NORMAL)\
|
|
{\
|
|
MENU_ITEM_TOGGLE_P(_T(MSG_MODE), _T(MSG_NORMAL), lcd_silent_mode_set);\
|
|
}\
|
|
else MENU_ITEM_TOGGLE_P(_T(MSG_MODE), _T(MSG_STEALTH), lcd_silent_mode_set);\
|
|
if (SilentModeMenu == SILENT_MODE_NORMAL)\
|
|
{\
|
|
if (lcd_crash_detect_enabled()) MENU_ITEM_TOGGLE_P(_T(MSG_CRASHDETECT), _T(MSG_ON), crash_mode_switch);\
|
|
else MENU_ITEM_TOGGLE_P(_T(MSG_CRASHDETECT), _T(MSG_OFF), crash_mode_switch);\
|
|
}\
|
|
else MENU_ITEM_TOGGLE_P(_T(MSG_CRASHDETECT), NULL, lcd_crash_mode_info);\
|
|
}\
|
|
}\
|
|
while (0)
|
|
|
|
#else //TMC2130
|
|
#define SETTINGS_SILENT_MODE \
|
|
do\
|
|
{\
|
|
if(!farm_mode)\
|
|
{\
|
|
switch (SilentModeMenu)\
|
|
{\
|
|
case SILENT_MODE_POWER:\
|
|
MENU_ITEM_TOGGLE_P(_T(MSG_MODE), _T(MSG_HIGH_POWER), lcd_silent_mode_set);\
|
|
break;\
|
|
case SILENT_MODE_SILENT:\
|
|
MENU_ITEM_TOGGLE_P(_T(MSG_MODE), _T(MSG_SILENT), lcd_silent_mode_set);\
|
|
break;\
|
|
case SILENT_MODE_AUTO:\
|
|
MENU_ITEM_TOGGLE_P(_T(MSG_MODE), _T(MSG_AUTO_POWER), lcd_silent_mode_set);\
|
|
break;\
|
|
default:\
|
|
MENU_ITEM_TOGGLE_P(_T(MSG_MODE), _T(MSG_HIGH_POWER), lcd_silent_mode_set);\
|
|
break; /* (probably) not needed*/\
|
|
}\
|
|
}\
|
|
}\
|
|
while (0)
|
|
#endif //TMC2130
|
|
|
|
#ifndef MMU_FORCE_STEALTH_MODE
|
|
#define SETTINGS_MMU_MODE \
|
|
do\
|
|
{\
|
|
if (mmu_enabled)\
|
|
{\
|
|
if (SilentModeMenu_MMU == 0) MENU_ITEM_TOGGLE_P(_T(MSG_MMU_MODE), _T(MSG_NORMAL), lcd_silent_mode_mmu_set);\
|
|
else MENU_ITEM_TOGGLE_P(_T(MSG_MMU_MODE), _T(MSG_STEALTH), lcd_silent_mode_mmu_set);\
|
|
}\
|
|
}\
|
|
while (0)
|
|
#else //MMU_FORCE_STEALTH_MODE
|
|
#define SETTINGS_MMU_MODE
|
|
#endif //MMU_FORCE_STEALTH_MODE
|
|
|
|
#ifdef SDCARD_SORT_ALPHA
|
|
#define SETTINGS_SD \
|
|
do\
|
|
{\
|
|
if (card.ToshibaFlashAir_isEnabled())\
|
|
MENU_ITEM_TOGGLE_P(_T(MSG_SD_CARD), _T(MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY), lcd_toshiba_flash_air_compatibility_toggle);\
|
|
else\
|
|
MENU_ITEM_TOGGLE_P(_T(MSG_SD_CARD), _T(MSG_NORMAL), lcd_toshiba_flash_air_compatibility_toggle);\
|
|
\
|
|
if (!farm_mode)\
|
|
{\
|
|
uint8_t sdSort;\
|
|
EEPROM_read(EEPROM_SD_SORT, (uint8_t*)&sdSort, sizeof(sdSort));\
|
|
switch (sdSort)\
|
|
{\
|
|
case SD_SORT_TIME: MENU_ITEM_TOGGLE_P(_T(MSG_SORT), _T(MSG_SORT_TIME), lcd_sort_type_set); break;\
|
|
case SD_SORT_ALPHA: MENU_ITEM_TOGGLE_P(_T(MSG_SORT), _T(MSG_SORT_ALPHA), lcd_sort_type_set); break;\
|
|
default: MENU_ITEM_TOGGLE_P(_T(MSG_SORT), _T(MSG_NONE), lcd_sort_type_set);\
|
|
}\
|
|
}\
|
|
}\
|
|
while (0)
|
|
#else // SDCARD_SORT_ALPHA
|
|
#define SETTINGS_SD \
|
|
do\
|
|
{\
|
|
if (card.ToshibaFlashAir_isEnabled())\
|
|
MENU_ITEM_TOGGLE_P(_T(MSG_SD_CARD), _T(MSG_TOSHIBA_FLASH_AIR_COMPATIBILITY), lcd_toshiba_flash_air_compatibility_toggle);\
|
|
else\
|
|
MENU_ITEM_TOGGLE_P(_T(MSG_SD_CARD), _T(MSG_NORMAL), lcd_toshiba_flash_air_compatibility_toggle);\
|
|
}\
|
|
while (0)
|
|
#endif // SDCARD_SORT_ALPHA
|
|
|
|
/*
|
|
#define SETTINGS_MBL_MODE \
|
|
do\
|
|
{\
|
|
switch(e_mbl_type)\
|
|
{\
|
|
case e_MBL_FAST:\
|
|
MENU_ITEM_FUNCTION_P(_i("Mode [Fast]"),mbl_mode_set);\
|
|
break; \
|
|
case e_MBL_OPTIMAL:\
|
|
MENU_ITEM_FUNCTION_P(_i("Mode [Optimal]"), mbl_mode_set); \
|
|
break; \
|
|
case e_MBL_PREC:\
|
|
MENU_ITEM_FUNCTION_P(_i("Mode [Precise]"), mbl_mode_set); \
|
|
break; \
|
|
default:\
|
|
MENU_ITEM_FUNCTION_P(_i("Mode [Optimal]"), mbl_mode_set); \
|
|
break; \
|
|
}\
|
|
}\
|
|
while (0)
|
|
*/
|
|
|
|
#define SETTINGS_SOUND \
|
|
do\
|
|
{\
|
|
switch(eSoundMode)\
|
|
{\
|
|
case e_SOUND_MODE_LOUD:\
|
|
MENU_ITEM_TOGGLE_P(_T(MSG_SOUND), _T(MSG_SOUND_LOUD), lcd_sound_state_set);\
|
|
break;\
|
|
case e_SOUND_MODE_ONCE:\
|
|
MENU_ITEM_TOGGLE_P(_T(MSG_SOUND), _T(MSG_SOUND_ONCE), lcd_sound_state_set);\
|
|
break;\
|
|
case e_SOUND_MODE_SILENT:\
|
|
MENU_ITEM_TOGGLE_P(_T(MSG_SOUND), _T(MSG_SILENT), lcd_sound_state_set);\
|
|
break;\
|
|
case e_SOUND_MODE_BLIND:\
|
|
MENU_ITEM_TOGGLE_P(_T(MSG_SOUND), _T(MSG_SOUND_BLIND), lcd_sound_state_set);\
|
|
break;\
|
|
default:\
|
|
MENU_ITEM_TOGGLE_P(_T(MSG_SOUND), _T(MSG_SOUND_LOUD), lcd_sound_state_set);\
|
|
}\
|
|
}\
|
|
while (0)
|
|
|
|
//-//
|
|
static void lcd_check_mode_set(void)
|
|
{
|
|
switch(oCheckMode)
|
|
{
|
|
case ClCheckMode::_None:
|
|
oCheckMode=ClCheckMode::_Warn;
|
|
break;
|
|
case ClCheckMode::_Warn:
|
|
oCheckMode=ClCheckMode::_Strict;
|
|
break;
|
|
case ClCheckMode::_Strict:
|
|
oCheckMode=ClCheckMode::_None;
|
|
break;
|
|
default:
|
|
oCheckMode=ClCheckMode::_None;
|
|
}
|
|
eeprom_update_byte((uint8_t*)EEPROM_CHECK_MODE,(uint8_t)oCheckMode);
|
|
}
|
|
|
|
#define SETTINGS_MODE \
|
|
do\
|
|
{\
|
|
switch(oCheckMode)\
|
|
{\
|
|
case ClCheckMode::_None:\
|
|
MENU_ITEM_TOGGLE_P(_T(MSG_NOZZLE), _T(MSG_NONE), lcd_check_mode_set);\
|
|
break;\
|
|
case ClCheckMode::_Warn:\
|
|
MENU_ITEM_TOGGLE_P(_T(MSG_NOZZLE), _T(MSG_WARN), lcd_check_mode_set);\
|
|
break;\
|
|
case ClCheckMode::_Strict:\
|
|
MENU_ITEM_TOGGLE_P(_T(MSG_NOZZLE), _T(MSG_STRICT), lcd_check_mode_set);\
|
|
break;\
|
|
default:\
|
|
MENU_ITEM_TOGGLE_P(_T(MSG_NOZZLE), _T(MSG_NONE), lcd_check_mode_set);\
|
|
}\
|
|
}\
|
|
while (0)
|
|
|
|
static void lcd_nozzle_diameter_set(void)
|
|
{
|
|
uint16_t nDiameter;
|
|
|
|
switch(oNozzleDiameter)
|
|
{
|
|
case ClNozzleDiameter::_Diameter_250:
|
|
oNozzleDiameter=ClNozzleDiameter::_Diameter_400;
|
|
nDiameter=400;
|
|
break;
|
|
case ClNozzleDiameter::_Diameter_400:
|
|
oNozzleDiameter=ClNozzleDiameter::_Diameter_600;
|
|
nDiameter=600;
|
|
break;
|
|
case ClNozzleDiameter::_Diameter_600:
|
|
oNozzleDiameter=ClNozzleDiameter::_Diameter_250;
|
|
nDiameter=250;
|
|
break;
|
|
default:
|
|
oNozzleDiameter=ClNozzleDiameter::_Diameter_400;
|
|
nDiameter=400;
|
|
}
|
|
eeprom_update_byte((uint8_t*)EEPROM_NOZZLE_DIAMETER,(uint8_t)oNozzleDiameter);
|
|
eeprom_update_word((uint16_t*)EEPROM_NOZZLE_DIAMETER_uM,nDiameter);
|
|
}
|
|
|
|
#define SETTINGS_NOZZLE \
|
|
do\
|
|
{\
|
|
float fNozzleDiam;\
|
|
switch(oNozzleDiameter)\
|
|
{\
|
|
case ClNozzleDiameter::_Diameter_250: fNozzleDiam = 0.25f; break;\
|
|
case ClNozzleDiameter::_Diameter_400: fNozzleDiam = 0.4f; break;\
|
|
case ClNozzleDiameter::_Diameter_600: fNozzleDiam = 0.6f; break;\
|
|
default: fNozzleDiam = 0.4f; break;\
|
|
}\
|
|
MENU_ITEM_TOGGLE(_T(MSG_NOZZLE_DIAMETER), ftostr12ns(fNozzleDiam), lcd_nozzle_diameter_set);\
|
|
}\
|
|
while (0)
|
|
|
|
static void lcd_check_model_set(void)
|
|
{
|
|
switch(oCheckModel)
|
|
{
|
|
case ClCheckModel::_None:
|
|
oCheckModel=ClCheckModel::_Warn;
|
|
break;
|
|
case ClCheckModel::_Warn:
|
|
oCheckModel=ClCheckModel::_Strict;
|
|
break;
|
|
case ClCheckModel::_Strict:
|
|
oCheckModel=ClCheckModel::_None;
|
|
break;
|
|
default:
|
|
oCheckModel=ClCheckModel::_None;
|
|
}
|
|
eeprom_update_byte((uint8_t*)EEPROM_CHECK_MODEL,(uint8_t)oCheckModel);
|
|
}
|
|
|
|
#define SETTINGS_MODEL \
|
|
do\
|
|
{\
|
|
switch(oCheckModel)\
|
|
{\
|
|
case ClCheckModel::_None:\
|
|
MENU_ITEM_TOGGLE_P(_T(MSG_MODEL), _T(MSG_NONE), lcd_check_model_set);\
|
|
break;\
|
|
case ClCheckModel::_Warn:\
|
|
MENU_ITEM_TOGGLE_P(_T(MSG_MODEL), _T(MSG_WARN), lcd_check_model_set);\
|
|
break;\
|
|
case ClCheckModel::_Strict:\
|
|
MENU_ITEM_TOGGLE_P(_T(MSG_MODEL), _T(MSG_STRICT), lcd_check_model_set);\
|
|
break;\
|
|
default:\
|
|
MENU_ITEM_TOGGLE_P(_T(MSG_MODEL), _T(MSG_NONE), lcd_check_model_set);\
|
|
}\
|
|
}\
|
|
while (0)
|
|
|
|
static void lcd_check_version_set(void)
|
|
{
|
|
switch(oCheckVersion)
|
|
{
|
|
case ClCheckVersion::_None:
|
|
oCheckVersion=ClCheckVersion::_Warn;
|
|
break;
|
|
case ClCheckVersion::_Warn:
|
|
oCheckVersion=ClCheckVersion::_Strict;
|
|
break;
|
|
case ClCheckVersion::_Strict:
|
|
oCheckVersion=ClCheckVersion::_None;
|
|
break;
|
|
default:
|
|
oCheckVersion=ClCheckVersion::_None;
|
|
}
|
|
eeprom_update_byte((uint8_t*)EEPROM_CHECK_VERSION,(uint8_t)oCheckVersion);
|
|
}
|
|
|
|
#define SETTINGS_VERSION \
|
|
do\
|
|
{\
|
|
switch(oCheckVersion)\
|
|
{\
|
|
case ClCheckVersion::_None:\
|
|
MENU_ITEM_TOGGLE_P(_T(MSG_FIRMWARE), _T(MSG_NONE), lcd_check_version_set);\
|
|
break;\
|
|
case ClCheckVersion::_Warn:\
|
|
MENU_ITEM_TOGGLE_P(_T(MSG_FIRMWARE), _T(MSG_WARN), lcd_check_version_set);\
|
|
break;\
|
|
case ClCheckVersion::_Strict:\
|
|
MENU_ITEM_TOGGLE_P(_T(MSG_FIRMWARE), _T(MSG_STRICT), lcd_check_version_set);\
|
|
break;\
|
|
default:\
|
|
MENU_ITEM_TOGGLE_P(_T(MSG_FIRMWARE), _T(MSG_NONE), lcd_check_version_set);\
|
|
}\
|
|
}\
|
|
while (0)
|
|
|
|
static void lcd_check_gcode_set(void)
|
|
{
|
|
switch(oCheckGcode)
|
|
{
|
|
case ClCheckGcode::_None:
|
|
oCheckGcode=ClCheckGcode::_Warn;
|
|
break;
|
|
case ClCheckGcode::_Warn:
|
|
oCheckGcode=ClCheckGcode::_Strict;
|
|
break;
|
|
case ClCheckGcode::_Strict:
|
|
oCheckGcode=ClCheckGcode::_None;
|
|
break;
|
|
default:
|
|
oCheckGcode=ClCheckGcode::_None;
|
|
}
|
|
eeprom_update_byte((uint8_t*)EEPROM_CHECK_GCODE,(uint8_t)oCheckGcode);
|
|
}
|
|
|
|
#define SETTINGS_GCODE \
|
|
do\
|
|
{\
|
|
switch(oCheckGcode)\
|
|
{\
|
|
case ClCheckGcode::_None:\
|
|
MENU_ITEM_TOGGLE_P(_T(MSG_GCODE), _T(MSG_NONE), lcd_check_gcode_set);\
|
|
break;\
|
|
case ClCheckGcode::_Warn:\
|
|
MENU_ITEM_TOGGLE_P(_T(MSG_GCODE), _T(MSG_WARN), lcd_check_gcode_set);\
|
|
break;\
|
|
case ClCheckGcode::_Strict:\
|
|
MENU_ITEM_TOGGLE_P(_T(MSG_GCODE), _T(MSG_STRICT), lcd_check_gcode_set);\
|
|
break;\
|
|
default:\
|
|
MENU_ITEM_TOGGLE_P(_T(MSG_GCODE), _T(MSG_NONE), lcd_check_gcode_set);\
|
|
}\
|
|
}\
|
|
while (0)
|
|
|
|
static void lcd_checking_menu(void)
|
|
{
|
|
MENU_BEGIN();
|
|
MENU_ITEM_BACK_P(_T(MSG_HW_SETUP));
|
|
SETTINGS_MODE;
|
|
SETTINGS_MODEL;
|
|
SETTINGS_VERSION;
|
|
//-// temporarily disabled
|
|
//SETTINGS_GCODE;
|
|
MENU_END();
|
|
}
|
|
|
|
#if IR_SENSOR_ANALOG
|
|
static void lcd_fsensor_actionNA_set(void)
|
|
{
|
|
switch(oFsensorActionNA)
|
|
{
|
|
case ClFsensorActionNA::_Continue:
|
|
oFsensorActionNA=ClFsensorActionNA::_Pause;
|
|
break;
|
|
case ClFsensorActionNA::_Pause:
|
|
oFsensorActionNA=ClFsensorActionNA::_Continue;
|
|
break;
|
|
default:
|
|
oFsensorActionNA=ClFsensorActionNA::_Continue;
|
|
}
|
|
eeprom_update_byte((uint8_t*)EEPROM_FSENSOR_ACTION_NA,(uint8_t)oFsensorActionNA);
|
|
}
|
|
|
|
#define FSENSOR_ACTION_NA \
|
|
do\
|
|
{\
|
|
switch(oFsensorActionNA)\
|
|
{\
|
|
case ClFsensorActionNA::_Continue:\
|
|
MENU_ITEM_TOGGLE_P(_T(MSG_FS_ACTION), _T(MSG_FS_CONTINUE), lcd_fsensor_actionNA_set);\
|
|
break;\
|
|
case ClFsensorActionNA::_Pause:\
|
|
MENU_ITEM_TOGGLE_P(_T(MSG_FS_ACTION), _T(MSG_FS_PAUSE), lcd_fsensor_actionNA_set);\
|
|
break;\
|
|
default:\
|
|
oFsensorActionNA=ClFsensorActionNA::_Continue;\
|
|
}\
|
|
}\
|
|
while (0)
|
|
#endif //IR_SENSOR_ANALOG
|
|
|
|
template <uint8_t number>
|
|
static void select_sheet_menu()
|
|
{
|
|
selected_sheet = number;
|
|
lcd_sheet_menu();
|
|
}
|
|
|
|
static void sheets_menu()
|
|
{
|
|
MENU_BEGIN();
|
|
MENU_ITEM_BACK_P(_i("HW Setup"));
|
|
MENU_ITEM_SUBMENU_E(EEPROM_Sheets_base->s[0], select_sheet_menu<0>);
|
|
MENU_ITEM_SUBMENU_E(EEPROM_Sheets_base->s[1], select_sheet_menu<1>);
|
|
MENU_ITEM_SUBMENU_E(EEPROM_Sheets_base->s[2], select_sheet_menu<2>);
|
|
MENU_ITEM_SUBMENU_E(EEPROM_Sheets_base->s[3], select_sheet_menu<3>);
|
|
MENU_ITEM_SUBMENU_E(EEPROM_Sheets_base->s[4], select_sheet_menu<4>);
|
|
MENU_ITEM_SUBMENU_E(EEPROM_Sheets_base->s[5], select_sheet_menu<5>);
|
|
MENU_ITEM_SUBMENU_E(EEPROM_Sheets_base->s[6], select_sheet_menu<6>);
|
|
MENU_ITEM_SUBMENU_E(EEPROM_Sheets_base->s[7], select_sheet_menu<7>);
|
|
MENU_END();
|
|
}
|
|
|
|
void lcd_hw_setup_menu(void) // can not be "static"
|
|
{
|
|
MENU_BEGIN();
|
|
MENU_ITEM_BACK_P(_T(bSettings?MSG_SETTINGS:MSG_BACK)); // i.e. default menu-item / menu-item after checking mismatch
|
|
|
|
MENU_ITEM_SUBMENU_P(_i("Steel sheets"), sheets_menu);
|
|
SETTINGS_NOZZLE;
|
|
MENU_ITEM_SUBMENU_P(_i("Checks"), lcd_checking_menu);
|
|
|
|
#if IR_SENSOR_ANALOG
|
|
FSENSOR_ACTION_NA;
|
|
#endif //IR_SENSOR_ANALOG
|
|
MENU_END();
|
|
}
|
|
|
|
static void lcd_settings_menu()
|
|
{
|
|
EEPROM_read(EEPROM_SILENT, (uint8_t*)&SilentModeMenu, sizeof(SilentModeMenu));
|
|
MENU_BEGIN();
|
|
MENU_ITEM_BACK_P(_T(MSG_MAIN));
|
|
|
|
MENU_ITEM_SUBMENU_P(_i("Temperature"), lcd_control_temperature_menu);////MSG_TEMPERATURE
|
|
if (!homing_flag)
|
|
MENU_ITEM_SUBMENU_P(_i("Move axis"), lcd_move_menu_1mm);////MSG_MOVE_AXIS
|
|
if (!isPrintPaused)
|
|
MENU_ITEM_GCODE_P(_i("Disable steppers"), PSTR("M84"));////MSG_DISABLE_STEPPERS
|
|
|
|
SETTINGS_FILAMENT_SENSOR;
|
|
|
|
SETTINGS_AUTO_DEPLETE;
|
|
|
|
SETTINGS_CUTTER;
|
|
|
|
MENU_ITEM_TOGGLE_P(_i("Fans check"), fans_check_enabled ? _T(MSG_ON) : _T(MSG_OFF), lcd_set_fan_check);
|
|
|
|
SETTINGS_SILENT_MODE;
|
|
|
|
if(!farm_mode)
|
|
{
|
|
bSettings=true; // flag ('fake parameter') for 'lcd_hw_setup_menu()' function
|
|
MENU_ITEM_SUBMENU_P(_i("HW Setup"), lcd_hw_setup_menu);////MSG_HW_SETUP
|
|
}
|
|
|
|
SETTINGS_MMU_MODE;
|
|
|
|
MENU_ITEM_SUBMENU_P(_i("Mesh bed leveling"), lcd_mesh_bed_leveling_settings);////MSG_MBL_SETTINGS c=18 r=1
|
|
|
|
#if defined (TMC2130) && defined (LINEARITY_CORRECTION)
|
|
MENU_ITEM_SUBMENU_P(_i("Lin. correction"), lcd_settings_linearity_correction_menu);
|
|
#endif //LINEARITY_CORRECTION && TMC2130
|
|
|
|
MENU_ITEM_TOGGLE_P(_T(MSG_TEMP_CALIBRATION), temp_cal_active ? _T(MSG_ON) : _T(MSG_OFF), lcd_temp_calibration_set);
|
|
|
|
#ifdef HAS_SECOND_SERIAL_PORT
|
|
MENU_ITEM_TOGGLE_P(_T(MSG_RPI_PORT), (selectedSerialPort == 0) ? _T(MSG_OFF) : _T(MSG_ON), lcd_second_serial_set);
|
|
#endif //HAS_SECOND_SERIAL
|
|
|
|
if (!isPrintPaused && !homing_flag)
|
|
MENU_ITEM_SUBMENU_P(_T(MSG_BABYSTEP_Z), lcd_babystep_z);
|
|
|
|
#if (LANG_MODE != 0)
|
|
MENU_ITEM_SUBMENU_P(_i("Select language"), lcd_language_menu);////MSG_LANGUAGE_SELECT
|
|
#endif //(LANG_MODE != 0)
|
|
|
|
SETTINGS_SD;
|
|
SETTINGS_SOUND;
|
|
|
|
if (farm_mode)
|
|
{
|
|
MENU_ITEM_SUBMENU_P(PSTR("Farm number"), lcd_farm_no);
|
|
MENU_ITEM_FUNCTION_P(PSTR("Disable farm mode"), lcd_disable_farm_mode);
|
|
}
|
|
|
|
MENU_END();
|
|
}
|
|
|
|
#ifdef TMC2130
|
|
static void lcd_ustep_linearity_menu_save()
|
|
{
|
|
eeprom_update_byte((uint8_t*)EEPROM_TMC2130_WAVE_X_FAC, tmc2130_wave_fac[X_AXIS]);
|
|
eeprom_update_byte((uint8_t*)EEPROM_TMC2130_WAVE_Y_FAC, tmc2130_wave_fac[Y_AXIS]);
|
|
eeprom_update_byte((uint8_t*)EEPROM_TMC2130_WAVE_Z_FAC, tmc2130_wave_fac[Z_AXIS]);
|
|
eeprom_update_byte((uint8_t*)EEPROM_TMC2130_WAVE_E_FAC, tmc2130_wave_fac[E_AXIS]);
|
|
}
|
|
#endif //TMC2130
|
|
|
|
#ifdef TMC2130
|
|
static void lcd_settings_linearity_correction_menu_save()
|
|
{
|
|
bool changed = false;
|
|
if (tmc2130_wave_fac[X_AXIS] < TMC2130_WAVE_FAC1000_MIN) tmc2130_wave_fac[X_AXIS] = 0;
|
|
if (tmc2130_wave_fac[Y_AXIS] < TMC2130_WAVE_FAC1000_MIN) tmc2130_wave_fac[Y_AXIS] = 0;
|
|
if (tmc2130_wave_fac[Z_AXIS] < TMC2130_WAVE_FAC1000_MIN) tmc2130_wave_fac[Z_AXIS] = 0;
|
|
if (tmc2130_wave_fac[E_AXIS] < TMC2130_WAVE_FAC1000_MIN) tmc2130_wave_fac[E_AXIS] = 0;
|
|
changed |= (eeprom_read_byte((uint8_t*)EEPROM_TMC2130_WAVE_X_FAC) != tmc2130_wave_fac[X_AXIS]);
|
|
changed |= (eeprom_read_byte((uint8_t*)EEPROM_TMC2130_WAVE_Y_FAC) != tmc2130_wave_fac[Y_AXIS]);
|
|
changed |= (eeprom_read_byte((uint8_t*)EEPROM_TMC2130_WAVE_Z_FAC) != tmc2130_wave_fac[Z_AXIS]);
|
|
changed |= (eeprom_read_byte((uint8_t*)EEPROM_TMC2130_WAVE_E_FAC) != tmc2130_wave_fac[E_AXIS]);
|
|
lcd_ustep_linearity_menu_save();
|
|
if (changed) tmc2130_init();
|
|
}
|
|
#endif //TMC2130
|
|
|
|
static void lcd_calibration_menu()
|
|
{
|
|
MENU_BEGIN();
|
|
MENU_ITEM_BACK_P(_T(MSG_MAIN));
|
|
if (!isPrintPaused)
|
|
{
|
|
MENU_ITEM_FUNCTION_P(_i("Wizard"), lcd_wizard);////MSG_WIZARD c=17 r=1
|
|
if (lcd_commands_type == LcdCommands::Idle)
|
|
{
|
|
MENU_ITEM_SUBMENU_P(_T(MSG_V2_CALIBRATION), lcd_first_layer_calibration_reset);
|
|
}
|
|
MENU_ITEM_GCODE_P(_T(MSG_AUTO_HOME), PSTR("G28 W"));
|
|
#ifdef TMC2130
|
|
MENU_ITEM_FUNCTION_P(_i("Belt test "), lcd_belttest_v);////MSG_BELTTEST
|
|
#endif //TMC2130
|
|
MENU_ITEM_FUNCTION_P(_i("Selftest "), lcd_selftest_v);////MSG_SELFTEST
|
|
#ifdef MK1BP
|
|
// MK1
|
|
// "Calibrate Z"
|
|
MENU_ITEM_GCODE_P(_T(MSG_HOMEYZ), PSTR("G28 Z"));
|
|
#else //MK1BP
|
|
// MK2
|
|
MENU_ITEM_FUNCTION_P(_i("Calibrate XYZ"), lcd_mesh_calibration);////MSG_CALIBRATE_BED
|
|
// "Calibrate Z" with storing the reference values to EEPROM.
|
|
MENU_ITEM_SUBMENU_P(_T(MSG_HOMEYZ), lcd_mesh_calibration_z);
|
|
#ifndef SNMM
|
|
//MENU_ITEM_FUNCTION_P(_i("Calibrate E"), lcd_calibrate_extruder);////MSG_CALIBRATE_E c=20 r=1
|
|
#endif
|
|
// "Mesh Bed Leveling"
|
|
MENU_ITEM_SUBMENU_P(_i("Mesh Bed Leveling"), lcd_mesh_bedleveling);////MSG_MESH_BED_LEVELING
|
|
|
|
#endif //MK1BP
|
|
|
|
MENU_ITEM_SUBMENU_P(_i("Bed level correct"), lcd_adjust_bed);////MSG_BED_CORRECTION_MENU
|
|
MENU_ITEM_SUBMENU_P(_i("PID calibration"), pid_extruder);////MSG_PID_EXTRUDER c=17 r=1
|
|
#ifndef TMC2130
|
|
MENU_ITEM_SUBMENU_P(_i("Show end stops"), menu_show_end_stops);////MSG_SHOW_END_STOPS c=17 r=1
|
|
#endif
|
|
#ifndef MK1BP
|
|
MENU_ITEM_GCODE_P(_i("Reset XYZ calibr."), PSTR("M44"));////MSG_CALIBRATE_BED_RESET
|
|
#endif //MK1BP
|
|
#ifndef SNMM
|
|
//MENU_ITEM_FUNCTION_P(MSG_RESET_CALIBRATE_E, lcd_extr_cal_reset);
|
|
#endif
|
|
#ifndef MK1BP
|
|
MENU_ITEM_SUBMENU_P(_i("Temp. calibration"), lcd_pinda_calibration_menu);////MSG_CALIBRATION_PINDA_MENU c=17 r=1
|
|
#endif //MK1BP
|
|
}
|
|
|
|
MENU_END();
|
|
}
|
|
|
|
void bowden_menu() {
|
|
int enc_dif = lcd_encoder_diff;
|
|
int cursor_pos = 0;
|
|
lcd_clear();
|
|
lcd_set_cursor(0, 0);
|
|
lcd_print(">");
|
|
for (uint_least8_t i = 0; i < 4; i++) {
|
|
lcd_set_cursor(1, i);
|
|
lcd_print("Extruder ");
|
|
lcd_print(i);
|
|
lcd_print(": ");
|
|
EEPROM_read_B(EEPROM_BOWDEN_LENGTH + i * 2, &bowden_length[i]);
|
|
lcd_print(bowden_length[i] - 48);
|
|
|
|
}
|
|
enc_dif = lcd_encoder_diff;
|
|
lcd_consume_click();
|
|
while (1) {
|
|
|
|
manage_heater();
|
|
manage_inactivity(true);
|
|
|
|
if (abs((enc_dif - lcd_encoder_diff)) > 2) {
|
|
|
|
if (enc_dif > lcd_encoder_diff) {
|
|
cursor_pos--;
|
|
}
|
|
|
|
if (enc_dif < lcd_encoder_diff) {
|
|
cursor_pos++;
|
|
}
|
|
|
|
if (cursor_pos > 3) {
|
|
cursor_pos = 3;
|
|
Sound_MakeSound(e_SOUND_TYPE_BlindAlert);
|
|
}
|
|
|
|
if (cursor_pos < 0) {
|
|
cursor_pos = 0;
|
|
Sound_MakeSound(e_SOUND_TYPE_BlindAlert);
|
|
}
|
|
|
|
lcd_set_cursor(0, 0);
|
|
lcd_print(" ");
|
|
lcd_set_cursor(0, 1);
|
|
lcd_print(" ");
|
|
lcd_set_cursor(0, 2);
|
|
lcd_print(" ");
|
|
lcd_set_cursor(0, 3);
|
|
lcd_print(" ");
|
|
lcd_set_cursor(0, cursor_pos);
|
|
lcd_print(">");
|
|
Sound_MakeSound(e_SOUND_TYPE_EncoderMove);
|
|
enc_dif = lcd_encoder_diff;
|
|
_delay(100);
|
|
}
|
|
|
|
if (lcd_clicked()) {
|
|
Sound_MakeSound(e_SOUND_TYPE_ButtonEcho);
|
|
lcd_clear();
|
|
while (1) {
|
|
|
|
manage_heater();
|
|
manage_inactivity(true);
|
|
|
|
lcd_set_cursor(1, 1);
|
|
lcd_print("Extruder ");
|
|
lcd_print(cursor_pos);
|
|
lcd_print(": ");
|
|
lcd_set_cursor(13, 1);
|
|
lcd_print(bowden_length[cursor_pos] - 48);
|
|
|
|
if (abs((enc_dif - lcd_encoder_diff)) > 2) {
|
|
if (enc_dif > lcd_encoder_diff) {
|
|
bowden_length[cursor_pos]--;
|
|
lcd_set_cursor(13, 1);
|
|
lcd_print(bowden_length[cursor_pos] - 48);
|
|
enc_dif = lcd_encoder_diff;
|
|
}
|
|
|
|
if (enc_dif < lcd_encoder_diff) {
|
|
bowden_length[cursor_pos]++;
|
|
lcd_set_cursor(13, 1);
|
|
lcd_print(bowden_length[cursor_pos] - 48);
|
|
enc_dif = lcd_encoder_diff;
|
|
}
|
|
}
|
|
_delay(100);
|
|
if (lcd_clicked()) {
|
|
Sound_MakeSound(e_SOUND_TYPE_ButtonEcho);
|
|
EEPROM_save_B(EEPROM_BOWDEN_LENGTH + cursor_pos * 2, &bowden_length[cursor_pos]);
|
|
if (lcd_show_fullscreen_message_yes_no_and_wait_P(PSTR("Continue with another bowden?"))) {
|
|
lcd_update_enable(true);
|
|
lcd_clear();
|
|
enc_dif = lcd_encoder_diff;
|
|
lcd_set_cursor(0, cursor_pos);
|
|
lcd_print(">");
|
|
for (uint_least8_t i = 0; i < 4; i++) {
|
|
lcd_set_cursor(1, i);
|
|
lcd_print("Extruder ");
|
|
lcd_print(i);
|
|
lcd_print(": ");
|
|
EEPROM_read_B(EEPROM_BOWDEN_LENGTH + i * 2, &bowden_length[i]);
|
|
lcd_print(bowden_length[i] - 48);
|
|
|
|
}
|
|
break;
|
|
}
|
|
else return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//#ifdef SNMM
|
|
|
|
static char snmm_stop_print_menu() { //menu for choosing which filaments will be unloaded in stop print
|
|
lcd_clear();
|
|
lcd_puts_at_P(0,0,_T(MSG_UNLOAD_FILAMENT)); lcd_print(":");
|
|
lcd_set_cursor(0, 1); lcd_print(">");
|
|
lcd_puts_at_P(1,2,_i("Used during print"));////MSG_USED c=19 r=1
|
|
lcd_puts_at_P(1,3,_i("Current"));////MSG_CURRENT c=19 r=1
|
|
char cursor_pos = 1;
|
|
int enc_dif = 0;
|
|
KEEPALIVE_STATE(PAUSED_FOR_USER);
|
|
lcd_consume_click();
|
|
while (1) {
|
|
manage_heater();
|
|
manage_inactivity(true);
|
|
if (abs((enc_dif - lcd_encoder_diff)) > 4) {
|
|
|
|
if ((abs(enc_dif - lcd_encoder_diff)) > 1) {
|
|
if (enc_dif > lcd_encoder_diff) cursor_pos--;
|
|
if (enc_dif < lcd_encoder_diff) cursor_pos++;
|
|
if (cursor_pos > 3) {
|
|
cursor_pos = 3;
|
|
Sound_MakeSound(e_SOUND_TYPE_BlindAlert);
|
|
}
|
|
if (cursor_pos < 1){
|
|
cursor_pos = 1;
|
|
Sound_MakeSound(e_SOUND_TYPE_BlindAlert);
|
|
}
|
|
|
|
lcd_set_cursor(0, 1);
|
|
lcd_print(" ");
|
|
lcd_set_cursor(0, 2);
|
|
lcd_print(" ");
|
|
lcd_set_cursor(0, 3);
|
|
lcd_print(" ");
|
|
lcd_set_cursor(0, cursor_pos);
|
|
lcd_print(">");
|
|
enc_dif = lcd_encoder_diff;
|
|
Sound_MakeSound(e_SOUND_TYPE_EncoderMove);
|
|
_delay(100);
|
|
}
|
|
}
|
|
if (lcd_clicked()) {
|
|
Sound_MakeSound(e_SOUND_TYPE_ButtonEcho);
|
|
KEEPALIVE_STATE(IN_HANDLER);
|
|
return(cursor_pos - 1);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
//! @brief Select one of numbered items
|
|
//!
|
|
//! Create list of items with header. Header can not be selected.
|
|
//! Each item has text description passed by function parameter and
|
|
//! number. There are 5 numbered items, if mmu_enabled, 4 otherwise.
|
|
//! Items are numbered from 1 to 4 or 5. But index returned starts at 0.
|
|
//! There can be last item with different text and no number.
|
|
//!
|
|
//! @param header Header text
|
|
//! @param item Item text
|
|
//! @param last_item Last item text, or nullptr if there is no Last item
|
|
//! @return selected item index, first item index is 0
|
|
uint8_t choose_menu_P(const char *header, const char *item, const char *last_item)
|
|
{
|
|
//following code should handle 3 to 127 number of items well
|
|
const int8_t items_no = last_item?(mmu_enabled?6:5):(mmu_enabled?5:4);
|
|
const uint8_t item_len = item?strlen_P(item):0;
|
|
int8_t first = 0;
|
|
int8_t enc_dif = lcd_encoder_diff;
|
|
int8_t cursor_pos = 1;
|
|
|
|
lcd_clear();
|
|
|
|
KEEPALIVE_STATE(PAUSED_FOR_USER);
|
|
while (1)
|
|
{
|
|
manage_heater();
|
|
manage_inactivity(true);
|
|
|
|
if (abs((enc_dif - lcd_encoder_diff)) > 4)
|
|
{
|
|
if (enc_dif > lcd_encoder_diff)
|
|
{
|
|
cursor_pos--;
|
|
}
|
|
|
|
if (enc_dif < lcd_encoder_diff)
|
|
{
|
|
cursor_pos++;
|
|
}
|
|
enc_dif = lcd_encoder_diff;
|
|
Sound_MakeSound(e_SOUND_TYPE_EncoderMove);
|
|
}
|
|
|
|
if (cursor_pos > 3)
|
|
{
|
|
cursor_pos = 3;
|
|
if (first < items_no - 3)
|
|
{
|
|
first++;
|
|
lcd_clear();
|
|
} else { // here we are at the very end of the list
|
|
Sound_MakeSound(e_SOUND_TYPE_BlindAlert);
|
|
}
|
|
}
|
|
|
|
if (cursor_pos < 1)
|
|
{
|
|
cursor_pos = 1;
|
|
if (first > 0)
|
|
{
|
|
first--;
|
|
lcd_clear();
|
|
} else { // here we are at the very end of the list
|
|
Sound_MakeSound(e_SOUND_TYPE_BlindAlert);
|
|
}
|
|
}
|
|
|
|
if (header) lcd_puts_at_P(0,0,header);
|
|
|
|
const bool last_visible = (first == items_no - 3);
|
|
const uint_least8_t ordinary_items = (last_item&&last_visible)?2:3;
|
|
|
|
for (uint_least8_t i = 0; i < ordinary_items; i++)
|
|
{
|
|
if (item) lcd_puts_at_P(1, i + 1, item);
|
|
}
|
|
|
|
for (uint_least8_t i = 0; i < ordinary_items; i++)
|
|
{
|
|
lcd_set_cursor(2 + item_len, i+1);
|
|
lcd_print(first + i + 1);
|
|
}
|
|
|
|
if (last_item&&last_visible) lcd_puts_at_P(1, 3, last_item);
|
|
|
|
lcd_set_cursor(0, 1);
|
|
lcd_print(" ");
|
|
lcd_set_cursor(0, 2);
|
|
lcd_print(" ");
|
|
lcd_set_cursor(0, 3);
|
|
lcd_print(" ");
|
|
lcd_set_cursor(0, cursor_pos);
|
|
lcd_print(">");
|
|
_delay(100);
|
|
|
|
if (lcd_clicked())
|
|
{
|
|
Sound_MakeSound(e_SOUND_TYPE_ButtonEcho);
|
|
KEEPALIVE_STATE(IN_HANDLER);
|
|
lcd_encoder_diff = 0;
|
|
return(cursor_pos + first - 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
char reset_menu() {
|
|
#ifdef SNMM
|
|
int items_no = 5;
|
|
#else
|
|
int items_no = 4;
|
|
#endif
|
|
static int first = 0;
|
|
int enc_dif = 0;
|
|
char cursor_pos = 0;
|
|
const char *item [items_no];
|
|
|
|
item[0] = "Language";
|
|
item[1] = "Statistics";
|
|
item[2] = "Shipping prep";
|
|
item[3] = "All Data";
|
|
#ifdef SNMM
|
|
item[4] = "Bowden length";
|
|
#endif // SNMM
|
|
|
|
enc_dif = lcd_encoder_diff;
|
|
lcd_clear();
|
|
lcd_set_cursor(0, 0);
|
|
lcd_print(">");
|
|
lcd_consume_click();
|
|
while (1) {
|
|
|
|
for (uint_least8_t i = 0; i < 4; i++) {
|
|
lcd_set_cursor(1, i);
|
|
lcd_print(item[first + i]);
|
|
}
|
|
|
|
manage_heater();
|
|
manage_inactivity(true);
|
|
|
|
if (abs((enc_dif - lcd_encoder_diff)) > 4) {
|
|
|
|
if ((abs(enc_dif - lcd_encoder_diff)) > 1) {
|
|
if (enc_dif > lcd_encoder_diff) {
|
|
cursor_pos--;
|
|
}
|
|
|
|
if (enc_dif < lcd_encoder_diff) {
|
|
cursor_pos++;
|
|
}
|
|
|
|
if (cursor_pos > 3) {
|
|
cursor_pos = 3;
|
|
Sound_MakeSound(e_SOUND_TYPE_BlindAlert);
|
|
if (first < items_no - 4) {
|
|
first++;
|
|
lcd_clear();
|
|
}
|
|
}
|
|
|
|
if (cursor_pos < 0) {
|
|
cursor_pos = 0;
|
|
Sound_MakeSound(e_SOUND_TYPE_BlindAlert);
|
|
if (first > 0) {
|
|
first--;
|
|
lcd_clear();
|
|
}
|
|
}
|
|
lcd_set_cursor(0, 0);
|
|
lcd_print(" ");
|
|
lcd_set_cursor(0, 1);
|
|
lcd_print(" ");
|
|
lcd_set_cursor(0, 2);
|
|
lcd_print(" ");
|
|
lcd_set_cursor(0, 3);
|
|
lcd_print(" ");
|
|
lcd_set_cursor(0, cursor_pos);
|
|
lcd_print(">");
|
|
Sound_MakeSound(e_SOUND_TYPE_EncoderMove);
|
|
enc_dif = lcd_encoder_diff;
|
|
_delay(100);
|
|
}
|
|
|
|
}
|
|
|
|
if (lcd_clicked()) {
|
|
Sound_MakeSound(e_SOUND_TYPE_ButtonEcho);
|
|
return(cursor_pos + first);
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
static void lcd_disable_farm_mode()
|
|
{
|
|
int8_t disable = lcd_show_fullscreen_message_yes_no_and_wait_P(PSTR("Disable farm mode?"), true, false); //allow timeouting, default no
|
|
if (disable)
|
|
{
|
|
enquecommand_P(PSTR("G99"));
|
|
lcd_return_to_status();
|
|
}
|
|
lcd_update_enable(true);
|
|
lcd_draw_update = 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void fil_load_menu()
|
|
{
|
|
MENU_BEGIN();
|
|
MENU_ITEM_BACK_P(_T(MSG_MAIN));
|
|
MENU_ITEM_FUNCTION_P(_i("Load all"), load_all); ////MSG_LOAD_ALL c=17
|
|
MENU_ITEM_FUNCTION_NR_P(_T(MSG_LOAD_FILAMENT), '1', extr_adj, 0); ////MSG_LOAD_FILAMENT_1 c=16
|
|
MENU_ITEM_FUNCTION_NR_P(_T(MSG_LOAD_FILAMENT), '2', extr_adj, 1); ////MSG_LOAD_FILAMENT_2 c=17
|
|
MENU_ITEM_FUNCTION_NR_P(_T(MSG_LOAD_FILAMENT), '3', extr_adj, 2); ////MSG_LOAD_FILAMENT_3 c=17
|
|
MENU_ITEM_FUNCTION_NR_P(_T(MSG_LOAD_FILAMENT), '4', extr_adj, 3); ////MSG_LOAD_FILAMENT_4 c=17
|
|
|
|
if (mmu_enabled)
|
|
{
|
|
MENU_ITEM_FUNCTION_NR_P(_T(MSG_LOAD_FILAMENT), '5', extr_adj, 4);
|
|
}
|
|
MENU_END();
|
|
}
|
|
|
|
static void mmu_load_to_nozzle_menu()
|
|
{
|
|
if (bFilamentAction)
|
|
{
|
|
MENU_BEGIN();
|
|
MENU_ITEM_BACK_P(_T(MSG_MAIN));
|
|
MENU_ITEM_FUNCTION_NR_P(_T(MSG_LOAD_FILAMENT), '1', lcd_mmu_load_to_nozzle, 0);
|
|
MENU_ITEM_FUNCTION_NR_P(_T(MSG_LOAD_FILAMENT), '2', lcd_mmu_load_to_nozzle, 1);
|
|
MENU_ITEM_FUNCTION_NR_P(_T(MSG_LOAD_FILAMENT), '3', lcd_mmu_load_to_nozzle, 2);
|
|
MENU_ITEM_FUNCTION_NR_P(_T(MSG_LOAD_FILAMENT), '4', lcd_mmu_load_to_nozzle, 3);
|
|
MENU_ITEM_FUNCTION_NR_P(_T(MSG_LOAD_FILAMENT), '5', lcd_mmu_load_to_nozzle, 4);
|
|
MENU_END();
|
|
}
|
|
else
|
|
{
|
|
eFilamentAction = FilamentAction::MmuLoad;
|
|
preheat_or_continue();
|
|
}
|
|
}
|
|
|
|
static void mmu_eject_filament(uint8_t filament)
|
|
{
|
|
menu_back();
|
|
mmu_eject_filament(filament, true);
|
|
}
|
|
|
|
static void mmu_fil_eject_menu()
|
|
{
|
|
if (bFilamentAction)
|
|
{
|
|
MENU_BEGIN();
|
|
MENU_ITEM_BACK_P(_T(MSG_MAIN));
|
|
MENU_ITEM_FUNCTION_NR_P(_T(MSG_EJECT_FILAMENT), '1', mmu_eject_filament, 0);
|
|
MENU_ITEM_FUNCTION_NR_P(_T(MSG_EJECT_FILAMENT), '2', mmu_eject_filament, 1);
|
|
MENU_ITEM_FUNCTION_NR_P(_T(MSG_EJECT_FILAMENT), '3', mmu_eject_filament, 2);
|
|
MENU_ITEM_FUNCTION_NR_P(_T(MSG_EJECT_FILAMENT), '4', mmu_eject_filament, 3);
|
|
MENU_ITEM_FUNCTION_NR_P(_T(MSG_EJECT_FILAMENT), '5', mmu_eject_filament, 4);
|
|
MENU_END();
|
|
}
|
|
else
|
|
{
|
|
eFilamentAction = FilamentAction::MmuEject;
|
|
preheat_or_continue();
|
|
}
|
|
}
|
|
|
|
#ifdef MMU_HAS_CUTTER
|
|
|
|
static void mmu_cut_filament_menu()
|
|
{
|
|
if(bFilamentAction)
|
|
{
|
|
MENU_BEGIN();
|
|
MENU_ITEM_BACK_P(_T(MSG_MAIN));
|
|
MENU_ITEM_FUNCTION_NR_P(_T(MSG_CUT_FILAMENT), '1', mmu_cut_filament, 0);
|
|
MENU_ITEM_FUNCTION_NR_P(_T(MSG_CUT_FILAMENT), '2', mmu_cut_filament, 1);
|
|
MENU_ITEM_FUNCTION_NR_P(_T(MSG_CUT_FILAMENT), '3', mmu_cut_filament, 2);
|
|
MENU_ITEM_FUNCTION_NR_P(_T(MSG_CUT_FILAMENT), '4', mmu_cut_filament, 3);
|
|
MENU_ITEM_FUNCTION_NR_P(_T(MSG_CUT_FILAMENT), '5', mmu_cut_filament, 4);
|
|
MENU_END();
|
|
}
|
|
else
|
|
{
|
|
eFilamentAction=FilamentAction::MmuCut;
|
|
bFilamentFirstRun=false;
|
|
if(target_temperature[0]>=EXTRUDE_MINTEMP)
|
|
{
|
|
bFilamentPreheatState=true;
|
|
mFilamentItem(target_temperature[0],target_temperature_bed);
|
|
}
|
|
else lcd_generic_preheat_menu();
|
|
}
|
|
}
|
|
#endif //MMU_HAS_CUTTER
|
|
|
|
#ifdef SNMM
|
|
static void fil_unload_menu()
|
|
{
|
|
MENU_BEGIN();
|
|
MENU_ITEM_BACK_P(_T(MSG_MAIN));
|
|
MENU_ITEM_FUNCTION_P(_i("Unload all"), extr_unload_all);////MSG_UNLOAD_ALL c=17
|
|
MENU_ITEM_FUNCTION_P(_i("Unload filament 1"), extr_unload_0);////MSG_UNLOAD_FILAMENT_1 c=17
|
|
MENU_ITEM_FUNCTION_P(_i("Unload filament 2"), extr_unload_1);////MSG_UNLOAD_FILAMENT_2 c=17
|
|
MENU_ITEM_FUNCTION_P(_i("Unload filament 3"), extr_unload_2);////MSG_UNLOAD_FILAMENT_3 c=17
|
|
MENU_ITEM_FUNCTION_P(_i("Unload filament 4"), extr_unload_3);////MSG_UNLOAD_FILAMENT_4 c=17
|
|
|
|
if (mmu_enabled)
|
|
MENU_ITEM_FUNCTION_P(_i("Unload filament 5"), extr_unload_4);////MSG_UNLOAD_FILAMENT_5 c=17
|
|
|
|
MENU_END();
|
|
}
|
|
|
|
|
|
static void change_extr_menu(){
|
|
MENU_BEGIN();
|
|
MENU_ITEM_BACK_P(_T(MSG_MAIN));
|
|
MENU_ITEM_FUNCTION_P(_i("Extruder 1"), extr_change_0);////MSG_EXTRUDER_1 c=17 r=1
|
|
MENU_ITEM_FUNCTION_P(_i("Extruder 2"), extr_change_1);////MSG_EXTRUDER_2 c=17 r=1
|
|
MENU_ITEM_FUNCTION_P(_i("Extruder 3"), extr_change_2);////MSG_EXTRUDER_3 c=17 r=1
|
|
MENU_ITEM_FUNCTION_P(_i("Extruder 4"), extr_change_3);////MSG_EXTRUDER_4 c=17 r=1
|
|
|
|
MENU_END();
|
|
}
|
|
#endif //SNMM
|
|
|
|
//unload filament for single material printer (used in M702 gcode)
|
|
void unload_filament()
|
|
{
|
|
custom_message_type = CustomMsg::FilamentLoading;
|
|
lcd_setstatuspgm(_T(MSG_UNLOADING_FILAMENT));
|
|
|
|
raise_z_above(MIN_Z_FOR_UNLOAD);
|
|
|
|
// extr_unload2();
|
|
|
|
current_position[E_AXIS] -= 45;
|
|
plan_buffer_line_curposXYZE(5200 / 60, active_extruder);
|
|
st_synchronize();
|
|
current_position[E_AXIS] -= 15;
|
|
plan_buffer_line_curposXYZE(1000 / 60, active_extruder);
|
|
st_synchronize();
|
|
current_position[E_AXIS] -= 20;
|
|
plan_buffer_line_curposXYZE(1000 / 60, active_extruder);
|
|
st_synchronize();
|
|
|
|
lcd_display_message_fullscreen_P(_T(MSG_PULL_OUT_FILAMENT));
|
|
|
|
//disable extruder steppers so filament can be removed
|
|
disable_e0();
|
|
disable_e1();
|
|
disable_e2();
|
|
_delay(100);
|
|
|
|
Sound_MakeSound(e_SOUND_TYPE_StandardPrompt);
|
|
uint8_t counterBeep = 0;
|
|
while (!lcd_clicked() && (counterBeep < 50)) {
|
|
delay_keep_alive(100);
|
|
counterBeep++;
|
|
}
|
|
st_synchronize();
|
|
while (lcd_clicked()) delay_keep_alive(100);
|
|
|
|
lcd_update_enable(true);
|
|
|
|
lcd_setstatuspgm(_T(WELCOME_MSG));
|
|
custom_message_type = CustomMsg::Status;
|
|
|
|
}
|
|
|
|
static void lcd_farm_no()
|
|
{
|
|
char step = 0;
|
|
int enc_dif = 0;
|
|
int _farmno = farm_no;
|
|
int _ret = 0;
|
|
lcd_clear();
|
|
|
|
lcd_set_cursor(0, 0);
|
|
lcd_print("Farm no");
|
|
|
|
do
|
|
{
|
|
|
|
if (abs((enc_dif - lcd_encoder_diff)) > 2) {
|
|
if (enc_dif > lcd_encoder_diff) {
|
|
switch (step) {
|
|
case(0): if (_farmno >= 100) _farmno -= 100; break;
|
|
case(1): if (_farmno % 100 >= 10) _farmno -= 10; break;
|
|
case(2): if (_farmno % 10 >= 1) _farmno--; break;
|
|
default: break;
|
|
}
|
|
}
|
|
|
|
if (enc_dif < lcd_encoder_diff) {
|
|
switch (step) {
|
|
case(0): if (_farmno < 900) _farmno += 100; break;
|
|
case(1): if (_farmno % 100 < 90) _farmno += 10; break;
|
|
case(2): if (_farmno % 10 <= 8)_farmno++; break;
|
|
default: break;
|
|
}
|
|
}
|
|
enc_dif = 0;
|
|
lcd_encoder_diff = 0;
|
|
}
|
|
|
|
lcd_set_cursor(0, 2);
|
|
if (_farmno < 100) lcd_print("0");
|
|
if (_farmno < 10) lcd_print("0");
|
|
lcd_print(_farmno);
|
|
lcd_print(" ");
|
|
lcd_set_cursor(0, 3);
|
|
lcd_print(" ");
|
|
|
|
|
|
lcd_set_cursor(step, 3);
|
|
lcd_print("^");
|
|
_delay(100);
|
|
|
|
if (lcd_clicked())
|
|
{
|
|
_delay(200);
|
|
step++;
|
|
if(step == 3) {
|
|
_ret = 1;
|
|
farm_no = _farmno;
|
|
EEPROM_save_B(EEPROM_FARM_NUMBER, &farm_no);
|
|
prusa_statistics(20);
|
|
lcd_return_to_status();
|
|
}
|
|
}
|
|
|
|
manage_heater();
|
|
} while (_ret == 0);
|
|
|
|
}
|
|
|
|
|
|
unsigned char lcd_choose_color() {
|
|
//function returns index of currently chosen item
|
|
//following part can be modified from 2 to 255 items:
|
|
//-----------------------------------------------------
|
|
unsigned char items_no = 2;
|
|
const char *item[items_no];
|
|
item[0] = "Orange";
|
|
item[1] = "Black";
|
|
//-----------------------------------------------------
|
|
uint_least8_t active_rows;
|
|
static int first = 0;
|
|
int enc_dif = 0;
|
|
unsigned char cursor_pos = 1;
|
|
enc_dif = lcd_encoder_diff;
|
|
lcd_clear();
|
|
lcd_set_cursor(0, 1);
|
|
lcd_print(">");
|
|
|
|
active_rows = items_no < 3 ? items_no : 3;
|
|
lcd_consume_click();
|
|
while (1) {
|
|
lcd_puts_at_P(0, 0, PSTR("Choose color:"));
|
|
for (uint_least8_t i = 0; i < active_rows; i++) {
|
|
lcd_set_cursor(1, i+1);
|
|
lcd_print(item[first + i]);
|
|
}
|
|
|
|
manage_heater();
|
|
manage_inactivity(true);
|
|
proc_commands();
|
|
if (abs((enc_dif - lcd_encoder_diff)) > 12) {
|
|
|
|
if (enc_dif > lcd_encoder_diff) {
|
|
cursor_pos--;
|
|
}
|
|
|
|
if (enc_dif < lcd_encoder_diff) {
|
|
cursor_pos++;
|
|
}
|
|
|
|
if (cursor_pos > active_rows) {
|
|
cursor_pos = active_rows;
|
|
Sound_MakeSound(e_SOUND_TYPE_BlindAlert);
|
|
if (first < items_no - active_rows) {
|
|
first++;
|
|
lcd_clear();
|
|
}
|
|
}
|
|
|
|
if (cursor_pos < 1) {
|
|
cursor_pos = 1;
|
|
Sound_MakeSound(e_SOUND_TYPE_BlindAlert);
|
|
if (first > 0) {
|
|
first--;
|
|
lcd_clear();
|
|
}
|
|
}
|
|
lcd_set_cursor(0, 1);
|
|
lcd_print(" ");
|
|
lcd_set_cursor(0, 2);
|
|
lcd_print(" ");
|
|
lcd_set_cursor(0, 3);
|
|
lcd_print(" ");
|
|
lcd_set_cursor(0, cursor_pos);
|
|
lcd_print(">");
|
|
Sound_MakeSound(e_SOUND_TYPE_EncoderMove);
|
|
enc_dif = lcd_encoder_diff;
|
|
_delay(100);
|
|
|
|
}
|
|
|
|
if (lcd_clicked()) {
|
|
Sound_MakeSound(e_SOUND_TYPE_ButtonEcho);
|
|
switch(cursor_pos + first - 1) {
|
|
case 0: return 1; break;
|
|
case 1: return 0; break;
|
|
default: return 99; break;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void lcd_confirm_print()
|
|
{
|
|
uint8_t filament_type;
|
|
int enc_dif = 0;
|
|
int cursor_pos = 1;
|
|
int _ret = 0;
|
|
int _t = 0;
|
|
|
|
enc_dif = lcd_encoder_diff;
|
|
lcd_clear();
|
|
|
|
lcd_set_cursor(0, 0);
|
|
lcd_print("Print ok ?");
|
|
|
|
do
|
|
{
|
|
if (abs(enc_dif - lcd_encoder_diff) > 12) {
|
|
if (enc_dif > lcd_encoder_diff) {
|
|
cursor_pos--;
|
|
}
|
|
|
|
if (enc_dif < lcd_encoder_diff) {
|
|
cursor_pos++;
|
|
}
|
|
enc_dif = lcd_encoder_diff;
|
|
}
|
|
|
|
if (cursor_pos > 2) { cursor_pos = 2; }
|
|
if (cursor_pos < 1) { cursor_pos = 1; }
|
|
|
|
lcd_set_cursor(0, 2); lcd_print(" ");
|
|
lcd_set_cursor(0, 3); lcd_print(" ");
|
|
lcd_set_cursor(2, 2);
|
|
lcd_puts_P(_T(MSG_YES));
|
|
lcd_set_cursor(2, 3);
|
|
lcd_puts_P(_T(MSG_NO));
|
|
lcd_set_cursor(0, 1 + cursor_pos);
|
|
lcd_print(">");
|
|
_delay(100);
|
|
|
|
_t = _t + 1;
|
|
if (_t>100)
|
|
{
|
|
prusa_statistics(99);
|
|
_t = 0;
|
|
}
|
|
if (lcd_clicked())
|
|
{
|
|
filament_type = FARM_FILAMENT_COLOR_NONE;
|
|
if (cursor_pos == 1)
|
|
{
|
|
_ret = 1;
|
|
// filament_type = lcd_choose_color();
|
|
prusa_statistics(4, filament_type);
|
|
no_response = true; //we need confirmation by recieving PRUSA thx
|
|
important_status = 4;
|
|
saved_filament_type = filament_type;
|
|
NcTime = _millis();
|
|
}
|
|
if (cursor_pos == 2)
|
|
{
|
|
_ret = 2;
|
|
// filament_type = lcd_choose_color();
|
|
prusa_statistics(5, filament_type);
|
|
no_response = true; //we need confirmation by recieving PRUSA thx
|
|
important_status = 5;
|
|
saved_filament_type = filament_type;
|
|
NcTime = _millis();
|
|
}
|
|
}
|
|
|
|
manage_heater();
|
|
manage_inactivity();
|
|
proc_commands();
|
|
|
|
} while (_ret == 0);
|
|
|
|
}
|
|
|
|
#include "w25x20cl.h"
|
|
|
|
#ifdef LCD_TEST
|
|
static void lcd_test_menu()
|
|
{
|
|
W25X20CL_SPI_ENTER();
|
|
w25x20cl_enable_wr();
|
|
w25x20cl_chip_erase();
|
|
w25x20cl_disable_wr();
|
|
}
|
|
#endif //LCD_TEST
|
|
|
|
static bool fan_error_selftest()
|
|
{
|
|
#ifdef FANCHECK
|
|
|
|
fanSpeed = 255;
|
|
#ifdef FAN_SOFT_PWM
|
|
fanSpeedSoftPwm = 255;
|
|
#endif //FAN_SOFT_PWM
|
|
manage_heater(); //enables print fan
|
|
setExtruderAutoFanState(EXTRUDER_0_AUTO_FAN_PIN, 1); //force enables the extruder fan untill the first manage_heater() call.
|
|
#ifdef FAN_SOFT_PWM
|
|
extruder_autofan_last_check = _millis();
|
|
fan_measuring = true;
|
|
#endif //FAN_SOFT_PWM
|
|
_delay(1000); //delay_keep_alive would turn off extruder fan, because temerature is too low (maybe)
|
|
manage_heater();
|
|
fanSpeed = 0;
|
|
#ifdef FAN_SOFT_PWM
|
|
fanSpeedSoftPwm = 0;
|
|
#endif //FAN_SOFT_PWM
|
|
manage_heater();
|
|
#ifdef TACH_0
|
|
if (fan_speed[0] <= 20) { //extruder fan error
|
|
LCD_ALERTMESSAGERPGM(MSG_FANCHECK_EXTRUDER);
|
|
return 1;
|
|
}
|
|
#endif
|
|
#ifdef TACH_1
|
|
if (fan_speed[1] <= 20) { //print fan error
|
|
LCD_ALERTMESSAGERPGM(MSG_FANCHECK_PRINT);
|
|
return 1;
|
|
}
|
|
#endif
|
|
return 0;
|
|
|
|
#endif //FANCHECK
|
|
}
|
|
|
|
//! @brief Resume paused print
|
|
//! @todo It is not good to call restore_print_from_ram_and_continue() from function called by lcd_update(),
|
|
//! as restore_print_from_ram_and_continue() calls lcd_update() internally.
|
|
void lcd_resume_print()
|
|
{
|
|
lcd_return_to_status();
|
|
lcd_reset_alert_level();
|
|
lcd_setstatuspgm(_T(MSG_RESUMING_PRINT));
|
|
lcd_reset_alert_level(); //for fan speed error
|
|
|
|
if (fan_error_selftest()) return; //abort if error persists
|
|
|
|
restore_print_from_ram_and_continue(0.0);
|
|
pause_time += (_millis() - start_pause_print); //accumulate time when print is paused for correct statistics calculation
|
|
refresh_cmd_timeout();
|
|
isPrintPaused = false;
|
|
SERIAL_PROTOCOLLNRPGM(MSG_OCTOPRINT_RESUMED); //resume octoprint
|
|
}
|
|
|
|
static void change_sheet()
|
|
{
|
|
eeprom_update_byte(&(EEPROM_Sheets_base->active_sheet), selected_sheet);
|
|
menu_back(3);
|
|
}
|
|
|
|
|
|
|
|
static void lcd_rename_sheet_menu()
|
|
{
|
|
struct MenuData
|
|
{
|
|
bool initialized;
|
|
uint8_t selected;
|
|
char name[sizeof(Sheet::name)];
|
|
};
|
|
static_assert(sizeof(menu_data)>= sizeof(MenuData),"MenuData doesn't fit into menu_data");
|
|
MenuData* menuData = (MenuData*)&(menu_data[0]);
|
|
|
|
if (!menuData->initialized)
|
|
{
|
|
eeprom_read_block(menuData->name, EEPROM_Sheets_base->s[selected_sheet].name, sizeof(Sheet::name));
|
|
lcd_encoder = menuData->name[0];
|
|
menuData->initialized = true;
|
|
}
|
|
if (lcd_encoder < '\x20') lcd_encoder = '\x20';
|
|
if (lcd_encoder > '\x7F') lcd_encoder = '\x7F';
|
|
|
|
menuData->name[menuData->selected] = lcd_encoder;
|
|
lcd_set_cursor(0,0);
|
|
for (uint_least8_t i = 0; i < sizeof(Sheet::name); ++i)
|
|
{
|
|
lcd_putc(menuData->name[i]);
|
|
}
|
|
lcd_set_cursor(menuData->selected, 1);
|
|
lcd_putc('^');
|
|
if (lcd_clicked())
|
|
{
|
|
if ((menuData->selected + 1u) < sizeof(Sheet::name))
|
|
{
|
|
lcd_encoder = menuData->name[++(menuData->selected)];
|
|
}
|
|
else
|
|
{
|
|
eeprom_update_block(menuData->name,
|
|
EEPROM_Sheets_base->s[selected_sheet].name,
|
|
sizeof(Sheet::name));
|
|
menu_back();
|
|
}
|
|
}
|
|
}
|
|
|
|
static void lcd_reset_sheet()
|
|
{
|
|
SheetName sheetName;
|
|
eeprom_default_sheet_name(selected_sheet, sheetName);
|
|
eeprom_update_word(reinterpret_cast<uint16_t *>(&(EEPROM_Sheets_base->s[selected_sheet].z_offset)),EEPROM_EMPTY_VALUE16);
|
|
eeprom_update_block(sheetName.c,EEPROM_Sheets_base->s[selected_sheet].name,sizeof(Sheet::name));
|
|
if (selected_sheet == eeprom_read_byte(&(EEPROM_Sheets_base->active_sheet)))
|
|
{
|
|
eeprom_switch_to_next_sheet();
|
|
if((-1 == eeprom_next_initialized_sheet(0)) && (CALIBRATION_STATUS_CALIBRATED == calibration_status()))
|
|
{
|
|
calibration_status_store(CALIBRATION_STATUS_LIVE_ADJUST);
|
|
}
|
|
}
|
|
|
|
menu_back();
|
|
}
|
|
|
|
//! @brief Activate selected_sheet and run first layer calibration
|
|
static void activate_calibrate_sheet()
|
|
{
|
|
eeprom_update_byte(&(EEPROM_Sheets_base->active_sheet), selected_sheet);
|
|
lcd_first_layer_calibration_reset();
|
|
}
|
|
|
|
static void lcd_sheet_menu()
|
|
{
|
|
MENU_BEGIN();
|
|
MENU_ITEM_BACK_P(_i("Steel sheets"));
|
|
|
|
if(eeprom_is_sheet_initialized(selected_sheet)){
|
|
MENU_ITEM_SUBMENU_P(_i("Select"), change_sheet); //// c=18
|
|
}
|
|
|
|
if (lcd_commands_type == LcdCommands::Idle)
|
|
{
|
|
MENU_ITEM_SUBMENU_P(_T(MSG_V2_CALIBRATION), activate_calibrate_sheet);
|
|
}
|
|
MENU_ITEM_SUBMENU_P(_i("Rename"), lcd_rename_sheet_menu); //// c=18
|
|
MENU_ITEM_FUNCTION_P(_i("Reset"), lcd_reset_sheet); //// c=18
|
|
|
|
MENU_END();
|
|
}
|
|
|
|
static void lcd_main_menu()
|
|
{
|
|
|
|
MENU_BEGIN();
|
|
|
|
// Majkl superawesome menu
|
|
|
|
|
|
MENU_ITEM_BACK_P(_T(MSG_WATCH));
|
|
|
|
#ifdef RESUME_DEBUG
|
|
if (!saved_printing)
|
|
MENU_ITEM_FUNCTION_P(PSTR("tst - Save"), lcd_menu_test_save);
|
|
else
|
|
MENU_ITEM_FUNCTION_P(PSTR("tst - Restore"), lcd_menu_test_restore);
|
|
#endif //RESUME_DEBUG
|
|
|
|
#ifdef TMC2130_DEBUG
|
|
MENU_ITEM_FUNCTION_P(PSTR("recover print"), recover_print);
|
|
MENU_ITEM_FUNCTION_P(PSTR("power panic"), uvlo_);
|
|
#endif //TMC2130_DEBUG
|
|
|
|
if ( ( IS_SD_PRINTING || is_usb_printing || (lcd_commands_type == LcdCommands::Layer1Cal)) && (current_position[Z_AXIS] < Z_HEIGHT_HIDE_LIVE_ADJUST_MENU) && !homing_flag && !mesh_bed_leveling_flag)
|
|
{
|
|
MENU_ITEM_SUBMENU_P(_T(MSG_BABYSTEP_Z), lcd_babystep_z);//8
|
|
}
|
|
|
|
|
|
if ( moves_planned() || IS_SD_PRINTING || is_usb_printing || (lcd_commands_type == LcdCommands::Layer1Cal))
|
|
{
|
|
MENU_ITEM_SUBMENU_P(_i("Tune"), lcd_tune_menu);////MSG_TUNE
|
|
} else
|
|
{
|
|
MENU_ITEM_SUBMENU_P(_i("Preheat"), lcd_preheat_menu);////MSG_PREHEAT
|
|
}
|
|
|
|
|
|
#ifdef FANCHECK
|
|
if((fan_check_error == EFCE_FIXED) && (saved_printing_type == PRINTING_TYPE_USB))
|
|
MENU_ITEM_SUBMENU_P(_i("Resume print"), lcd_resume_print);////MSG_RESUME_PRINT
|
|
#endif
|
|
|
|
#ifdef SDSUPPORT
|
|
if (card.cardOK || lcd_commands_type == LcdCommands::Layer1Cal)
|
|
{
|
|
if (card.isFileOpen())
|
|
{
|
|
if (mesh_bed_leveling_flag == false && homing_flag == false) {
|
|
if (card.sdprinting)
|
|
{
|
|
MENU_ITEM_FUNCTION_P(_i("Pause print"), lcd_pause_print);////MSG_PAUSE_PRINT
|
|
}
|
|
else
|
|
{
|
|
#ifdef FANCHECK
|
|
if((fan_check_error == EFCE_FIXED) || (fan_check_error == EFCE_OK))
|
|
MENU_ITEM_SUBMENU_P(_i("Resume print"), lcd_resume_print);////MSG_RESUME_PRINT
|
|
#else
|
|
MENU_ITEM_SUBMENU_P(_i("Resume print"), lcd_resume_print);////MSG_RESUME_PRINT
|
|
#endif
|
|
|
|
}
|
|
MENU_ITEM_SUBMENU_P(_T(MSG_STOP_PRINT), lcd_sdcard_stop);
|
|
}
|
|
}
|
|
else if (lcd_commands_type == LcdCommands::Layer1Cal && mesh_bed_leveling_flag == false && homing_flag == false) {
|
|
//MENU_ITEM_SUBMENU_P(_T(MSG_STOP_PRINT), lcd_sdcard_stop);
|
|
}
|
|
else
|
|
{
|
|
if (!is_usb_printing && (lcd_commands_type != LcdCommands::Layer1Cal))
|
|
{
|
|
//if (farm_mode) MENU_ITEM_SUBMENU_P(MSG_FARM_CARD_MENU, lcd_farm_sdcard_menu);
|
|
/*else*/ {
|
|
bMain=true; // flag ('fake parameter') for 'lcd_sdcard_menu()' function
|
|
MENU_ITEM_SUBMENU_P(_T(MSG_CARD_MENU), lcd_sdcard_menu);
|
|
}
|
|
}
|
|
#if SDCARDDETECT < 1
|
|
MENU_ITEM_GCODE_P(_i("Change SD card"), PSTR("M21")); // SD-card changed by user////MSG_CNG_SDCARD
|
|
#endif
|
|
}
|
|
|
|
} else
|
|
{
|
|
bMain=true; // flag (i.e. 'fake parameter') for 'lcd_sdcard_menu()' function
|
|
MENU_ITEM_SUBMENU_P(_i("No SD card"), lcd_sdcard_menu);////MSG_NO_CARD
|
|
#if SDCARDDETECT < 1
|
|
MENU_ITEM_GCODE_P(_i("Init. SD card"), PSTR("M21")); // Manually initialize the SD-card via user interface////MSG_INIT_SDCARD
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
if(!isPrintPaused && !IS_SD_PRINTING && !is_usb_printing && (lcd_commands_type != LcdCommands::Layer1Cal))
|
|
{
|
|
if (!farm_mode)
|
|
{
|
|
const int8_t sheet = eeprom_read_byte(&(EEPROM_Sheets_base->active_sheet));
|
|
const int8_t nextSheet = eeprom_next_initialized_sheet(sheet);
|
|
if ((nextSheet >= 0) && (sheet != nextSheet)) // show menu only if we have 2 or more sheets initialized
|
|
{
|
|
MENU_ITEM_FUNCTION_E(EEPROM_Sheets_base->s[sheet], eeprom_switch_to_next_sheet);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (IS_SD_PRINTING || is_usb_printing || (lcd_commands_type == LcdCommands::Layer1Cal))
|
|
{
|
|
if (farm_mode)
|
|
{
|
|
MENU_ITEM_SUBMENU_P(PSTR("Farm number"), lcd_farm_no);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (mmu_enabled)
|
|
{
|
|
MENU_ITEM_SUBMENU_P(_T(MSG_LOAD_FILAMENT), fil_load_menu);
|
|
MENU_ITEM_SUBMENU_P(_i("Load to nozzle"), mmu_load_to_nozzle_menu);
|
|
//-// MENU_ITEM_FUNCTION_P(_T(MSG_UNLOAD_FILAMENT), extr_unload);
|
|
//bFilamentFirstRun=true;
|
|
MENU_ITEM_SUBMENU_P(_T(MSG_UNLOAD_FILAMENT), mmu_unload_filament);
|
|
MENU_ITEM_SUBMENU_P(_i("Eject filament"), mmu_fil_eject_menu);
|
|
#ifdef MMU_HAS_CUTTER
|
|
MENU_ITEM_SUBMENU_P(_i("Cut filament"), mmu_cut_filament_menu);
|
|
#endif //MMU_HAS_CUTTER
|
|
}
|
|
else
|
|
{
|
|
#ifdef SNMM
|
|
MENU_ITEM_SUBMENU_P(_T(MSG_UNLOAD_FILAMENT), fil_unload_menu);
|
|
MENU_ITEM_SUBMENU_P(_i("Change extruder"), change_extr_menu);////MSG_CHANGE_EXTR c=20 r=1
|
|
#endif
|
|
#ifdef FILAMENT_SENSOR
|
|
if ((fsensor_autoload_enabled == true) && (fsensor_enabled == true) && (mmu_enabled == false))
|
|
MENU_ITEM_SUBMENU_P(_i("AutoLoad filament"), lcd_menu_AutoLoadFilament);////MSG_AUTOLOAD_FILAMENT c=17
|
|
else
|
|
#endif //FILAMENT_SENSOR
|
|
{
|
|
bFilamentFirstRun=true;
|
|
MENU_ITEM_SUBMENU_P(_T(MSG_LOAD_FILAMENT), lcd_LoadFilament);
|
|
}
|
|
bFilamentFirstRun=true;
|
|
MENU_ITEM_SUBMENU_P(_T(MSG_UNLOAD_FILAMENT), lcd_unLoadFilament);
|
|
}
|
|
MENU_ITEM_SUBMENU_P(_T(MSG_SETTINGS), lcd_settings_menu);
|
|
if(!isPrintPaused) MENU_ITEM_SUBMENU_P(_T(MSG_MENU_CALIBRATION), lcd_calibration_menu);
|
|
|
|
}
|
|
|
|
if (!is_usb_printing && (lcd_commands_type != LcdCommands::Layer1Cal))
|
|
{
|
|
MENU_ITEM_SUBMENU_P(_i("Statistics "), lcd_menu_statistics);////MSG_STATISTICS
|
|
}
|
|
|
|
#if defined(TMC2130) || defined(FILAMENT_SENSOR)
|
|
MENU_ITEM_SUBMENU_P(_i("Fail stats"), lcd_menu_fails_stats);
|
|
#endif
|
|
if (mmu_enabled) {
|
|
MENU_ITEM_SUBMENU_P(_i("Fail stats MMU"), lcd_menu_fails_stats_mmu);
|
|
}
|
|
MENU_ITEM_SUBMENU_P(_i("Support"), lcd_support_menu);////MSG_SUPPORT
|
|
#ifdef LCD_TEST
|
|
MENU_ITEM_SUBMENU_P(_i("W25x20CL init"), lcd_test_menu);////MSG_SUPPORT
|
|
#endif //LCD_TEST
|
|
|
|
MENU_END();
|
|
|
|
}
|
|
|
|
void stack_error() {
|
|
Sound_MakeCustom(1000,0,true);
|
|
lcd_display_message_fullscreen_P(_i("Error - static memory has been overwritten"));////MSG_STACK_ERROR c=20 r=4
|
|
//err_triggered = 1;
|
|
while (1) delay_keep_alive(1000);
|
|
}
|
|
|
|
#ifdef DEBUG_STEPPER_TIMER_MISSED
|
|
bool stepper_timer_overflow_state = false;
|
|
uint16_t stepper_timer_overflow_max = 0;
|
|
uint16_t stepper_timer_overflow_last = 0;
|
|
uint16_t stepper_timer_overflow_cnt = 0;
|
|
void stepper_timer_overflow() {
|
|
char msg[28];
|
|
sprintf_P(msg, PSTR("#%d %d max %d"), ++ stepper_timer_overflow_cnt, stepper_timer_overflow_last >> 1, stepper_timer_overflow_max >> 1);
|
|
lcd_setstatus(msg);
|
|
stepper_timer_overflow_state = false;
|
|
if (stepper_timer_overflow_last > stepper_timer_overflow_max)
|
|
stepper_timer_overflow_max = stepper_timer_overflow_last;
|
|
SERIAL_ECHOPGM("Stepper timer overflow: ");
|
|
MYSERIAL.print(msg);
|
|
SERIAL_ECHOLNPGM("");
|
|
|
|
WRITE(BEEPER, LOW);
|
|
}
|
|
#endif /* DEBUG_STEPPER_TIMER_MISSED */
|
|
|
|
|
|
static void lcd_colorprint_change() {
|
|
|
|
enquecommand_P(PSTR("M600"));
|
|
|
|
custom_message_type = CustomMsg::FilamentLoading; //just print status message
|
|
lcd_setstatuspgm(_T(MSG_FINISHING_MOVEMENTS));
|
|
lcd_return_to_status();
|
|
lcd_draw_update = 3;
|
|
}
|
|
|
|
static void lcd_tune_menu()
|
|
{
|
|
typedef struct
|
|
{
|
|
menu_data_edit_t reserved; //!< reserved for number editing functions
|
|
int8_t status; //!< To recognize, whether the menu has been just initialized.
|
|
//! Backup of extrudemultiply, to recognize, that the value has been changed and
|
|
//! it needs to be applied.
|
|
int16_t extrudemultiply;
|
|
} _menu_data_t;
|
|
static_assert(sizeof(menu_data)>= sizeof(_menu_data_t),"_menu_data_t doesn't fit into menu_data");
|
|
_menu_data_t* _md = (_menu_data_t*)&(menu_data[0]);
|
|
if (_md->status == 0)
|
|
{
|
|
// Menu was entered. Mark the menu as entered and save the current extrudemultiply value.
|
|
_md->status = 1;
|
|
_md->extrudemultiply = extrudemultiply;
|
|
}
|
|
else if (_md->extrudemultiply != extrudemultiply)
|
|
{
|
|
// extrudemultiply has been changed from the child menu. Apply the new value.
|
|
_md->extrudemultiply = extrudemultiply;
|
|
calculate_extruder_multipliers();
|
|
}
|
|
|
|
EEPROM_read(EEPROM_SILENT, (uint8_t*)&SilentModeMenu, sizeof(SilentModeMenu));
|
|
|
|
|
|
|
|
MENU_BEGIN();
|
|
MENU_ITEM_BACK_P(_T(MSG_MAIN)); //1
|
|
MENU_ITEM_EDIT_int3_P(_i("Speed"), &feedmultiply, 10, 999);//2////MSG_SPEED
|
|
|
|
MENU_ITEM_EDIT_int3_P(_T(MSG_NOZZLE), &target_temperature[0], 0, HEATER_0_MAXTEMP - 10);//3
|
|
MENU_ITEM_EDIT_int3_P(_T(MSG_BED), &target_temperature_bed, 0, BED_MAXTEMP - 10);//4
|
|
|
|
MENU_ITEM_EDIT_int3_P(_T(MSG_FAN_SPEED), &fanSpeed, 0, 255);//5
|
|
MENU_ITEM_EDIT_int3_P(_i("Flow"), &extrudemultiply, 10, 999);//6////MSG_FLOW
|
|
#ifdef FILAMENTCHANGEENABLE
|
|
MENU_ITEM_FUNCTION_P(_T(MSG_FILAMENTCHANGE), lcd_colorprint_change);//7
|
|
#endif
|
|
|
|
#ifdef FILAMENT_SENSOR
|
|
if (FSensorStateMenu == 0) {
|
|
if (fsensor_not_responding && (mmu_enabled == false)) {
|
|
/* Filament sensor not working*/
|
|
MENU_ITEM_TOGGLE_P(_T(MSG_FSENSOR), _T(MSG_NA), lcd_fsensor_state_set);
|
|
}
|
|
else {
|
|
/* Filament sensor turned off, working, no problems*/
|
|
MENU_ITEM_TOGGLE_P(_T(MSG_FSENSOR), _T(MSG_OFF), lcd_fsensor_state_set);
|
|
}
|
|
}
|
|
else {
|
|
MENU_ITEM_TOGGLE_P(_T(MSG_FSENSOR), _T(MSG_ON), lcd_fsensor_state_set);
|
|
}
|
|
#if IR_SENSOR_ANALOG
|
|
FSENSOR_ACTION_NA;
|
|
#endif //IR_SENSOR_ANALOG
|
|
#endif //FILAMENT_SENSOR
|
|
|
|
SETTINGS_AUTO_DEPLETE;
|
|
|
|
SETTINGS_CUTTER;
|
|
|
|
if(farm_mode)
|
|
{
|
|
MENU_ITEM_TOGGLE_P(_i("Fans check"), fans_check_enabled ? _T(MSG_ON) : _T(MSG_OFF), lcd_set_fan_check);
|
|
}
|
|
|
|
#ifdef TMC2130
|
|
if(!farm_mode)
|
|
{
|
|
if (SilentModeMenu == SILENT_MODE_NORMAL) MENU_ITEM_TOGGLE_P(_T(MSG_MODE), _T(MSG_NORMAL), lcd_silent_mode_set);
|
|
else MENU_ITEM_TOGGLE_P(_T(MSG_MODE), _T(MSG_STEALTH), lcd_silent_mode_set);
|
|
|
|
if (SilentModeMenu == SILENT_MODE_NORMAL)
|
|
{
|
|
if (lcd_crash_detect_enabled()) MENU_ITEM_TOGGLE_P(_T(MSG_CRASHDETECT), _T(MSG_ON), crash_mode_switch);
|
|
else MENU_ITEM_TOGGLE_P(_T(MSG_CRASHDETECT), _T(MSG_OFF), crash_mode_switch);
|
|
}
|
|
else MENU_ITEM_TOGGLE_P(_T(MSG_CRASHDETECT), NULL, lcd_crash_mode_info);
|
|
}
|
|
#else //TMC2130
|
|
if (!farm_mode) { //dont show in menu if we are in farm mode
|
|
switch (SilentModeMenu) {
|
|
case SILENT_MODE_POWER: MENU_ITEM_TOGGLE_P(_T(MSG_MODE), _T(MSG_HIGH_POWER), lcd_silent_mode_set); break;
|
|
case SILENT_MODE_SILENT: MENU_ITEM_TOGGLE_P(_T(MSG_MODE), _T(MSG_SILENT), lcd_silent_mode_set); break;
|
|
case SILENT_MODE_AUTO: MENU_ITEM_TOGGLE_P(_T(MSG_MODE), _T(MSG_AUTO_POWER), lcd_silent_mode_set); break;
|
|
default: MENU_ITEM_TOGGLE_P(_T(MSG_MODE), _T(MSG_HIGH_POWER), lcd_silent_mode_set); break; // (probably) not needed
|
|
}
|
|
}
|
|
#endif //TMC2130
|
|
SETTINGS_MMU_MODE;
|
|
SETTINGS_SOUND;
|
|
MENU_END();
|
|
}
|
|
|
|
static void mbl_magnets_elimination_toggle() {
|
|
bool magnet_elimination = (eeprom_read_byte((uint8_t*)EEPROM_MBL_MAGNET_ELIMINATION) > 0);
|
|
magnet_elimination = !magnet_elimination;
|
|
eeprom_update_byte((uint8_t*)EEPROM_MBL_MAGNET_ELIMINATION, (uint8_t)magnet_elimination);
|
|
}
|
|
|
|
static void mbl_mesh_toggle() {
|
|
uint8_t mesh_nr = eeprom_read_byte((uint8_t*)EEPROM_MBL_POINTS_NR);
|
|
if(mesh_nr == 3) mesh_nr = 7;
|
|
else mesh_nr = 3;
|
|
eeprom_update_byte((uint8_t*)EEPROM_MBL_POINTS_NR, mesh_nr);
|
|
}
|
|
|
|
static void mbl_probe_nr_toggle() {
|
|
mbl_z_probe_nr = eeprom_read_byte((uint8_t*)EEPROM_MBL_PROBE_NR);
|
|
switch (mbl_z_probe_nr) {
|
|
case 1: mbl_z_probe_nr = 3; break;
|
|
case 3: mbl_z_probe_nr = 5; break;
|
|
case 5: mbl_z_probe_nr = 1; break;
|
|
default: mbl_z_probe_nr = 3; break;
|
|
}
|
|
eeprom_update_byte((uint8_t*)EEPROM_MBL_PROBE_NR, mbl_z_probe_nr);
|
|
}
|
|
|
|
static void lcd_mesh_bed_leveling_settings()
|
|
{
|
|
|
|
bool magnet_elimination = (eeprom_read_byte((uint8_t*)EEPROM_MBL_MAGNET_ELIMINATION) > 0);
|
|
uint8_t points_nr = eeprom_read_byte((uint8_t*)EEPROM_MBL_POINTS_NR);
|
|
char sToggle[4]; //enough for nxn format
|
|
|
|
MENU_BEGIN();
|
|
MENU_ITEM_BACK_P(_T(MSG_SETTINGS));
|
|
sToggle[0] = points_nr + '0';
|
|
sToggle[1] = 'x';
|
|
sToggle[2] = points_nr + '0';
|
|
sToggle[3] = 0;
|
|
MENU_ITEM_TOGGLE(_T(MSG_MESH), sToggle, mbl_mesh_toggle);
|
|
sToggle[0] = mbl_z_probe_nr + '0';
|
|
sToggle[1] = 0;
|
|
MENU_ITEM_TOGGLE(_T(MSG_Z_PROBE_NR), sToggle, mbl_probe_nr_toggle);
|
|
MENU_ITEM_TOGGLE_P(_T(MSG_MAGNETS_COMP), (points_nr == 7) ? (magnet_elimination ? _T(MSG_ON): _T(MSG_OFF)) : _T(MSG_NA), mbl_magnets_elimination_toggle);
|
|
MENU_END();
|
|
//SETTINGS_MBL_MODE;
|
|
}
|
|
|
|
static void lcd_control_temperature_menu()
|
|
{
|
|
#ifdef PIDTEMP
|
|
// set up temp variables - undo the default scaling
|
|
// raw_Ki = unscalePID_i(Ki);
|
|
// raw_Kd = unscalePID_d(Kd);
|
|
#endif
|
|
|
|
MENU_BEGIN();
|
|
MENU_ITEM_BACK_P(_T(MSG_SETTINGS));
|
|
#if TEMP_SENSOR_0 != 0
|
|
MENU_ITEM_EDIT_int3_P(_T(MSG_NOZZLE), &target_temperature[0], 0, HEATER_0_MAXTEMP - 10);
|
|
#endif
|
|
#if TEMP_SENSOR_1 != 0
|
|
MENU_ITEM_EDIT_int3_P(_i("Nozzle2"), &target_temperature[1], 0, HEATER_1_MAXTEMP - 10);////MSG_NOZZLE1
|
|
#endif
|
|
#if TEMP_SENSOR_2 != 0
|
|
MENU_ITEM_EDIT_int3_P(_i("Nozzle3"), &target_temperature[2], 0, HEATER_2_MAXTEMP - 10);////MSG_NOZZLE2
|
|
#endif
|
|
#if TEMP_SENSOR_BED != 0
|
|
MENU_ITEM_EDIT_int3_P(_T(MSG_BED), &target_temperature_bed, 0, BED_MAXTEMP - 3);
|
|
#endif
|
|
MENU_ITEM_EDIT_int3_P(_T(MSG_FAN_SPEED), &fanSpeed, 0, 255);
|
|
#if defined AUTOTEMP && (TEMP_SENSOR_0 != 0)
|
|
//MENU_ITEM_EDIT removed, following code must be redesigned if AUTOTEMP enabled
|
|
MENU_ITEM_EDIT(bool, MSG_AUTOTEMP, &autotemp_enabled);
|
|
MENU_ITEM_EDIT(float3, _i(" \002 Min"), &autotemp_min, 0, HEATER_0_MAXTEMP - 10);////MSG_MIN
|
|
MENU_ITEM_EDIT(float3, _i(" \002 Max"), &autotemp_max, 0, HEATER_0_MAXTEMP - 10);////MSG_MAX
|
|
MENU_ITEM_EDIT(float32, _i(" \002 Fact"), &autotemp_factor, 0.0, 1.0);////MSG_FACTOR
|
|
#endif
|
|
|
|
MENU_END();
|
|
}
|
|
|
|
|
|
#if SDCARDDETECT == -1
|
|
static void lcd_sd_refresh()
|
|
{
|
|
card.initsd();
|
|
menu_top = 0;
|
|
}
|
|
#endif
|
|
static void lcd_sd_updir()
|
|
{
|
|
card.updir();
|
|
menu_top = 0;
|
|
}
|
|
|
|
void lcd_print_stop()
|
|
{
|
|
//-//
|
|
if(!card.sdprinting)
|
|
{
|
|
SERIAL_ECHOLNRPGM(MSG_OCTOPRINT_CANCEL); // for Octoprint
|
|
}
|
|
saved_printing = false;
|
|
saved_printing_type = PRINTING_TYPE_NONE;
|
|
cancel_heatup = true;
|
|
#ifdef MESH_BED_LEVELING
|
|
mbl.active = false;
|
|
#endif
|
|
// Stop the stoppers, update the position from the stoppers.
|
|
if (mesh_bed_leveling_flag == false && homing_flag == false)
|
|
{
|
|
planner_abort_hard();
|
|
// Because the planner_abort_hard() initialized current_position[Z] from the stepper,
|
|
// Z baystep is no more applied. Reset it.
|
|
babystep_reset();
|
|
}
|
|
// Clean the input command queue.
|
|
cmdqueue_reset();
|
|
lcd_setstatuspgm(_T(MSG_PRINT_ABORTED));
|
|
card.sdprinting = false;
|
|
card.closefile();
|
|
stoptime = _millis();
|
|
unsigned long t = (stoptime - starttime - pause_time) / 1000; //time in s
|
|
pause_time = 0;
|
|
save_statistics(total_filament_used, t);
|
|
lcd_return_to_status();
|
|
lcd_ignore_click(true);
|
|
lcd_commands_step = 0;
|
|
lcd_commands_type = LcdCommands::StopPrint;
|
|
// Turn off the print fan
|
|
SET_OUTPUT(FAN_PIN);
|
|
WRITE(FAN_PIN, 0);
|
|
fanSpeed = 0;
|
|
}
|
|
|
|
void lcd_sdcard_stop()
|
|
{
|
|
|
|
lcd_set_cursor(0, 0);
|
|
lcd_puts_P(_T(MSG_STOP_PRINT));
|
|
lcd_set_cursor(2, 2);
|
|
lcd_puts_P(_T(MSG_NO));
|
|
lcd_set_cursor(2, 3);
|
|
lcd_puts_P(_T(MSG_YES));
|
|
lcd_set_cursor(0, 2); lcd_print(" ");
|
|
lcd_set_cursor(0, 3); lcd_print(" ");
|
|
|
|
if ((int32_t)lcd_encoder > 2) { lcd_encoder = 2; }
|
|
if ((int32_t)lcd_encoder < 1) { lcd_encoder = 1; }
|
|
|
|
lcd_set_cursor(0, 1 + lcd_encoder);
|
|
lcd_print(">");
|
|
|
|
if (lcd_clicked())
|
|
{
|
|
Sound_MakeSound(e_SOUND_TYPE_ButtonEcho);
|
|
if ((int32_t)lcd_encoder == 1)
|
|
{
|
|
lcd_return_to_status();
|
|
}
|
|
if ((int32_t)lcd_encoder == 2)
|
|
{
|
|
lcd_print_stop();
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
void lcd_sdcard_menu()
|
|
{
|
|
uint8_t sdSort = eeprom_read_byte((uint8_t*)EEPROM_SD_SORT);
|
|
|
|
if (presort_flag == true) {
|
|
presort_flag = false;
|
|
card.presort();
|
|
}
|
|
if (lcd_draw_update == 0 && LCD_CLICKED == 0)
|
|
//_delay(100);
|
|
return; // nothing to do (so don't thrash the SD card)
|
|
uint16_t fileCnt = card.getnrfilenames();
|
|
|
|
|
|
MENU_BEGIN();
|
|
MENU_ITEM_BACK_P(_T(bMain?MSG_MAIN:MSG_BACK)); // i.e. default menu-item / menu-item after card insertion
|
|
card.getWorkDirName();
|
|
if (card.filename[0] == '/')
|
|
{
|
|
#if SDCARDDETECT == -1
|
|
MENU_ITEM_FUNCTION_P(_T(MSG_REFRESH), lcd_sd_refresh);
|
|
#endif
|
|
} else {
|
|
MENU_ITEM_FUNCTION_P(PSTR(LCD_STR_FOLDER ".."), lcd_sd_updir);
|
|
}
|
|
|
|
for (uint16_t i = 0; i < fileCnt; i++)
|
|
{
|
|
if (menu_item == menu_line)
|
|
{
|
|
const uint16_t nr = ((sdSort == SD_SORT_NONE) || farm_mode || (sdSort == SD_SORT_TIME)) ? (fileCnt - 1 - i) : i;
|
|
/*#ifdef SDCARD_RATHERRECENTFIRST
|
|
#ifndef SDCARD_SORT_ALPHA
|
|
fileCnt - 1 -
|
|
#endif
|
|
#endif
|
|
i;*/
|
|
#ifdef SDCARD_SORT_ALPHA
|
|
if (sdSort == SD_SORT_NONE) card.getfilename(nr);
|
|
else card.getfilename_sorted(nr);
|
|
#else
|
|
card.getfilename(nr);
|
|
#endif
|
|
|
|
if (card.filenameIsDir)
|
|
MENU_ITEM_SDDIR(card.filename, card.longFilename);
|
|
else
|
|
MENU_ITEM_SDFILE(_T(MSG_CARD_MENU), card.filename, card.longFilename);
|
|
} else {
|
|
MENU_ITEM_DUMMY();
|
|
}
|
|
}
|
|
MENU_END();
|
|
}
|
|
#ifdef TMC2130
|
|
static void lcd_belttest_v()
|
|
{
|
|
lcd_belttest();
|
|
menu_back_if_clicked();
|
|
}
|
|
void lcd_belttest_print(const char* msg, uint16_t X, uint16_t Y)
|
|
{
|
|
lcd_clear();
|
|
lcd_printf_P(
|
|
_N(
|
|
"%S:\n"
|
|
"%S\n"
|
|
"X:%d\n"
|
|
"Y:%d"
|
|
),
|
|
_i("Belt status"),
|
|
msg,
|
|
X,Y
|
|
);
|
|
}
|
|
void lcd_belttest()
|
|
{
|
|
int _progress = 0;
|
|
bool _result = true;
|
|
uint16_t X = eeprom_read_word((uint16_t*)(EEPROM_BELTSTATUS_X));
|
|
uint16_t Y = eeprom_read_word((uint16_t*)(EEPROM_BELTSTATUS_Y));
|
|
lcd_belttest_print(_i("Checking X..."), X, Y);
|
|
|
|
_delay(2000);
|
|
KEEPALIVE_STATE(IN_HANDLER);
|
|
|
|
_result = lcd_selfcheck_axis_sg(X_AXIS);
|
|
X = eeprom_read_word((uint16_t*)(EEPROM_BELTSTATUS_X));
|
|
if (!_result){
|
|
lcd_belttest_print(_i("Error"), X, Y);
|
|
return;
|
|
}
|
|
|
|
lcd_belttest_print(_i("Checking Y..."), X, Y);
|
|
_result = lcd_selfcheck_axis_sg(Y_AXIS);
|
|
Y = eeprom_read_word((uint16_t*)(EEPROM_BELTSTATUS_Y));
|
|
|
|
if (!_result){
|
|
lcd_belttest_print(_i("Error"), X, Y);
|
|
lcd_clear();
|
|
return;
|
|
}
|
|
|
|
|
|
lcd_belttest_print(_i("Done"), X, Y);
|
|
|
|
KEEPALIVE_STATE(NOT_BUSY);
|
|
_delay(3000);
|
|
}
|
|
#endif //TMC2130
|
|
|
|
#if IR_SENSOR_ANALOG
|
|
static bool lcd_selftest_IRsensor()
|
|
{
|
|
bool bAction;
|
|
bool bPCBrev03b;
|
|
uint16_t volt_IR_int;
|
|
float volt_IR;
|
|
|
|
volt_IR_int=current_voltage_raw_IR;
|
|
bPCBrev03b=(volt_IR_int<((int)IRsensor_Hopen_TRESHOLD));
|
|
volt_IR=VOLT_DIV_REF*((float)volt_IR_int/(1023*OVERSAMPLENR));
|
|
printf_P(PSTR("Measured filament sensor high level: %4.2fV\n"),volt_IR);
|
|
if(volt_IR_int<((int)IRsensor_Hmin_TRESHOLD))
|
|
{
|
|
lcd_selftest_error(TestError::FsensorLevel,"HIGH","");
|
|
return(false);
|
|
}
|
|
lcd_show_fullscreen_message_and_wait_P(_i("Please insert filament (but not load them!) into extruder and then press the knob."));
|
|
volt_IR_int=current_voltage_raw_IR;
|
|
volt_IR=VOLT_DIV_REF*((float)volt_IR_int/(1023*OVERSAMPLENR));
|
|
printf_P(PSTR("Measured filament sensor low level: %4.2fV\n"),volt_IR);
|
|
if(volt_IR_int>((int)IRsensor_Lmax_TRESHOLD))
|
|
{
|
|
lcd_selftest_error(TestError::FsensorLevel,"LOW","");
|
|
return(false);
|
|
}
|
|
if((bPCBrev03b?1:0)!=(uint8_t)oFsensorPCB) // safer then "(uint8_t)bPCBrev03b"
|
|
{
|
|
printf_P(PSTR("Filament sensor board change detected: revision %S\n"),bPCBrev03b?PSTR("03b or newer"):PSTR("03 or older"));
|
|
oFsensorPCB=bPCBrev03b?ClFsensorPCB::_Rev03b:ClFsensorPCB::_Old;
|
|
eeprom_update_byte((uint8_t*)EEPROM_FSENSOR_PCB,(uint8_t)oFsensorPCB);
|
|
}
|
|
return(true);
|
|
}
|
|
#endif //IR_SENSOR_ANALOG
|
|
|
|
static void lcd_selftest_v()
|
|
{
|
|
(void)lcd_selftest();
|
|
}
|
|
|
|
bool lcd_selftest()
|
|
{
|
|
int _progress = 0;
|
|
bool _result = true;
|
|
bool _swapped_fan = false;
|
|
lcd_wait_for_cool_down();
|
|
lcd_clear();
|
|
lcd_set_cursor(0, 0); lcd_puts_P(_i("Self test start "));////MSG_SELFTEST_START c=20
|
|
#ifdef TMC2130
|
|
FORCE_HIGH_POWER_START;
|
|
#endif // TMC2130
|
|
#if !IR_SENSOR_ANALOG
|
|
_delay(2000);
|
|
#endif //!IR_SENSOR_ANALOG
|
|
KEEPALIVE_STATE(IN_HANDLER);
|
|
#if IR_SENSOR_ANALOG
|
|
bool bAction;
|
|
bAction=lcd_show_fullscreen_message_yes_no_and_wait_P(_i("Is filament unloaded?"),false,true);
|
|
if(!bAction)
|
|
return(false);
|
|
#endif //IR_SENSOR_ANALOG
|
|
|
|
_progress = lcd_selftest_screen(TestScreen::ExtruderFan, _progress, 3, true, 2000);
|
|
#if (defined(FANCHECK) && defined(TACH_0))
|
|
switch (lcd_selftest_fan_auto(0)){ // check extruder Fan
|
|
case FanCheck::ExtruderFan:
|
|
_result = false;
|
|
break;
|
|
case FanCheck::SwappedFan:
|
|
_swapped_fan = true;
|
|
// no break
|
|
default:
|
|
_result = true;
|
|
break;
|
|
}
|
|
#else //defined(TACH_0)
|
|
_result = lcd_selftest_manual_fan_check(0, false);
|
|
#endif //defined(TACH_0)
|
|
if (!_result)
|
|
{
|
|
lcd_selftest_error(TestError::ExtruderFan, "", "");
|
|
}
|
|
|
|
if (_result)
|
|
{
|
|
_progress = lcd_selftest_screen(TestScreen::PrintFan, _progress, 3, true, 2000);
|
|
#if (defined(FANCHECK) && defined(TACH_1))
|
|
switch (lcd_selftest_fan_auto(1)){ // check print fan
|
|
case FanCheck::PrintFan:
|
|
_result = false;
|
|
break;
|
|
case FanCheck::SwappedFan:
|
|
_swapped_fan = true;
|
|
// no break
|
|
default:
|
|
_result = true;
|
|
break;
|
|
}
|
|
#else //defined(TACH_1)
|
|
_result = lcd_selftest_manual_fan_check(1, false);
|
|
#endif //defined(TACH_1)
|
|
if (!_result)
|
|
{
|
|
lcd_selftest_error(TestError::PrintFan, "", ""); //print fan not spinning
|
|
}
|
|
}
|
|
|
|
if (_swapped_fan) {
|
|
//turn on print fan and check that left extruder fan is not spinning
|
|
_result = lcd_selftest_manual_fan_check(1, true);
|
|
if (_result) {
|
|
//print fan is stil turned on; check that it is spinning
|
|
_result = lcd_selftest_manual_fan_check(1, false, true);
|
|
if (!_result){
|
|
lcd_selftest_error(TestError::PrintFan, "", "");
|
|
}
|
|
}
|
|
else {
|
|
// fans are swapped
|
|
lcd_selftest_error(TestError::SwappedFan, "", "");
|
|
}
|
|
}
|
|
|
|
if (_result)
|
|
{
|
|
_progress = lcd_selftest_screen(TestScreen::FansOk, _progress, 3, true, 2000);
|
|
#ifndef TMC2130
|
|
_result = lcd_selfcheck_endstops();
|
|
#else
|
|
_result = true;
|
|
#endif
|
|
}
|
|
|
|
if (_result)
|
|
{
|
|
//current_position[Z_AXIS] += 15; //move Z axis higher to avoid false triggering of Z end stop in case that we are very low - just above heatbed
|
|
_progress = lcd_selftest_screen(TestScreen::AxisX, _progress, 3, true, 2000);
|
|
#ifdef TMC2130
|
|
_result = lcd_selfcheck_axis_sg(X_AXIS);
|
|
#else
|
|
_result = lcd_selfcheck_axis(X_AXIS, X_MAX_POS);
|
|
#endif //TMC2130
|
|
}
|
|
|
|
|
|
|
|
|
|
if (_result)
|
|
{
|
|
_progress = lcd_selftest_screen(TestScreen::AxisX, _progress, 3, true, 0);
|
|
|
|
#ifndef TMC2130
|
|
_result = lcd_selfcheck_pulleys(X_AXIS);
|
|
#endif
|
|
}
|
|
|
|
|
|
if (_result)
|
|
{
|
|
_progress = lcd_selftest_screen(TestScreen::AxisY, _progress, 3, true, 1500);
|
|
#ifdef TMC2130
|
|
_result = lcd_selfcheck_axis_sg(Y_AXIS);
|
|
#else
|
|
_result = lcd_selfcheck_axis(Y_AXIS, Y_MAX_POS);
|
|
#endif // TMC2130
|
|
}
|
|
|
|
if (_result)
|
|
{
|
|
_progress = lcd_selftest_screen(TestScreen::AxisZ, _progress, 3, true, 0);
|
|
#ifndef TMC2130
|
|
_result = lcd_selfcheck_pulleys(Y_AXIS);
|
|
#endif // TMC2130
|
|
}
|
|
|
|
|
|
if (_result)
|
|
{
|
|
#ifdef TMC2130
|
|
tmc2130_home_exit();
|
|
enable_endstops(false);
|
|
current_position[X_AXIS] = current_position[X_AXIS] + 14;
|
|
current_position[Y_AXIS] = current_position[Y_AXIS] + 12;
|
|
#endif
|
|
|
|
//homeaxis(X_AXIS);
|
|
//homeaxis(Y_AXIS);
|
|
current_position[Z_AXIS] = current_position[Z_AXIS] + 10;
|
|
plan_buffer_line_curposXYZE(manual_feedrate[0] / 60, active_extruder);
|
|
st_synchronize();
|
|
_progress = lcd_selftest_screen(TestScreen::AxisZ, _progress, 3, true, 1500);
|
|
_result = lcd_selfcheck_axis(2, Z_MAX_POS);
|
|
if (eeprom_read_byte((uint8_t*)EEPROM_WIZARD_ACTIVE) != 1) {
|
|
enquecommand_P(PSTR("G28 W"));
|
|
enquecommand_P(PSTR("G1 Z15 F1000"));
|
|
}
|
|
}
|
|
|
|
#ifdef TMC2130
|
|
if (_result)
|
|
{
|
|
current_position[Z_AXIS] = current_position[Z_AXIS] + 10;
|
|
plan_buffer_line_curposXYZE(manual_feedrate[0] / 60, active_extruder);
|
|
st_synchronize();
|
|
_progress = lcd_selftest_screen(TestScreen::Home, 0, 2, true, 0);
|
|
bool bres = tmc2130_home_calibrate(X_AXIS);
|
|
_progress = lcd_selftest_screen(TestScreen::Home, 1, 2, true, 0);
|
|
bres &= tmc2130_home_calibrate(Y_AXIS);
|
|
_progress = lcd_selftest_screen(TestScreen::Home, 2, 2, true, 0);
|
|
if (bres)
|
|
eeprom_update_byte((uint8_t*)EEPROM_TMC2130_HOME_ENABLED, 1);
|
|
_result = bres;
|
|
}
|
|
#endif //TMC2130
|
|
|
|
if (_result)
|
|
{
|
|
_progress = lcd_selftest_screen(TestScreen::Bed, _progress, 3, true, 2000);
|
|
_result = lcd_selfcheck_check_heater(true);
|
|
}
|
|
|
|
if (_result)
|
|
{
|
|
_progress = lcd_selftest_screen(TestScreen::Hotend, _progress, 3, true, 1000);
|
|
_result = lcd_selfcheck_check_heater(false);
|
|
}
|
|
if (_result)
|
|
{
|
|
_progress = lcd_selftest_screen(TestScreen::HotendOk, _progress, 3, true, 2000); //nozzle ok
|
|
}
|
|
#ifdef FILAMENT_SENSOR
|
|
if (_result)
|
|
{
|
|
|
|
if (mmu_enabled)
|
|
{
|
|
_progress = lcd_selftest_screen(TestScreen::Fsensor, _progress, 3, true, 2000); //check filaments sensor
|
|
_result = selftest_irsensor();
|
|
if (_result)
|
|
{
|
|
_progress = lcd_selftest_screen(TestScreen::FsensorOk, _progress, 3, true, 2000); //fil sensor OK
|
|
}
|
|
} else
|
|
{
|
|
#ifdef PAT9125
|
|
_progress = lcd_selftest_screen(TestScreen::Fsensor, _progress, 3, true, 2000); //check filaments sensor
|
|
_result = lcd_selftest_fsensor();
|
|
if (_result)
|
|
{
|
|
_progress = lcd_selftest_screen(TestScreen::FsensorOk, _progress, 3, true, 2000); //fil sensor OK
|
|
}
|
|
#endif //PAT9125
|
|
#if IR_SENSOR_ANALOG
|
|
_progress = lcd_selftest_screen(TestScreen::Fsensor, _progress, 3, true, 2000); //check filament sensor
|
|
_result = lcd_selftest_IRsensor();
|
|
if (_result)
|
|
{
|
|
_progress = lcd_selftest_screen(TestScreen::FsensorOk, _progress, 3, true, 2000); //filament sensor OK
|
|
}
|
|
#endif //IR_SENSOR_ANALOG
|
|
}
|
|
}
|
|
#endif //FILAMENT_SENSOR
|
|
if (_result)
|
|
{
|
|
_progress = lcd_selftest_screen(TestScreen::AllCorrect, _progress, 3, true, 5000); //all correct
|
|
}
|
|
else
|
|
{
|
|
_progress = lcd_selftest_screen(TestScreen::Failed, _progress, 3, true, 5000);
|
|
}
|
|
lcd_reset_alert_level();
|
|
enquecommand_P(PSTR("M84"));
|
|
lcd_update_enable(true);
|
|
|
|
if (_result)
|
|
{
|
|
LCD_ALERTMESSAGERPGM(_i("Self test OK"));////MSG_SELFTEST_OK
|
|
}
|
|
else
|
|
{
|
|
LCD_ALERTMESSAGERPGM(_T(MSG_SELFTEST_FAILED));
|
|
}
|
|
#ifdef TMC2130
|
|
FORCE_HIGH_POWER_END;
|
|
#endif // TMC2130
|
|
KEEPALIVE_STATE(NOT_BUSY);
|
|
return(_result);
|
|
}
|
|
|
|
#ifdef TMC2130
|
|
|
|
static void reset_crash_det(unsigned char axis) {
|
|
current_position[axis] += 10;
|
|
plan_buffer_line_curposXYZE(manual_feedrate[0] / 60, active_extruder);
|
|
st_synchronize();
|
|
if (eeprom_read_byte((uint8_t*)EEPROM_CRASH_DET)) tmc2130_sg_stop_on_crash = true;
|
|
}
|
|
|
|
static bool lcd_selfcheck_axis_sg(unsigned char axis) {
|
|
// each axis length is measured twice
|
|
float axis_length, current_position_init, current_position_final;
|
|
float measured_axis_length[2];
|
|
float margin = 60;
|
|
float max_error_mm = 5;
|
|
switch (axis) {
|
|
case 0: axis_length = X_MAX_POS; break;
|
|
case 1: axis_length = Y_MAX_POS + 8; break;
|
|
default: axis_length = 210; break;
|
|
}
|
|
|
|
tmc2130_sg_stop_on_crash = false;
|
|
tmc2130_home_exit();
|
|
enable_endstops(true);
|
|
|
|
if (axis == X_AXIS) { //there is collision between cables and PSU cover in X axis if Z coordinate is too low
|
|
|
|
current_position[Z_AXIS] += 17;
|
|
plan_buffer_line_curposXYZE(manual_feedrate[0] / 60, active_extruder);
|
|
tmc2130_home_enter(Z_AXIS_MASK);
|
|
st_synchronize();
|
|
tmc2130_home_exit();
|
|
}
|
|
|
|
// first axis length measurement begin
|
|
|
|
current_position[axis] -= (axis_length + margin);
|
|
plan_buffer_line_curposXYZE(manual_feedrate[0] / 60, active_extruder);
|
|
|
|
|
|
st_synchronize();
|
|
|
|
tmc2130_sg_meassure_start(axis);
|
|
|
|
current_position_init = st_get_position_mm(axis);
|
|
|
|
current_position[axis] += 2 * margin;
|
|
plan_buffer_line_curposXYZE(manual_feedrate[0] / 60, active_extruder);
|
|
st_synchronize();
|
|
|
|
current_position[axis] += axis_length;
|
|
plan_buffer_line_curposXYZE(manual_feedrate[0] / 60, active_extruder);
|
|
|
|
st_synchronize();
|
|
|
|
uint16_t sg1 = tmc2130_sg_meassure_stop();
|
|
printf_P(PSTR("%c AXIS SG1=%d\n"), 'X'+axis, sg1);
|
|
eeprom_write_word(((uint16_t*)((axis == X_AXIS)?EEPROM_BELTSTATUS_X:EEPROM_BELTSTATUS_Y)), sg1);
|
|
|
|
current_position_final = st_get_position_mm(axis);
|
|
measured_axis_length[0] = abs(current_position_final - current_position_init);
|
|
|
|
|
|
// first measurement end and second measurement begin
|
|
|
|
|
|
current_position[axis] -= margin;
|
|
plan_buffer_line_curposXYZE(manual_feedrate[0] / 60, active_extruder);
|
|
st_synchronize();
|
|
|
|
current_position[axis] -= (axis_length + margin);
|
|
plan_buffer_line_curposXYZE(manual_feedrate[0] / 60, active_extruder);
|
|
|
|
st_synchronize();
|
|
|
|
current_position_init = st_get_position_mm(axis);
|
|
|
|
measured_axis_length[1] = abs(current_position_final - current_position_init);
|
|
|
|
|
|
//end of second measurement, now check for possible errors:
|
|
|
|
for(uint_least8_t i = 0; i < 2; i++){ //check if measured axis length corresponds to expected length
|
|
printf_P(_N("Measured axis length:%.3f\n"), measured_axis_length[i]);
|
|
if (abs(measured_axis_length[i] - axis_length) > max_error_mm) {
|
|
enable_endstops(false);
|
|
|
|
const char *_error_1;
|
|
|
|
if (axis == X_AXIS) _error_1 = "X";
|
|
if (axis == Y_AXIS) _error_1 = "Y";
|
|
if (axis == Z_AXIS) _error_1 = "Z";
|
|
|
|
lcd_selftest_error(TestError::Axis, _error_1, "");
|
|
current_position[axis] = 0;
|
|
plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
|
|
reset_crash_det(axis);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
printf_P(_N("Axis length difference:%.3f\n"), abs(measured_axis_length[0] - measured_axis_length[1]));
|
|
|
|
if (abs(measured_axis_length[0] - measured_axis_length[1]) > 1) { //check if difference between first and second measurement is low
|
|
//loose pulleys
|
|
const char *_error_1;
|
|
|
|
if (axis == X_AXIS) _error_1 = "X";
|
|
if (axis == Y_AXIS) _error_1 = "Y";
|
|
if (axis == Z_AXIS) _error_1 = "Z";
|
|
|
|
lcd_selftest_error(TestError::Pulley, _error_1, "");
|
|
current_position[axis] = 0;
|
|
plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
|
|
reset_crash_det(axis);
|
|
|
|
return false;
|
|
}
|
|
current_position[axis] = 0;
|
|
plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
|
|
reset_crash_det(axis);
|
|
return true;
|
|
}
|
|
#endif //TMC2130
|
|
|
|
//#ifndef TMC2130
|
|
|
|
static bool lcd_selfcheck_axis(int _axis, int _travel)
|
|
{
|
|
// printf_P(PSTR("lcd_selfcheck_axis %d, %d\n"), _axis, _travel);
|
|
bool _stepdone = false;
|
|
bool _stepresult = false;
|
|
int _progress = 0;
|
|
int _travel_done = 0;
|
|
int _err_endstop = 0;
|
|
int _lcd_refresh = 0;
|
|
_travel = _travel + (_travel / 10);
|
|
|
|
if (_axis == X_AXIS) {
|
|
current_position[Z_AXIS] += 17;
|
|
plan_buffer_line_curposXYZE(manual_feedrate[0] / 60, active_extruder);
|
|
}
|
|
|
|
do {
|
|
current_position[_axis] = current_position[_axis] - 1;
|
|
|
|
plan_buffer_line_curposXYZE(manual_feedrate[0] / 60, active_extruder);
|
|
st_synchronize();
|
|
#ifdef TMC2130
|
|
if ((READ(Z_MIN_PIN) ^ (bool)Z_MIN_ENDSTOP_INVERTING))
|
|
#else //TMC2130
|
|
if ((READ(X_MIN_PIN) ^ (bool)X_MIN_ENDSTOP_INVERTING) ||
|
|
(READ(Y_MIN_PIN) ^ (bool)Y_MIN_ENDSTOP_INVERTING) ||
|
|
(READ(Z_MIN_PIN) ^ (bool)Z_MIN_ENDSTOP_INVERTING))
|
|
#endif //TMC2130
|
|
{
|
|
if (_axis == 0)
|
|
{
|
|
_stepresult = ((READ(X_MIN_PIN) ^ X_MIN_ENDSTOP_INVERTING) == 1) ? true : false;
|
|
_err_endstop = ((READ(Y_MIN_PIN) ^ Y_MIN_ENDSTOP_INVERTING) == 1) ? 1 : 2;
|
|
|
|
}
|
|
if (_axis == 1)
|
|
{
|
|
_stepresult = ((READ(Y_MIN_PIN) ^ Y_MIN_ENDSTOP_INVERTING) == 1) ? true : false;
|
|
_err_endstop = ((READ(X_MIN_PIN) ^ X_MIN_ENDSTOP_INVERTING) == 1) ? 0 : 2;
|
|
|
|
}
|
|
if (_axis == 2)
|
|
{
|
|
_stepresult = ((READ(Z_MIN_PIN) ^ Z_MIN_ENDSTOP_INVERTING) == 1) ? true : false;
|
|
_err_endstop = ((READ(X_MIN_PIN) ^ X_MIN_ENDSTOP_INVERTING) == 1) ? 0 : 1;
|
|
printf_P(PSTR("lcd_selfcheck_axis %d, %d\n"), _stepresult, _err_endstop);
|
|
/*disable_x();
|
|
disable_y();
|
|
disable_z();*/
|
|
}
|
|
_stepdone = true;
|
|
}
|
|
|
|
if (_lcd_refresh < 6)
|
|
{
|
|
_lcd_refresh++;
|
|
}
|
|
else
|
|
{
|
|
_progress = lcd_selftest_screen(static_cast<TestScreen>(static_cast<int>(TestScreen::AxisX) + _axis), _progress, 3, false, 0);
|
|
_lcd_refresh = 0;
|
|
}
|
|
|
|
manage_heater();
|
|
manage_inactivity(true);
|
|
|
|
//_delay(100);
|
|
(_travel_done <= _travel) ? _travel_done++ : _stepdone = true;
|
|
|
|
} while (!_stepdone);
|
|
|
|
|
|
//current_position[_axis] = current_position[_axis] + 15;
|
|
//plan_buffer_line_curposXYZE(manual_feedrate[0] / 60, active_extruder);
|
|
|
|
if (!_stepresult)
|
|
{
|
|
const char *_error_1;
|
|
const char *_error_2;
|
|
|
|
if (_axis == X_AXIS) _error_1 = "X";
|
|
if (_axis == Y_AXIS) _error_1 = "Y";
|
|
if (_axis == Z_AXIS) _error_1 = "Z";
|
|
|
|
if (_err_endstop == 0) _error_2 = "X";
|
|
if (_err_endstop == 1) _error_2 = "Y";
|
|
if (_err_endstop == 2) _error_2 = "Z";
|
|
|
|
|
|
if (_travel_done >= _travel)
|
|
{
|
|
lcd_selftest_error(TestError::Endstop, _error_1, _error_2);
|
|
}
|
|
else
|
|
{
|
|
lcd_selftest_error(TestError::Motor, _error_1, _error_2);
|
|
}
|
|
}
|
|
|
|
return _stepresult;
|
|
}
|
|
|
|
#ifndef TMC2130
|
|
static bool lcd_selfcheck_pulleys(int axis)
|
|
{
|
|
float tmp_motor_loud[3] = DEFAULT_PWM_MOTOR_CURRENT_LOUD;
|
|
float tmp_motor[3] = DEFAULT_PWM_MOTOR_CURRENT;
|
|
float current_position_init;
|
|
float move;
|
|
bool endstop_triggered = false;
|
|
int i;
|
|
unsigned long timeout_counter;
|
|
refresh_cmd_timeout();
|
|
manage_inactivity(true);
|
|
|
|
if (axis == 0) move = 50; //X_AXIS
|
|
else move = 50; //Y_AXIS
|
|
|
|
current_position_init = current_position[axis];
|
|
|
|
current_position[axis] += 2;
|
|
plan_buffer_line_curposXYZE(manual_feedrate[0] / 60, active_extruder);
|
|
for (i = 0; i < 5; i++) {
|
|
refresh_cmd_timeout();
|
|
current_position[axis] = current_position[axis] + move;
|
|
st_current_set(0, 850); //set motor current higher
|
|
plan_buffer_line_curposXYZE(200, active_extruder);
|
|
st_synchronize();
|
|
if (SilentModeMenu != SILENT_MODE_OFF) st_current_set(0, tmp_motor[0]); //set back to normal operation currents
|
|
else st_current_set(0, tmp_motor_loud[0]); //set motor current back
|
|
current_position[axis] = current_position[axis] - move;
|
|
plan_buffer_line_curposXYZE(50, active_extruder);
|
|
st_synchronize();
|
|
if (((READ(X_MIN_PIN) ^ X_MIN_ENDSTOP_INVERTING) == 1) ||
|
|
((READ(Y_MIN_PIN) ^ Y_MIN_ENDSTOP_INVERTING) == 1)) {
|
|
lcd_selftest_error(TestError::Pulley, (axis == 0) ? "X" : "Y", "");
|
|
return(false);
|
|
}
|
|
}
|
|
timeout_counter = _millis() + 2500;
|
|
endstop_triggered = false;
|
|
manage_inactivity(true);
|
|
while (!endstop_triggered) {
|
|
if (((READ(X_MIN_PIN) ^ X_MIN_ENDSTOP_INVERTING) == 1) ||
|
|
((READ(Y_MIN_PIN) ^ Y_MIN_ENDSTOP_INVERTING) == 1)) {
|
|
endstop_triggered = true;
|
|
if (current_position_init - 1 <= current_position[axis] && current_position_init + 1 >= current_position[axis]) {
|
|
current_position[axis] += (axis == X_AXIS) ? 13 : 9;
|
|
plan_buffer_line_curposXYZE(manual_feedrate[0] / 60, active_extruder);
|
|
st_synchronize();
|
|
return(true);
|
|
}
|
|
else {
|
|
lcd_selftest_error(TestError::Pulley, (axis == 0) ? "X" : "Y", "");
|
|
return(false);
|
|
}
|
|
}
|
|
else {
|
|
current_position[axis] -= 1;
|
|
plan_buffer_line_curposXYZE(manual_feedrate[0] / 60, active_extruder);
|
|
st_synchronize();
|
|
if (_millis() > timeout_counter) {
|
|
lcd_selftest_error(TestError::Pulley, (axis == 0) ? "X" : "Y", "");
|
|
return(false);
|
|
}
|
|
}
|
|
}
|
|
return(true);
|
|
}
|
|
|
|
|
|
static bool lcd_selfcheck_endstops()
|
|
{
|
|
bool _result = true;
|
|
|
|
if (((READ(X_MIN_PIN) ^ X_MIN_ENDSTOP_INVERTING) == 1) ||
|
|
((READ(Y_MIN_PIN) ^ Y_MIN_ENDSTOP_INVERTING) == 1) ||
|
|
((READ(Z_MIN_PIN) ^ Z_MIN_ENDSTOP_INVERTING) == 1))
|
|
{
|
|
if ((READ(X_MIN_PIN) ^ X_MIN_ENDSTOP_INVERTING) == 1) current_position[0] += 10;
|
|
if ((READ(Y_MIN_PIN) ^ Y_MIN_ENDSTOP_INVERTING) == 1) current_position[1] += 10;
|
|
if ((READ(Z_MIN_PIN) ^ Z_MIN_ENDSTOP_INVERTING) == 1) current_position[2] += 10;
|
|
}
|
|
plan_buffer_line_curposXYZE(manual_feedrate[0] / 60, active_extruder);
|
|
_delay(500);
|
|
|
|
if (((READ(X_MIN_PIN) ^ X_MIN_ENDSTOP_INVERTING) == 1) ||
|
|
((READ(Y_MIN_PIN) ^ Y_MIN_ENDSTOP_INVERTING) == 1) ||
|
|
((READ(Z_MIN_PIN) ^ Z_MIN_ENDSTOP_INVERTING) == 1))
|
|
{
|
|
_result = false;
|
|
char _error[4] = "";
|
|
if ((READ(X_MIN_PIN) ^ X_MIN_ENDSTOP_INVERTING) == 1) strcat(_error, "X");
|
|
if ((READ(Y_MIN_PIN) ^ Y_MIN_ENDSTOP_INVERTING) == 1) strcat(_error, "Y");
|
|
if ((READ(Z_MIN_PIN) ^ Z_MIN_ENDSTOP_INVERTING) == 1) strcat(_error, "Z");
|
|
lcd_selftest_error(TestError::Endstops, _error, "");
|
|
}
|
|
manage_heater();
|
|
manage_inactivity(true);
|
|
return _result;
|
|
}
|
|
#endif //not defined TMC2130
|
|
|
|
static bool lcd_selfcheck_check_heater(bool _isbed)
|
|
{
|
|
int _counter = 0;
|
|
int _progress = 0;
|
|
bool _stepresult = false;
|
|
bool _docycle = true;
|
|
|
|
int _checked_snapshot = (_isbed) ? degBed() : degHotend(0);
|
|
int _opposite_snapshot = (_isbed) ? degHotend(0) : degBed();
|
|
int _cycles = (_isbed) ? 180 : 60; //~ 90s / 30s
|
|
|
|
target_temperature[0] = (_isbed) ? 0 : 200;
|
|
target_temperature_bed = (_isbed) ? 100 : 0;
|
|
manage_heater();
|
|
manage_inactivity(true);
|
|
KEEPALIVE_STATE(NOT_BUSY); //we are sending temperatures on serial line, so no need to send host keepalive messages
|
|
|
|
do {
|
|
_counter++;
|
|
_docycle = (_counter < _cycles) ? true : false;
|
|
|
|
manage_heater();
|
|
manage_inactivity(true);
|
|
_progress = (_isbed) ? lcd_selftest_screen(TestScreen::Bed, _progress, 2, false, 400) : lcd_selftest_screen(TestScreen::Hotend, _progress, 2, false, 400);
|
|
/*if (_isbed) {
|
|
MYSERIAL.print("Bed temp:");
|
|
MYSERIAL.println(degBed());
|
|
}
|
|
else {
|
|
MYSERIAL.print("Hotend temp:");
|
|
MYSERIAL.println(degHotend(0));
|
|
}*/
|
|
if(_counter%5 == 0) serialecho_temperatures(); //show temperatures once in two seconds
|
|
|
|
} while (_docycle);
|
|
|
|
target_temperature[0] = 0;
|
|
target_temperature_bed = 0;
|
|
manage_heater();
|
|
|
|
int _checked_result = (_isbed) ? degBed() - _checked_snapshot : degHotend(0) - _checked_snapshot;
|
|
int _opposite_result = (_isbed) ? degHotend(0) - _opposite_snapshot : degBed() - _opposite_snapshot;
|
|
/*
|
|
MYSERIAL.println("");
|
|
MYSERIAL.print("Checked result:");
|
|
MYSERIAL.println(_checked_result);
|
|
MYSERIAL.print("Opposite result:");
|
|
MYSERIAL.println(_opposite_result);
|
|
*/
|
|
|
|
if (_opposite_result < ((_isbed) ? 30 : 9))
|
|
{
|
|
if (_checked_result >= ((_isbed) ? 9 : 30))
|
|
{
|
|
_stepresult = true;
|
|
}
|
|
else
|
|
{
|
|
lcd_selftest_error(TestError::Heater, "", "");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lcd_selftest_error(TestError::Bed, "", "");
|
|
}
|
|
|
|
manage_heater();
|
|
manage_inactivity(true);
|
|
KEEPALIVE_STATE(IN_HANDLER);
|
|
return _stepresult;
|
|
|
|
}
|
|
static void lcd_selftest_error(TestError testError, const char *_error_1, const char *_error_2)
|
|
{
|
|
lcd_beeper_quick_feedback();
|
|
|
|
target_temperature[0] = 0;
|
|
target_temperature_bed = 0;
|
|
manage_heater();
|
|
manage_inactivity();
|
|
|
|
lcd_clear();
|
|
|
|
lcd_set_cursor(0, 0);
|
|
lcd_puts_P(_i("Selftest error !"));////MSG_SELFTEST_ERROR
|
|
lcd_set_cursor(0, 1);
|
|
lcd_puts_P(_i("Please check :"));////MSG_SELFTEST_PLEASECHECK
|
|
|
|
switch (testError)
|
|
{
|
|
case TestError::Heater:
|
|
lcd_set_cursor(0, 2);
|
|
lcd_puts_P(_i("Heater/Thermistor"));////MSG_SELFTEST_HEATERTHERMISTOR
|
|
lcd_set_cursor(0, 3);
|
|
lcd_puts_P(_i("Not connected"));////MSG_SELFTEST_NOTCONNECTED
|
|
break;
|
|
case TestError::Bed:
|
|
lcd_set_cursor(0, 2);
|
|
lcd_puts_P(_i("Bed / Heater"));////MSG_SELFTEST_BEDHEATER
|
|
lcd_set_cursor(0, 3);
|
|
lcd_puts_P(_T(MSG_SELFTEST_WIRINGERROR));
|
|
break;
|
|
case TestError::Endstops:
|
|
lcd_set_cursor(0, 2);
|
|
lcd_puts_P(_i("Endstops"));////MSG_SELFTEST_ENDSTOPS
|
|
lcd_set_cursor(0, 3);
|
|
lcd_puts_P(_T(MSG_SELFTEST_WIRINGERROR));
|
|
lcd_set_cursor(17, 3);
|
|
lcd_print(_error_1);
|
|
break;
|
|
case TestError::Motor:
|
|
lcd_set_cursor(0, 2);
|
|
lcd_puts_P(_T(MSG_SELFTEST_MOTOR));
|
|
lcd_set_cursor(18, 2);
|
|
lcd_print(_error_1);
|
|
lcd_set_cursor(0, 3);
|
|
lcd_puts_P(_i("Endstop"));////MSG_SELFTEST_ENDSTOP
|
|
lcd_set_cursor(18, 3);
|
|
lcd_print(_error_2);
|
|
break;
|
|
case TestError::Endstop:
|
|
lcd_set_cursor(0, 2);
|
|
lcd_puts_P(_i("Endstop not hit"));////MSG_SELFTEST_ENDSTOP_NOTHIT c=20 r=1
|
|
lcd_set_cursor(0, 3);
|
|
lcd_puts_P(_T(MSG_SELFTEST_MOTOR));
|
|
lcd_set_cursor(18, 3);
|
|
lcd_print(_error_1);
|
|
break;
|
|
case TestError::PrintFan:
|
|
lcd_set_cursor(0, 2);
|
|
lcd_puts_P(_T(MSG_SELFTEST_COOLING_FAN));
|
|
lcd_set_cursor(0, 3);
|
|
lcd_puts_P(_T(MSG_SELFTEST_WIRINGERROR));
|
|
lcd_set_cursor(18, 3);
|
|
lcd_print(_error_1);
|
|
break;
|
|
case TestError::ExtruderFan:
|
|
lcd_set_cursor(0, 2);
|
|
lcd_puts_P(_T(MSG_SELFTEST_EXTRUDER_FAN));
|
|
lcd_set_cursor(0, 3);
|
|
lcd_puts_P(_T(MSG_SELFTEST_WIRINGERROR));
|
|
lcd_set_cursor(18, 3);
|
|
lcd_print(_error_1);
|
|
break;
|
|
case TestError::Pulley:
|
|
lcd_set_cursor(0, 2);
|
|
lcd_puts_P(_i("Loose pulley"));////MSG_LOOSE_PULLEY c=20 r=1
|
|
lcd_set_cursor(0, 3);
|
|
lcd_puts_P(_T(MSG_SELFTEST_MOTOR));
|
|
lcd_set_cursor(18, 3);
|
|
lcd_print(_error_1);
|
|
break;
|
|
case TestError::Axis:
|
|
lcd_set_cursor(0, 2);
|
|
lcd_puts_P(_i("Axis length"));////MSG_SELFTEST_AXIS_LENGTH
|
|
lcd_set_cursor(0, 3);
|
|
lcd_puts_P(_i("Axis"));////MSG_SELFTEST_AXIS
|
|
lcd_set_cursor(18, 3);
|
|
lcd_print(_error_1);
|
|
break;
|
|
case TestError::SwappedFan:
|
|
lcd_set_cursor(0, 2);
|
|
lcd_puts_P(_i("Front/left fans"));////MSG_SELFTEST_FANS
|
|
lcd_set_cursor(0, 3);
|
|
lcd_puts_P(_i("Swapped"));////MSG_SELFTEST_SWAPPED
|
|
lcd_set_cursor(18, 3);
|
|
lcd_print(_error_1);
|
|
break;
|
|
case TestError::WiringFsensor:
|
|
lcd_set_cursor(0, 2);
|
|
lcd_puts_P(_T(MSG_SELFTEST_FILAMENT_SENSOR));
|
|
lcd_set_cursor(0, 3);
|
|
lcd_puts_P(_T(MSG_SELFTEST_WIRINGERROR));
|
|
break;
|
|
case TestError::TriggeringFsensor:
|
|
lcd_set_cursor(0, 2);
|
|
lcd_puts_P(_T(MSG_SELFTEST_FILAMENT_SENSOR));
|
|
lcd_set_cursor(0, 3);
|
|
lcd_puts_P(_i("False triggering"));////c=20
|
|
break;
|
|
case TestError::FsensorLevel:
|
|
lcd_set_cursor(0, 2);
|
|
lcd_puts_P(_T(MSG_SELFTEST_FILAMENT_SENSOR));
|
|
lcd_set_cursor(0, 3);
|
|
lcd_printf_P(_i("%s level expected"),_error_1);////c=20
|
|
break;
|
|
}
|
|
|
|
_delay(1000);
|
|
lcd_beeper_quick_feedback();
|
|
|
|
do {
|
|
_delay(100);
|
|
manage_heater();
|
|
manage_inactivity();
|
|
} while (!lcd_clicked());
|
|
|
|
LCD_ALERTMESSAGERPGM(_T(MSG_SELFTEST_FAILED));
|
|
lcd_return_to_status();
|
|
|
|
}
|
|
|
|
#ifdef FILAMENT_SENSOR
|
|
#ifdef PAT9125
|
|
static bool lcd_selftest_fsensor(void)
|
|
{
|
|
fsensor_init();
|
|
if (fsensor_not_responding)
|
|
{
|
|
lcd_selftest_error(TestError::WiringFsensor, "", "");
|
|
}
|
|
return (!fsensor_not_responding);
|
|
}
|
|
#endif //PAT9125
|
|
|
|
//! @brief Self-test of infrared barrier filament sensor mounted on MK3S with MMUv2 printer
|
|
//!
|
|
//! Test whether sensor is not triggering filament presence when extruder idler is moving without filament.
|
|
//!
|
|
//! Steps:
|
|
//! * Backup current active extruder temperature
|
|
//! * Pre-heat to PLA extrude temperature.
|
|
//! * Unload filament possibly present.
|
|
//! * Move extruder idler same way as during filament load
|
|
//! and sample IR_SENSOR_PIN.
|
|
//! * Check that pin doesn't go low.
|
|
//!
|
|
//! @retval true passed
|
|
//! @retval false failed
|
|
static bool selftest_irsensor()
|
|
{
|
|
class TempBackup
|
|
{
|
|
public:
|
|
TempBackup():
|
|
m_temp(degTargetHotend(active_extruder)),
|
|
m_extruder(active_extruder){}
|
|
~TempBackup(){setTargetHotend(m_temp,m_extruder);}
|
|
private:
|
|
float m_temp;
|
|
uint8_t m_extruder;
|
|
};
|
|
uint8_t progress;
|
|
{
|
|
TempBackup tempBackup;
|
|
setTargetHotend(ABS_PREHEAT_HOTEND_TEMP,active_extruder);
|
|
mmu_wait_for_heater_blocking();
|
|
progress = lcd_selftest_screen(TestScreen::Fsensor, 0, 1, true, 0);
|
|
mmu_filament_ramming();
|
|
}
|
|
progress = lcd_selftest_screen(TestScreen::Fsensor, progress, 1, true, 0);
|
|
mmu_command(MmuCmd::U0);
|
|
manage_response(false, false);
|
|
|
|
for(uint_least8_t i = 0; i < 200; ++i)
|
|
{
|
|
if (0 == (i % 32)) progress = lcd_selftest_screen(TestScreen::Fsensor, progress, 1, true, 0);
|
|
|
|
mmu_load_step(false);
|
|
while (blocks_queued())
|
|
{
|
|
if (PIN_GET(IR_SENSOR_PIN) == 0)
|
|
{
|
|
lcd_selftest_error(TestError::TriggeringFsensor, "", "");
|
|
return false;
|
|
}
|
|
#ifdef TMC2130
|
|
manage_heater();
|
|
// Vojtech: Don't disable motors inside the planner!
|
|
if (!tmc2130_update_sg())
|
|
{
|
|
manage_inactivity(true);
|
|
}
|
|
#else //TMC2130
|
|
manage_heater();
|
|
// Vojtech: Don't disable motors inside the planner!
|
|
manage_inactivity(true);
|
|
#endif //TMC2130
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
#endif //FILAMENT_SENSOR
|
|
|
|
static bool lcd_selftest_manual_fan_check(int _fan, bool check_opposite,
|
|
bool _default)
|
|
{
|
|
|
|
bool _result = check_opposite;
|
|
lcd_clear();
|
|
|
|
lcd_set_cursor(0, 0); lcd_puts_P(_T(MSG_SELFTEST_FAN));
|
|
|
|
switch (_fan)
|
|
{
|
|
case 0:
|
|
// extruder cooling fan
|
|
lcd_set_cursor(0, 1);
|
|
if(check_opposite == true) lcd_puts_P(_T(MSG_SELFTEST_COOLING_FAN));
|
|
else lcd_puts_P(_T(MSG_SELFTEST_EXTRUDER_FAN));
|
|
SET_OUTPUT(EXTRUDER_0_AUTO_FAN_PIN);
|
|
WRITE(EXTRUDER_0_AUTO_FAN_PIN, 1);
|
|
break;
|
|
case 1:
|
|
// object cooling fan
|
|
lcd_set_cursor(0, 1);
|
|
if (check_opposite == true) lcd_puts_P(_T(MSG_SELFTEST_EXTRUDER_FAN));
|
|
else lcd_puts_P(_T(MSG_SELFTEST_COOLING_FAN));
|
|
SET_OUTPUT(FAN_PIN);
|
|
#ifdef FAN_SOFT_PWM
|
|
fanSpeedSoftPwm = 255;
|
|
#else //FAN_SOFT_PWM
|
|
analogWrite(FAN_PIN, 255);
|
|
#endif //FAN_SOFT_PWM
|
|
|
|
break;
|
|
}
|
|
_delay(500);
|
|
|
|
lcd_set_cursor(1, 2); lcd_puts_P(_T(MSG_SELFTEST_FAN_YES));
|
|
lcd_set_cursor(0, 3); lcd_print(">");
|
|
lcd_set_cursor(1, 3); lcd_puts_P(_T(MSG_SELFTEST_FAN_NO));
|
|
|
|
int8_t enc_dif = int(_default)*3;
|
|
|
|
KEEPALIVE_STATE(PAUSED_FOR_USER);
|
|
|
|
lcd_button_pressed = false;
|
|
do
|
|
{
|
|
switch (_fan)
|
|
{
|
|
case 0:
|
|
// extruder cooling fan
|
|
SET_OUTPUT(EXTRUDER_0_AUTO_FAN_PIN);
|
|
WRITE(EXTRUDER_0_AUTO_FAN_PIN, 1);
|
|
break;
|
|
case 1:
|
|
// object cooling fan
|
|
SET_OUTPUT(FAN_PIN);
|
|
#ifdef FAN_SOFT_PWM
|
|
fanSpeedSoftPwm = 255;
|
|
#else //FAN_SOFT_PWM
|
|
analogWrite(FAN_PIN, 255);
|
|
#endif //FAN_SOFT_PWM
|
|
break;
|
|
}
|
|
if (abs((enc_dif - lcd_encoder_diff)) > 2) {
|
|
if (enc_dif > lcd_encoder_diff) {
|
|
_result = !check_opposite;
|
|
lcd_set_cursor(0, 2); lcd_print(">");
|
|
lcd_set_cursor(1, 2); lcd_puts_P(_T(MSG_SELFTEST_FAN_YES));
|
|
lcd_set_cursor(0, 3); lcd_print(" ");
|
|
lcd_set_cursor(1, 3); lcd_puts_P(_T(MSG_SELFTEST_FAN_NO));
|
|
}
|
|
|
|
if (enc_dif < lcd_encoder_diff) {
|
|
_result = check_opposite;
|
|
lcd_set_cursor(0, 2); lcd_print(" ");
|
|
lcd_set_cursor(1, 2); lcd_puts_P(_T(MSG_SELFTEST_FAN_YES));
|
|
lcd_set_cursor(0, 3); lcd_print(">");
|
|
lcd_set_cursor(1, 3); lcd_puts_P(_T(MSG_SELFTEST_FAN_NO));
|
|
}
|
|
enc_dif = 0;
|
|
lcd_encoder_diff = 0;
|
|
}
|
|
|
|
|
|
manage_heater();
|
|
_delay(100);
|
|
|
|
} while (!lcd_clicked());
|
|
KEEPALIVE_STATE(IN_HANDLER);
|
|
SET_OUTPUT(EXTRUDER_0_AUTO_FAN_PIN);
|
|
WRITE(EXTRUDER_0_AUTO_FAN_PIN, 0);
|
|
SET_OUTPUT(FAN_PIN);
|
|
#ifdef FAN_SOFT_PWM
|
|
fanSpeedSoftPwm = 0;
|
|
#else //FAN_SOFT_PWM
|
|
analogWrite(FAN_PIN, 0);
|
|
#endif //FAN_SOFT_PWM
|
|
fanSpeed = 0;
|
|
manage_heater();
|
|
|
|
return _result;
|
|
}
|
|
|
|
#ifdef FANCHECK
|
|
static FanCheck lcd_selftest_fan_auto(int _fan)
|
|
{
|
|
switch (_fan) {
|
|
case 0:
|
|
fanSpeed = 0;
|
|
manage_heater(); //turn off fan
|
|
setExtruderAutoFanState(EXTRUDER_0_AUTO_FAN_PIN, 1); //extruder fan
|
|
#ifdef FAN_SOFT_PWM
|
|
extruder_autofan_last_check = _millis();
|
|
fan_measuring = true;
|
|
#endif //FAN_SOFT_PWM
|
|
_delay(2000); //delay_keep_alive would turn off extruder fan, because temerature is too low
|
|
|
|
manage_heater(); //count average fan speed from 2s delay and turn off fans
|
|
|
|
printf_P(PSTR("Test 1:\n"));
|
|
printf_P(PSTR("Print fan speed: %d \n"), fan_speed[1]);
|
|
printf_P(PSTR("Extr fan speed: %d \n"), fan_speed[0]);
|
|
|
|
if (!fan_speed[0]) {
|
|
return FanCheck::ExtruderFan;
|
|
}
|
|
#ifdef FAN_SOFT_PWM
|
|
else if (fan_speed[0] > 50 ) { // printerFan is faster
|
|
return FanCheck::SwappedFan;
|
|
}
|
|
break;
|
|
#endif
|
|
|
|
case 1:
|
|
//will it work with Thotend > 50 C ?
|
|
#ifdef FAN_SOFT_PWM
|
|
fanSpeed = 255;
|
|
fanSpeedSoftPwm = 255;
|
|
extruder_autofan_last_check = _millis(); //store time when measurement starts
|
|
fan_measuring = true; //start fan measuring, rest is on manage_heater
|
|
#else //FAN_SOFT_PWM
|
|
fanSpeed = 150; //print fan
|
|
#endif //FAN_SOFT_PWM
|
|
for (uint8_t i = 0; i < 5; i++) {
|
|
delay_keep_alive(1000);
|
|
lcd_set_cursor(18, 3);
|
|
lcd_print("-");
|
|
delay_keep_alive(1000);
|
|
lcd_set_cursor(18, 3);
|
|
lcd_print("|");
|
|
}
|
|
fanSpeed = 0;
|
|
|
|
#ifdef FAN_SOFT_PWM
|
|
fanSpeedSoftPwm = 0;
|
|
#else //FAN_SOFT_PWM
|
|
manage_heater(); //turn off fan
|
|
manage_inactivity(true); //to turn off print fan
|
|
#endif //FAN_SOFT_PWM
|
|
printf_P(PSTR("Test 2:\n"));
|
|
printf_P(PSTR("Print fan speed: %d \n"), fan_speed[1]);
|
|
printf_P(PSTR("Extr fan speed: %d \n"), fan_speed[0]);
|
|
if (!fan_speed[1]) {
|
|
return FanCheck::PrintFan;
|
|
}
|
|
|
|
#ifdef FAN_SOFT_PWM
|
|
fanSpeed = 80;
|
|
fanSpeedSoftPwm = 80;
|
|
|
|
for (uint8_t i = 0; i < 5; i++) {
|
|
delay_keep_alive(1000);
|
|
lcd_set_cursor(18, 3);
|
|
lcd_print("-");
|
|
delay_keep_alive(1000);
|
|
lcd_set_cursor(18, 3);
|
|
lcd_print("|");
|
|
}
|
|
fanSpeed = 0;
|
|
|
|
// noctua speed is between 17 and 24, turbine more then 30
|
|
if (fan_speed[1] < 30) {
|
|
return FanCheck::SwappedFan;
|
|
}
|
|
#else
|
|
// fan is spinning, but measured RPM are too low for print fan, it must
|
|
// be left extruder fan
|
|
else if (fan_speed[1] < 34) {
|
|
return FanCheck::SwappedFan;
|
|
}
|
|
#endif //FAN_SOFT_PWM
|
|
break;
|
|
}
|
|
return FanCheck::Success;
|
|
}
|
|
|
|
#endif //FANCHECK
|
|
|
|
static int lcd_selftest_screen(TestScreen screen, int _progress, int _progress_scale, bool _clear, int _delay)
|
|
{
|
|
|
|
lcd_update_enable(false);
|
|
|
|
const char *_indicator = (_progress >= _progress_scale) ? "-" : "|";
|
|
|
|
if (_clear) lcd_clear();
|
|
|
|
|
|
lcd_set_cursor(0, 0);
|
|
|
|
if (screen == TestScreen::ExtruderFan) lcd_puts_P(_T(MSG_SELFTEST_FAN));
|
|
if (screen == TestScreen::PrintFan) lcd_puts_P(_T(MSG_SELFTEST_FAN));
|
|
if (screen == TestScreen::FansOk) lcd_puts_P(_T(MSG_SELFTEST_FAN));
|
|
if (screen == TestScreen::EndStops) lcd_puts_P(_i("Checking endstops"));////MSG_SELFTEST_CHECK_ENDSTOPS c=20
|
|
if (screen == TestScreen::AxisX) lcd_puts_P(_i("Checking X axis "));////MSG_SELFTEST_CHECK_X c=20
|
|
if (screen == TestScreen::AxisY) lcd_puts_P(_i("Checking Y axis "));////MSG_SELFTEST_CHECK_Y c=20
|
|
if (screen == TestScreen::AxisZ) lcd_puts_P(_i("Checking Z axis "));////MSG_SELFTEST_CHECK_Z c=20
|
|
if (screen == TestScreen::Bed) lcd_puts_P(_T(MSG_SELFTEST_CHECK_BED));
|
|
if (screen == TestScreen::Hotend
|
|
|| screen == TestScreen::HotendOk) lcd_puts_P(_i("Checking hotend "));////MSG_SELFTEST_CHECK_HOTEND c=20
|
|
if (screen == TestScreen::Fsensor) lcd_puts_P(_T(MSG_SELFTEST_CHECK_FSENSOR));
|
|
if (screen == TestScreen::FsensorOk) lcd_puts_P(_T(MSG_SELFTEST_CHECK_FSENSOR));
|
|
if (screen == TestScreen::AllCorrect) lcd_puts_P(_i("All correct "));////MSG_SELFTEST_CHECK_ALLCORRECT c=20
|
|
if (screen == TestScreen::Failed) lcd_puts_P(_T(MSG_SELFTEST_FAILED));
|
|
if (screen == TestScreen::Home) lcd_puts_P(_i("Calibrating home"));////c=20 r=1
|
|
|
|
lcd_set_cursor(0, 1);
|
|
lcd_puts_P(separator);
|
|
if ((screen >= TestScreen::ExtruderFan) && (screen <= TestScreen::FansOk))
|
|
{
|
|
//SERIAL_ECHOLNPGM("Fan test");
|
|
lcd_puts_at_P(0, 2, _i("Extruder fan:"));////MSG_SELFTEST_EXTRUDER_FAN_SPEED c=18
|
|
lcd_set_cursor(18, 2);
|
|
(screen < TestScreen::PrintFan) ? lcd_print(_indicator) : lcd_print("OK");
|
|
lcd_puts_at_P(0, 3, _i("Print fan:"));////MSG_SELFTEST_PRINT_FAN_SPEED c=18
|
|
lcd_set_cursor(18, 3);
|
|
(screen < TestScreen::FansOk) ? lcd_print(_indicator) : lcd_print("OK");
|
|
}
|
|
else if (screen >= TestScreen::Fsensor && screen <= TestScreen::FsensorOk)
|
|
{
|
|
lcd_puts_at_P(0, 2, _T(MSG_SELFTEST_FILAMENT_SENSOR));
|
|
lcd_putc(':');
|
|
lcd_set_cursor(18, 2);
|
|
(screen == TestScreen::Fsensor) ? lcd_print(_indicator) : lcd_print("OK");
|
|
}
|
|
else if (screen < TestScreen::Fsensor)
|
|
{
|
|
//SERIAL_ECHOLNPGM("Other tests");
|
|
|
|
TestScreen _step_block = TestScreen::AxisX;
|
|
lcd_selftest_screen_step(2, 2, ((screen == _step_block) ? 1 : (screen < _step_block) ? 0 : 2), "X", _indicator);
|
|
|
|
_step_block = TestScreen::AxisY;
|
|
lcd_selftest_screen_step(2, 8, ((screen == _step_block) ? 1 : (screen < _step_block) ? 0 : 2), "Y", _indicator);
|
|
|
|
_step_block = TestScreen::AxisZ;
|
|
lcd_selftest_screen_step(2, 14, ((screen == _step_block) ? 1 : (screen < _step_block) ? 0 : 2), "Z", _indicator);
|
|
|
|
_step_block = TestScreen::Bed;
|
|
lcd_selftest_screen_step(3, 0, ((screen == _step_block) ? 1 : (screen < _step_block) ? 0 : 2), "Bed", _indicator);
|
|
|
|
_step_block = TestScreen::Hotend;
|
|
lcd_selftest_screen_step(3, 9, ((screen == _step_block) ? 1 : (screen < _step_block) ? 0 : 2), "Hotend", _indicator);
|
|
}
|
|
|
|
if (_delay > 0) delay_keep_alive(_delay);
|
|
_progress++;
|
|
|
|
return (_progress >= _progress_scale * 2) ? 0 : _progress;
|
|
}
|
|
|
|
static void lcd_selftest_screen_step(int _row, int _col, int _state, const char *_name, const char *_indicator)
|
|
{
|
|
lcd_set_cursor(_col, _row);
|
|
|
|
switch (_state)
|
|
{
|
|
case 1:
|
|
lcd_print(_name);
|
|
lcd_set_cursor(_col + strlen(_name), _row);
|
|
lcd_print(":");
|
|
lcd_set_cursor(_col + strlen(_name) + 1, _row);
|
|
lcd_print(_indicator);
|
|
break;
|
|
case 2:
|
|
lcd_print(_name);
|
|
lcd_set_cursor(_col + strlen(_name), _row);
|
|
lcd_print(":");
|
|
lcd_set_cursor(_col + strlen(_name) + 1, _row);
|
|
lcd_print("OK");
|
|
break;
|
|
default:
|
|
lcd_print(_name);
|
|
}
|
|
}
|
|
|
|
|
|
/** End of menus **/
|
|
|
|
/** Menu action functions **/
|
|
|
|
static bool check_file(const char* filename) {
|
|
if (farm_mode) return true;
|
|
bool result = false;
|
|
uint32_t filesize;
|
|
card.openFile((char*)filename, true);
|
|
filesize = card.getFileSize();
|
|
if (filesize > END_FILE_SECTION) {
|
|
card.setIndex(filesize - END_FILE_SECTION);
|
|
|
|
}
|
|
|
|
while (!card.eof() && !result) {
|
|
card.sdprinting = true;
|
|
get_command();
|
|
result = check_commands();
|
|
|
|
}
|
|
card.printingHasFinished();
|
|
strncpy_P(lcd_status_message, _T(WELCOME_MSG), LCD_WIDTH);
|
|
lcd_finishstatus();
|
|
return result;
|
|
|
|
}
|
|
|
|
static void menu_action_sdfile(const char* filename)
|
|
{
|
|
loading_flag = false;
|
|
char cmd[30];
|
|
char* c;
|
|
bool result = true;
|
|
sprintf_P(cmd, PSTR("M23 %s"), filename);
|
|
for (c = &cmd[4]; *c; c++)
|
|
*c = tolower(*c);
|
|
|
|
const char end[5] = ".gco";
|
|
|
|
//we are storing just first 8 characters of 8.3 filename assuming that extension is always ".gco"
|
|
for (uint_least8_t i = 0; i < 8; i++) {
|
|
if (strcmp((cmd + i + 4), end) == 0) {
|
|
//filename is shorter then 8.3, store '\0' character on position where ".gco" string was found to terminate stored string properly
|
|
eeprom_write_byte((uint8_t*)EEPROM_FILENAME + i, '\0');
|
|
break;
|
|
}
|
|
else {
|
|
eeprom_write_byte((uint8_t*)EEPROM_FILENAME + i, cmd[i + 4]);
|
|
}
|
|
}
|
|
|
|
uint8_t depth = (uint8_t)card.getWorkDirDepth();
|
|
eeprom_write_byte((uint8_t*)EEPROM_DIR_DEPTH, depth);
|
|
|
|
for (uint_least8_t i = 0; i < depth; i++) {
|
|
for (uint_least8_t j = 0; j < 8; j++) {
|
|
eeprom_write_byte((uint8_t*)EEPROM_DIRS + j + 8 * i, dir_names[i][j]);
|
|
}
|
|
}
|
|
|
|
if (!check_file(filename)) {
|
|
result = lcd_show_fullscreen_message_yes_no_and_wait_P(_i("File incomplete. Continue anyway?"), false, false);////MSG_FILE_INCOMPLETE c=20 r=2
|
|
lcd_update_enable(true);
|
|
}
|
|
if (result) {
|
|
enquecommand(cmd);
|
|
enquecommand_P(PSTR("M24"));
|
|
}
|
|
|
|
lcd_return_to_status();
|
|
}
|
|
|
|
void menu_action_sddirectory(const char* filename)
|
|
{
|
|
uint8_t depth = (uint8_t)card.getWorkDirDepth();
|
|
|
|
strcpy(dir_names[depth], filename);
|
|
MYSERIAL.println(dir_names[depth]);
|
|
card.chdir(filename);
|
|
lcd_encoder = 0;
|
|
}
|
|
|
|
/** LCD API **/
|
|
|
|
void ultralcd_init()
|
|
{
|
|
{
|
|
uint8_t autoDepleteRaw = eeprom_read_byte(reinterpret_cast<uint8_t*>(EEPROM_AUTO_DEPLETE));
|
|
if (0xff == autoDepleteRaw) lcd_autoDeplete = false;
|
|
else lcd_autoDeplete = autoDepleteRaw;
|
|
|
|
}
|
|
lcd_init();
|
|
lcd_refresh();
|
|
lcd_longpress_func = menu_lcd_longpress_func;
|
|
lcd_charsetup_func = menu_lcd_charsetup_func;
|
|
lcd_lcdupdate_func = menu_lcd_lcdupdate_func;
|
|
menu_menu = lcd_status_screen;
|
|
menu_lcd_charsetup_func();
|
|
|
|
SET_INPUT(BTN_EN1);
|
|
SET_INPUT(BTN_EN2);
|
|
WRITE(BTN_EN1, HIGH);
|
|
WRITE(BTN_EN2, HIGH);
|
|
#if BTN_ENC > 0
|
|
SET_INPUT(BTN_ENC);
|
|
WRITE(BTN_ENC, HIGH);
|
|
#endif
|
|
|
|
#if defined (SDSUPPORT) && defined(SDCARDDETECT) && (SDCARDDETECT > 0)
|
|
pinMode(SDCARDDETECT, INPUT);
|
|
WRITE(SDCARDDETECT, HIGH);
|
|
lcd_oldcardstatus = IS_SD_INSERTED;
|
|
#endif//(SDCARDDETECT > 0)
|
|
lcd_encoder_diff = 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void lcd_printer_connected() {
|
|
printer_connected = true;
|
|
}
|
|
|
|
static void lcd_send_status() {
|
|
if (farm_mode && no_response && ((_millis() - NcTime) > (NC_TIME * 1000))) {
|
|
//send important status messages periodicaly
|
|
prusa_statistics(important_status, saved_filament_type);
|
|
NcTime = _millis();
|
|
#ifdef FARM_CONNECT_MESSAGE
|
|
lcd_connect_printer();
|
|
#endif //FARM_CONNECT_MESSAGE
|
|
}
|
|
}
|
|
|
|
#ifdef FARM_CONNECT_MESSAGE
|
|
static void lcd_connect_printer() {
|
|
lcd_update_enable(false);
|
|
lcd_clear();
|
|
|
|
int i = 0;
|
|
int t = 0;
|
|
lcd_set_custom_characters_progress();
|
|
lcd_puts_at_P(0, 0, _i("Connect printer to"));
|
|
lcd_puts_at_P(0, 1, _i("monitoring or hold"));
|
|
lcd_puts_at_P(0, 2, _i("the knob to continue"));
|
|
while (no_response) {
|
|
i++;
|
|
t++;
|
|
delay_keep_alive(100);
|
|
proc_commands();
|
|
if (t == 10) {
|
|
prusa_statistics(important_status, saved_filament_type);
|
|
t = 0;
|
|
}
|
|
if (READ(BTN_ENC)) { //if button is not pressed
|
|
i = 0;
|
|
lcd_puts_at_P(0, 3, PSTR(" "));
|
|
}
|
|
if (i!=0) lcd_puts_at_P((i * 20) / (NC_BUTTON_LONG_PRESS * 10), 3, "\x01");
|
|
if (i == NC_BUTTON_LONG_PRESS * 10) {
|
|
no_response = false;
|
|
}
|
|
}
|
|
lcd_set_custom_characters_degree();
|
|
lcd_update_enable(true);
|
|
lcd_update(2);
|
|
}
|
|
#endif //FARM_CONNECT_MESSAGE
|
|
|
|
void lcd_ping() { //chceck if printer is connected to monitoring when in farm mode
|
|
if (farm_mode) {
|
|
bool empty = is_buffer_empty();
|
|
if ((_millis() - PingTime) * 0.001 > (empty ? PING_TIME : PING_TIME_LONG)) { //if commands buffer is empty use shorter time period
|
|
//if there are comamnds in buffer, some long gcodes can delay execution of ping command
|
|
//therefore longer period is used
|
|
printer_connected = false;
|
|
}
|
|
else {
|
|
lcd_printer_connected();
|
|
}
|
|
}
|
|
}
|
|
void lcd_ignore_click(bool b)
|
|
{
|
|
ignore_click = b;
|
|
wait_for_unclick = false;
|
|
}
|
|
|
|
void lcd_finishstatus() {
|
|
int len = strlen(lcd_status_message);
|
|
if (len > 0) {
|
|
while (len < LCD_WIDTH) {
|
|
lcd_status_message[len++] = ' ';
|
|
}
|
|
}
|
|
lcd_status_message[LCD_WIDTH] = '\0';
|
|
lcd_draw_update = 2;
|
|
|
|
}
|
|
void lcd_setstatus(const char* message)
|
|
{
|
|
if (lcd_status_message_level > 0)
|
|
return;
|
|
strncpy(lcd_status_message, message, LCD_WIDTH);
|
|
lcd_finishstatus();
|
|
}
|
|
void lcd_updatestatuspgm(const char *message){
|
|
strncpy_P(lcd_status_message, message, LCD_WIDTH);
|
|
lcd_status_message[LCD_WIDTH] = 0;
|
|
lcd_finishstatus();
|
|
// hack lcd_draw_update to 1, i.e. without clear
|
|
lcd_draw_update = 1;
|
|
}
|
|
|
|
void lcd_setstatuspgm(const char* message)
|
|
{
|
|
if (lcd_status_message_level > 0)
|
|
return;
|
|
lcd_updatestatuspgm(message);
|
|
}
|
|
void lcd_setalertstatuspgm(const char* message)
|
|
{
|
|
lcd_setstatuspgm(message);
|
|
lcd_status_message_level = 1;
|
|
lcd_return_to_status();
|
|
}
|
|
void lcd_reset_alert_level()
|
|
{
|
|
lcd_status_message_level = 0;
|
|
}
|
|
|
|
uint8_t get_message_level()
|
|
{
|
|
return lcd_status_message_level;
|
|
}
|
|
|
|
void menu_lcd_longpress_func(void)
|
|
{
|
|
if (homing_flag || mesh_bed_leveling_flag || menu_menu == lcd_babystep_z || menu_menu == lcd_move_z)
|
|
{
|
|
// disable longpress during re-entry, while homing or calibration
|
|
lcd_quick_feedback();
|
|
return;
|
|
}
|
|
|
|
// explicitely listed menus which are allowed to rise the move-z or live-adj-z functions
|
|
// The lists are not the same for both functions, so first decide which function is to be performed
|
|
if ( (moves_planned() || IS_SD_PRINTING || is_usb_printing )){ // long press as live-adj-z
|
|
if(( current_position[Z_AXIS] < Z_HEIGHT_HIDE_LIVE_ADJUST_MENU ) // only allow live-adj-z up to 2mm of print height
|
|
&& ( menu_menu == lcd_status_screen // and in listed menus...
|
|
|| menu_menu == lcd_main_menu
|
|
|| menu_menu == lcd_tune_menu
|
|
|| menu_menu == lcd_support_menu
|
|
)
|
|
){
|
|
lcd_clear();
|
|
menu_submenu(lcd_babystep_z);
|
|
} else {
|
|
// otherwise consume the long press as normal click
|
|
if( menu_menu != lcd_status_screen )
|
|
menu_back();
|
|
}
|
|
} else { // long press as move-z
|
|
if(menu_menu == lcd_status_screen
|
|
|| menu_menu == lcd_main_menu
|
|
|| menu_menu == lcd_preheat_menu
|
|
|| menu_menu == lcd_sdcard_menu
|
|
|| menu_menu == lcd_settings_menu
|
|
|| menu_menu == lcd_control_temperature_menu
|
|
#if (LANG_MODE != 0)
|
|
|| menu_menu == lcd_language
|
|
#endif
|
|
|| menu_menu == lcd_support_menu
|
|
){
|
|
move_menu_scale = 1.0;
|
|
menu_submenu(lcd_move_z);
|
|
} else {
|
|
// otherwise consume the long press as normal click
|
|
if( menu_menu != lcd_status_screen )
|
|
menu_back();
|
|
}
|
|
}
|
|
}
|
|
|
|
void menu_lcd_charsetup_func(void)
|
|
{
|
|
if (menu_menu == lcd_status_screen)
|
|
lcd_set_custom_characters_degree();
|
|
else
|
|
lcd_set_custom_characters_arrows();
|
|
}
|
|
|
|
static inline bool z_menu_expired()
|
|
{
|
|
return (menu_menu == lcd_babystep_z
|
|
&& lcd_timeoutToStatus.expired(LCD_TIMEOUT_TO_STATUS_BABYSTEP_Z));
|
|
}
|
|
static inline bool other_menu_expired()
|
|
{
|
|
return (menu_menu != lcd_status_screen
|
|
&& menu_menu != lcd_babystep_z
|
|
&& lcd_timeoutToStatus.expired(LCD_TIMEOUT_TO_STATUS));
|
|
}
|
|
static inline bool forced_menu_expire()
|
|
{
|
|
bool retval = (menu_menu != lcd_status_screen
|
|
&& forceMenuExpire);
|
|
forceMenuExpire = false;
|
|
return retval;
|
|
}
|
|
|
|
void menu_lcd_lcdupdate_func(void)
|
|
{
|
|
#if (SDCARDDETECT > 0)
|
|
if ((IS_SD_INSERTED != lcd_oldcardstatus))
|
|
{
|
|
lcd_draw_update = 2;
|
|
lcd_oldcardstatus = IS_SD_INSERTED;
|
|
lcd_refresh(); // to maybe revive the LCD if static electricity killed it.
|
|
if (lcd_oldcardstatus)
|
|
{
|
|
card.initsd();
|
|
LCD_MESSAGERPGM(_T(WELCOME_MSG));
|
|
bMain=false; // flag (i.e. 'fake parameter') for 'lcd_sdcard_menu()' function
|
|
menu_submenu(lcd_sdcard_menu);
|
|
//get_description();
|
|
}
|
|
else
|
|
{
|
|
if(menu_menu==lcd_sdcard_menu)
|
|
menu_back();
|
|
card.release();
|
|
LCD_MESSAGERPGM(_i("Card removed"));////MSG_SD_REMOVED
|
|
}
|
|
}
|
|
#endif//CARDINSERTED
|
|
if (lcd_next_update_millis < _millis())
|
|
{
|
|
if (abs(lcd_encoder_diff) >= ENCODER_PULSES_PER_STEP)
|
|
{
|
|
if (lcd_draw_update == 0)
|
|
lcd_draw_update = 1;
|
|
lcd_encoder += lcd_encoder_diff / ENCODER_PULSES_PER_STEP;
|
|
Sound_MakeSound(e_SOUND_TYPE_EncoderMove);
|
|
lcd_encoder_diff = 0;
|
|
lcd_timeoutToStatus.start();
|
|
}
|
|
|
|
if (LCD_CLICKED) lcd_timeoutToStatus.start();
|
|
|
|
(*menu_menu)();
|
|
|
|
if (z_menu_expired() || other_menu_expired() || forced_menu_expire())
|
|
{
|
|
// Exiting a menu. Let's call the menu function the last time with menu_leaving flag set to true
|
|
// to give it a chance to save its state.
|
|
// This is useful for example, when the babystep value has to be written into EEPROM.
|
|
if (menu_menu != NULL)
|
|
{
|
|
menu_leaving = 1;
|
|
(*menu_menu)();
|
|
menu_leaving = 0;
|
|
}
|
|
lcd_clear();
|
|
lcd_return_to_status();
|
|
lcd_draw_update = 2;
|
|
}
|
|
if (lcd_draw_update == 2) lcd_clear();
|
|
if (lcd_draw_update) lcd_draw_update--;
|
|
lcd_next_update_millis = _millis() + LCD_UPDATE_INTERVAL;
|
|
}
|
|
if (!SdFatUtil::test_stack_integrity()) stack_error();
|
|
lcd_ping(); //check that we have received ping command if we are in farm mode
|
|
lcd_send_status();
|
|
if (lcd_commands_type == LcdCommands::Layer1Cal) lcd_commands();
|
|
}
|
|
|
|
#ifdef TMC2130
|
|
//! @brief Is crash detection enabled?
|
|
//!
|
|
//! @retval true crash detection enabled
|
|
//! @retval false crash detection disabled
|
|
bool lcd_crash_detect_enabled()
|
|
{
|
|
return eeprom_read_byte((uint8_t*)EEPROM_CRASH_DET);
|
|
}
|
|
|
|
void lcd_crash_detect_enable()
|
|
{
|
|
tmc2130_sg_stop_on_crash = true;
|
|
eeprom_update_byte((uint8_t*)EEPROM_CRASH_DET, 0xFF);
|
|
}
|
|
|
|
void lcd_crash_detect_disable()
|
|
{
|
|
tmc2130_sg_stop_on_crash = false;
|
|
tmc2130_sg_crash = 0;
|
|
eeprom_update_byte((uint8_t*)EEPROM_CRASH_DET, 0x00);
|
|
}
|
|
#endif
|