Browse Source

Merge pull request #536 from mkbel/menu_return

Menu return
XPila 7 years ago
parent
commit
f487691070
3 changed files with 131 additions and 60 deletions
  1. 29 0
      Firmware/MenuStack.cpp
  2. 34 0
      Firmware/MenuStack.h
  3. 68 60
      Firmware/ultralcd.cpp

+ 29 - 0
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];
+}

+ 34 - 0
Firmware/MenuStack.h

@@ -0,0 +1,34 @@
+/**
+ * @file
+ * @author Marek Bel
+ */
+
+#ifndef MENUSTACK_H
+#define MENUSTACK_H
+
+#include <stdint.h>
+
+/** 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_ */

+ 68 - 60
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();
 
@@ -117,7 +118,7 @@ union Data
   byte b[2];
   int value;
 };
-
+static MenuStack menuStack;
 int8_t ReInitLCD = 0;
 
 int8_t SDscrool = 0;
@@ -235,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);
@@ -332,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;
@@ -351,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");
@@ -522,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
@@ -967,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"));
@@ -1377,6 +1396,7 @@ static void lcd_return_to_status() {
   );
 
     lcd_goto_menu(lcd_status_screen, 0, false);
+    menuStack.reset();
 }
 
 
@@ -1529,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 chips 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. */
@@ -1629,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
@@ -1814,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()
@@ -2196,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(); {
   }
 }
 
@@ -2218,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();
@@ -2370,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() {
@@ -2385,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);
@@ -2392,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;
 }
 
@@ -3018,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.
@@ -3406,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
 
@@ -3530,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
@@ -3596,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"));
@@ -4619,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;
@@ -6669,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++;
-}
+/** Menu action functions **/
 
-static void lcd_pop_encoder(void)
+/**
+ * @brief Go up in menu structure
+ * @param data unused parameter
+ */
+static void menu_action_back(menuFunc_t data)
 {
-	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();
+    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) {
@@ -7115,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;
 			  }
@@ -7127,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);
 				  }
 			  }
 		  }
@@ -7137,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