Browse Source

Checkpoint:

- Rename lcd_show_multiscreen_message_two_choices_and_wait_P to lcd_show_multiscreen_message_with_choices_and_wait_P

- Move MMU error screen from ReportError() to ReportErrorHook()

- Fix the menu selection to work for menus with either two choices or three choices

- The buttons shown on the MMU error menu are now determined by the definition of btnOperation[]
Guðni Már Gilbert 2 years ago
parent
commit
83fefe10c1
5 changed files with 162 additions and 80 deletions
  1. 5 45
      Firmware/mmu2.cpp
  2. 22 8
      Firmware/mmu2/errors_list.h
  3. 103 2
      Firmware/mmu2_reporting.cpp
  4. 31 24
      Firmware/ultralcd.cpp
  5. 1 1
      Firmware/ultralcd.h

+ 5 - 45
Firmware/mmu2.cpp

@@ -615,56 +615,16 @@ void MMU2::ReportError(ErrorCode ec) {
         // The longest error description in errors_list.h is 144 bytes.
         // and the longest error title is 20 bytes. msg buffer needs
         // to have enough space to fit both.
-        //char msg[192];
-        //int len = snprintf(msg, sizeof(msg), "MMU2:E=%hu ", (uint16_t)ec);
+        char msg[192];
+        int len = snprintf(msg, sizeof(msg), "MMU2:E=%hu ", (uint16_t)ec);
         // Append a human readable form of the error code(s)
-        //TranslateErr((uint16_t)ec, &msg[len], 192 - len);
-
-        const uint16_t ei = MMUErrorCodeIndex((uint16_t)ec);
-          // Testing
-        uint8_t choice_selected = 0;
-        back_to_choices:
-        // 504 = ERR_SYSTEM_VERSION_MISMATCH
-        lcd_clear();
-        lcd_update_enable(false);
-        lcd_printf_P(PSTR("%S\nprusa3d.com/ERR04%hu"),
-            static_cast<const char * const>(pgm_read_ptr(&errorTitles[ei])),
-            reinterpret_cast<uint16_t>(const_cast<void*>(pgm_read_ptr(&errorCodes[ei])))
-        );
-        choice_selected = lcd_show_multiscreen_message_two_choices_and_wait_P(
-            NULL, // NULL, since title screen is not in PROGMEM
-            false,
-            false,
-            btnRetry,
-            btnContinue,
-            btnMore,
-            7,
-            13
-        );
-
-        if (choice_selected == 2) {
-            // 'More' show error description
-            lcd_show_fullscreen_message_and_wait_P(
-                static_cast<const char * const>(pgm_read_ptr(&errorDescs[ei]))
-            );
-
-            // Return back to the choice menu
-            goto back_to_choices;
-        } else if(choice_selected == 1) {
-            // 'Done' return to status screen
-            lcd_update_enable(true);
-            lcd_return_to_status();
-        } else {
-            // 'Retry' TODO: not yet implemented
-            lcd_update_enable(true);
-            lcd_return_to_status();
-        }
+        TranslateErr((uint16_t)ec, &msg[len], 192 - len);
 
         // beware - the prefix in the message ("MMU2") will get stripped by the logging subsystem
         // and a correct MMU2 component will be assigned accordingly - see appmain.cpp
         // Therefore I'm not calling MMU2_ERROR_MSG or MMU2_ECHO_MSG here
-        //SERIAL_ECHO_START;
-        //SERIAL_ECHOLN(msg);
+        SERIAL_ECHO_START;
+        SERIAL_ECHOLN(msg);
     }
 
     static_assert(mmu2Magic[0] == 'M' 

+ 22 - 8
Firmware/mmu2/errors_list.h

@@ -243,17 +243,20 @@ static const char * const errorDescs[] PROGMEM = {
     descRUNTIME_ERROR,
 };
 
+#define BUTTON_OP_HIGH_NIBBLE_MSK 0xF0
+#define BUTTON_OP_LOW_NIBBLE_MSK  0x0F
+
 /// Will be mapped onto dialog button responses in the FW
 /// Those responses have their unique+translated texts as well
 enum class ButtonOperations : uint8_t {
-    NoOperation,
-    Retry,
-    SlowLoad,
-    Continue,
-    RestartMMU,
-    Unload,
-    StopPrint,
-    DisableMMU,
+    NoOperation = 0,
+    Retry       = 1,
+    SlowLoad    = 2,
+    Continue    = 3,
+    RestartMMU  = 4,
+    Unload      = 5,
+    StopPrint   = 6,
+    DisableMMU  = 7,
 };
 
 // we have max 3 buttons/operations to select from
@@ -271,6 +274,17 @@ static const char btnStop[] PROGMEM_I1 = ISTR("Stop");
 static const char btnDisableMMU[] PROGMEM_I1 = ISTR("Disable");
 static const char btnMore[] PROGMEM_I1 = ISTR("More\x01");
 
+// Used to parse the buttons from Btns().
+static const char * const btnOperation[] PROGMEM = {
+    btnRetry,
+    btnSlowLoad,
+    btnContinue,
+    btnRestartMMU,
+    btnUnload,
+    btnStop,
+    btnDisableMMU
+};
+
 // We have 8 different operations/buttons at this time, so we need at least 4 bits to encode each.
 // Since one of the buttons is always "More", we can skip that one.
 // Therefore we need just 1 byte to describe the necessary buttons for each screen.

+ 103 - 2
Firmware/mmu2_reporting.cpp

@@ -1,4 +1,7 @@
 #include "mmu2_reporting.h"
+#include "mmu2_error_converter.h"
+#include "mmu2/error_codes.h"
+#include "mmu2/errors_list.h"
 #include "ultralcd.h"
 
 namespace MMU2 {
@@ -16,8 +19,106 @@ void EndReport(CommandInProgress cip, uint16_t ec) {
 }
 
 void ReportErrorHook(CommandInProgress cip, uint16_t ec) {
-    // @@TODO - display an error screen - we still don't know how that will look like
-    // The only thing we know is the fact, that the screen must not block the MMU automaton
+    //! Show an error screen
+    //! When an MMU error occurs, the LCD content will look like this:
+    //! |01234567890123456789|
+    //! |MMU FW update needed|     <- title/header of the error: max 20 characters
+    //! |prusa3d.com/ERR04504|     <- URL 20 characters
+    //! |                    |     <- empty line
+    //! |>Retry  >Done >MoreW|     <- buttons
+    const uint16_t ei = MMUErrorCodeIndex((uint16_t)ec);
+    uint8_t choice_selected = 0;
+    bool two_choices = false;
+
+    // Read and determine what operations should be shown on the menu
+    // Note: uint16_t is used here to avoid compiler warning. uint8_t is only half the size of void*
+    uint8_t button_operation = reinterpret_cast<uint16_t>(const_cast<void*>(pgm_read_ptr(&errorButtons[ei])));
+    uint8_t button_high_nibble = (button_operation & BUTTON_OP_HIGH_NIBBLE_MSK) >> 4;
+    uint8_t button_low_nibble = button_operation & BUTTON_OP_LOW_NIBBLE_MSK;
+
+    // Check if the menu should have three or two choices
+    if (button_low_nibble == (uint8_t)ButtonOperations::NoOperation)
+    {
+        // Two operations not specified, the error menu should only show two choices
+        two_choices = true;
+    }
+
+back_to_choices:
+    lcd_clear();
+    lcd_update_enable(false);
+
+    // Print title and header
+    lcd_printf_P(PSTR("%S\nprusa3d.com/ERR04%hu"),
+        static_cast<const char * const>(pgm_read_ptr(&errorTitles[ei])),
+        reinterpret_cast<uint16_t>(const_cast<void*>(pgm_read_ptr(&errorCodes[ei])))
+    );
+
+    // Render the choices and store selection in 'choice_selected'
+    choice_selected = lcd_show_multiscreen_message_with_choices_and_wait_P(
+        NULL, // NULL, since title screen is not in PROGMEM
+        false,
+        false,
+        two_choices ?
+            static_cast<const char * const>(pgm_read_ptr(&btnOperation[button_high_nibble - 1]))
+            : static_cast<const char * const>(pgm_read_ptr(&btnOperation[button_low_nibble - 1])),
+        two_choices ?
+            btnMore
+            : static_cast<const char * const>(pgm_read_ptr(&btnOperation[button_high_nibble - 1])),
+        two_choices ? nullptr : btnMore,
+        two_choices ? 
+            10 // If two choices, allow the first choice to have more characters
+            : 7,
+        13
+    );
+
+    if ((two_choices && choice_selected == 1)      // Two choices and middle button selected
+        || (!two_choices && choice_selected == 2)) // Three choices and right most button selected
+    {
+        // 'More' show error description
+        lcd_show_fullscreen_message_and_wait_P(
+            static_cast<const char * const>(pgm_read_ptr(&errorDescs[ei]))
+        );
+
+        // Return back to the choice menu
+        goto back_to_choices;
+    } else if(choice_selected == 1) {
+        // TODO: User selected middle choice, not sure what to do.
+        //       At the moment just return to the status screen
+        switch (button_high_nibble)
+        {
+        case (uint8_t)ButtonOperations::Retry:
+        case (uint8_t)ButtonOperations::SlowLoad:
+        case (uint8_t)ButtonOperations::Continue:
+        case (uint8_t)ButtonOperations::RestartMMU:
+        case (uint8_t)ButtonOperations::Unload:
+        case (uint8_t)ButtonOperations::StopPrint:
+        case (uint8_t)ButtonOperations::DisableMMU:
+        default:
+            lcd_update_enable(true);
+            lcd_return_to_status();
+            break;
+        }
+    } else {
+        // TODO: User selected the left most choice, not sure what to do.
+        //       At the moment just return to the status screen
+        switch ( two_choices ?
+            button_high_nibble
+            : button_low_nibble
+        )
+        {
+        case (uint8_t)ButtonOperations::Retry:
+        case (uint8_t)ButtonOperations::SlowLoad:
+        case (uint8_t)ButtonOperations::Continue:
+        case (uint8_t)ButtonOperations::RestartMMU:
+        case (uint8_t)ButtonOperations::Unload:
+        case (uint8_t)ButtonOperations::StopPrint:
+        case (uint8_t)ButtonOperations::DisableMMU:
+        default:
+            lcd_update_enable(true);
+            lcd_return_to_status();
+            break;
+        }
+    }
 }
 
 void ReportProgressHook(CommandInProgress cip, uint16_t ec) {

+ 31 - 24
Firmware/ultralcd.cpp

@@ -3193,7 +3193,7 @@ lcd_wait_for_click_delay(0);
 //! @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), nullptr, 10);
+    return lcd_show_multiscreen_message_with_choices_and_wait_P(msg, allow_timeouting, default_yes, _T(MSG_YES), _T(MSG_NO), nullptr, 10);
 }
 //! @brief Show a two-choice prompt on the last line of the LCD
 //! @param first_selected Show first choice as selected if true, the second otherwise
@@ -3202,10 +3202,10 @@ int8_t lcd_show_multiscreen_message_yes_no_and_wait_P(const char *msg, bool allo
 void lcd_show_two_choices_prompt_P(uint8_t first_selected, const char *first_choice, const char *second_choice, uint8_t second_col)
 {
     lcd_set_cursor(0, 3);
-    lcd_print(first_selected? '>': ' ');
+    lcd_print(first_selected == 0 ? '>': ' ');
     lcd_puts_P(first_choice);
     lcd_set_cursor(second_col, 3);
-    lcd_print(!first_selected? '>': ' ');
+    lcd_print(first_selected == 1 ? '>': ' ');
     lcd_puts_P(second_choice);
 }
 
@@ -3224,14 +3224,18 @@ void lcd_show_three_choices_prompt_P(uint8_t selected, const char *first_choice,
 
 //! @brief Show single or multiple screen message with two possible choices and wait with possible timeout
 //! @param msg Message to show. If NULL, do not clear the screen and handle choice selection only.
-//! @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
+//! @param allow_timeouting bool, if true, allows time outing of the screen
+//! @param default_first uint8_t, Control which choice is selected first. 0: left most, 1: middle, 2: right most choice. The first choice is selected by default
+//! @param first_choice text caption of first possible choice. Must be in PROGMEM
+//! @param second_choice text caption of second possible choice. Must be in PROGMEM
+//! @param third_choice text caption of second possible choice. Must be in PROGMEM. When not set to nullptr first_choice and second_choice may not be more than 5 characters long.
+//! @param second_col column on LCD where second_choice starts
+//! @param third_col column on LCD where second_choice starts
+//! @retval 0 first choice selected by user
 //! @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,
+//! @retval 2 third choice selected by user
+//! @retval -1 screen timed out (only possible if allow_timeouting is true)
+int8_t lcd_show_multiscreen_message_with_choices_and_wait_P(const char *msg, bool allow_timeouting, bool default_first,
         const char *first_choice, const char *second_choice, const char *third_choice, uint8_t second_col, uint8_t third_col)
 {
 	const char *msg_next = msg ? lcd_display_message_fullscreen_P(msg) : NULL;
@@ -3242,7 +3246,7 @@ int8_t lcd_show_multiscreen_message_two_choices_and_wait_P(const char *msg, bool
 	uint8_t yes = default_first ? 1 : 0;
 	if (!msg_next) {
 		if (third_choice)
-		{ // third_choice is not nullptr, safe to derefence
+		{ // third_choice is not nullptr, safe to dereference
 			lcd_show_three_choices_prompt_P(yes, first_choice, second_choice, third_choice, second_col, third_col);
 		} else {
 			lcd_show_two_choices_prompt_P(yes, first_choice, second_choice, second_col);
@@ -3265,21 +3269,24 @@ int8_t lcd_show_multiscreen_message_two_choices_and_wait_P(const char *msg, bool
 
 			if (abs(enc_dif - lcd_encoder_diff) >= ENCODER_PULSES_PER_STEP) {
 				if (msg_next == NULL) {
-					if (enc_dif > lcd_encoder_diff) {
-						// Rotating knob counter clockwise
-						if (yes != 0) yes = yes - 1;
-					}
-
-					else if (enc_dif < lcd_encoder_diff) {
-						// Rotating knob clockwise
-						if (yes != 2) yes = yes + 1;
-					}
-
-					// Render the options:
 					if (third_choice)
-					{ // third_choice is not nullptr, safe to derefence
+					{ // third_choice is not nullptr, safe to dereference
+						if (enc_dif > lcd_encoder_diff && yes != 0) {
+							// Rotating knob counter clockwise
+							yes = yes - 1;
+						} else if (enc_dif < lcd_encoder_diff && yes != 2) {
+							// Rotating knob clockwise
+							yes = yes + 1;
+						}
 						lcd_show_three_choices_prompt_P(yes, first_choice, second_choice, third_choice, second_col, third_col);
 					} else {
+						if (enc_dif > lcd_encoder_diff && yes != 0) {
+							// Rotating knob counter clockwise
+							yes = 0;
+						} else if (enc_dif < lcd_encoder_diff && yes != 1) {
+							// Rotating knob clockwise
+							yes = 1;
+						}
 						lcd_show_two_choices_prompt_P(yes, first_choice, second_choice, second_col);
 					}
 					enc_dif = lcd_encoder_diff;
@@ -3309,7 +3316,7 @@ int8_t lcd_show_multiscreen_message_two_choices_and_wait_P(const char *msg, bool
 		}
 		if (msg_next == NULL) {
 			if (third_choice)
-			{ // third_choice is not nullptr, safe to derefence
+			{ // third_choice is not nullptr, safe to dereference
 				lcd_show_three_choices_prompt_P(yes, first_choice, second_choice, third_choice, second_col, third_col);
 			} else {
 				lcd_show_two_choices_prompt_P(yes, first_choice, second_choice, second_col);

+ 1 - 1
Firmware/ultralcd.h

@@ -75,7 +75,7 @@ extern void lcd_show_fullscreen_message_and_wait_P(const char *msg);
 extern int8_t lcd_show_yes_no_and_wait(bool allow_timeouting = true, bool default_yes = false);
 // 0: no, 1: yes, -1: timeouted
 extern int8_t lcd_show_fullscreen_message_yes_no_and_wait_P(const char *msg, bool allow_timeouting = true, bool default_yes = false);
-extern int8_t lcd_show_multiscreen_message_two_choices_and_wait_P(const char *msg, bool allow_timeouting, bool default_yes,
+extern int8_t lcd_show_multiscreen_message_with_choices_and_wait_P(const char *msg, bool allow_timeouting, bool default_yes,
         const char *first_choice, const char *second_choice, const char *third_choice = nullptr, uint8_t second_col = 7, uint8_t third_col = 13);
 extern int8_t lcd_show_multiscreen_message_yes_no_and_wait_P(const char *msg, bool allow_timeouting = true, bool default_yes = false);
 // Ask the user to move the Z axis up to the end stoppers and let