Example #1
0
/* Main status screen. It's up to the implementation specific part to show what is needed. As this is very display dependend */
static void lcd_status_screen()
{
    if (lcd_status_update_delay)
        lcd_status_update_delay--;
    else
        lcdDrawUpdate = 1;
    if (lcdDrawUpdate)
    {
        lcd_implementation_status_screen();
        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 */
    }
#ifdef ULTIPANEL
    if (LCD_CLICKED)
    {
        currentMenu = lcd_main_menu;
        encoderPosition = 0;
        lcd_quick_feedback();
    }

    // Dead zone at 100% feedrate
    if ((feedmultiply < 100 && (feedmultiply + int(encoderPosition)) > 100) ||
            (feedmultiply > 100 && (feedmultiply + int(encoderPosition)) < 100))
    {
        encoderPosition = 0;
        feedmultiply = 100;
    }

    if (feedmultiply == 100 && int(encoderPosition) > ENCODER_FEEDRATE_DEADZONE)
    {
        feedmultiply += int(encoderPosition) - ENCODER_FEEDRATE_DEADZONE;
        encoderPosition = 0;
    }
    else if (feedmultiply == 100 && int(encoderPosition) < -ENCODER_FEEDRATE_DEADZONE)
    {
        feedmultiply += int(encoderPosition) + ENCODER_FEEDRATE_DEADZONE;
        encoderPosition = 0;	
    }
    else if (feedmultiply != 100)
    {
        feedmultiply += int(encoderPosition);
        encoderPosition = 0;
    }

    if (feedmultiply < 10)
        feedmultiply = 10;
    if (feedmultiply > 999)
        feedmultiply = 999;
#endif//ULTIPANEL
}
static void lcd_move_e()
{
    if (blocking_enc>=millis() || LCD_CLICKED)
    {
        while (movesplanned() < 3)
        {
            current_position[E_AXIS] += 0.5;
            lcd_implementation_drawedit(PSTR("Extruder"), ftostr31(current_position[E_AXIS]));
            plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 3, active_extruder);
        }
    }else{
        lcd_quick_feedback();
        currentMenu = lcd_move_menu_axis;
        encoderPosition = prevEncoderPosition;
    }
}
static void lcd_babystep_z()
{
    if (encoderPosition != 0)
    {
        babystepsTodo[Z_AXIS]+=BABYSTEP_Z_MULTIPLICATOR*(int)encoderPosition;
        encoderPosition=0;
        lcdDrawUpdate = 1;
    }
    if (lcdDrawUpdate)
    {
        lcd_implementation_drawedit(PSTR(MSG_BABYSTEPPING_Z),"");
    }
    if (LCD_CLICKED)
    {
        lcd_quick_feedback();
        currentMenu = lcd_tune_menu;
        encoderPosition = 0;
    }
}
Example #4
0
static void lcd_babystep_y()
{
    if (encoderPosition != 0)
    {
        babystepsTodo[Y_AXIS]+=(int)encoderPosition;
        encoderPosition=0;
        lcdDrawUpdate = 1;
    }
    if (lcdDrawUpdate)
    {
        lcd_implementation_drawedit(PSTR("Babystepping Y"),"");
    }
    if (LCD_CLICKED)
    {
        lcd_quick_feedback();
        currentMenu = lcd_tune_menu;
        encoderPosition = 0;
    }
}
    /**
     * Detect ubl_lcd_clicked, debounce it, and return true for cancel
     */
    bool user_canceled() {
      if (!ubl_lcd_clicked()) return false;
      safe_delay(10);                       // Wait for click to settle

      #if ENABLED(ULTRA_LCD)
        lcd_setstatusPGM(PSTR("Mesh Validation Stopped."), 99);
        lcd_quick_feedback();
      #endif

      while (!ubl_lcd_clicked()) idle();    // Wait for button release

      // If the button is suddenly pressed again,
      // ask the user to resolve the issue
      lcd_setstatusPGM(PSTR("Release button"), 99); // will never appear...
      while (ubl_lcd_clicked()) idle();             // unless this loop happens
      lcd_reset_status();

      return true;
    }
Example #6
0
static void lcd_move_e()
{
    if (encoderPosition != 0)
    {
        current_position[E_AXIS] += float((int)encoderPosition) * move_menu_scale;
        encoderPosition = 0;
        plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], 20, active_extruder);
        lcdDrawUpdate = 1;
    }
    if (lcdDrawUpdate)
    {
        lcd_implementation_drawedit(PSTR("Extruder"), ftostr31(current_position[E_AXIS]));
    }
    if (LCD_CLICKED)
    {
        lcd_quick_feedback();
        currentMenu = lcd_move_menu_axis;
        encoderPosition = 0;
    }
}
Example #7
0
static void lcd_set_contrast()
{
    if (encoderPosition != 0)
    {
        lcd_contrast -= encoderPosition;
        if (lcd_contrast < 0) lcd_contrast = 0;
        else if (lcd_contrast > 63) lcd_contrast = 63;
        encoderPosition = 0;
        lcdDrawUpdate = 1;
        u8g.setContrast(lcd_contrast);
    }
    if (lcdDrawUpdate)
    {
        lcd_implementation_drawedit(PSTR("Contrast"), itostr2(lcd_contrast));
    }
    if (LCD_CLICKED)
    {
        lcd_quick_feedback();
        currentMenu = lcd_control_menu;
        encoderPosition = 0;
    }
}
Example #8
0
/* 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 (lcd_status_update_delay)
        lcd_status_update_delay--;
    else
        lcdDrawUpdate = 1;
    if (lcdDrawUpdate)
    {
        lcd_implementation_status_screen();
        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 */
    }
#ifdef ULTIPANEL

    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)
    {
        currentMenu = lcd_main_menu;
        encoderPosition = 0;
        lcd_quick_feedback();
        lcd_implementation_init(); // to maybe revive the LCD if static electricity killed it.
    }

#ifdef ULTIPANEL_FEEDMULTIPLY
    // Dead zone at 100% feedrate
    if ((feedmultiply < 100 && (feedmultiply + int(encoderPosition)) > 100) ||
            (feedmultiply > 100 && (feedmultiply + int(encoderPosition)) < 100))
    {
        encoderPosition = 0;
        feedmultiply = 100;
    }

    if (feedmultiply == 100 && int(encoderPosition) > ENCODER_FEEDRATE_DEADZONE)
    {
        feedmultiply += int(encoderPosition) - ENCODER_FEEDRATE_DEADZONE;
        encoderPosition = 0;
    }
    else if (feedmultiply == 100 && int(encoderPosition) < -ENCODER_FEEDRATE_DEADZONE)
    {
        feedmultiply += int(encoderPosition) + ENCODER_FEEDRATE_DEADZONE;
        encoderPosition = 0;
    }
    else if (feedmultiply != 100)
    {
        feedmultiply += int(encoderPosition);
        encoderPosition = 0;
    }
#endif//ULTIPANEL_FEEDMULTIPLY

    if (feedmultiply < 10)
        feedmultiply = 10;
    if (feedmultiply > 999)
        feedmultiply = 999;
#endif//ULTIPANEL
}
Example #9
0
/* 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 (lcd_status_update_delay)
        lcd_status_update_delay--;
    else
        lcdDrawUpdate = 1;
    if (lcdDrawUpdate)
    {
        ReInitLCD++;
        
        if(ReInitLCD == 30){
            lcd_implementation_init( // to maybe revive the LCD if static electricity killed it.
          #if defined(LCD_PROGRESS_BAR) && defined(SDSUPPORT)
            currentMenu == lcd_status_screen
          #endif
        );
            ReInitLCD =0 ;
        }else{

            if((ReInitLCD%10) == 0){
              //lcd_implementation_nodisplay();
              lcd_implementation_init_noclear( // to maybe revive the LCD if static electricity killed it.
              #if defined(LCD_PROGRESS_BAR) && defined(SDSUPPORT)
                currentMenu == lcd_status_screen
              #endif
            );
              
            }

        }

        
        //lcd_implementation_display();
        lcd_implementation_status_screen();
        //lcd_implementation_clear();
        
        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 */
    }
#ifdef ULTIPANEL

    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_goto_menu(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
          #endif
        );
        #ifdef FILAMENT_LCD_DISPLAY
          message_millis = millis();  // get status message to show up for a while
        #endif
    }

#ifdef ULTIPANEL_FEEDMULTIPLY
    // Dead zone at 100% feedrate
    if ((feedmultiply < 100 && (feedmultiply + int(encoderPosition)) > 100) ||
            (feedmultiply > 100 && (feedmultiply + int(encoderPosition)) < 100))
    {
        encoderPosition = 0;
        feedmultiply = 100;
    }

    if (feedmultiply == 100 && int(encoderPosition) > ENCODER_FEEDRATE_DEADZONE)
    {
        feedmultiply += int(encoderPosition) - ENCODER_FEEDRATE_DEADZONE;
        encoderPosition = 0;
    }
    else if (feedmultiply == 100 && int(encoderPosition) < -ENCODER_FEEDRATE_DEADZONE)
    {
        feedmultiply += int(encoderPosition) + ENCODER_FEEDRATE_DEADZONE;
        encoderPosition = 0;
    }
    else if (feedmultiply != 100)
    {
        feedmultiply += int(encoderPosition);
        encoderPosition = 0;
    }
#endif //ULTIPANEL_FEEDMULTIPLY

    if (feedmultiply < 10)
        feedmultiply = 10;
    else if (feedmultiply > 999)
        feedmultiply = 999;
#endif //ULTIPANEL
}
Example #10
0
/* 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 defined(LCD_PROGRESS_BAR) && defined(SDSUPPORT) && !defined(DOGLCD)
    uint16_t mil = millis();
    #ifndef PROGRESS_MSG_ONCE
      if (mil > progressBarTick + PROGRESS_BAR_MSG_TIME + PROGRESS_BAR_BAR_TIME) {
        progressBarTick = mil;
      }
    #endif
    #if PROGRESS_MSG_EXPIRE > 0
      // keep the message alive if paused, count down otherwise
      if (messageTick > 0) {
        if (card.isFileOpen()) {
          if (IS_SD_PRINTING) {
            if ((mil-messageTick) >= PROGRESS_MSG_EXPIRE) {
              lcd_status_message[0] = '\0';
              messageTick = 0;
            }
          }
          else {
            messageTick += LCD_UPDATE_INTERVAL;
          }
        }
        else {
          messageTick = 0;
        }
      }
    #endif
  #endif //LCD_PROGRESS_BAR

    if (lcd_status_update_delay)
        lcd_status_update_delay--;
    else
        lcdDrawUpdate = 1;

    if (lcdDrawUpdate) {
        lcd_implementation_status_screen();
        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 */
    }

#ifdef ULTIPANEL

    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_goto_menu(lcd_main_menu);
        lcd_implementation_init( // to maybe revive the LCD if static electricity killed it.
          #if defined(LCD_PROGRESS_BAR) && defined(SDSUPPORT) && !defined(DOGLCD)
            currentMenu == lcd_status_screen
          #endif
        );
        #ifdef FILAMENT_LCD_DISPLAY
          message_millis = millis();  // get status message to show up for a while
        #endif
    }

#ifdef ULTIPANEL_FEEDMULTIPLY
    // Dead zone at 100% feedrate
    if ((feedmultiply < 100 && (feedmultiply + int(encoderPosition)) > 100) ||
            (feedmultiply > 100 && (feedmultiply + int(encoderPosition)) < 100))
    {
        encoderPosition = 0;
        feedmultiply = 100;
    }

    if (feedmultiply == 100 && int(encoderPosition) > ENCODER_FEEDRATE_DEADZONE)
    {
        feedmultiply += int(encoderPosition) - ENCODER_FEEDRATE_DEADZONE;
        encoderPosition = 0;
    }
    else if (feedmultiply == 100 && int(encoderPosition) < -ENCODER_FEEDRATE_DEADZONE)
    {
        feedmultiply += int(encoderPosition) + ENCODER_FEEDRATE_DEADZONE;
        encoderPosition = 0;
    }
    else if (feedmultiply != 100)
    {
        feedmultiply += int(encoderPosition);
        encoderPosition = 0;
    }
#endif //ULTIPANEL_FEEDMULTIPLY

    if (feedmultiply < 10)
        feedmultiply = 10;
    else if (feedmultiply > 999)
        feedmultiply = 999;
#endif //ULTIPANEL
}
  /**
   * Prime the nozzle if needed. Return true on error.
   */
  bool unified_bed_leveling::prime_nozzle() {

    #if ENABLED(NEWPANEL)
      float Total_Prime = 0.0;

      if (g26_prime_flag == -1) {  // The user wants to control how much filament gets purged

        has_control_of_lcd_panel = true;
        lcd_setstatusPGM(PSTR("User-Controlled Prime"), 99);
        chirp_at_user();

        set_destination_to_current();

        recover_filament(destination); // Make sure G26 doesn't think the filament is retracted().

        while (!ubl_lcd_clicked()) {
          chirp_at_user();
          destination[E_AXIS] += 0.25;
          #ifdef PREVENT_LENGTHY_EXTRUDE
            Total_Prime += 0.25;
            if (Total_Prime >= EXTRUDE_MAXLENGTH) return UBL_ERR;
          #endif
          G26_line_to_destination(planner.max_feedrate_mm_s[E_AXIS] / 15.0);

          stepper.synchronize();    // Without this synchronize, the purge is more consistent,
                                    // but because the planner has a buffer, we won't be able
                                    // to stop as quickly.  So we put up with the less smooth
                                    // action to give the user a more responsive 'Stop'.
          set_destination_to_current();
          idle();
        }

        while (ubl_lcd_clicked()) idle();           // Debounce Encoder Wheel

        #if ENABLED(ULTRA_LCD)
          strcpy_P(lcd_status_message, PSTR("Done Priming")); // We can't do lcd_setstatusPGM() without having it continue;
                                                              // So...  We cheat to get a message up.
          lcd_setstatusPGM(PSTR("Done Priming"), 99);
          lcd_quick_feedback();
        #endif

        has_control_of_lcd_panel = false;

      }
      else {
    #else
    {
    #endif
      #if ENABLED(ULTRA_LCD)
        lcd_setstatusPGM(PSTR("Fixed Length Prime."), 99);
        lcd_quick_feedback();
      #endif
      set_destination_to_current();
      destination[E_AXIS] += g26_prime_length;
      G26_line_to_destination(planner.max_feedrate_mm_s[E_AXIS] / 15.0);
      stepper.synchronize();
      set_destination_to_current();
      retract_filament(destination);
    }

    return UBL_OK;
  }
  /**
   * G26: Mesh Validation Pattern generation.
   *
   * Used to interactively edit UBL's Mesh by placing the
   * nozzle in a problem area and doing a G29 P4 R command.
   */
  void gcode_G26() {
    SERIAL_ECHOLNPGM("G26 command started.  Waiting for heater(s).");
    float tmp, start_angle, end_angle;
    int   i, xi, yi;
    mesh_index_pair location;

    // Don't allow Mesh Validation without homing first,
    // or if the parameter parsing did not go OK, abort
    if (axis_unhomed_error(true, true, true) || parse_G26_parameters()) return;

    if (current_position[Z_AXIS] < Z_CLEARANCE_BETWEEN_PROBES) {
      do_blocking_move_to_z(Z_CLEARANCE_BETWEEN_PROBES);
      stepper.synchronize();
      set_current_to_destination();
    }

    if (turn_on_heaters()) goto LEAVE;

    current_position[E_AXIS] = 0.0;
    sync_plan_position_e();

    if (prime_flag && prime_nozzle()) goto LEAVE;

    /**
     *  Bed is preheated
     *
     *  Nozzle is at temperature
     *
     *  Filament is primed!
     *
     *  It's  "Show Time" !!!
     */

    ZERO(circle_flags);
    ZERO(horizontal_mesh_line_flags);
    ZERO(vertical_mesh_line_flags);

    // Move nozzle to the specified height for the first layer
    set_destination_to_current();
    destination[Z_AXIS] = layer_height;
    move_to(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], 0.0);
    move_to(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], ooze_amount);

    ubl.has_control_of_lcd_panel = true;
    //debug_current_and_destination(PSTR("Starting G26 Mesh Validation Pattern."));

    /**
     * Declare and generate a sin() & cos() table to be used during the circle drawing.  This will lighten
     * the CPU load and make the arc drawing faster and more smooth
     */
    float sin_table[360 / 30 + 1], cos_table[360 / 30 + 1];
    for (i = 0; i <= 360 / 30; i++) {
      cos_table[i] = SIZE_OF_INTERSECTION_CIRCLES * cos(RADIANS(valid_trig_angle(i * 30.0)));
      sin_table[i] = SIZE_OF_INTERSECTION_CIRCLES * sin(RADIANS(valid_trig_angle(i * 30.0)));
    }

    do {

      if (ubl_lcd_clicked()) {              // Check if the user wants to stop the Mesh Validation
        #if ENABLED(ULTRA_LCD)
          lcd_setstatuspgm(PSTR("Mesh Validation Stopped."), 99);
          lcd_quick_feedback();
        #endif
        while (!ubl_lcd_clicked()) {         // Wait until the user is done pressing the
          idle();                            // Encoder Wheel if that is why we are leaving
          lcd_reset_alert_level();
          lcd_setstatuspgm(PSTR(""));
        }
        while (ubl_lcd_clicked()) {          // Wait until the user is done pressing the
          idle();                            // Encoder Wheel if that is why we are leaving
          lcd_setstatuspgm(PSTR("Unpress Wheel"), 99);
        }
        goto LEAVE;
      }

      location = continue_with_closest
        ? find_closest_circle_to_print(current_position[X_AXIS], current_position[Y_AXIS])
        : find_closest_circle_to_print(x_pos, y_pos); // Find the closest Mesh Intersection to where we are now.

      if (location.x_index >= 0 && location.y_index >= 0) {
        const float circle_x = pgm_read_float(&ubl.mesh_index_to_xpos[location.x_index]),
                    circle_y = pgm_read_float(&ubl.mesh_index_to_ypos[location.y_index]);

        // Let's do a couple of quick sanity checks.  We can pull this code out later if we never see it catch a problem
        #ifdef DELTA
          if (HYPOT2(circle_x, circle_y) > sq(DELTA_PRINTABLE_RADIUS)) {
            SERIAL_ERROR_START;
            SERIAL_ERRORLNPGM("Attempt to print outside of DELTA_PRINTABLE_RADIUS.");
            goto LEAVE;
          }
        #endif

        // TODO: Change this to use `position_is_reachable`
        if (!WITHIN(circle_x, X_MIN_POS, X_MAX_POS) || !WITHIN(circle_y, Y_MIN_POS, Y_MAX_POS)) {
          SERIAL_ERROR_START;
          SERIAL_ERRORLNPGM("Attempt to print off the bed.");
          goto LEAVE;
        }

        xi = location.x_index;  // Just to shrink the next few lines and make them easier to understand
        yi = location.y_index;

        if (ubl.g26_debug_flag) {
          SERIAL_ECHOPAIR("   Doing circle at: (xi=", xi);
          SERIAL_ECHOPAIR(", yi=", yi);
          SERIAL_CHAR(')');
          SERIAL_EOL;
        }

        start_angle = 0.0;    // assume it is going to be a full circle
        end_angle   = 360.0;
        if (xi == 0) {       // Check for bottom edge
          start_angle = -90.0;
          end_angle   =  90.0;
          if (yi == 0)        // it is an edge, check for the two left corners
            start_angle = 0.0;
          else if (yi == GRID_MAX_POINTS_Y - 1)
            end_angle = 0.0;
        }
        else if (xi == GRID_MAX_POINTS_X - 1) { // Check for top edge
          start_angle =  90.0;
          end_angle   = 270.0;
          if (yi == 0)                  // it is an edge, check for the two right corners
            end_angle = 180.0;
          else if (yi == GRID_MAX_POINTS_Y - 1)
            start_angle = 180.0;
        }
        else if (yi == 0) {
          start_angle =   0.0;         // only do the top   side of the cirlce
          end_angle   = 180.0;
        }
        else if (yi == GRID_MAX_POINTS_Y - 1) {
          start_angle = 180.0;         // only do the bottom side of the cirlce
          end_angle   = 360.0;
        }

        for (tmp = start_angle; tmp < end_angle - 0.1; tmp += 30.0) {
          int tmp_div_30 = tmp / 30.0;
          if (tmp_div_30 < 0) tmp_div_30 += 360 / 30;
          if (tmp_div_30 > 11) tmp_div_30 -= 360 / 30;

          float x = circle_x + cos_table[tmp_div_30],    // for speed, these are now a lookup table entry
                y = circle_y + sin_table[tmp_div_30],
                xe = circle_x + cos_table[tmp_div_30 + 1],
                ye = circle_y + sin_table[tmp_div_30 + 1];
          #ifdef DELTA
            if (HYPOT2(x, y) > sq(DELTA_PRINTABLE_RADIUS))   // Check to make sure this part of
              continue;                                      // the 'circle' is on the bed.  If
          #else                                              // not, we need to skip
            x  = constrain(x, X_MIN_POS + 1, X_MAX_POS - 1); // This keeps us from bumping the endstops
            y  = constrain(y, Y_MIN_POS + 1, Y_MAX_POS - 1);
            xe = constrain(xe, X_MIN_POS + 1, X_MAX_POS - 1);
            ye = constrain(ye, Y_MIN_POS + 1, Y_MAX_POS - 1);
          #endif

          //if (ubl.g26_debug_flag) {
          //  char ccc, *cptr, seg_msg[50], seg_num[10];
          //  strcpy(seg_msg, "   segment: ");
          //  strcpy(seg_num, "    \n");
          //  cptr = (char*) "01234567890ABCDEF????????";
          //  ccc = cptr[tmp_div_30];
          //  seg_num[1] = ccc;
          //  strcat(seg_msg, seg_num);
          //  debug_current_and_destination(seg_msg);
          //}

          print_line_from_here_to_there(LOGICAL_X_POSITION(x), LOGICAL_Y_POSITION(y), layer_height, LOGICAL_X_POSITION(xe), LOGICAL_Y_POSITION(ye), layer_height);

        }

        //debug_current_and_destination(PSTR("Looking for lines to connect."));
        look_for_lines_to_connect();
        //debug_current_and_destination(PSTR("Done with line connect."));
      }

      //debug_current_and_destination(PSTR("Done with current circle."));

    } while (location.x_index >= 0 && location.y_index >= 0);

    LEAVE:
    lcd_reset_alert_level();
    lcd_setstatuspgm(PSTR("Leaving G26"));

    retract_filament(destination);
    destination[Z_AXIS] = Z_CLEARANCE_BETWEEN_PROBES;

    //debug_current_and_destination(PSTR("ready to do Z-Raise."));
    move_to(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], 0); // Raise the nozzle
    //debug_current_and_destination(PSTR("done doing Z-Raise."));

    destination[X_AXIS] = x_pos;                                               // Move back to the starting position
    destination[Y_AXIS] = y_pos;
    //destination[Z_AXIS] = Z_CLEARANCE_BETWEEN_PROBES;                        // Keep the nozzle where it is

    move_to(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], 0); // Move back to the starting position
    //debug_current_and_destination(PSTR("done doing X/Y move."));

    ubl.has_control_of_lcd_panel = false;     // Give back control of the LCD Panel!

    if (!keep_heaters_on) {
      #if HAS_TEMP_BED
        thermalManager.setTargetBed(0);
      #endif
      thermalManager.setTargetHotend(0, 0);
    }
  }