diff --git a/Firmware/Configuration.h b/Firmware/Configuration.h index 20296e399..c08050469 100644 --- a/Firmware/Configuration.h +++ b/Firmware/Configuration.h @@ -7,12 +7,12 @@ #define STR(x) STR_HELPER(x) // Firmware version -#define FW_VERSION "3.1.2-alpha" -#define FW_COMMIT_NR 255 +#define FW_VERSION "3.1.3" +#define FW_COMMIT_NR 309 // FW_VERSION_UNKNOWN means this is an unofficial build. // The firmware should only be checked into github with this symbol. #define FW_DEV_VERSION FW_VERSION_UNKNOWN -#define FW_REPOSITORY "Prusa3D/MK3" +#define FW_REPOSITORY "Unknown" #define FW_VERSION_FULL FW_VERSION "-" STR(FW_COMMIT_NR) // Debug version has debugging enabled (the symbol DEBUG_BUILD is set). diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp index 102482401..70b77f680 100644 --- a/Firmware/Marlin_main.cpp +++ b/Firmware/Marlin_main.cpp @@ -54,6 +54,7 @@ #include "pins_arduino.h" #include "math.h" #include "util.h" +#include "Timer.h" #include @@ -3228,7 +3229,8 @@ void process_commands() #ifdef PINDA_THERMISTOR if (true) { - if (!(axis_known_position[X_AXIS] && axis_known_position[Y_AXIS] && axis_known_position[Z_AXIS])) { + if (!(axis_known_position[X_AXIS] && axis_known_position[Y_AXIS] && axis_known_position[Z_AXIS])) + { // We don't know where we are! HOME! // Push the commands to the front of the message queue in the reverse order! // There shall be always enough space reserved for these commands. @@ -3238,7 +3240,14 @@ void process_commands() } lcd_show_fullscreen_message_and_wait_P(MSG_TEMP_CAL_WARNING); bool result = lcd_show_fullscreen_message_yes_no_and_wait_P(MSG_STEEL_SHEET_CHECK, false, false); - if (result) lcd_show_fullscreen_message_and_wait_P(MSG_REMOVE_STEEL_SHEET); + if (result) + { + current_position[Z_AXIS] = 50; + current_position[Y_AXIS] = 190; + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3000 / 60, active_extruder); + st_synchronize(); + lcd_show_fullscreen_message_and_wait_P(MSG_REMOVE_STEEL_SHEET); + } lcd_update_enable(true); KEEPALIVE_STATE(NOT_BUSY); //no need to print busy messages as we print current temperatures periodicaly SERIAL_ECHOLNPGM("PINDA probe calibration start"); @@ -6720,6 +6729,31 @@ void handle_status_leds(void) { } #endif +#ifdef SAFETYTIMER +/** + * @brief Turn off heating after 15 minutes of inactivity + */ +static void handleSafetyTimer() +{ + static_assert(EXTRUDERS == 1,"Implemented only for one extruder."); + static Timer safetyTimer; + if (IS_SD_PRINTING || is_usb_printing || (custom_message_type == 4) || (lcd_commands_type == LCD_COMMAND_V2_CAL) || + (!degTargetBed() && !degTargetHotend(0))) + { + safetyTimer.stop(); + } + else if ((degTargetBed() || degTargetHotend(0)) && (!safetyTimer.running())) + { + safetyTimer.start(); + } + else if (safetyTimer.expired(15*60*1000)) + { + setTargetBed(0); + setTargetHotend(0, 0); + } +} +#endif //SAFETYTIMER + void manage_inactivity(bool ignore_stepper_queue/*=false*/) //default argument set in Marlin.h { #ifdef PAT9125 @@ -6763,18 +6797,7 @@ void manage_inactivity(bool ignore_stepper_queue/*=false*/) //default argument s #endif //PAT9125 #ifdef SAFETYTIMER - static uint32_t safety_timer = 0; - if (degTargetBed() || degTargetHotend(0)) - { - if ((safety_timer == 0) || IS_SD_PRINTING || is_usb_printing || (custom_message_type == 4) || (lcd_commands_type == LCD_COMMAND_V2_CAL)) - safety_timer = millis(); - else if ((safety_timer + (15*60*1000)) < millis()) - { - setTargetBed(0); - setTargetHotend(0, 0); - safety_timer = 0; - } - } + handleSafetyTimer(); #endif //SAFETYTIMER diff --git a/Firmware/MenuStack.cpp b/Firmware/MenuStack.cpp new file mode 100644 index 000000000..5e17a7d92 --- /dev/null +++ b/Firmware/MenuStack.cpp @@ -0,0 +1,29 @@ +/** + * @file + * @author Marek Bel + */ + +#include "MenuStack.h" +/** + * @brief Push menu on stack + * @param menu + * @param position selected position in menu being pushed + */ +void MenuStack::push(menuFunc_t menu, uint8_t position) +{ + if (m_index >= max_depth) return; + m_stack[m_index].menu = menu; + m_stack[m_index].position = position; + ++m_index; +} + +/** + * @brief Pop menu from stack + * @return Record containing menu function pointer and previously selected line number + */ +MenuStack::Record MenuStack::pop() +{ + if (m_index != 0) m_index--; + + return m_stack[m_index]; +} diff --git a/Firmware/MenuStack.h b/Firmware/MenuStack.h new file mode 100644 index 000000000..04754449c --- /dev/null +++ b/Firmware/MenuStack.h @@ -0,0 +1,34 @@ +/** + * @file + * @author Marek Bel + */ + +#ifndef MENUSTACK_H +#define MENUSTACK_H + +#include + +/** Pointer to function implementing menu.*/ +typedef void (*menuFunc_t)(); +/** + * @brief Stack implementation for navigating menu structure + */ +class MenuStack +{ +public: + struct Record + { + menuFunc_t menu; + uint8_t position; + }; + MenuStack():m_stack(),m_index(0) {} + void push(menuFunc_t menu, uint8_t position); + Record pop(); + void reset(){m_index = 0;} +private: + static const int max_depth = 4; + Record m_stack[max_depth]; + uint8_t m_index; +}; + +#endif /* FIRMWARE_MENUSTACK_H_ */ diff --git a/Firmware/Timer.cpp b/Firmware/Timer.cpp new file mode 100644 index 000000000..78f47a45b --- /dev/null +++ b/Firmware/Timer.cpp @@ -0,0 +1,55 @@ +/** + * @file + * @author Marek Bel + */ + +#include "Timer.h" +#include "Arduino.h" + +Timer::Timer() : m_isRunning(false), m_started() +{ +} + +/** + * @brief Start timer + */ +void Timer::start() +{ + m_started = millis(); + m_isRunning = true; +} + +/** + * @brief Timer has expired + * + * Timer is considered expired after msPeriod has passed from time the timer was started. + * This function must be called at least each (unsigned long maximum value - msPeriod) milliseconds to be sure to + * catch first expiration. + * This function is expected to handle wrap around of time register well. + * + * @param msPeriod Time interval in milliseconds. + * @retval true Timer has expired + * @retval false Timer not expired yet, or is not running, or time window in which is timer considered expired passed. + */ +bool Timer::expired(unsigned long msPeriod) +{ + if (!m_isRunning) return false; + bool expired = false; + const unsigned long now = millis(); + if (m_started <= m_started + msPeriod) + { + if ((now >= m_started + msPeriod) || (now < m_started)) + { + expired = true; + } + } + else + { + if ((now >= m_started + msPeriod) && (now < m_started)) + { + expired = true; + } + } + if (expired) m_isRunning = false; + return expired; +} diff --git a/Firmware/Timer.h b/Firmware/Timer.h new file mode 100644 index 000000000..0d3a89dcb --- /dev/null +++ b/Firmware/Timer.h @@ -0,0 +1,30 @@ +/* + * @file + * @author Marek Bel + */ + +#ifndef TIMER_H +#define TIMER_H + +/** + * @brief simple timer + * + * Simple and memory saving implementation. Should handle timer register wrap around well. + * Maximum period is at least 49 days. Resolution is one millisecond. To save memory, doesn't store timer period. + * If you wish timer which is storing period, derive from this. If you need time intervals smaller than 65 seconds + * consider implementing timer with smaller underlying type. + */ +class Timer +{ +public: + Timer(); + void start(); + void stop(){m_isRunning = false;} + bool running(){return m_isRunning;} + bool expired(unsigned long msPeriod); +private: + bool m_isRunning; + unsigned long m_started; +}; + +#endif /* TIMER_H */ diff --git a/Firmware/language_all.cpp b/Firmware/language_all.cpp index 3eb8ba85b..1df6655c2 100644 --- a/Firmware/language_all.cpp +++ b/Firmware/language_all.cpp @@ -61,8 +61,10 @@ const char * const MSG_AUTO_HOME_LANG_TABLE[1] PROGMEM = { }; const char MSG_AUTO_MODE_ON_EN[] PROGMEM = "Mode [auto power]"; -const char * const MSG_AUTO_MODE_ON_LANG_TABLE[1] PROGMEM = { - MSG_AUTO_MODE_ON_EN +const char MSG_AUTO_MODE_ON_CZ[] PROGMEM = "Mod [automaticky]"; +const char * const MSG_AUTO_MODE_ON_LANG_TABLE[LANG_NUM] PROGMEM = { + MSG_AUTO_MODE_ON_EN, + MSG_AUTO_MODE_ON_CZ }; const char MSG_A_RETRACT_EN[] PROGMEM = "A-retract"; @@ -1986,14 +1988,14 @@ const char * const MSG_SHOW_END_STOPS_LANG_TABLE[LANG_NUM] PROGMEM = { }; const char MSG_SILENT_MODE_OFF_EN[] PROGMEM = "Mode [high power]"; -const char MSG_SILENT_MODE_OFF_CZ[] PROGMEM = "Mod [Normal]"; +const char MSG_SILENT_MODE_OFF_CZ[] PROGMEM = "Mod [vys. vykon]"; const char * const MSG_SILENT_MODE_OFF_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_SILENT_MODE_OFF_EN, MSG_SILENT_MODE_OFF_CZ }; const char MSG_SILENT_MODE_ON_EN[] PROGMEM = "Mode [silent]"; -const char MSG_SILENT_MODE_ON_CZ[] PROGMEM = "Mod [Stealth]"; +const char MSG_SILENT_MODE_ON_CZ[] PROGMEM = "Mod [tichy]"; const char * const MSG_SILENT_MODE_ON_LANG_TABLE[LANG_NUM] PROGMEM = { MSG_SILENT_MODE_ON_EN, MSG_SILENT_MODE_ON_CZ diff --git a/Firmware/language_all.h b/Firmware/language_all.h index bbc8e6fef..fb1daedf9 100644 --- a/Firmware/language_all.h +++ b/Firmware/language_all.h @@ -40,8 +40,8 @@ extern const char* const MSG_AUTOLOAD_FILAMENT_LANG_TABLE[LANG_NUM]; #define MSG_AUTOLOAD_FILAMENT LANG_TABLE_SELECT(MSG_AUTOLOAD_FILAMENT_LANG_TABLE) extern const char* const MSG_AUTO_HOME_LANG_TABLE[1]; #define MSG_AUTO_HOME LANG_TABLE_SELECT_EXPLICIT(MSG_AUTO_HOME_LANG_TABLE, 0) -extern const char* const MSG_AUTO_MODE_ON_LANG_TABLE[1]; -#define MSG_AUTO_MODE_ON LANG_TABLE_SELECT_EXPLICIT(MSG_AUTO_MODE_ON_LANG_TABLE, 0) +extern const char* const MSG_AUTO_MODE_ON_LANG_TABLE[LANG_NUM]; +#define MSG_AUTO_MODE_ON LANG_TABLE_SELECT(MSG_AUTO_MODE_ON_LANG_TABLE) extern const char* const MSG_A_RETRACT_LANG_TABLE[1]; #define MSG_A_RETRACT LANG_TABLE_SELECT_EXPLICIT(MSG_A_RETRACT_LANG_TABLE, 0) extern const char* const MSG_BABYSTEPPING_X_LANG_TABLE[1]; diff --git a/Firmware/language_cz.h b/Firmware/language_cz.h index 355b786e8..8e05ff318 100644 --- a/Firmware/language_cz.h +++ b/Firmware/language_cz.h @@ -103,8 +103,9 @@ #define MSG_INSERT_FILAMENT "Vlozte filament" #define MSG_CHANGING_FILAMENT "Vymena filamentu!" -#define MSG_SILENT_MODE_ON "Mod [Stealth]" -#define MSG_SILENT_MODE_OFF "Mod [Normal]" +#define MSG_SILENT_MODE_ON "Mod [tichy]" +#define MSG_SILENT_MODE_OFF "Mod [vys. vykon]" +#define MSG_AUTO_MODE_ON "Mod [automaticky]" #define MSG_REBOOT "Restartujte tiskarnu" #define MSG_TAKE_EFFECT " pro projeveni zmen" diff --git a/Firmware/mesh_bed_calibration.cpp b/Firmware/mesh_bed_calibration.cpp index 8db94cd42..322acbef1 100644 --- a/Firmware/mesh_bed_calibration.cpp +++ b/Firmware/mesh_bed_calibration.cpp @@ -20,7 +20,7 @@ float world2machine_shift[2]; #define WEIGHT_FIRST_ROW_Y_LOW (0.0f) #define BED_ZERO_REF_X (- 22.f + X_PROBE_OFFSET_FROM_EXTRUDER) // -22 + 23 = 1 -#define BED_ZERO_REF_Y (- 0.6f + Y_PROBE_OFFSET_FROM_EXTRUDER) // -0.6 + 5 = 4.4 +#define BED_ZERO_REF_Y (- 0.6f + Y_PROBE_OFFSET_FROM_EXTRUDER + 4) // -0.6 + 5 = 4.4 // Scaling of the real machine axes against the programmed dimensions in the firmware. // The correction is tiny, here around 0.5mm on 250mm length. @@ -56,10 +56,10 @@ const float bed_skew_angle_extreme = (0.25f * M_PI / 180.f); // Positions of the bed reference points in the machine coordinates, referenced to the P.I.N.D.A sensor. // The points are the following: center front, center right, center rear, center left. const float bed_ref_points_4[] PROGMEM = { - 13.f - BED_ZERO_REF_X, 10.4f - 4.f - BED_ZERO_REF_Y, - 221.f - BED_ZERO_REF_X, 10.4f - 4.f - BED_ZERO_REF_Y, - 221.f - BED_ZERO_REF_X, 202.4f - 4.f - BED_ZERO_REF_Y, - 13.f - BED_ZERO_REF_X, 202.4f - 4.f - BED_ZERO_REF_Y + 13.f - BED_ZERO_REF_X, 10.4f - BED_ZERO_REF_Y, + 221.f - BED_ZERO_REF_X, 10.4f - BED_ZERO_REF_Y, + 221.f - BED_ZERO_REF_X, 202.4f - BED_ZERO_REF_Y, + 13.f - BED_ZERO_REF_X, 202.4f - BED_ZERO_REF_Y }; const float bed_ref_points[] PROGMEM = { diff --git a/Firmware/ultralcd.cpp b/Firmware/ultralcd.cpp index b892dca5e..84f8ed2e1 100644 --- a/Firmware/ultralcd.cpp +++ b/Firmware/ultralcd.cpp @@ -1,6 +1,7 @@ #include "temperature.h" #include "ultralcd.h" #ifdef ULTRA_LCD +#include "MenuStack.h" #include "Marlin.h" #include "language.h" #include "cardreader.h" @@ -39,7 +40,7 @@ extern bool fsensor_enabled; #endif //PAT9125 //Function pointer to menu functions. -typedef void (*menuFunc_t)(); + static void lcd_sd_updir(); @@ -91,6 +92,18 @@ union MenuData int rear2; } adjustBed; + struct TuneMenu + { + // editMenuParentState is used when an edit menu is entered, so it knows + // the return menu and encoder state. + struct EditMenuParentState editMenuParentState; + // To recognize, whether the menu has been just initialized. + int8_t status; + // Backup of extrudemultiply, to recognize, that the value has been changed and + // it needs to be applied. + int16_t extrudemultiply; + } tuneMenu; + // editMenuParentState is used when an edit menu is entered, so it knows // the return menu and encoder state. struct EditMenuParentState editMenuParentState; @@ -105,7 +118,7 @@ union Data byte b[2]; int value; }; - +static MenuStack menuStack; int8_t ReInitLCD = 0; int8_t SDscrool = 0; @@ -223,7 +236,7 @@ static void lcd_delta_calibrate_menu(); static void lcd_quick_feedback();//Cause an LCD refresh, and give the user visual or audible feedback that something has happened /* Different types of actions that can be used in menu items. */ -static void menu_action_back(menuFunc_t data); +static void menu_action_back(menuFunc_t data = 0); #define menu_action_back_RAM menu_action_back static void menu_action_submenu(menuFunc_t data); static void menu_action_gcode(const char* pgcode); @@ -320,14 +333,12 @@ volatile uint8_t slow_buttons;//Contains the bits of the currently pressed butto uint8_t currentMenuViewOffset; /* scroll offset in the current menu */ uint8_t lastEncoderBits; uint16_t encoderPosition; -uint16_t savedEncoderPosition; #if (SDCARDDETECT > 0) bool lcd_oldcardstatus; #endif #endif //ULTIPANEL menuFunc_t currentMenu = lcd_status_screen; /* function pointer to the currently active menu */ -menuFunc_t savedMenu; uint32_t lcd_next_update_millis; uint8_t lcd_status_update_delay; bool ignore_click = false; @@ -339,6 +350,25 @@ uint8_t lcdDrawUpdate = 2; /* Set to none-zero when the LCD nee // float raw_Ki, raw_Kd; #endif + +/** + * @brief Go to menu + * + * In MENU_ITEM(submenu,... ) use MENU_ITEM(back,...) or + * menu_action_back() and menu_action_submenu() instead, otherwise menuStack will be broken. + * + * It is acceptable to call lcd_goto_menu(menu) directly from MENU_ITEM(function,...), if destination menu + * is the same, from which function was called. + * + * @param menu target menu + * @param encoder position in target menu + * @param feedback + * * true sound feedback (click) + * * false no feedback + * @param reset_menu_state + * * true reset menu state global union + * * false do not reset menu state global union + */ static void lcd_goto_menu(menuFunc_t menu, const uint32_t encoder = 0, const bool feedback = true, bool reset_menu_state = true) { asm("cli"); @@ -510,8 +540,8 @@ static void lcd_status_screen() if (current_click && (lcd_commands_type != LCD_COMMAND_STOP_PRINT)) //click is aborted unless stop print finishes { - - lcd_goto_menu(lcd_main_menu); + menuStack.reset(); //redundant, as already done in lcd_return_to_status(), just to be sure + menu_action_submenu(lcd_main_menu); lcd_implementation_init( // to maybe revive the LCD if static electricity killed it. #if defined(LCD_PROGRESS_BAR) && defined(SDSUPPORT) currentMenu == lcd_status_screen @@ -955,7 +985,8 @@ void lcd_commands() { lcd_implementation_clear(); - lcd_goto_menu(lcd_babystep_z, 0, false); + menuStack.reset(); + menu_action_submenu(lcd_babystep_z); enquecommand_P(PSTR("G1 X60.0 E9.0 F1000.0")); //intro line enquecommand_P(PSTR("G1 X100.0 E12.5 F1000.0")); //intro line enquecommand_P(PSTR("G92 E0.0")); @@ -1365,6 +1396,7 @@ static void lcd_return_to_status() { ); lcd_goto_menu(lcd_status_screen, 0, false); + menuStack.reset(); } @@ -1517,7 +1549,7 @@ static void lcd_menu_extruder_info() lcd.print(itostr3(pat9125_b)); // 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 + /* 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. */ @@ -1617,9 +1649,7 @@ static void lcd_menu_fails_stats() fprintf_P(lcdout, PSTR(ESC_H(0,0)"Last print failures"ESC_H(1,1)"Filam. runouts %-3d"ESC_H(0,2)"Total failures"ESC_H(1,3)"Filam. runouts %-3d"), filamentLast, filamentTotal); if (lcd_clicked()) { - lcd_quick_feedback(); - //lcd_return_to_status(); - lcd_goto_menu(lcd_main_menu, 8); //TODO: Remove hard coded encoder value. + menu_action_back(); } } #endif //TMC2130 @@ -1802,13 +1832,13 @@ static void lcd_support_menu() void lcd_set_fan_check() { fans_check_enabled = !fans_check_enabled; eeprom_update_byte((unsigned char *)EEPROM_FAN_CHECK_ENABLED, fans_check_enabled); - lcd_goto_menu(lcd_settings_menu, 8); + lcd_goto_menu(lcd_settings_menu); //doesn't break menuStack } void lcd_set_filament_autoload() { filament_autoload_enabled = !filament_autoload_enabled; eeprom_update_byte((unsigned char *)EEPROM_FSENS_AUTOLOAD_ENABLED, filament_autoload_enabled); - lcd_goto_menu(lcd_settings_menu, 8); + lcd_goto_menu(lcd_settings_menu); //doesn't break menuStack } void lcd_unLoadFilament() @@ -2184,7 +2214,7 @@ static void _lcd_move(const char *name, int axis, int min, int max) { } } if (lcdDrawUpdate) lcd_implementation_drawedit(name, ftostr31(current_position[axis])); - if (LCD_CLICKED) lcd_goto_menu(lcd_move_menu_axis); { + if (LCD_CLICKED) menu_action_back(); { } } @@ -2206,7 +2236,7 @@ static void lcd_move_e() { lcd_implementation_drawedit(PSTR("Extruder"), ftostr31(current_position[E_AXIS])); } - if (LCD_CLICKED) lcd_goto_menu(lcd_move_menu_axis); + if (LCD_CLICKED) menu_action_back(); } else { lcd_implementation_clear(); @@ -2358,7 +2388,7 @@ static void _lcd_babystep(int axis, const char *msg) (axis == 0) ? EEPROM_BABYSTEP_X : ((axis == 1) ? EEPROM_BABYSTEP_Y : EEPROM_BABYSTEP_Z), &menuData.babyStep.babystepMem[axis]); } - if (LCD_CLICKED) lcd_goto_menu(lcd_main_menu); + if (LCD_CLICKED) menu_action_back(); } static void lcd_babystep_x() { @@ -2373,6 +2403,14 @@ static void lcd_babystep_z() { static void lcd_adjust_bed(); +/** + * @brief adjust bed reset menu item function + * + * To be used as MENU_ITEM(function,...) inside lcd_adjust_bed submenu. In such case lcd_goto_menu usage + * is correct and doesn't break menuStack. + * Because we did not leave the menu, the menuData did not reset. + * Force refresh of the bed leveling data. + */ static void lcd_adjust_bed_reset() { eeprom_update_byte((unsigned char*)EEPROM_BED_CORRECTION_VALID, 1); @@ -2380,9 +2418,7 @@ static void lcd_adjust_bed_reset() 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); - lcd_goto_menu(lcd_adjust_bed, 0, false); - // Because we did not leave the menu, the menuData did not reset. - // Force refresh of the bed leveling data. + lcd_goto_menu(lcd_adjust_bed, 0, false); //doesn't break menuStack menuData.adjustBed.status = 0; } @@ -3006,7 +3042,7 @@ static void lcd_show_end_stops() { static void menu_show_end_stops() { lcd_show_end_stops(); - if (LCD_CLICKED) lcd_goto_menu(lcd_calibration_menu); + if (LCD_CLICKED) lcd_goto_menu(lcd_calibration_menu); //doesn't break menuStack } // Lets the user move the Z carriage up to the end stoppers. @@ -3394,7 +3430,7 @@ static void lcd_sort_type_set() { } eeprom_update_byte((unsigned char *)EEPROM_SD_SORT, sdSort); presort_flag = true; - lcd_goto_menu(lcd_settings_menu, 8); + lcd_goto_menu(lcd_settings_menu); //doesn't break menuStack } #endif //SDCARD_SORT_ALPHA @@ -3518,8 +3554,8 @@ static void lcd_fsensor_state_set() lcd_fsensor_fail(); } } - if (IS_SD_PRINTING || is_usb_printing || (lcd_commands_type == LCD_COMMAND_V2_CAL)) lcd_goto_menu(lcd_tune_menu, 7); - else lcd_goto_menu(lcd_settings_menu, 7); + if (IS_SD_PRINTING || is_usb_printing || (lcd_commands_type == LCD_COMMAND_V2_CAL)) lcd_goto_menu(lcd_tune_menu); + else lcd_goto_menu(lcd_settings_menu); //doesn't break menuStack } #endif //PAT9125 @@ -3584,16 +3620,18 @@ void lcd_temp_calibration_set() { temp_cal_active = !temp_cal_active; eeprom_update_byte((unsigned char *)EEPROM_TEMP_CAL_ACTIVE, temp_cal_active); digipot_init(); - lcd_goto_menu(lcd_settings_menu, 10); + lcd_goto_menu(lcd_settings_menu); //doesn't break menuStack } +#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); - lcd_goto_menu(lcd_settings_menu, 11); + lcd_goto_menu(lcd_settings_menu);//doesn't break menuStack } +#endif //HAS_SECOND_SERIAL_PORT void lcd_calibrate_pinda() { enquecommand_P(PSTR("G76")); @@ -4607,7 +4645,7 @@ static void lcd_disable_farm_mode() { lcd_return_to_status(); } else { - lcd_goto_menu(lcd_settings_menu); + lcd_goto_menu(lcd_settings_menu); //doesn't break menuStack } lcd_update_enable(true); lcdDrawUpdate = 2; @@ -5326,7 +5364,17 @@ static void lcd_colorprint_change() { static void lcd_tune_menu() { - EEPROM_read(EEPROM_SILENT, (uint8_t*)&SilentModeMenu, sizeof(SilentModeMenu)); + if (menuData.tuneMenu.status == 0) { + // Menu was entered. Mark the menu as entered and save the current extrudemultiply value. + menuData.tuneMenu.status = 1; + menuData.tuneMenu.extrudemultiply = extrudemultiply; + } else if (menuData.tuneMenu.extrudemultiply != extrudemultiply) { + // extrudemultiply has been changed from the child menu. Apply the new value. + menuData.tuneMenu.extrudemultiply = extrudemultiply; + calculate_extruder_multipliers(); + } + + EEPROM_read(EEPROM_SILENT, (uint8_t*)&SilentModeMenu, sizeof(SilentModeMenu)); @@ -6647,32 +6695,24 @@ static void lcd_quick_feedback() lcd_implementation_quick_feedback(); } -#define ENC_STACK_SIZE 3 -static uint8_t enc_stack[ENC_STACK_SIZE]; //encoder is originaly uint16, but for menu -static uint8_t enc_stack_cnt = 0; - -static void lcd_push_encoder(void) -{ - if (enc_stack_cnt >= ENC_STACK_SIZE) return; - enc_stack[enc_stack_cnt] = encoderPosition; - enc_stack_cnt++; -} - -static void lcd_pop_encoder(void) -{ - if (enc_stack_cnt == 0) return; - enc_stack_cnt--; - encoderPosition = enc_stack[enc_stack_cnt]; -} - - /** Menu action functions **/ -static void menu_action_back(menuFunc_t data) { - lcd_goto_menu(data); - lcd_pop_encoder(); + +/** + * @brief Go up in menu structure + * @param data unused parameter + */ +static void menu_action_back(menuFunc_t data) +{ + MenuStack::Record record = menuStack.pop(); + lcd_goto_menu(record.menu); + encoderPosition = record.position; } +/** + * @brief Go deeper into menu structure + * @param data nested menu + */ static void menu_action_submenu(menuFunc_t data) { - lcd_push_encoder(); + menuStack.push(currentMenu, encoderPosition); lcd_goto_menu(data); } static void menu_action_gcode(const char* pgcode) { @@ -7093,10 +7133,6 @@ void lcd_buttons_update() if (millis() > button_blanking_time) { button_blanking_time = millis() + BUTTON_BLANKING_TIME; if (button_pressed == false && long_press_active == false) { - if (currentMenu != lcd_move_z) { - savedMenu = currentMenu; - savedEncoderPosition = encoderPosition; - } long_press_timer = millis(); button_pressed = true; } @@ -7105,7 +7141,7 @@ void lcd_buttons_update() long_press_active = true; move_menu_scale = 1.0; - lcd_goto_menu(lcd_move_z); + menu_action_submenu(lcd_move_z); } } } @@ -7115,13 +7151,7 @@ void lcd_buttons_update() button_blanking_time = millis() + BUTTON_BLANKING_TIME; if (long_press_active == false) { //button released before long press gets activated - if (currentMenu == lcd_move_z) { - //return to previously active menu and previous encoder position - lcd_goto_menu(savedMenu, savedEncoderPosition); - } - else { newbutton |= EN_C; - } } else if (currentMenu == lcd_move_z) lcd_quick_feedback(); //button_pressed is set back to false via lcd_quick_feedback function