Merge pull request #536 from mkbel/menu_return

Menu return
This commit is contained in:
XPila 2018-03-13 14:30:48 +01:00 committed by GitHub
commit f487691070
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 132 additions and 61 deletions

29
Firmware/MenuStack.cpp Normal file
View File

@ -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
Firmware/MenuStack.h Normal file
View File

@ -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_ */

View File

@ -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++;
}
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) {
@ -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