/* 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; } }
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; }
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; } }
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; } }
/* 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 }
/* 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 }
/* 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); } }