diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 2d81336cb4..4ecd0c6d2f 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -257,6 +257,44 @@ #define EXTRUDE_MINTEMP 170 #define EXTRUDE_MAXLENGTH (X_MAX_LENGTH+Y_MAX_LENGTH) //prevent extrusion of very large distances. +/*================== Thermal Runaway Protection ============================== +This is a feature to protect your printer from burn up in flames if it has +a thermistor coming off place (this happened to a friend of mine recently and +motivated me writing this feature). + +The issue: If a thermistor come off, it will read a lower temperature than actual. +The system will turn the heater on forever, burning up the filament and anything +else around. + +After the temperature reaches the target for the first time, this feature will +start measuring for how long the current temperature stays below the target +minus _HYSTERESIS (set_temperature - THERMAL_RUNAWAY_PROTECTION_HYSTERESIS). + +If it stays longer than _PERIOD, it means the thermistor temperature +cannot catch up with the target, so something *may be* wrong. Then, to be on the +safe side, the system will he halt. + +Bear in mind the count down will just start AFTER the first time the +thermistor temperature is over the target, so you will have no problem if +your extruder heater takes 2 minutes to hit the target on heating. + +*/ +// If you want to enable this feature for all your extruder heaters, +// uncomment the 2 defines below: + +// Parameters for all extruder heaters +//#define THERMAL_RUNAWAY_PROTECTION_PERIOD 40 //in seconds +//#define THERMAL_RUNAWAY_PROTECTION_HYSTERESIS 4 // in degree Celsius + +// If you want to enable this feature for your bed heater, +// uncomment the 2 defines below: + +// Parameters for the bed heater +//#define THERMAL_RUNAWAY_PROTECTION_BED_PERIOD 20 //in seconds +//#define THERMAL_RUNAWAY_PROTECTION_BED_HYSTERESIS 2 // in degree Celsius +//=========================================================================== + + //=========================================================================== //=============================Mechanical Settings=========================== //=========================================================================== diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 245f65c9ef..6398f4161b 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -410,9 +410,11 @@ const unsigned int dropsegments=5; //everything with less than this number of st #ifdef FWRETRACT #define MIN_RETRACT 0.1 //minimum extruded mm to accept a automatic gcode retraction attempt #define RETRACT_LENGTH 3 //default retract length (positive mm) + #define RETRACT_LENGTH_SWAP 13 //default swap retract length (positive mm), for extruder change #define RETRACT_FEEDRATE 45 //default feedrate for retracting (mm/s) #define RETRACT_ZLIFT 0 //default retract Z-lift #define RETRACT_RECOVER_LENGTH 0 //default additional recover length (mm, added to retract length when recovering) + #define RETRACT_RECOVER_LENGTH_SWAP 0 //default additional swap recover length (mm, added to retract length when recovering from extruder change) #define RETRACT_RECOVER_FEEDRATE 8 //default feedrate for recovering from retraction (mm/s) #endif diff --git a/Marlin/Marlin.h b/Marlin/Marlin.h index 989110f5fe..9e6ba2636a 100644 --- a/Marlin/Marlin.h +++ b/Marlin/Marlin.h @@ -238,9 +238,9 @@ extern unsigned char fanSpeedSoftPwm; #ifdef FWRETRACT extern bool autoretract_enabled; -extern bool retracted; -extern float retract_length, retract_feedrate, retract_zlift; -extern float retract_recover_length, retract_recover_feedrate; +extern bool retracted[EXTRUDERS]; +extern float retract_length, retract_length_swap, retract_feedrate, retract_zlift; +extern float retract_recover_length, retract_recover_length_swap, retract_recover_feedrate; #endif extern unsigned long starttime; diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp index 4e7ed80101..2b0a1f52bd 100644 --- a/Marlin/Marlin_main.cpp +++ b/Marlin/Marlin_main.cpp @@ -254,11 +254,29 @@ int EtoPPressure=0; #ifdef FWRETRACT bool autoretract_enabled=false; - bool retracted=false; + bool retracted[EXTRUDERS]={false + #if EXTRUDERS > 1 + , false + #if EXTRUDERS > 2 + , false + #endif + #endif + }; + bool retracted_swap[EXTRUDERS]={false + #if EXTRUDERS > 1 + , false + #if EXTRUDERS > 2 + , false + #endif + #endif + }; + float retract_length = RETRACT_LENGTH; + float retract_length_swap = RETRACT_LENGTH_SWAP; float retract_feedrate = RETRACT_FEEDRATE; float retract_zlift = RETRACT_ZLIFT; float retract_recover_length = RETRACT_RECOVER_LENGTH; + float retract_recover_length_swap = RETRACT_RECOVER_LENGTH_SWAP; float retract_recover_feedrate = RETRACT_RECOVER_FEEDRATE; #endif @@ -291,6 +309,8 @@ int EtoPPressure=0; float axis_scaling[3]={1,1,1}; // Build size scaling, default to 1 #endif +bool cancel_heatup = false ; + //=========================================================================== //=============================Private Variables============================= //=========================================================================== @@ -1184,23 +1204,27 @@ void refresh_cmd_timeout(void) } #ifdef FWRETRACT - void retract(bool retracting) { - if(retracting && !retracted) { + void retract(bool retracting, bool swapretract = false) { + if(retracting && !retracted[active_extruder]) { destination[X_AXIS]=current_position[X_AXIS]; destination[Y_AXIS]=current_position[Y_AXIS]; destination[Z_AXIS]=current_position[Z_AXIS]; destination[E_AXIS]=current_position[E_AXIS]; - current_position[E_AXIS]+=retract_length/volumetric_multiplier[active_extruder]; + if (swapretract) { + current_position[E_AXIS]+=retract_length_swap/volumetric_multiplier[active_extruder]; + } else { + current_position[E_AXIS]+=retract_length/volumetric_multiplier[active_extruder]; + } plan_set_e_position(current_position[E_AXIS]); float oldFeedrate = feedrate; feedrate=retract_feedrate*60; - retracted=true; + retracted[active_extruder]=true; prepare_move(); current_position[Z_AXIS]-=retract_zlift; plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); prepare_move(); feedrate = oldFeedrate; - } else if(!retracting && retracted) { + } else if(!retracting && retracted[active_extruder]) { destination[X_AXIS]=current_position[X_AXIS]; destination[Y_AXIS]=current_position[Y_AXIS]; destination[Z_AXIS]=current_position[Z_AXIS]; @@ -1208,11 +1232,15 @@ void refresh_cmd_timeout(void) current_position[Z_AXIS]+=retract_zlift; plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]); //prepare_move(); - current_position[E_AXIS]-=(retract_length+retract_recover_length)/volumetric_multiplier[active_extruder]; + if (swapretract) { + current_position[E_AXIS]-=(retract_length_swap+retract_recover_length_swap)/volumetric_multiplier[active_extruder]; + } else { + current_position[E_AXIS]-=(retract_length+retract_recover_length)/volumetric_multiplier[active_extruder]; + } plan_set_e_position(current_position[E_AXIS]); float oldFeedrate = feedrate; feedrate=retract_recover_feedrate*60; - retracted=false; + retracted[active_extruder]=false; prepare_move(); feedrate = oldFeedrate; } @@ -1284,10 +1312,19 @@ void process_commands() break; #ifdef FWRETRACT case 10: // G10 retract + #if EXTRUDERS > 1 + retracted_swap[active_extruder]=(code_seen('S') && code_value_long() == 1); // checks for swap retract argument + retract(true,retracted_swap[active_extruder]); + #else retract(true); + #endif break; case 11: // G11 retract_recover + #if EXTRUDERS > 1 + retract(false,retracted_swap[active_extruder]); + #else retract(false); + #endif break; #endif //FWRETRACT case 28: //G28 Home all Axis one at a time @@ -2038,14 +2075,16 @@ void process_commands() /* See if we are heating up or cooling down */ target_direction = isHeatingHotend(tmp_extruder); // true if heating, false if cooling + + cancel_heatup = false; #ifdef TEMP_RESIDENCY_TIME long residencyStart; residencyStart = -1; /* continue to loop until we have reached the target temp _and_ until TEMP_RESIDENCY_TIME hasn't passed since we reached it */ - while((residencyStart == -1) || - (residencyStart >= 0 && (((unsigned int) (millis() - residencyStart)) < (TEMP_RESIDENCY_TIME * 1000UL))) ) { + while((!cancel_heatup)&&((residencyStart == -1) || + (residencyStart >= 0 && (((unsigned int) (millis() - residencyStart)) < (TEMP_RESIDENCY_TIME * 1000UL)))) ) { #else while ( target_direction ? (isHeatingHotend(tmp_extruder)) : (isCoolingHotend(tmp_extruder)&&(CooldownNoWait==false)) ) { #endif //TEMP_RESIDENCY_TIME @@ -2101,10 +2140,11 @@ void process_commands() CooldownNoWait = false; } codenum = millis(); - + + cancel_heatup = false; target_direction = isHeatingBed(); // true if heating, false if cooling - while ( target_direction ? (isHeatingBed()) : (isCoolingBed()&&(CooldownNoWait==false)) ) + while ( (target_direction)&&(!cancel_heatup) ? (isHeatingBed()) : (isCoolingBed()&&(CooldownNoWait==false)) ) { if(( millis() - codenum) > 1000 ) //Print Temp Reading every 1 second while heating up. { @@ -2514,8 +2554,28 @@ void process_commands() int t= code_value() ; switch(t) { - case 0: autoretract_enabled=false;retracted=false;break; - case 1: autoretract_enabled=true;retracted=false;break; + case 0: + { + autoretract_enabled=false; + retracted[0]=false; + #if EXTRUDERS > 1 + retracted[1]=false; + #endif + #if EXTRUDERS > 2 + retracted[2]=false; + #endif + }break; + case 1: + { + autoretract_enabled=true; + retracted[0]=false; + #if EXTRUDERS > 1 + retracted[1]=false; + #endif + #if EXTRUDERS > 2 + retracted[2]=false; + #endif + }break; default: SERIAL_ECHO_START; SERIAL_ECHOPGM(MSG_UNKNOWN_COMMAND); diff --git a/Marlin/language.h b/Marlin/language.h index c032aca89e..8522018bf1 100644 --- a/Marlin/language.h +++ b/Marlin/language.h @@ -171,9 +171,11 @@ #define MSG_KILLED "KILLED. " #define MSG_STOPPED "STOPPED. " #define MSG_CONTROL_RETRACT "Retract mm" + #define MSG_CONTROL_RETRACT_SWAP "Swap Re.mm" #define MSG_CONTROL_RETRACTF "Retract V" #define MSG_CONTROL_RETRACT_ZLIFT "Hop mm" #define MSG_CONTROL_RETRACT_RECOVER "UnRet +mm" + #define MSG_CONTROL_RETRACT_RECOVER_SWAP "S UnRet+mm" #define MSG_CONTROL_RETRACT_RECOVERF "UnRet V" #define MSG_AUTORETRACT "AutoRetr." #define MSG_FILAMENTCHANGE "Change filament" @@ -371,9 +373,11 @@ #define MSG_STOPPED "Zatrzymany. " #define MSG_STEPPER_RELEASED "Zwolniony." #define MSG_CONTROL_RETRACT "Wycofaj mm" + #define MSG_CONTROL_RETRACT_SWAP "Z Wycof. mm" #define MSG_CONTROL_RETRACTF "Wycofaj V" #define MSG_CONTROL_RETRACT_ZLIFT "Skok Z mm:" #define MSG_CONTROL_RETRACT_RECOVER "Cof. wycof. +mm" + #define MSG_CONTROL_RETRACT_RECOVER_SWAP "Z Cof. wyc. +mm" #define MSG_CONTROL_RETRACT_RECOVERF "Cof. wycof. V" #define MSG_AUTORETRACT "Auto. wycofanie" #define MSG_FILAMENTCHANGE "Zmien filament" @@ -572,9 +576,11 @@ #define MSG_STOPPED "STOPPE." #define MSG_STEPPER_RELEASED "RELACHE." #define MSG_CONTROL_RETRACT "Retraction mm" + #define MSG_CONTROL_RETRACT_SWAP "Ech. Retr. mm" #define MSG_CONTROL_RETRACTF "Retraction V" #define MSG_CONTROL_RETRACT_ZLIFT "Hop mm" #define MSG_CONTROL_RETRACT_RECOVER "UnRet +mm" + #define MSG_CONTROL_RETRACT_RECOVER_SWAP "Ech. UnRet +mm" #define MSG_CONTROL_RETRACT_RECOVERF "UnRet V" #define MSG_AUTORETRACT "Retract. Auto." #define MSG_FILAMENTCHANGE "Changer filament" @@ -774,9 +780,11 @@ #define MSG_STOPPED "GESTOPPT" #define MSG_STEPPER_RELEASED "Stepper frei" #define MSG_CONTROL_RETRACT "Retract mm" + #define MSG_CONTROL_RETRACT_SWAP "Wechs. Retract mm" #define MSG_CONTROL_RETRACTF "Retract V" #define MSG_CONTROL_RETRACT_ZLIFT "Hop mm" #define MSG_CONTROL_RETRACT_RECOVER "UnRet +mm" + #define MSG_CONTROL_RETRACT_RECOVER_SWAP "Wechs. UnRet +mm" #define MSG_CONTROL_RETRACT_RECOVERF "UnRet V" #define MSG_AUTORETRACT "AutoRetr." #define MSG_FILAMENTCHANGE "Filament wechseln" @@ -972,9 +980,11 @@ #define MSG_KILLED "PARADA DE EMERG." #define MSG_STOPPED "PARADA" #define MSG_CONTROL_RETRACT "Retraer mm" + #define MSG_CONTROL_RETRACT_SWAP "Interc. Retraer mm" #define MSG_CONTROL_RETRACTF "Retraer V" #define MSG_CONTROL_RETRACT_ZLIFT "Levantar mm" #define MSG_CONTROL_RETRACT_RECOVER "DesRet +mm" + #define MSG_CONTROL_RETRACT_RECOVER_SWAP "Interc. DesRet +mm" #define MSG_CONTROL_RETRACT_RECOVERF "DesRet V" #define MSG_AUTORETRACT "AutoRetr." #define MSG_FILAMENTCHANGE "Cambiar filamento" @@ -1179,9 +1189,11 @@ #define MSG_KILLED "УБИТО." #define MSG_STOPPED "ОСТАНОВЛЕНО." #define MSG_CONTROL_RETRACT "Откат mm:" + #define MSG_CONTROL_RETRACT_SWAP "своп Откат mm:" #define MSG_CONTROL_RETRACTF "Откат V:" #define MSG_CONTROL_RETRACT_ZLIFT "Прыжок mm:" #define MSG_CONTROL_RETRACT_RECOVER "Возврат +mm:" + #define MSG_CONTROL_RETRACT_RECOVER_SWAP "своп Возврат +mm:" #define MSG_CONTROL_RETRACT_RECOVERF "Возврат V:" #define MSG_AUTORETRACT "АвтоОткат:" #define MSG_FILAMENTCHANGE "Change filament" @@ -1376,9 +1388,11 @@ #define MSG_KILLED "UCCISO. " #define MSG_STOPPED "ARRESTATO. " #define MSG_CONTROL_RETRACT "Ritrai mm" + #define MSG_CONTROL_RETRACT_SWAP "Scamb. Ritrai mm" #define MSG_CONTROL_RETRACTF "Ritrai V" #define MSG_CONTROL_RETRACT_ZLIFT "Salta mm" #define MSG_CONTROL_RETRACT_RECOVER "UnRet +mm" + #define MSG_CONTROL_RETRACT_RECOVER_SWAP "Scamb. UnRet +mm" #define MSG_CONTROL_RETRACT_RECOVERF "UnRet V" #define MSG_AUTORETRACT "AutoArretramento" #define MSG_FILAMENTCHANGE "Cambia filamento" @@ -1581,9 +1595,11 @@ #define MSG_STOPPED "PARADA. " #define MSG_STEPPER_RELEASED "Lancado." #define MSG_CONTROL_RETRACT " Retrair mm:" + #define MSG_CONTROL_RETRACT_SWAP "Troca Retrair mm:" #define MSG_CONTROL_RETRACTF " Retrair V:" #define MSG_CONTROL_RETRACT_ZLIFT " Levantar mm:" #define MSG_CONTROL_RETRACT_RECOVER " DesRet +mm:" + #define MSG_CONTROL_RETRACT_RECOVER_SWAP "Troca DesRet +mm:" #define MSG_CONTROL_RETRACT_RECOVERF " DesRet V:" #define MSG_AUTORETRACT " AutoRetr.:" #define MSG_FILAMENTCHANGE "Change filament" @@ -1781,9 +1797,11 @@ #define MSG_KILLED "KILLED. " #define MSG_STOPPED "STOPPED. " #define MSG_CONTROL_RETRACT "Veda mm" + #define MSG_CONTROL_RETRACT_SWAP "Va. Veda mm" #define MSG_CONTROL_RETRACTF "Veda V" #define MSG_CONTROL_RETRACT_ZLIFT "Z mm" #define MSG_CONTROL_RETRACT_RECOVER "UnRet +mm" + #define MSG_CONTROL_RETRACT_RECOVER_SWAP "Va. UnRet +mm" #define MSG_CONTROL_RETRACT_RECOVERF "UnRet V" #define MSG_AUTORETRACT "AutoVeto." #define MSG_FILAMENTCHANGE "Change filament" @@ -1979,9 +1997,11 @@ #define MSG_KILLED "ATURADA D'EMERCH." #define MSG_STOPPED "ATURADA." #define MSG_CONTROL_RETRACT "Retraer mm" + #define MSG_CONTROL_RETRACT_SWAP "Swap Retraer mm" #define MSG_CONTROL_RETRACTF "Retraer F" #define MSG_CONTROL_RETRACT_ZLIFT "Devantar mm" #define MSG_CONTROL_RETRACT_RECOVER "DesRet +mm" + #define MSG_CONTROL_RETRACT_RECOVER_SWAP "Swap DesRet +mm" #define MSG_CONTROL_RETRACT_RECOVERF "DesRet F" #define MSG_AUTORETRACT "AutoRetr." #define MSG_FILAMENTCHANGE "Cambear" @@ -2185,9 +2205,11 @@ #define MSG_KILLED "AFGEBROKEN. " #define MSG_STOPPED "GESTOPT. " #define MSG_CONTROL_RETRACT "Retract mm" + #define MSG_CONTROL_RETRACT_SWAP "Ruil Retract mm" #define MSG_CONTROL_RETRACTF "Retract F" #define MSG_CONTROL_RETRACT_ZLIFT "Hop mm" #define MSG_CONTROL_RETRACT_RECOVER "UnRet +mm" + #define MSG_CONTROL_RETRACT_RECOVER_SWAP "Ruil UnRet +mm" #define MSG_CONTROL_RETRACT_RECOVERF "UnRet F" #define MSG_AUTORETRACT "AutoRetr." #define MSG_FILAMENTCHANGE "Verv. Filament" @@ -2384,9 +2406,11 @@ #define MSG_KILLED "PARADA DE EMERG. " #define MSG_STOPPED "ATURAT. " #define MSG_CONTROL_RETRACT "Retreure mm" + #define MSG_CONTROL_RETRACT_SWAP "Swap Retreure mm" #define MSG_CONTROL_RETRACTF "Retreure F" #define MSG_CONTROL_RETRACT_ZLIFT "Aixecar mm" #define MSG_CONTROL_RETRACT_RECOVER "DesRet +mm" + #define MSG_CONTROL_RETRACT_RECOVER_SWAP "Swap DesRet +mm" #define MSG_CONTROL_RETRACT_RECOVERF "DesRet F" #define MSG_AUTORETRACT "AutoRetr." #define MSG_FILAMENTCHANGE "Canviar filament" @@ -2582,9 +2606,11 @@ #define MSG_KILLED "LARRIALDI GELDIA" #define MSG_STOPPED "GELDITUTA. " #define MSG_CONTROL_RETRACT "Atzera egin mm" + #define MSG_CONTROL_RETRACT_SWAP "Swap Atzera egin mm" #define MSG_CONTROL_RETRACTF "Atzera egin V" #define MSG_CONTROL_RETRACT_ZLIFT "Igo mm" #define MSG_CONTROL_RETRACT_RECOVER "Atzera egin +mm" + #define MSG_CONTROL_RETRACT_RECOVER_SWAP "Swap Atzera egin +mm" #define MSG_CONTROL_RETRACT_RECOVERF "Atzera egin V" #define MSG_AUTORETRACT "Atzera egin" #define MSG_FILAMENTCHANGE "Aldatu filament." diff --git a/Marlin/temperature.cpp b/Marlin/temperature.cpp index aac6ca66f5..a10c255af9 100644 --- a/Marlin/temperature.cpp +++ b/Marlin/temperature.cpp @@ -416,6 +416,10 @@ void manage_heater() for(int e = 0; e < EXTRUDERS; e++) { + #ifdef THERMAL_RUNAWAY_PROTECTION_PERIOD && THERMAL_RUNAWAY_PROTECTION_PERIOD > 0 + thermal_runaway_protection(&thermal_runaway_state_machine[e], &thermal_runaway_timer[e], current_temperature[e], target_temperature[e], e, THERMAL_RUNAWAY_PROTECTION_PERIOD, THERMAL_RUNAWAY_PROTECTION_HYSTERESIS); + #endif + #ifdef PIDTEMP pid_input = current_temperature[e]; @@ -526,6 +530,10 @@ void manage_heater() #if TEMP_SENSOR_BED != 0 + #ifdef THERMAL_RUNAWAY_PROTECTION_PERIOD && THERMAL_RUNAWAY_PROTECTION_PERIOD > 0 + thermal_runaway_protection(&thermal_runaway_bed_state_machine, &thermal_runaway_bed_timer, current_temperature_bed, target_temperature_bed, 9, THERMAL_RUNAWAY_PROTECTION_BED_PERIOD, THERMAL_RUNAWAY_PROTECTION_BED_HYSTERESIS); + #endif + #ifdef PIDTEMPBED pid_input = current_temperature_bed; @@ -896,6 +904,66 @@ void setWatch() #endif } +#ifdef THERMAL_RUNAWAY_PROTECTION_PERIOD && THERMAL_RUNAWAY_PROTECTION_PERIOD > 0 +void thermal_runaway_protection(int *state, unsigned long *timer, float temperature, float target_temperature, int heater_id, int period_seconds, int hysteresis_degc) +{ +/* + SERIAL_ECHO_START; + SERIAL_ECHO("Thermal Thermal Runaway Running. Heater ID:"); + SERIAL_ECHO(heater_id); + SERIAL_ECHO(" ; State:"); + SERIAL_ECHO(*state); + SERIAL_ECHO(" ; Timer:"); + SERIAL_ECHO(*timer); + SERIAL_ECHO(" ; Temperature:"); + SERIAL_ECHO(temperature); + SERIAL_ECHO(" ; Target Temp:"); + SERIAL_ECHO(target_temperature); + SERIAL_ECHOLN(""); +*/ + if ((target_temperature == 0) || thermal_runaway) + { + *state = 0; + *timer = 0; + return; + } + switch (*state) + { + case 0: // "Heater Inactive" state + if (target_temperature > 0) *state = 1; + break; + case 1: // "First Heating" state + if (temperature >= target_temperature) *state = 2; + break; + case 2: // "Temperature Stable" state + if (temperature >= (target_temperature - hysteresis_degc)) + { + *timer = millis(); + } + else if ( (millis() - *timer) > period_seconds*1000) + { + SERIAL_ERROR_START; + SERIAL_ERRORLNPGM("Thermal Runaway, system stopped! Heater_ID: "); + SERIAL_ERRORLN((int)heater_id); + LCD_ALERTMESSAGEPGM("THERMAL RUNAWAY"); + thermal_runaway = true; + while(1) + { + disable_heater(); + disable_x(); + disable_y(); + disable_z(); + disable_e0(); + disable_e1(); + disable_e2(); + manage_heater(); + lcd_update(); + } + } + break; + } +} +#endif void disable_heater() { diff --git a/Marlin/temperature.h b/Marlin/temperature.h index a8580def56..df2b5deacf 100644 --- a/Marlin/temperature.h +++ b/Marlin/temperature.h @@ -154,6 +154,17 @@ void disable_heater(); void setWatch(); void updatePID(); +#ifdef THERMAL_RUNAWAY_PROTECTION_PERIOD && THERMAL_RUNAWAY_PROTECTION_PERIOD > 0 +void thermal_runaway_protection(int *state, unsigned long *timer, float temperature, float target_temperature, int heater_id, int period_seconds, int hysteresis_degc); +static int thermal_runaway_state_machine[3]; // = {0,0,0}; +static unsigned long thermal_runaway_timer[3]; // = {0,0,0}; +static bool thermal_runaway = false; + #if TEMP_SENSOR_BED != 0 + static int thermal_runaway_bed_state_machine; + static unsigned long thermal_runaway_bed_timer; + #endif +#endif + FORCE_INLINE void autotempShutdown(){ #ifdef AUTOTEMP if(autotemp_enabled) diff --git a/Marlin/ultralcd.cpp b/Marlin/ultralcd.cpp index 0c3ee32a96..2e2c2fd0bf 100644 --- a/Marlin/ultralcd.cpp +++ b/Marlin/ultralcd.cpp @@ -1,1630 +1,1638 @@ -#include "temperature.h" -#include "ultralcd.h" -#ifdef ULTRA_LCD -#include "Marlin.h" -#include "language.h" -#include "cardreader.h" -#include "temperature.h" -#include "stepper.h" -#include "ConfigurationStore.h" - -int8_t encoderDiff; /* encoderDiff is updated from interrupt context and added to encoderPosition every LCD update */ - -/* Configuration settings */ -int plaPreheatHotendTemp; -int plaPreheatHPBTemp; -int plaPreheatFanSpeed; - -int absPreheatHotendTemp; -int absPreheatHPBTemp; -int absPreheatFanSpeed; - - -#ifdef ULTIPANEL -static float manual_feedrate[] = MANUAL_FEEDRATE; -#endif // ULTIPANEL - -/* !Configuration settings */ - -//Function pointer to menu functions. -typedef void (*menuFunc_t)(); - -uint8_t lcd_status_message_level; -char lcd_status_message[LCD_WIDTH+1] = WELCOME_MSG; - -#ifdef DOGLCD -#include "dogm_lcd_implementation.h" -#else -#include "ultralcd_implementation_hitachi_HD44780.h" -#endif - -/** forward declarations **/ - -void copy_and_scalePID_i(); -void copy_and_scalePID_d(); - -/* Different menus */ -static void lcd_status_screen(); -#ifdef ULTIPANEL -extern bool powersupply; -static void lcd_main_menu(); -static void lcd_tune_menu(); -static void lcd_prepare_menu(); -static void lcd_move_menu(); -static void lcd_control_menu(); -static void lcd_control_temperature_menu(); -static void lcd_control_temperature_preheat_pla_settings_menu(); -static void lcd_control_temperature_preheat_abs_settings_menu(); -static void lcd_control_motion_menu(); -#ifdef DOGLCD -static void lcd_set_contrast(); -#endif -static void lcd_control_retract_menu(); -static void lcd_sdcard_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_submenu(menuFunc_t data); -static void menu_action_gcode(const char* pgcode); -static void menu_action_function(menuFunc_t data); -static void menu_action_sdfile(const char* filename, char* longFilename); -static void menu_action_sddirectory(const char* filename, char* longFilename); -static void menu_action_setting_edit_bool(const char* pstr, bool* ptr); -static void menu_action_setting_edit_int3(const char* pstr, int* ptr, int minValue, int maxValue); -static void menu_action_setting_edit_float3(const char* pstr, float* ptr, float minValue, float maxValue); -static void menu_action_setting_edit_float32(const char* pstr, float* ptr, float minValue, float maxValue); -static void menu_action_setting_edit_float5(const char* pstr, float* ptr, float minValue, float maxValue); -static void menu_action_setting_edit_float51(const char* pstr, float* ptr, float minValue, float maxValue); -static void menu_action_setting_edit_float52(const char* pstr, float* ptr, float minValue, float maxValue); -static void menu_action_setting_edit_long5(const char* pstr, unsigned long* ptr, unsigned long minValue, unsigned long maxValue); -static void menu_action_setting_edit_callback_bool(const char* pstr, bool* ptr, menuFunc_t callbackFunc); -static void menu_action_setting_edit_callback_int3(const char* pstr, int* ptr, int minValue, int maxValue, menuFunc_t callbackFunc); -static void menu_action_setting_edit_callback_float3(const char* pstr, float* ptr, float minValue, float maxValue, menuFunc_t callbackFunc); -static void menu_action_setting_edit_callback_float32(const char* pstr, float* ptr, float minValue, float maxValue, menuFunc_t callbackFunc); -static void menu_action_setting_edit_callback_float5(const char* pstr, float* ptr, float minValue, float maxValue, menuFunc_t callbackFunc); -static void menu_action_setting_edit_callback_float51(const char* pstr, float* ptr, float minValue, float maxValue, menuFunc_t callbackFunc); -static void menu_action_setting_edit_callback_float52(const char* pstr, float* ptr, float minValue, float maxValue, menuFunc_t callbackFunc); -static void menu_action_setting_edit_callback_long5(const char* pstr, unsigned long* ptr, unsigned long minValue, unsigned long maxValue, menuFunc_t callbackFunc); - -#define ENCODER_FEEDRATE_DEADZONE 10 - -#if !defined(LCD_I2C_VIKI) - #ifndef ENCODER_STEPS_PER_MENU_ITEM - #define ENCODER_STEPS_PER_MENU_ITEM 5 - #endif - #ifndef ENCODER_PULSES_PER_STEP - #define ENCODER_PULSES_PER_STEP 1 - #endif -#else - #ifndef ENCODER_STEPS_PER_MENU_ITEM - #define ENCODER_STEPS_PER_MENU_ITEM 2 // VIKI LCD rotary encoder uses a different number of steps per rotation - #endif - #ifndef ENCODER_PULSES_PER_STEP - #define ENCODER_PULSES_PER_STEP 1 - #endif -#endif - - -/* Helper macros for menus */ -#define START_MENU() do { \ - if (encoderPosition > 0x8000) encoderPosition = 0; \ - if (encoderPosition / ENCODER_STEPS_PER_MENU_ITEM < currentMenuViewOffset) currentMenuViewOffset = encoderPosition / ENCODER_STEPS_PER_MENU_ITEM;\ - uint8_t _lineNr = currentMenuViewOffset, _menuItemNr; \ - bool wasClicked = LCD_CLICKED;\ - for(uint8_t _drawLineNr = 0; _drawLineNr < LCD_HEIGHT; _drawLineNr++, _lineNr++) { \ - _menuItemNr = 0; -#define MENU_ITEM(type, label, args...) do { \ - if (_menuItemNr == _lineNr) { \ - if (lcdDrawUpdate) { \ - const char* _label_pstr = PSTR(label); \ - if ((encoderPosition / ENCODER_STEPS_PER_MENU_ITEM) == _menuItemNr) { \ - lcd_implementation_drawmenu_ ## type ## _selected (_drawLineNr, _label_pstr , ## args ); \ - }else{\ - lcd_implementation_drawmenu_ ## type (_drawLineNr, _label_pstr , ## args ); \ - }\ - }\ - if (wasClicked && (encoderPosition / ENCODER_STEPS_PER_MENU_ITEM) == _menuItemNr) {\ - lcd_quick_feedback(); \ - menu_action_ ## type ( args ); \ - return;\ - }\ - }\ - _menuItemNr++;\ -} while(0) -#define MENU_ITEM_DUMMY() do { _menuItemNr++; } while(0) -#define MENU_ITEM_EDIT(type, label, args...) MENU_ITEM(setting_edit_ ## type, label, PSTR(label) , ## args ) -#define MENU_ITEM_EDIT_CALLBACK(type, label, args...) MENU_ITEM(setting_edit_callback_ ## type, label, PSTR(label) , ## args ) -#define END_MENU() \ - if (encoderPosition / ENCODER_STEPS_PER_MENU_ITEM >= _menuItemNr) encoderPosition = _menuItemNr * ENCODER_STEPS_PER_MENU_ITEM - 1; \ - if ((uint8_t)(encoderPosition / ENCODER_STEPS_PER_MENU_ITEM) >= currentMenuViewOffset + LCD_HEIGHT) { currentMenuViewOffset = (encoderPosition / ENCODER_STEPS_PER_MENU_ITEM) - LCD_HEIGHT + 1; lcdDrawUpdate = 1; _lineNr = currentMenuViewOffset - 1; _drawLineNr = -1; } \ - } } while(0) - -/** Used variables to keep track of the menu */ -#ifndef REPRAPWORLD_KEYPAD -volatile uint8_t buttons;//Contains the bits of the currently pressed buttons. -#else -volatile uint8_t buttons_reprapworld_keypad; // to store the reprapworld_keypad shift register values -#endif -#ifdef LCD_HAS_SLOW_BUTTONS -volatile uint8_t slow_buttons;//Contains the bits of the currently pressed buttons. -#endif -uint8_t currentMenuViewOffset; /* scroll offset in the current menu */ -uint32_t blocking_enc; -uint8_t lastEncoderBits; -uint32_t encoderPosition; -#if (SDCARDDETECT > 0) -bool lcd_oldcardstatus; -#endif -#endif//ULTIPANEL - -menuFunc_t currentMenu = lcd_status_screen; /* function pointer to the currently active menu */ -uint32_t lcd_next_update_millis; -uint8_t lcd_status_update_delay; -uint8_t lcdDrawUpdate = 2; /* Set to none-zero when the LCD needs to draw, decreased after every draw. Set to 2 in LCD routines so the LCD gets at least 1 full redraw (first redraw is partial) */ - -//prevMenu and prevEncoderPosition are used to store the previous menu location when editing settings. -menuFunc_t prevMenu = NULL; -uint16_t prevEncoderPosition; -//Variables used when editing values. -const char* editLabel; -void* editValue; -int32_t minEditValue, maxEditValue; -menuFunc_t callbackFunc; - -// place-holders for Ki and Kd edits -float raw_Ki, raw_Kd; - -/* 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 - if (LCD_CLICKED) - { - 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 -} - -#ifdef ULTIPANEL -static void lcd_return_to_status() -{ - encoderPosition = 0; - currentMenu = lcd_status_screen; -} - -static void lcd_sdcard_pause() -{ - card.pauseSDPrint(); -} -static void lcd_sdcard_resume() -{ - card.startFileprint(); -} - -static void lcd_sdcard_stop() -{ - card.sdprinting = false; - card.closefile(); - quickStop(); - if(SD_FINISHED_STEPPERRELEASE) - { - enquecommand_P(PSTR(SD_FINISHED_RELEASECOMMAND)); - } - autotempShutdown(); -} - -/* Menu implementation */ -static void lcd_main_menu() -{ - START_MENU(); - MENU_ITEM(back, MSG_WATCH, lcd_status_screen); - if (movesplanned() || IS_SD_PRINTING) - { - MENU_ITEM(submenu, MSG_TUNE, lcd_tune_menu); - }else{ - MENU_ITEM(submenu, MSG_PREPARE, lcd_prepare_menu); - } - MENU_ITEM(submenu, MSG_CONTROL, lcd_control_menu); -#ifdef SDSUPPORT - if (card.cardOK) - { - if (card.isFileOpen()) - { - if (card.sdprinting) - MENU_ITEM(function, MSG_PAUSE_PRINT, lcd_sdcard_pause); - else - MENU_ITEM(function, MSG_RESUME_PRINT, lcd_sdcard_resume); - MENU_ITEM(function, MSG_STOP_PRINT, lcd_sdcard_stop); - }else{ - MENU_ITEM(submenu, MSG_CARD_MENU, lcd_sdcard_menu); -#if SDCARDDETECT < 1 - MENU_ITEM(gcode, MSG_CNG_SDCARD, PSTR("M21")); // SD-card changed by user -#endif - } - }else{ - MENU_ITEM(submenu, MSG_NO_CARD, lcd_sdcard_menu); -#if SDCARDDETECT < 1 - MENU_ITEM(gcode, MSG_INIT_SDCARD, PSTR("M21")); // Manually initialize the SD-card via user interface -#endif - } -#endif - END_MENU(); -} - -#ifdef SDSUPPORT -static void lcd_autostart_sd() -{ - card.lastnr=0; - card.setroot(); - card.checkautostart(true); -} -#endif - -#ifdef BABYSTEPPING -static void lcd_babystep_x() -{ - if (encoderPosition != 0) - { - babystepsTodo[X_AXIS]+=(int)encoderPosition; - encoderPosition=0; - lcdDrawUpdate = 1; - } - if (lcdDrawUpdate) - { - lcd_implementation_drawedit(PSTR(MSG_BABYSTEPPING_X),""); - } - 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(MSG_BABYSTEPPING_Y),""); - } - if (LCD_CLICKED) - { - lcd_quick_feedback(); - currentMenu = lcd_tune_menu; - encoderPosition = 0; - } -} - -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; - } -} -#endif //BABYSTEPPING - -static void lcd_tune_menu() -{ - START_MENU(); - MENU_ITEM(back, MSG_MAIN, lcd_main_menu); - MENU_ITEM_EDIT(int3, MSG_SPEED, &feedmultiply, 10, 999); - MENU_ITEM_EDIT(int3, MSG_NOZZLE, &target_temperature[0], 0, HEATER_0_MAXTEMP - 15); -#if TEMP_SENSOR_1 != 0 - MENU_ITEM_EDIT(int3, MSG_NOZZLE1, &target_temperature[1], 0, HEATER_1_MAXTEMP - 15); -#endif -#if TEMP_SENSOR_2 != 0 - MENU_ITEM_EDIT(int3, MSG_NOZZLE2, &target_temperature[2], 0, HEATER_2_MAXTEMP - 15); -#endif -#if TEMP_SENSOR_BED != 0 - MENU_ITEM_EDIT(int3, MSG_BED, &target_temperature_bed, 0, BED_MAXTEMP - 15); -#endif - MENU_ITEM_EDIT(int3, MSG_FAN_SPEED, &fanSpeed, 0, 255); - MENU_ITEM_EDIT(int3, MSG_FLOW, &extrudemultiply, 10, 999); - MENU_ITEM_EDIT(int3, MSG_FLOW0, &extruder_multiply[0], 10, 999); -#if TEMP_SENSOR_1 != 0 - MENU_ITEM_EDIT(int3, MSG_FLOW1, &extruder_multiply[1], 10, 999); -#endif -#if TEMP_SENSOR_2 != 0 - MENU_ITEM_EDIT(int3, MSG_FLOW2, &extruder_multiply[2], 10, 999); -#endif - -#ifdef BABYSTEPPING - #ifdef BABYSTEP_XY - MENU_ITEM(submenu, MSG_BABYSTEP_X, lcd_babystep_x); - MENU_ITEM(submenu, MSG_BABYSTEP_Y, lcd_babystep_y); - #endif //BABYSTEP_XY - MENU_ITEM(submenu, MSG_BABYSTEP_Z, lcd_babystep_z); -#endif -#ifdef FILAMENTCHANGEENABLE - MENU_ITEM(gcode, MSG_FILAMENTCHANGE, PSTR("M600")); -#endif - END_MENU(); -} - -void lcd_preheat_pla0() -{ - setTargetHotend0(plaPreheatHotendTemp); - setTargetBed(plaPreheatHPBTemp); - fanSpeed = plaPreheatFanSpeed; - lcd_return_to_status(); - setWatch(); // heater sanity check timer -} - -void lcd_preheat_abs0() -{ - setTargetHotend0(absPreheatHotendTemp); - setTargetBed(absPreheatHPBTemp); - fanSpeed = absPreheatFanSpeed; - lcd_return_to_status(); - setWatch(); // heater sanity check timer -} - -#if TEMP_SENSOR_1 != 0 //2nd extruder preheat -void lcd_preheat_pla1() -{ - setTargetHotend1(plaPreheatHotendTemp); - setTargetBed(plaPreheatHPBTemp); - fanSpeed = plaPreheatFanSpeed; - lcd_return_to_status(); - setWatch(); // heater sanity check timer -} - -void lcd_preheat_abs1() -{ - setTargetHotend1(absPreheatHotendTemp); - setTargetBed(absPreheatHPBTemp); - fanSpeed = absPreheatFanSpeed; - lcd_return_to_status(); - setWatch(); // heater sanity check timer -} -#endif //2nd extruder preheat - -#if TEMP_SENSOR_2 != 0 //3 extruder preheat -void lcd_preheat_pla2() -{ - setTargetHotend2(plaPreheatHotendTemp); - setTargetBed(plaPreheatHPBTemp); - fanSpeed = plaPreheatFanSpeed; - lcd_return_to_status(); - setWatch(); // heater sanity check timer -} - -void lcd_preheat_abs2() -{ - setTargetHotend2(absPreheatHotendTemp); - setTargetBed(absPreheatHPBTemp); - fanSpeed = absPreheatFanSpeed; - lcd_return_to_status(); - setWatch(); // heater sanity check timer -} -#endif //3 extruder preheat - -#if TEMP_SENSOR_1 != 0 || TEMP_SENSOR_2 != 0 //more than one extruder present -void lcd_preheat_pla012() -{ - setTargetHotend0(plaPreheatHotendTemp); - setTargetHotend1(plaPreheatHotendTemp); - setTargetHotend2(plaPreheatHotendTemp); - setTargetBed(plaPreheatHPBTemp); - fanSpeed = plaPreheatFanSpeed; - lcd_return_to_status(); - setWatch(); // heater sanity check timer -} - -void lcd_preheat_abs012() -{ - setTargetHotend0(absPreheatHotendTemp); - setTargetHotend1(absPreheatHotendTemp); - setTargetHotend2(absPreheatHotendTemp); - setTargetBed(absPreheatHPBTemp); - fanSpeed = absPreheatFanSpeed; - lcd_return_to_status(); - setWatch(); // heater sanity check timer -} -#endif //more than one extruder present - -void lcd_preheat_pla_bedonly() -{ - setTargetBed(plaPreheatHPBTemp); - fanSpeed = plaPreheatFanSpeed; - lcd_return_to_status(); - setWatch(); // heater sanity check timer -} - -void lcd_preheat_abs_bedonly() -{ - setTargetBed(absPreheatHPBTemp); - fanSpeed = absPreheatFanSpeed; - lcd_return_to_status(); - setWatch(); // heater sanity check timer -} - -static void lcd_preheat_pla_menu() -{ - START_MENU(); - MENU_ITEM(back, MSG_PREPARE, lcd_prepare_menu); - MENU_ITEM(function, MSG_PREHEAT_PLA0, lcd_preheat_pla0); -#if TEMP_SENSOR_1 != 0 //2 extruder preheat - MENU_ITEM(function, MSG_PREHEAT_PLA1, lcd_preheat_pla1); -#endif //2 extruder preheat -#if TEMP_SENSOR_2 != 0 //3 extruder preheat - MENU_ITEM(function, MSG_PREHEAT_PLA2, lcd_preheat_pla2); -#endif //3 extruder preheat -#if TEMP_SENSOR_1 != 0 || TEMP_SENSOR_2 != 0 //all extruder preheat - MENU_ITEM(function, MSG_PREHEAT_PLA012, lcd_preheat_pla012); -#endif //2 extruder preheat -#if TEMP_SENSOR_BED != 0 - MENU_ITEM(function, MSG_PREHEAT_PLA_BEDONLY, lcd_preheat_pla_bedonly); -#endif - END_MENU(); -} - -static void lcd_preheat_abs_menu() -{ - START_MENU(); - MENU_ITEM(back, MSG_PREPARE, lcd_prepare_menu); - MENU_ITEM(function, MSG_PREHEAT_ABS0, lcd_preheat_abs0); -#if TEMP_SENSOR_1 != 0 //2 extruder preheat - MENU_ITEM(function, MSG_PREHEAT_ABS1, lcd_preheat_abs1); -#endif //2 extruder preheat -#if TEMP_SENSOR_2 != 0 //3 extruder preheat - MENU_ITEM(function, MSG_PREHEAT_ABS2, lcd_preheat_abs2); -#endif //3 extruder preheat -#if TEMP_SENSOR_1 != 0 || TEMP_SENSOR_2 != 0 //all extruder preheat - MENU_ITEM(function, MSG_PREHEAT_ABS012, lcd_preheat_abs012); -#endif //2 extruder preheat -#if TEMP_SENSOR_BED != 0 - MENU_ITEM(function, MSG_PREHEAT_ABS_BEDONLY, lcd_preheat_abs_bedonly); -#endif - END_MENU(); -} - -void lcd_cooldown() -{ - setTargetHotend0(0); - setTargetHotend1(0); - setTargetHotend2(0); - setTargetBed(0); - fanSpeed = 0; - lcd_return_to_status(); -} - -static void lcd_prepare_menu() -{ - START_MENU(); - MENU_ITEM(back, MSG_MAIN, lcd_main_menu); -#ifdef SDSUPPORT - #ifdef MENU_ADDAUTOSTART - MENU_ITEM(function, MSG_AUTOSTART, lcd_autostart_sd); - #endif -#endif - MENU_ITEM(gcode, MSG_DISABLE_STEPPERS, PSTR("M84")); - MENU_ITEM(gcode, MSG_AUTO_HOME, PSTR("G28")); - //MENU_ITEM(gcode, MSG_SET_ORIGIN, PSTR("G92 X0 Y0 Z0")); -#if TEMP_SENSOR_0 != 0 - #if TEMP_SENSOR_1 != 0 || TEMP_SENSOR_2 != 0 || TEMP_SENSOR_BED != 0 - MENU_ITEM(submenu, MSG_PREHEAT_PLA, lcd_preheat_pla_menu); - MENU_ITEM(submenu, MSG_PREHEAT_ABS, lcd_preheat_abs_menu); - #else - MENU_ITEM(function, MSG_PREHEAT_PLA, lcd_preheat_pla0); - MENU_ITEM(function, MSG_PREHEAT_ABS, lcd_preheat_abs0); - #endif -#endif - MENU_ITEM(function, MSG_COOLDOWN, lcd_cooldown); -#if PS_ON_PIN > -1 - if (powersupply) - { - MENU_ITEM(gcode, MSG_SWITCH_PS_OFF, PSTR("M81")); - }else{ - MENU_ITEM(gcode, MSG_SWITCH_PS_ON, PSTR("M80")); - } -#endif - MENU_ITEM(submenu, MSG_MOVE_AXIS, lcd_move_menu); - END_MENU(); -} - -float move_menu_scale; -static void lcd_move_menu_axis(); - -static void lcd_move_x() -{ - if (encoderPosition != 0) - { - refresh_cmd_timeout(); - current_position[X_AXIS] += float((int)encoderPosition) * move_menu_scale; - if (min_software_endstops && current_position[X_AXIS] < X_MIN_POS) - current_position[X_AXIS] = X_MIN_POS; - if (max_software_endstops && current_position[X_AXIS] > X_MAX_POS) - current_position[X_AXIS] = X_MAX_POS; - encoderPosition = 0; - #ifdef DELTA - calculate_delta(current_position); - plan_buffer_line(delta[X_AXIS], delta[Y_AXIS], delta[Z_AXIS], current_position[E_AXIS], manual_feedrate[X_AXIS]/60, active_extruder); - #else - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], manual_feedrate[X_AXIS]/60, active_extruder); - #endif - lcdDrawUpdate = 1; - } - if (lcdDrawUpdate) - { - lcd_implementation_drawedit(PSTR("X"), ftostr31(current_position[X_AXIS])); - } - if (LCD_CLICKED) - { - lcd_quick_feedback(); - currentMenu = lcd_move_menu_axis; - encoderPosition = 0; - } -} -static void lcd_move_y() -{ - if (encoderPosition != 0) - { - refresh_cmd_timeout(); - current_position[Y_AXIS] += float((int)encoderPosition) * move_menu_scale; - if (min_software_endstops && current_position[Y_AXIS] < Y_MIN_POS) - current_position[Y_AXIS] = Y_MIN_POS; - if (max_software_endstops && current_position[Y_AXIS] > Y_MAX_POS) - current_position[Y_AXIS] = Y_MAX_POS; - encoderPosition = 0; - #ifdef DELTA - calculate_delta(current_position); - plan_buffer_line(delta[X_AXIS], delta[Y_AXIS], delta[Z_AXIS], current_position[E_AXIS], manual_feedrate[Y_AXIS]/60, active_extruder); - #else - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], manual_feedrate[Y_AXIS]/60, active_extruder); - #endif - lcdDrawUpdate = 1; - } - if (lcdDrawUpdate) - { - lcd_implementation_drawedit(PSTR("Y"), ftostr31(current_position[Y_AXIS])); - } - if (LCD_CLICKED) - { - lcd_quick_feedback(); - currentMenu = lcd_move_menu_axis; - encoderPosition = 0; - } -} -static void lcd_move_z() -{ - if (encoderPosition != 0) - { - refresh_cmd_timeout(); - current_position[Z_AXIS] += float((int)encoderPosition) * move_menu_scale; - if (min_software_endstops && current_position[Z_AXIS] < Z_MIN_POS) - current_position[Z_AXIS] = Z_MIN_POS; - if (max_software_endstops && current_position[Z_AXIS] > Z_MAX_POS) - current_position[Z_AXIS] = Z_MAX_POS; - encoderPosition = 0; - #ifdef DELTA - calculate_delta(current_position); - plan_buffer_line(delta[X_AXIS], delta[Y_AXIS], delta[Z_AXIS], current_position[E_AXIS], manual_feedrate[Z_AXIS]/60, active_extruder); - #else - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], manual_feedrate[Z_AXIS]/60, active_extruder); - #endif - lcdDrawUpdate = 1; - } - if (lcdDrawUpdate) - { - lcd_implementation_drawedit(PSTR("Z"), ftostr31(current_position[Z_AXIS])); - } - if (LCD_CLICKED) - { - lcd_quick_feedback(); - currentMenu = lcd_move_menu_axis; - encoderPosition = 0; - } -} -static void lcd_move_e() -{ - if (encoderPosition != 0) - { - current_position[E_AXIS] += float((int)encoderPosition) * move_menu_scale; - encoderPosition = 0; - #ifdef DELTA - calculate_delta(current_position); - plan_buffer_line(delta[X_AXIS], delta[Y_AXIS], delta[Z_AXIS], current_position[E_AXIS], manual_feedrate[E_AXIS]/60, active_extruder); - #else - plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], manual_feedrate[E_AXIS]/60, active_extruder); - #endif - 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_move_menu_axis() -{ - START_MENU(); - MENU_ITEM(back, MSG_MOVE_AXIS, lcd_move_menu); - MENU_ITEM(submenu, MSG_MOVE_X, lcd_move_x); - MENU_ITEM(submenu, MSG_MOVE_Y, lcd_move_y); - if (move_menu_scale < 10.0) - { - MENU_ITEM(submenu, MSG_MOVE_Z, lcd_move_z); - MENU_ITEM(submenu, MSG_MOVE_E, lcd_move_e); - } - END_MENU(); -} - -static void lcd_move_menu_10mm() -{ - move_menu_scale = 10.0; - lcd_move_menu_axis(); -} -static void lcd_move_menu_1mm() -{ - move_menu_scale = 1.0; - lcd_move_menu_axis(); -} -static void lcd_move_menu_01mm() -{ - move_menu_scale = 0.1; - lcd_move_menu_axis(); -} - -static void lcd_move_menu() -{ - START_MENU(); - MENU_ITEM(back, MSG_PREPARE, lcd_prepare_menu); - MENU_ITEM(submenu, MSG_MOVE_10MM, lcd_move_menu_10mm); - MENU_ITEM(submenu, MSG_MOVE_1MM, lcd_move_menu_1mm); - MENU_ITEM(submenu, MSG_MOVE_01MM, lcd_move_menu_01mm); - //TODO:X,Y,Z,E - END_MENU(); -} - -static void lcd_control_menu() -{ - START_MENU(); - MENU_ITEM(back, MSG_MAIN, lcd_main_menu); - MENU_ITEM(submenu, MSG_TEMPERATURE, lcd_control_temperature_menu); - MENU_ITEM(submenu, MSG_MOTION, lcd_control_motion_menu); -#ifdef DOGLCD -// MENU_ITEM_EDIT(int3, MSG_CONTRAST, &lcd_contrast, 0, 63); - MENU_ITEM(submenu, MSG_CONTRAST, lcd_set_contrast); -#endif -#ifdef FWRETRACT - MENU_ITEM(submenu, MSG_RETRACT, lcd_control_retract_menu); -#endif -#ifdef EEPROM_SETTINGS - MENU_ITEM(function, MSG_STORE_EPROM, Config_StoreSettings); - MENU_ITEM(function, MSG_LOAD_EPROM, Config_RetrieveSettings); -#endif - MENU_ITEM(function, MSG_RESTORE_FAILSAFE, Config_ResetDefault); - END_MENU(); -} - -static void lcd_control_temperature_menu() -{ -#ifdef PIDTEMP - // set up temp variables - undo the default scaling - raw_Ki = unscalePID_i(Ki); - raw_Kd = unscalePID_d(Kd); -#endif - - START_MENU(); - MENU_ITEM(back, MSG_CONTROL, lcd_control_menu); - MENU_ITEM_EDIT(int3, MSG_NOZZLE, &target_temperature[0], 0, HEATER_0_MAXTEMP - 15); -#if TEMP_SENSOR_1 != 0 - MENU_ITEM_EDIT(int3, MSG_NOZZLE1, &target_temperature[1], 0, HEATER_1_MAXTEMP - 15); -#endif -#if TEMP_SENSOR_2 != 0 - MENU_ITEM_EDIT(int3, MSG_NOZZLE2, &target_temperature[2], 0, HEATER_2_MAXTEMP - 15); -#endif -#if TEMP_SENSOR_BED != 0 - MENU_ITEM_EDIT(int3, MSG_BED, &target_temperature_bed, 0, BED_MAXTEMP - 15); -#endif - MENU_ITEM_EDIT(int3, MSG_FAN_SPEED, &fanSpeed, 0, 255); -#ifdef AUTOTEMP - MENU_ITEM_EDIT(bool, MSG_AUTOTEMP, &autotemp_enabled); - MENU_ITEM_EDIT(float3, MSG_MIN, &autotemp_min, 0, HEATER_0_MAXTEMP - 15); - MENU_ITEM_EDIT(float3, MSG_MAX, &autotemp_max, 0, HEATER_0_MAXTEMP - 15); - MENU_ITEM_EDIT(float32, MSG_FACTOR, &autotemp_factor, 0.0, 1.0); -#endif -#ifdef PIDTEMP - MENU_ITEM_EDIT(float52, MSG_PID_P, &Kp, 1, 9990); - // i is typically a small value so allows values below 1 - MENU_ITEM_EDIT_CALLBACK(float52, MSG_PID_I, &raw_Ki, 0.01, 9990, copy_and_scalePID_i); - MENU_ITEM_EDIT_CALLBACK(float52, MSG_PID_D, &raw_Kd, 1, 9990, copy_and_scalePID_d); -# ifdef PID_ADD_EXTRUSION_RATE - MENU_ITEM_EDIT(float3, MSG_PID_C, &Kc, 1, 9990); -# endif//PID_ADD_EXTRUSION_RATE -#endif//PIDTEMP - MENU_ITEM(submenu, MSG_PREHEAT_PLA_SETTINGS, lcd_control_temperature_preheat_pla_settings_menu); - MENU_ITEM(submenu, MSG_PREHEAT_ABS_SETTINGS, lcd_control_temperature_preheat_abs_settings_menu); - END_MENU(); -} - -static void lcd_control_temperature_preheat_pla_settings_menu() -{ - START_MENU(); - MENU_ITEM(back, MSG_TEMPERATURE, lcd_control_temperature_menu); - MENU_ITEM_EDIT(int3, MSG_FAN_SPEED, &plaPreheatFanSpeed, 0, 255); - MENU_ITEM_EDIT(int3, MSG_NOZZLE, &plaPreheatHotendTemp, 0, HEATER_0_MAXTEMP - 15); -#if TEMP_SENSOR_BED != 0 - MENU_ITEM_EDIT(int3, MSG_BED, &plaPreheatHPBTemp, 0, BED_MAXTEMP - 15); -#endif -#ifdef EEPROM_SETTINGS - MENU_ITEM(function, MSG_STORE_EPROM, Config_StoreSettings); -#endif - END_MENU(); -} - -static void lcd_control_temperature_preheat_abs_settings_menu() -{ - START_MENU(); - MENU_ITEM(back, MSG_TEMPERATURE, lcd_control_temperature_menu); - MENU_ITEM_EDIT(int3, MSG_FAN_SPEED, &absPreheatFanSpeed, 0, 255); - MENU_ITEM_EDIT(int3, MSG_NOZZLE, &absPreheatHotendTemp, 0, HEATER_0_MAXTEMP - 15); -#if TEMP_SENSOR_BED != 0 - MENU_ITEM_EDIT(int3, MSG_BED, &absPreheatHPBTemp, 0, BED_MAXTEMP - 15); -#endif -#ifdef EEPROM_SETTINGS - MENU_ITEM(function, MSG_STORE_EPROM, Config_StoreSettings); -#endif - END_MENU(); -} - -static void lcd_control_motion_menu() -{ - START_MENU(); - MENU_ITEM(back, MSG_CONTROL, lcd_control_menu); -#ifdef ENABLE_AUTO_BED_LEVELING - MENU_ITEM_EDIT(float32, MSG_ZPROBE_ZOFFSET, &zprobe_zoffset, 0.5, 50); -#endif - MENU_ITEM_EDIT(float5, MSG_ACC, &acceleration, 500, 99000); - MENU_ITEM_EDIT(float3, MSG_VXY_JERK, &max_xy_jerk, 1, 990); - MENU_ITEM_EDIT(float52, MSG_VZ_JERK, &max_z_jerk, 0.1, 990); - MENU_ITEM_EDIT(float3, MSG_VE_JERK, &max_e_jerk, 1, 990); - MENU_ITEM_EDIT(float3, MSG_VMAX MSG_X, &max_feedrate[X_AXIS], 1, 999); - MENU_ITEM_EDIT(float3, MSG_VMAX MSG_Y, &max_feedrate[Y_AXIS], 1, 999); - MENU_ITEM_EDIT(float3, MSG_VMAX MSG_Z, &max_feedrate[Z_AXIS], 1, 999); - MENU_ITEM_EDIT(float3, MSG_VMAX MSG_E, &max_feedrate[E_AXIS], 1, 999); - MENU_ITEM_EDIT(float3, MSG_VMIN, &minimumfeedrate, 0, 999); - MENU_ITEM_EDIT(float3, MSG_VTRAV_MIN, &mintravelfeedrate, 0, 999); - MENU_ITEM_EDIT_CALLBACK(long5, MSG_AMAX MSG_X, &max_acceleration_units_per_sq_second[X_AXIS], 100, 99000, reset_acceleration_rates); - MENU_ITEM_EDIT_CALLBACK(long5, MSG_AMAX MSG_Y, &max_acceleration_units_per_sq_second[Y_AXIS], 100, 99000, reset_acceleration_rates); - MENU_ITEM_EDIT_CALLBACK(long5, MSG_AMAX MSG_Z, &max_acceleration_units_per_sq_second[Z_AXIS], 100, 99000, reset_acceleration_rates); - MENU_ITEM_EDIT_CALLBACK(long5, MSG_AMAX MSG_E, &max_acceleration_units_per_sq_second[E_AXIS], 100, 99000, reset_acceleration_rates); - MENU_ITEM_EDIT(float5, MSG_A_RETRACT, &retract_acceleration, 100, 99000); - MENU_ITEM_EDIT(float52, MSG_XSTEPS, &axis_steps_per_unit[X_AXIS], 5, 9999); - MENU_ITEM_EDIT(float52, MSG_YSTEPS, &axis_steps_per_unit[Y_AXIS], 5, 9999); - MENU_ITEM_EDIT(float51, MSG_ZSTEPS, &axis_steps_per_unit[Z_AXIS], 5, 9999); - MENU_ITEM_EDIT(float51, MSG_ESTEPS, &axis_steps_per_unit[E_AXIS], 5, 9999); -#ifdef ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED - MENU_ITEM_EDIT(bool, MSG_ENDSTOP_ABORT, &abort_on_endstop_hit); -#endif -#ifdef SCARA - MENU_ITEM_EDIT(float74, MSG_XSCALE, &axis_scaling[X_AXIS],0.5,2); - MENU_ITEM_EDIT(float74, MSG_YSCALE, &axis_scaling[Y_AXIS],0.5,2); -#endif - END_MENU(); -} - -#ifdef DOGLCD -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(MSG_CONTRAST), itostr2(lcd_contrast)); - } - if (LCD_CLICKED) - { - lcd_quick_feedback(); - currentMenu = lcd_control_menu; - encoderPosition = 0; - } -} -#endif - -#ifdef FWRETRACT -static void lcd_control_retract_menu() -{ - START_MENU(); - MENU_ITEM(back, MSG_CONTROL, lcd_control_menu); - MENU_ITEM_EDIT(bool, MSG_AUTORETRACT, &autoretract_enabled); - MENU_ITEM_EDIT(float52, MSG_CONTROL_RETRACT, &retract_length, 0, 100); - MENU_ITEM_EDIT(float3, MSG_CONTROL_RETRACTF, &retract_feedrate, 1, 999); - MENU_ITEM_EDIT(float52, MSG_CONTROL_RETRACT_ZLIFT, &retract_zlift, 0, 999); - MENU_ITEM_EDIT(float52, MSG_CONTROL_RETRACT_RECOVER, &retract_recover_length, 0, 100); - MENU_ITEM_EDIT(float3, MSG_CONTROL_RETRACT_RECOVERF, &retract_recover_feedrate, 1, 999); - END_MENU(); -} -#endif - -#if SDCARDDETECT == -1 -static void lcd_sd_refresh() -{ - card.initsd(); - currentMenuViewOffset = 0; -} -#endif -static void lcd_sd_updir() -{ - card.updir(); - currentMenuViewOffset = 0; -} - -void lcd_sdcard_menu() -{ - if (lcdDrawUpdate == 0 && LCD_CLICKED == 0) - return; // nothing to do (so don't thrash the SD card) - uint16_t fileCnt = card.getnrfilenames(); - START_MENU(); - MENU_ITEM(back, MSG_MAIN, lcd_main_menu); - card.getWorkDirName(); - if(card.filename[0]=='/') - { -#if SDCARDDETECT == -1 - MENU_ITEM(function, LCD_STR_REFRESH MSG_REFRESH, lcd_sd_refresh); -#endif - }else{ - MENU_ITEM(function, LCD_STR_FOLDER "..", lcd_sd_updir); - } - - for(uint16_t i=0;i maxEditValue) \ - encoderPosition = maxEditValue; \ - if (lcdDrawUpdate) \ - lcd_implementation_drawedit(editLabel, _strFunc(((_type)encoderPosition) / scale)); \ - if (LCD_CLICKED) \ - { \ - *((_type*)editValue) = ((_type)encoderPosition) / scale; \ - lcd_quick_feedback(); \ - currentMenu = prevMenu; \ - encoderPosition = prevEncoderPosition; \ - } \ - } \ - void menu_edit_callback_ ## _name () \ - { \ - if ((int32_t)encoderPosition < minEditValue) \ - encoderPosition = minEditValue; \ - if ((int32_t)encoderPosition > maxEditValue) \ - encoderPosition = maxEditValue; \ - if (lcdDrawUpdate) \ - lcd_implementation_drawedit(editLabel, _strFunc(((_type)encoderPosition) / scale)); \ - if (LCD_CLICKED) \ - { \ - *((_type*)editValue) = ((_type)encoderPosition) / scale; \ - lcd_quick_feedback(); \ - currentMenu = prevMenu; \ - encoderPosition = prevEncoderPosition; \ - (*callbackFunc)();\ - } \ - } \ - static void menu_action_setting_edit_ ## _name (const char* pstr, _type* ptr, _type minValue, _type maxValue) \ - { \ - prevMenu = currentMenu; \ - prevEncoderPosition = encoderPosition; \ - \ - lcdDrawUpdate = 2; \ - currentMenu = menu_edit_ ## _name; \ - \ - editLabel = pstr; \ - editValue = ptr; \ - minEditValue = minValue * scale; \ - maxEditValue = maxValue * scale; \ - encoderPosition = (*ptr) * scale; \ - }\ - static void menu_action_setting_edit_callback_ ## _name (const char* pstr, _type* ptr, _type minValue, _type maxValue, menuFunc_t callback) \ - { \ - prevMenu = currentMenu; \ - prevEncoderPosition = encoderPosition; \ - \ - lcdDrawUpdate = 2; \ - currentMenu = menu_edit_callback_ ## _name; \ - \ - editLabel = pstr; \ - editValue = ptr; \ - minEditValue = minValue * scale; \ - maxEditValue = maxValue * scale; \ - encoderPosition = (*ptr) * scale; \ - callbackFunc = callback;\ - } -menu_edit_type(int, int3, itostr3, 1) -menu_edit_type(float, float3, ftostr3, 1) -menu_edit_type(float, float32, ftostr32, 100) -menu_edit_type(float, float5, ftostr5, 0.01) -menu_edit_type(float, float51, ftostr51, 10) -menu_edit_type(float, float52, ftostr52, 100) -menu_edit_type(unsigned long, long5, ftostr5, 0.01) - -#ifdef REPRAPWORLD_KEYPAD - static void reprapworld_keypad_move_z_up() { - encoderPosition = 1; - move_menu_scale = REPRAPWORLD_KEYPAD_MOVE_STEP; - lcd_move_z(); - } - static void reprapworld_keypad_move_z_down() { - encoderPosition = -1; - move_menu_scale = REPRAPWORLD_KEYPAD_MOVE_STEP; - lcd_move_z(); - } - static void reprapworld_keypad_move_x_left() { - encoderPosition = -1; - move_menu_scale = REPRAPWORLD_KEYPAD_MOVE_STEP; - lcd_move_x(); - } - static void reprapworld_keypad_move_x_right() { - encoderPosition = 1; - move_menu_scale = REPRAPWORLD_KEYPAD_MOVE_STEP; - lcd_move_x(); - } - static void reprapworld_keypad_move_y_down() { - encoderPosition = 1; - move_menu_scale = REPRAPWORLD_KEYPAD_MOVE_STEP; - lcd_move_y(); - } - static void reprapworld_keypad_move_y_up() { - encoderPosition = -1; - move_menu_scale = REPRAPWORLD_KEYPAD_MOVE_STEP; - lcd_move_y(); - } - static void reprapworld_keypad_move_home() { - enquecommand_P((PSTR("G28"))); // move all axis home - } -#endif - -/** End of menus **/ - -static void lcd_quick_feedback() -{ - lcdDrawUpdate = 2; - blocking_enc = millis() + 500; - lcd_implementation_quick_feedback(); -} - -/** Menu action functions **/ -static void menu_action_back(menuFunc_t data) -{ - currentMenu = data; - encoderPosition = 0; -} -static void menu_action_submenu(menuFunc_t data) -{ - currentMenu = data; - encoderPosition = 0; -} -static void menu_action_gcode(const char* pgcode) -{ - enquecommand_P(pgcode); -} -static void menu_action_function(menuFunc_t data) -{ - (*data)(); -} -static void menu_action_sdfile(const char* filename, char* longFilename) -{ - char cmd[30]; - char* c; - sprintf_P(cmd, PSTR("M23 %s"), filename); - for(c = &cmd[4]; *c; c++) - *c = tolower(*c); - enquecommand(cmd); - enquecommand_P(PSTR("M24")); - lcd_return_to_status(); -} -static void menu_action_sddirectory(const char* filename, char* longFilename) -{ - card.chdir(filename); - encoderPosition = 0; -} -static void menu_action_setting_edit_bool(const char* pstr, bool* ptr) -{ - *ptr = !(*ptr); -} -#endif//ULTIPANEL - -/** LCD API **/ -void lcd_init() -{ - lcd_implementation_init(); - -#ifdef NEWPANEL - pinMode(BTN_EN1,INPUT); - pinMode(BTN_EN2,INPUT); - WRITE(BTN_EN1,HIGH); - WRITE(BTN_EN2,HIGH); - #if BTN_ENC > 0 - pinMode(BTN_ENC,INPUT); - WRITE(BTN_ENC,HIGH); - #endif - #ifdef REPRAPWORLD_KEYPAD - pinMode(SHIFT_CLK,OUTPUT); - pinMode(SHIFT_LD,OUTPUT); - pinMode(SHIFT_OUT,INPUT); - WRITE(SHIFT_OUT,HIGH); - WRITE(SHIFT_LD,HIGH); - #endif -#else // Not NEWPANEL - #ifdef SR_LCD_2W_NL // Non latching 2 wire shift register - pinMode (SR_DATA_PIN, OUTPUT); - pinMode (SR_CLK_PIN, OUTPUT); - #elif defined(SHIFT_CLK) - pinMode(SHIFT_CLK,OUTPUT); - pinMode(SHIFT_LD,OUTPUT); - pinMode(SHIFT_EN,OUTPUT); - pinMode(SHIFT_OUT,INPUT); - WRITE(SHIFT_OUT,HIGH); - WRITE(SHIFT_LD,HIGH); - WRITE(SHIFT_EN,LOW); - #else - #ifdef ULTIPANEL - #error ULTIPANEL requires an encoder - #endif - #endif // SR_LCD_2W_NL -#endif//!NEWPANEL - -#if defined (SDSUPPORT) && defined(SDCARDDETECT) && (SDCARDDETECT > 0) - pinMode(SDCARDDETECT,INPUT); - WRITE(SDCARDDETECT, HIGH); - lcd_oldcardstatus = IS_SD_INSERTED; -#endif//(SDCARDDETECT > 0) -#ifdef LCD_HAS_SLOW_BUTTONS - slow_buttons = 0; -#endif - lcd_buttons_update(); -#ifdef ULTIPANEL - encoderDiff = 0; -#endif -} - -void lcd_update() -{ - static unsigned long timeoutToStatus = 0; - - #ifdef LCD_HAS_SLOW_BUTTONS - slow_buttons = lcd_implementation_read_slow_buttons(); // buttons which take too long to read in interrupt context - #endif - - lcd_buttons_update(); - - #if (SDCARDDETECT > 0) - if((IS_SD_INSERTED != lcd_oldcardstatus)) - { - lcdDrawUpdate = 2; - lcd_oldcardstatus = IS_SD_INSERTED; - lcd_implementation_init(); // to maybe revive the LCD if static electricity killed it. - - if(lcd_oldcardstatus) - { - card.initsd(); - LCD_MESSAGEPGM(MSG_SD_INSERTED); - } - else - { - card.release(); - LCD_MESSAGEPGM(MSG_SD_REMOVED); - } - } - #endif//CARDINSERTED - - if (lcd_next_update_millis < millis()) - { -#ifdef ULTIPANEL - #ifdef REPRAPWORLD_KEYPAD - if (REPRAPWORLD_KEYPAD_MOVE_Z_UP) { - reprapworld_keypad_move_z_up(); - } - if (REPRAPWORLD_KEYPAD_MOVE_Z_DOWN) { - reprapworld_keypad_move_z_down(); - } - if (REPRAPWORLD_KEYPAD_MOVE_X_LEFT) { - reprapworld_keypad_move_x_left(); - } - if (REPRAPWORLD_KEYPAD_MOVE_X_RIGHT) { - reprapworld_keypad_move_x_right(); - } - if (REPRAPWORLD_KEYPAD_MOVE_Y_DOWN) { - reprapworld_keypad_move_y_down(); - } - if (REPRAPWORLD_KEYPAD_MOVE_Y_UP) { - reprapworld_keypad_move_y_up(); - } - if (REPRAPWORLD_KEYPAD_MOVE_HOME) { - reprapworld_keypad_move_home(); - } - #endif - if (abs(encoderDiff) >= ENCODER_PULSES_PER_STEP) - { - lcdDrawUpdate = 1; - encoderPosition += encoderDiff / ENCODER_PULSES_PER_STEP; - encoderDiff = 0; - timeoutToStatus = millis() + LCD_TIMEOUT_TO_STATUS; - } - if (LCD_CLICKED) - timeoutToStatus = millis() + LCD_TIMEOUT_TO_STATUS; -#endif//ULTIPANEL - -#ifdef DOGLCD // Changes due to different driver architecture of the DOGM display - blink++; // Variable for fan animation and alive dot - u8g.firstPage(); - do - { - u8g.setFont(u8g_font_6x10_marlin); - u8g.setPrintPos(125,0); - if (blink % 2) u8g.setColorIndex(1); else u8g.setColorIndex(0); // Set color for the alive dot - u8g.drawPixel(127,63); // draw alive dot - u8g.setColorIndex(1); // black on white - (*currentMenu)(); - if (!lcdDrawUpdate) break; // Terminate display update, when nothing new to draw. This must be done before the last dogm.next() - } while( u8g.nextPage() ); -#else - (*currentMenu)(); -#endif - -#ifdef LCD_HAS_STATUS_INDICATORS - lcd_implementation_update_indicators(); -#endif - -#ifdef ULTIPANEL - if(timeoutToStatus < millis() && currentMenu != lcd_status_screen) - { - lcd_return_to_status(); - lcdDrawUpdate = 2; - } -#endif//ULTIPANEL - if (lcdDrawUpdate == 2) - lcd_implementation_clear(); - if (lcdDrawUpdate) - lcdDrawUpdate--; - lcd_next_update_millis = millis() + 100; - } -} - -void lcd_setstatus(const char* message) -{ - if (lcd_status_message_level > 0) - return; - strncpy(lcd_status_message, message, LCD_WIDTH); - lcdDrawUpdate = 2; -} -void lcd_setstatuspgm(const char* message) -{ - if (lcd_status_message_level > 0) - return; - strncpy_P(lcd_status_message, message, LCD_WIDTH); - lcdDrawUpdate = 2; -} -void lcd_setalertstatuspgm(const char* message) -{ - lcd_setstatuspgm(message); - lcd_status_message_level = 1; -#ifdef ULTIPANEL - lcd_return_to_status(); -#endif//ULTIPANEL -} -void lcd_reset_alert_level() -{ - lcd_status_message_level = 0; -} - -#ifdef DOGLCD -void lcd_setcontrast(uint8_t value) -{ - lcd_contrast = value & 63; - u8g.setContrast(lcd_contrast); -} -#endif - -#ifdef ULTIPANEL -/* Warning: This function is called from interrupt context */ -void lcd_buttons_update() -{ -#ifdef NEWPANEL - uint8_t newbutton=0; - if(READ(BTN_EN1)==0) newbutton|=EN_A; - if(READ(BTN_EN2)==0) newbutton|=EN_B; - #if BTN_ENC > 0 - if((blocking_enc>1; - if(READ(SHIFT_OUT)) - newbutton_reprapworld_keypad|=(1<<7); - WRITE(SHIFT_CLK,HIGH); - WRITE(SHIFT_CLK,LOW); - } - buttons_reprapworld_keypad=~newbutton_reprapworld_keypad; //invert it, because a pressed switch produces a logical 0 - #endif -#else //read it from the shift register - uint8_t newbutton=0; - WRITE(SHIFT_LD,LOW); - WRITE(SHIFT_LD,HIGH); - unsigned char tmp_buttons=0; - for(int8_t i=0;i<8;i++) - { - newbutton = newbutton>>1; - if(READ(SHIFT_OUT)) - newbutton|=(1<<7); - WRITE(SHIFT_CLK,HIGH); - WRITE(SHIFT_CLK,LOW); - } - buttons=~newbutton; //invert it, because a pressed switch produces a logical 0 -#endif//!NEWPANEL - - //manage encoder rotation - uint8_t enc=0; - if(buttons&EN_A) - enc|=(1<<0); - if(buttons&EN_B) - enc|=(1<<1); - if(enc != lastEncoderBits) - { - switch(enc) - { - case encrot0: - if(lastEncoderBits==encrot3) - encoderDiff++; - else if(lastEncoderBits==encrot1) - encoderDiff--; - break; - case encrot1: - if(lastEncoderBits==encrot0) - encoderDiff++; - else if(lastEncoderBits==encrot2) - encoderDiff--; - break; - case encrot2: - if(lastEncoderBits==encrot1) - encoderDiff++; - else if(lastEncoderBits==encrot3) - encoderDiff--; - break; - case encrot3: - if(lastEncoderBits==encrot2) - encoderDiff++; - else if(lastEncoderBits==encrot0) - encoderDiff--; - break; - } - } - lastEncoderBits = enc; -} - -void lcd_buzz(long duration, uint16_t freq) -{ -#ifdef LCD_USE_I2C_BUZZER - lcd.buzz(duration,freq); -#endif -} - -bool lcd_clicked() -{ - return LCD_CLICKED; -} -#endif//ULTIPANEL - -/********************************/ -/** Float conversion utilities **/ -/********************************/ -// convert float to string with +123.4 format -char conv[8]; -char *ftostr3(const float &x) -{ - return itostr3((int)x); -} - -char *itostr2(const uint8_t &x) -{ - //sprintf(conv,"%5.1f",x); - int xx=x; - conv[0]=(xx/10)%10+'0'; - conv[1]=(xx)%10+'0'; - conv[2]=0; - return conv; -} - -// convert float to string with +123.4 format -char *ftostr31(const float &x) -{ - int xx=x*10; - conv[0]=(xx>=0)?'+':'-'; - xx=abs(xx); - conv[1]=(xx/1000)%10+'0'; - conv[2]=(xx/100)%10+'0'; - conv[3]=(xx/10)%10+'0'; - conv[4]='.'; - conv[5]=(xx)%10+'0'; - conv[6]=0; - return conv; -} - -// convert float to string with 123.4 format -char *ftostr31ns(const float &x) -{ - int xx=x*10; - //conv[0]=(xx>=0)?'+':'-'; - xx=abs(xx); - conv[0]=(xx/1000)%10+'0'; - conv[1]=(xx/100)%10+'0'; - conv[2]=(xx/10)%10+'0'; - conv[3]='.'; - conv[4]=(xx)%10+'0'; - conv[5]=0; - return conv; -} - -char *ftostr32(const float &x) -{ - long xx=x*100; - if (xx >= 0) - conv[0]=(xx/10000)%10+'0'; - else - conv[0]='-'; - xx=abs(xx); - conv[1]=(xx/1000)%10+'0'; - conv[2]=(xx/100)%10+'0'; - conv[3]='.'; - conv[4]=(xx/10)%10+'0'; - conv[5]=(xx)%10+'0'; - conv[6]=0; - return conv; -} - -char *itostr31(const int &xx) -{ - conv[0]=(xx>=0)?'+':'-'; - conv[1]=(xx/1000)%10+'0'; - conv[2]=(xx/100)%10+'0'; - conv[3]=(xx/10)%10+'0'; - conv[4]='.'; - conv[5]=(xx)%10+'0'; - conv[6]=0; - return conv; -} - -char *itostr3(const int &xx) -{ - if (xx >= 100) - conv[0]=(xx/100)%10+'0'; - else - conv[0]=' '; - if (xx >= 10) - conv[1]=(xx/10)%10+'0'; - else - conv[1]=' '; - conv[2]=(xx)%10+'0'; - conv[3]=0; - return conv; -} - -char *itostr3left(const int &xx) -{ - if (xx >= 100) - { - conv[0]=(xx/100)%10+'0'; - conv[1]=(xx/10)%10+'0'; - conv[2]=(xx)%10+'0'; - conv[3]=0; - } - else if (xx >= 10) - { - conv[0]=(xx/10)%10+'0'; - conv[1]=(xx)%10+'0'; - conv[2]=0; - } - else - { - conv[0]=(xx)%10+'0'; - conv[1]=0; - } - return conv; -} - -char *itostr4(const int &xx) -{ - if (xx >= 1000) - conv[0]=(xx/1000)%10+'0'; - else - conv[0]=' '; - if (xx >= 100) - conv[1]=(xx/100)%10+'0'; - else - conv[1]=' '; - if (xx >= 10) - conv[2]=(xx/10)%10+'0'; - else - conv[2]=' '; - conv[3]=(xx)%10+'0'; - conv[4]=0; - return conv; -} - -// convert float to string with 12345 format -char *ftostr5(const float &x) -{ - long xx=abs(x); - if (xx >= 10000) - conv[0]=(xx/10000)%10+'0'; - else - conv[0]=' '; - if (xx >= 1000) - conv[1]=(xx/1000)%10+'0'; - else - conv[1]=' '; - if (xx >= 100) - conv[2]=(xx/100)%10+'0'; - else - conv[2]=' '; - if (xx >= 10) - conv[3]=(xx/10)%10+'0'; - else - conv[3]=' '; - conv[4]=(xx)%10+'0'; - conv[5]=0; - return conv; -} - -// convert float to string with +1234.5 format -char *ftostr51(const float &x) -{ - long xx=x*10; - conv[0]=(xx>=0)?'+':'-'; - xx=abs(xx); - conv[1]=(xx/10000)%10+'0'; - conv[2]=(xx/1000)%10+'0'; - conv[3]=(xx/100)%10+'0'; - conv[4]=(xx/10)%10+'0'; - conv[5]='.'; - conv[6]=(xx)%10+'0'; - conv[7]=0; - return conv; -} - -// convert float to string with +123.45 format -char *ftostr52(const float &x) -{ - long xx=x*100; - conv[0]=(xx>=0)?'+':'-'; - xx=abs(xx); - conv[1]=(xx/10000)%10+'0'; - conv[2]=(xx/1000)%10+'0'; - conv[3]=(xx/100)%10+'0'; - conv[4]='.'; - conv[5]=(xx/10)%10+'0'; - conv[6]=(xx)%10+'0'; - conv[7]=0; - return conv; -} - -// Callback for after editing PID i value -// grab the PID i value out of the temp variable; scale it; then update the PID driver -void copy_and_scalePID_i() -{ -#ifdef PIDTEMP - Ki = scalePID_i(raw_Ki); - updatePID(); -#endif -} - -// Callback for after editing PID d value -// grab the PID d value out of the temp variable; scale it; then update the PID driver -void copy_and_scalePID_d() -{ -#ifdef PIDTEMP - Kd = scalePID_d(raw_Kd); - updatePID(); -#endif -} - -#endif //ULTRA_LCD +#include "temperature.h" +#include "ultralcd.h" +#ifdef ULTRA_LCD +#include "Marlin.h" +#include "language.h" +#include "cardreader.h" +#include "temperature.h" +#include "stepper.h" +#include "ConfigurationStore.h" + +int8_t encoderDiff; /* encoderDiff is updated from interrupt context and added to encoderPosition every LCD update */ + +/* Configuration settings */ +int plaPreheatHotendTemp; +int plaPreheatHPBTemp; +int plaPreheatFanSpeed; + +int absPreheatHotendTemp; +int absPreheatHPBTemp; +int absPreheatFanSpeed; + + +#ifdef ULTIPANEL +static float manual_feedrate[] = MANUAL_FEEDRATE; +#endif // ULTIPANEL + +/* !Configuration settings */ + +//Function pointer to menu functions. +typedef void (*menuFunc_t)(); + +uint8_t lcd_status_message_level; +char lcd_status_message[LCD_WIDTH+1] = WELCOME_MSG; + +#ifdef DOGLCD +#include "dogm_lcd_implementation.h" +#else +#include "ultralcd_implementation_hitachi_HD44780.h" +#endif + +/** forward declarations **/ + +void copy_and_scalePID_i(); +void copy_and_scalePID_d(); + +/* Different menus */ +static void lcd_status_screen(); +#ifdef ULTIPANEL +extern bool powersupply; +static void lcd_main_menu(); +static void lcd_tune_menu(); +static void lcd_prepare_menu(); +static void lcd_move_menu(); +static void lcd_control_menu(); +static void lcd_control_temperature_menu(); +static void lcd_control_temperature_preheat_pla_settings_menu(); +static void lcd_control_temperature_preheat_abs_settings_menu(); +static void lcd_control_motion_menu(); +#ifdef DOGLCD +static void lcd_set_contrast(); +#endif +static void lcd_control_retract_menu(); +static void lcd_sdcard_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_submenu(menuFunc_t data); +static void menu_action_gcode(const char* pgcode); +static void menu_action_function(menuFunc_t data); +static void menu_action_sdfile(const char* filename, char* longFilename); +static void menu_action_sddirectory(const char* filename, char* longFilename); +static void menu_action_setting_edit_bool(const char* pstr, bool* ptr); +static void menu_action_setting_edit_int3(const char* pstr, int* ptr, int minValue, int maxValue); +static void menu_action_setting_edit_float3(const char* pstr, float* ptr, float minValue, float maxValue); +static void menu_action_setting_edit_float32(const char* pstr, float* ptr, float minValue, float maxValue); +static void menu_action_setting_edit_float5(const char* pstr, float* ptr, float minValue, float maxValue); +static void menu_action_setting_edit_float51(const char* pstr, float* ptr, float minValue, float maxValue); +static void menu_action_setting_edit_float52(const char* pstr, float* ptr, float minValue, float maxValue); +static void menu_action_setting_edit_long5(const char* pstr, unsigned long* ptr, unsigned long minValue, unsigned long maxValue); +static void menu_action_setting_edit_callback_bool(const char* pstr, bool* ptr, menuFunc_t callbackFunc); +static void menu_action_setting_edit_callback_int3(const char* pstr, int* ptr, int minValue, int maxValue, menuFunc_t callbackFunc); +static void menu_action_setting_edit_callback_float3(const char* pstr, float* ptr, float minValue, float maxValue, menuFunc_t callbackFunc); +static void menu_action_setting_edit_callback_float32(const char* pstr, float* ptr, float minValue, float maxValue, menuFunc_t callbackFunc); +static void menu_action_setting_edit_callback_float5(const char* pstr, float* ptr, float minValue, float maxValue, menuFunc_t callbackFunc); +static void menu_action_setting_edit_callback_float51(const char* pstr, float* ptr, float minValue, float maxValue, menuFunc_t callbackFunc); +static void menu_action_setting_edit_callback_float52(const char* pstr, float* ptr, float minValue, float maxValue, menuFunc_t callbackFunc); +static void menu_action_setting_edit_callback_long5(const char* pstr, unsigned long* ptr, unsigned long minValue, unsigned long maxValue, menuFunc_t callbackFunc); + +#define ENCODER_FEEDRATE_DEADZONE 10 + +#if !defined(LCD_I2C_VIKI) + #ifndef ENCODER_STEPS_PER_MENU_ITEM + #define ENCODER_STEPS_PER_MENU_ITEM 5 + #endif + #ifndef ENCODER_PULSES_PER_STEP + #define ENCODER_PULSES_PER_STEP 1 + #endif +#else + #ifndef ENCODER_STEPS_PER_MENU_ITEM + #define ENCODER_STEPS_PER_MENU_ITEM 2 // VIKI LCD rotary encoder uses a different number of steps per rotation + #endif + #ifndef ENCODER_PULSES_PER_STEP + #define ENCODER_PULSES_PER_STEP 1 + #endif +#endif + + +/* Helper macros for menus */ +#define START_MENU() do { \ + if (encoderPosition > 0x8000) encoderPosition = 0; \ + if (encoderPosition / ENCODER_STEPS_PER_MENU_ITEM < currentMenuViewOffset) currentMenuViewOffset = encoderPosition / ENCODER_STEPS_PER_MENU_ITEM;\ + uint8_t _lineNr = currentMenuViewOffset, _menuItemNr; \ + bool wasClicked = LCD_CLICKED;\ + for(uint8_t _drawLineNr = 0; _drawLineNr < LCD_HEIGHT; _drawLineNr++, _lineNr++) { \ + _menuItemNr = 0; +#define MENU_ITEM(type, label, args...) do { \ + if (_menuItemNr == _lineNr) { \ + if (lcdDrawUpdate) { \ + const char* _label_pstr = PSTR(label); \ + if ((encoderPosition / ENCODER_STEPS_PER_MENU_ITEM) == _menuItemNr) { \ + lcd_implementation_drawmenu_ ## type ## _selected (_drawLineNr, _label_pstr , ## args ); \ + }else{\ + lcd_implementation_drawmenu_ ## type (_drawLineNr, _label_pstr , ## args ); \ + }\ + }\ + if (wasClicked && (encoderPosition / ENCODER_STEPS_PER_MENU_ITEM) == _menuItemNr) {\ + lcd_quick_feedback(); \ + menu_action_ ## type ( args ); \ + return;\ + }\ + }\ + _menuItemNr++;\ +} while(0) +#define MENU_ITEM_DUMMY() do { _menuItemNr++; } while(0) +#define MENU_ITEM_EDIT(type, label, args...) MENU_ITEM(setting_edit_ ## type, label, PSTR(label) , ## args ) +#define MENU_ITEM_EDIT_CALLBACK(type, label, args...) MENU_ITEM(setting_edit_callback_ ## type, label, PSTR(label) , ## args ) +#define END_MENU() \ + if (encoderPosition / ENCODER_STEPS_PER_MENU_ITEM >= _menuItemNr) encoderPosition = _menuItemNr * ENCODER_STEPS_PER_MENU_ITEM - 1; \ + if ((uint8_t)(encoderPosition / ENCODER_STEPS_PER_MENU_ITEM) >= currentMenuViewOffset + LCD_HEIGHT) { currentMenuViewOffset = (encoderPosition / ENCODER_STEPS_PER_MENU_ITEM) - LCD_HEIGHT + 1; lcdDrawUpdate = 1; _lineNr = currentMenuViewOffset - 1; _drawLineNr = -1; } \ + } } while(0) + +/** Used variables to keep track of the menu */ +#ifndef REPRAPWORLD_KEYPAD +volatile uint8_t buttons;//Contains the bits of the currently pressed buttons. +#else +volatile uint8_t buttons_reprapworld_keypad; // to store the reprapworld_keypad shift register values +#endif +#ifdef LCD_HAS_SLOW_BUTTONS +volatile uint8_t slow_buttons;//Contains the bits of the currently pressed buttons. +#endif +uint8_t currentMenuViewOffset; /* scroll offset in the current menu */ +uint32_t blocking_enc; +uint8_t lastEncoderBits; +uint32_t encoderPosition; +#if (SDCARDDETECT > 0) +bool lcd_oldcardstatus; +#endif +#endif//ULTIPANEL + +menuFunc_t currentMenu = lcd_status_screen; /* function pointer to the currently active menu */ +uint32_t lcd_next_update_millis; +uint8_t lcd_status_update_delay; +uint8_t lcdDrawUpdate = 2; /* Set to none-zero when the LCD needs to draw, decreased after every draw. Set to 2 in LCD routines so the LCD gets at least 1 full redraw (first redraw is partial) */ + +//prevMenu and prevEncoderPosition are used to store the previous menu location when editing settings. +menuFunc_t prevMenu = NULL; +uint16_t prevEncoderPosition; +//Variables used when editing values. +const char* editLabel; +void* editValue; +int32_t minEditValue, maxEditValue; +menuFunc_t callbackFunc; + +// place-holders for Ki and Kd edits +float raw_Ki, raw_Kd; + +/* 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 + if (LCD_CLICKED) + { + 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 +} + +#ifdef ULTIPANEL +static void lcd_return_to_status() +{ + encoderPosition = 0; + currentMenu = lcd_status_screen; +} + +static void lcd_sdcard_pause() +{ + card.pauseSDPrint(); +} +static void lcd_sdcard_resume() +{ + card.startFileprint(); +} + +static void lcd_sdcard_stop() +{ + card.sdprinting = false; + card.closefile(); + quickStop(); + if(SD_FINISHED_STEPPERRELEASE) + { + enquecommand_P(PSTR(SD_FINISHED_RELEASECOMMAND)); + } + autotempShutdown(); + + cancel_heatup = true; +} + +/* Menu implementation */ +static void lcd_main_menu() +{ + START_MENU(); + MENU_ITEM(back, MSG_WATCH, lcd_status_screen); + if (movesplanned() || IS_SD_PRINTING) + { + MENU_ITEM(submenu, MSG_TUNE, lcd_tune_menu); + }else{ + MENU_ITEM(submenu, MSG_PREPARE, lcd_prepare_menu); + } + MENU_ITEM(submenu, MSG_CONTROL, lcd_control_menu); +#ifdef SDSUPPORT + if (card.cardOK) + { + if (card.isFileOpen()) + { + if (card.sdprinting) + MENU_ITEM(function, MSG_PAUSE_PRINT, lcd_sdcard_pause); + else + MENU_ITEM(function, MSG_RESUME_PRINT, lcd_sdcard_resume); + MENU_ITEM(function, MSG_STOP_PRINT, lcd_sdcard_stop); + }else{ + MENU_ITEM(submenu, MSG_CARD_MENU, lcd_sdcard_menu); +#if SDCARDDETECT < 1 + MENU_ITEM(gcode, MSG_CNG_SDCARD, PSTR("M21")); // SD-card changed by user +#endif + } + }else{ + MENU_ITEM(submenu, MSG_NO_CARD, lcd_sdcard_menu); +#if SDCARDDETECT < 1 + MENU_ITEM(gcode, MSG_INIT_SDCARD, PSTR("M21")); // Manually initialize the SD-card via user interface +#endif + } +#endif + END_MENU(); +} + +#ifdef SDSUPPORT +static void lcd_autostart_sd() +{ + card.lastnr=0; + card.setroot(); + card.checkautostart(true); +} +#endif + +#ifdef BABYSTEPPING +static void lcd_babystep_x() +{ + if (encoderPosition != 0) + { + babystepsTodo[X_AXIS]+=(int)encoderPosition; + encoderPosition=0; + lcdDrawUpdate = 1; + } + if (lcdDrawUpdate) + { + lcd_implementation_drawedit(PSTR(MSG_BABYSTEPPING_X),""); + } + 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(MSG_BABYSTEPPING_Y),""); + } + if (LCD_CLICKED) + { + lcd_quick_feedback(); + currentMenu = lcd_tune_menu; + encoderPosition = 0; + } +} + +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; + } +} +#endif //BABYSTEPPING + +static void lcd_tune_menu() +{ + START_MENU(); + MENU_ITEM(back, MSG_MAIN, lcd_main_menu); + MENU_ITEM_EDIT(int3, MSG_SPEED, &feedmultiply, 10, 999); + MENU_ITEM_EDIT(int3, MSG_NOZZLE, &target_temperature[0], 0, HEATER_0_MAXTEMP - 15); +#if TEMP_SENSOR_1 != 0 + MENU_ITEM_EDIT(int3, MSG_NOZZLE1, &target_temperature[1], 0, HEATER_1_MAXTEMP - 15); +#endif +#if TEMP_SENSOR_2 != 0 + MENU_ITEM_EDIT(int3, MSG_NOZZLE2, &target_temperature[2], 0, HEATER_2_MAXTEMP - 15); +#endif +#if TEMP_SENSOR_BED != 0 + MENU_ITEM_EDIT(int3, MSG_BED, &target_temperature_bed, 0, BED_MAXTEMP - 15); +#endif + MENU_ITEM_EDIT(int3, MSG_FAN_SPEED, &fanSpeed, 0, 255); + MENU_ITEM_EDIT(int3, MSG_FLOW, &extrudemultiply, 10, 999); + MENU_ITEM_EDIT(int3, MSG_FLOW0, &extruder_multiply[0], 10, 999); +#if TEMP_SENSOR_1 != 0 + MENU_ITEM_EDIT(int3, MSG_FLOW1, &extruder_multiply[1], 10, 999); +#endif +#if TEMP_SENSOR_2 != 0 + MENU_ITEM_EDIT(int3, MSG_FLOW2, &extruder_multiply[2], 10, 999); +#endif + +#ifdef BABYSTEPPING + #ifdef BABYSTEP_XY + MENU_ITEM(submenu, MSG_BABYSTEP_X, lcd_babystep_x); + MENU_ITEM(submenu, MSG_BABYSTEP_Y, lcd_babystep_y); + #endif //BABYSTEP_XY + MENU_ITEM(submenu, MSG_BABYSTEP_Z, lcd_babystep_z); +#endif +#ifdef FILAMENTCHANGEENABLE + MENU_ITEM(gcode, MSG_FILAMENTCHANGE, PSTR("M600")); +#endif + END_MENU(); +} + +void lcd_preheat_pla0() +{ + setTargetHotend0(plaPreheatHotendTemp); + setTargetBed(plaPreheatHPBTemp); + fanSpeed = plaPreheatFanSpeed; + lcd_return_to_status(); + setWatch(); // heater sanity check timer +} + +void lcd_preheat_abs0() +{ + setTargetHotend0(absPreheatHotendTemp); + setTargetBed(absPreheatHPBTemp); + fanSpeed = absPreheatFanSpeed; + lcd_return_to_status(); + setWatch(); // heater sanity check timer +} + +#if TEMP_SENSOR_1 != 0 //2nd extruder preheat +void lcd_preheat_pla1() +{ + setTargetHotend1(plaPreheatHotendTemp); + setTargetBed(plaPreheatHPBTemp); + fanSpeed = plaPreheatFanSpeed; + lcd_return_to_status(); + setWatch(); // heater sanity check timer +} + +void lcd_preheat_abs1() +{ + setTargetHotend1(absPreheatHotendTemp); + setTargetBed(absPreheatHPBTemp); + fanSpeed = absPreheatFanSpeed; + lcd_return_to_status(); + setWatch(); // heater sanity check timer +} +#endif //2nd extruder preheat + +#if TEMP_SENSOR_2 != 0 //3 extruder preheat +void lcd_preheat_pla2() +{ + setTargetHotend2(plaPreheatHotendTemp); + setTargetBed(plaPreheatHPBTemp); + fanSpeed = plaPreheatFanSpeed; + lcd_return_to_status(); + setWatch(); // heater sanity check timer +} + +void lcd_preheat_abs2() +{ + setTargetHotend2(absPreheatHotendTemp); + setTargetBed(absPreheatHPBTemp); + fanSpeed = absPreheatFanSpeed; + lcd_return_to_status(); + setWatch(); // heater sanity check timer +} +#endif //3 extruder preheat + +#if TEMP_SENSOR_1 != 0 || TEMP_SENSOR_2 != 0 //more than one extruder present +void lcd_preheat_pla012() +{ + setTargetHotend0(plaPreheatHotendTemp); + setTargetHotend1(plaPreheatHotendTemp); + setTargetHotend2(plaPreheatHotendTemp); + setTargetBed(plaPreheatHPBTemp); + fanSpeed = plaPreheatFanSpeed; + lcd_return_to_status(); + setWatch(); // heater sanity check timer +} + +void lcd_preheat_abs012() +{ + setTargetHotend0(absPreheatHotendTemp); + setTargetHotend1(absPreheatHotendTemp); + setTargetHotend2(absPreheatHotendTemp); + setTargetBed(absPreheatHPBTemp); + fanSpeed = absPreheatFanSpeed; + lcd_return_to_status(); + setWatch(); // heater sanity check timer +} +#endif //more than one extruder present + +void lcd_preheat_pla_bedonly() +{ + setTargetBed(plaPreheatHPBTemp); + fanSpeed = plaPreheatFanSpeed; + lcd_return_to_status(); + setWatch(); // heater sanity check timer +} + +void lcd_preheat_abs_bedonly() +{ + setTargetBed(absPreheatHPBTemp); + fanSpeed = absPreheatFanSpeed; + lcd_return_to_status(); + setWatch(); // heater sanity check timer +} + +static void lcd_preheat_pla_menu() +{ + START_MENU(); + MENU_ITEM(back, MSG_PREPARE, lcd_prepare_menu); + MENU_ITEM(function, MSG_PREHEAT_PLA0, lcd_preheat_pla0); +#if TEMP_SENSOR_1 != 0 //2 extruder preheat + MENU_ITEM(function, MSG_PREHEAT_PLA1, lcd_preheat_pla1); +#endif //2 extruder preheat +#if TEMP_SENSOR_2 != 0 //3 extruder preheat + MENU_ITEM(function, MSG_PREHEAT_PLA2, lcd_preheat_pla2); +#endif //3 extruder preheat +#if TEMP_SENSOR_1 != 0 || TEMP_SENSOR_2 != 0 //all extruder preheat + MENU_ITEM(function, MSG_PREHEAT_PLA012, lcd_preheat_pla012); +#endif //2 extruder preheat +#if TEMP_SENSOR_BED != 0 + MENU_ITEM(function, MSG_PREHEAT_PLA_BEDONLY, lcd_preheat_pla_bedonly); +#endif + END_MENU(); +} + +static void lcd_preheat_abs_menu() +{ + START_MENU(); + MENU_ITEM(back, MSG_PREPARE, lcd_prepare_menu); + MENU_ITEM(function, MSG_PREHEAT_ABS0, lcd_preheat_abs0); +#if TEMP_SENSOR_1 != 0 //2 extruder preheat + MENU_ITEM(function, MSG_PREHEAT_ABS1, lcd_preheat_abs1); +#endif //2 extruder preheat +#if TEMP_SENSOR_2 != 0 //3 extruder preheat + MENU_ITEM(function, MSG_PREHEAT_ABS2, lcd_preheat_abs2); +#endif //3 extruder preheat +#if TEMP_SENSOR_1 != 0 || TEMP_SENSOR_2 != 0 //all extruder preheat + MENU_ITEM(function, MSG_PREHEAT_ABS012, lcd_preheat_abs012); +#endif //2 extruder preheat +#if TEMP_SENSOR_BED != 0 + MENU_ITEM(function, MSG_PREHEAT_ABS_BEDONLY, lcd_preheat_abs_bedonly); +#endif + END_MENU(); +} + +void lcd_cooldown() +{ + setTargetHotend0(0); + setTargetHotend1(0); + setTargetHotend2(0); + setTargetBed(0); + fanSpeed = 0; + lcd_return_to_status(); +} + +static void lcd_prepare_menu() +{ + START_MENU(); + MENU_ITEM(back, MSG_MAIN, lcd_main_menu); +#ifdef SDSUPPORT + #ifdef MENU_ADDAUTOSTART + MENU_ITEM(function, MSG_AUTOSTART, lcd_autostart_sd); + #endif +#endif + MENU_ITEM(gcode, MSG_DISABLE_STEPPERS, PSTR("M84")); + MENU_ITEM(gcode, MSG_AUTO_HOME, PSTR("G28")); + //MENU_ITEM(gcode, MSG_SET_ORIGIN, PSTR("G92 X0 Y0 Z0")); +#if TEMP_SENSOR_0 != 0 + #if TEMP_SENSOR_1 != 0 || TEMP_SENSOR_2 != 0 || TEMP_SENSOR_BED != 0 + MENU_ITEM(submenu, MSG_PREHEAT_PLA, lcd_preheat_pla_menu); + MENU_ITEM(submenu, MSG_PREHEAT_ABS, lcd_preheat_abs_menu); + #else + MENU_ITEM(function, MSG_PREHEAT_PLA, lcd_preheat_pla0); + MENU_ITEM(function, MSG_PREHEAT_ABS, lcd_preheat_abs0); + #endif +#endif + MENU_ITEM(function, MSG_COOLDOWN, lcd_cooldown); +#if PS_ON_PIN > -1 + if (powersupply) + { + MENU_ITEM(gcode, MSG_SWITCH_PS_OFF, PSTR("M81")); + }else{ + MENU_ITEM(gcode, MSG_SWITCH_PS_ON, PSTR("M80")); + } +#endif + MENU_ITEM(submenu, MSG_MOVE_AXIS, lcd_move_menu); + END_MENU(); +} + +float move_menu_scale; +static void lcd_move_menu_axis(); + +static void lcd_move_x() +{ + if (encoderPosition != 0) + { + refresh_cmd_timeout(); + current_position[X_AXIS] += float((int)encoderPosition) * move_menu_scale; + if (min_software_endstops && current_position[X_AXIS] < X_MIN_POS) + current_position[X_AXIS] = X_MIN_POS; + if (max_software_endstops && current_position[X_AXIS] > X_MAX_POS) + current_position[X_AXIS] = X_MAX_POS; + encoderPosition = 0; + #ifdef DELTA + calculate_delta(current_position); + plan_buffer_line(delta[X_AXIS], delta[Y_AXIS], delta[Z_AXIS], current_position[E_AXIS], manual_feedrate[X_AXIS]/60, active_extruder); + #else + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], manual_feedrate[X_AXIS]/60, active_extruder); + #endif + lcdDrawUpdate = 1; + } + if (lcdDrawUpdate) + { + lcd_implementation_drawedit(PSTR("X"), ftostr31(current_position[X_AXIS])); + } + if (LCD_CLICKED) + { + lcd_quick_feedback(); + currentMenu = lcd_move_menu_axis; + encoderPosition = 0; + } +} +static void lcd_move_y() +{ + if (encoderPosition != 0) + { + refresh_cmd_timeout(); + current_position[Y_AXIS] += float((int)encoderPosition) * move_menu_scale; + if (min_software_endstops && current_position[Y_AXIS] < Y_MIN_POS) + current_position[Y_AXIS] = Y_MIN_POS; + if (max_software_endstops && current_position[Y_AXIS] > Y_MAX_POS) + current_position[Y_AXIS] = Y_MAX_POS; + encoderPosition = 0; + #ifdef DELTA + calculate_delta(current_position); + plan_buffer_line(delta[X_AXIS], delta[Y_AXIS], delta[Z_AXIS], current_position[E_AXIS], manual_feedrate[Y_AXIS]/60, active_extruder); + #else + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], manual_feedrate[Y_AXIS]/60, active_extruder); + #endif + lcdDrawUpdate = 1; + } + if (lcdDrawUpdate) + { + lcd_implementation_drawedit(PSTR("Y"), ftostr31(current_position[Y_AXIS])); + } + if (LCD_CLICKED) + { + lcd_quick_feedback(); + currentMenu = lcd_move_menu_axis; + encoderPosition = 0; + } +} +static void lcd_move_z() +{ + if (encoderPosition != 0) + { + refresh_cmd_timeout(); + current_position[Z_AXIS] += float((int)encoderPosition) * move_menu_scale; + if (min_software_endstops && current_position[Z_AXIS] < Z_MIN_POS) + current_position[Z_AXIS] = Z_MIN_POS; + if (max_software_endstops && current_position[Z_AXIS] > Z_MAX_POS) + current_position[Z_AXIS] = Z_MAX_POS; + encoderPosition = 0; + #ifdef DELTA + calculate_delta(current_position); + plan_buffer_line(delta[X_AXIS], delta[Y_AXIS], delta[Z_AXIS], current_position[E_AXIS], manual_feedrate[Z_AXIS]/60, active_extruder); + #else + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], manual_feedrate[Z_AXIS]/60, active_extruder); + #endif + lcdDrawUpdate = 1; + } + if (lcdDrawUpdate) + { + lcd_implementation_drawedit(PSTR("Z"), ftostr31(current_position[Z_AXIS])); + } + if (LCD_CLICKED) + { + lcd_quick_feedback(); + currentMenu = lcd_move_menu_axis; + encoderPosition = 0; + } +} +static void lcd_move_e() +{ + if (encoderPosition != 0) + { + current_position[E_AXIS] += float((int)encoderPosition) * move_menu_scale; + encoderPosition = 0; + #ifdef DELTA + calculate_delta(current_position); + plan_buffer_line(delta[X_AXIS], delta[Y_AXIS], delta[Z_AXIS], current_position[E_AXIS], manual_feedrate[E_AXIS]/60, active_extruder); + #else + plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS], manual_feedrate[E_AXIS]/60, active_extruder); + #endif + 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_move_menu_axis() +{ + START_MENU(); + MENU_ITEM(back, MSG_MOVE_AXIS, lcd_move_menu); + MENU_ITEM(submenu, MSG_MOVE_X, lcd_move_x); + MENU_ITEM(submenu, MSG_MOVE_Y, lcd_move_y); + if (move_menu_scale < 10.0) + { + MENU_ITEM(submenu, MSG_MOVE_Z, lcd_move_z); + MENU_ITEM(submenu, MSG_MOVE_E, lcd_move_e); + } + END_MENU(); +} + +static void lcd_move_menu_10mm() +{ + move_menu_scale = 10.0; + lcd_move_menu_axis(); +} +static void lcd_move_menu_1mm() +{ + move_menu_scale = 1.0; + lcd_move_menu_axis(); +} +static void lcd_move_menu_01mm() +{ + move_menu_scale = 0.1; + lcd_move_menu_axis(); +} + +static void lcd_move_menu() +{ + START_MENU(); + MENU_ITEM(back, MSG_PREPARE, lcd_prepare_menu); + MENU_ITEM(submenu, MSG_MOVE_10MM, lcd_move_menu_10mm); + MENU_ITEM(submenu, MSG_MOVE_1MM, lcd_move_menu_1mm); + MENU_ITEM(submenu, MSG_MOVE_01MM, lcd_move_menu_01mm); + //TODO:X,Y,Z,E + END_MENU(); +} + +static void lcd_control_menu() +{ + START_MENU(); + MENU_ITEM(back, MSG_MAIN, lcd_main_menu); + MENU_ITEM(submenu, MSG_TEMPERATURE, lcd_control_temperature_menu); + MENU_ITEM(submenu, MSG_MOTION, lcd_control_motion_menu); +#ifdef DOGLCD +// MENU_ITEM_EDIT(int3, MSG_CONTRAST, &lcd_contrast, 0, 63); + MENU_ITEM(submenu, MSG_CONTRAST, lcd_set_contrast); +#endif +#ifdef FWRETRACT + MENU_ITEM(submenu, MSG_RETRACT, lcd_control_retract_menu); +#endif +#ifdef EEPROM_SETTINGS + MENU_ITEM(function, MSG_STORE_EPROM, Config_StoreSettings); + MENU_ITEM(function, MSG_LOAD_EPROM, Config_RetrieveSettings); +#endif + MENU_ITEM(function, MSG_RESTORE_FAILSAFE, Config_ResetDefault); + END_MENU(); +} + +static void lcd_control_temperature_menu() +{ +#ifdef PIDTEMP + // set up temp variables - undo the default scaling + raw_Ki = unscalePID_i(Ki); + raw_Kd = unscalePID_d(Kd); +#endif + + START_MENU(); + MENU_ITEM(back, MSG_CONTROL, lcd_control_menu); + MENU_ITEM_EDIT(int3, MSG_NOZZLE, &target_temperature[0], 0, HEATER_0_MAXTEMP - 15); +#if TEMP_SENSOR_1 != 0 + MENU_ITEM_EDIT(int3, MSG_NOZZLE1, &target_temperature[1], 0, HEATER_1_MAXTEMP - 15); +#endif +#if TEMP_SENSOR_2 != 0 + MENU_ITEM_EDIT(int3, MSG_NOZZLE2, &target_temperature[2], 0, HEATER_2_MAXTEMP - 15); +#endif +#if TEMP_SENSOR_BED != 0 + MENU_ITEM_EDIT(int3, MSG_BED, &target_temperature_bed, 0, BED_MAXTEMP - 15); +#endif + MENU_ITEM_EDIT(int3, MSG_FAN_SPEED, &fanSpeed, 0, 255); +#ifdef AUTOTEMP + MENU_ITEM_EDIT(bool, MSG_AUTOTEMP, &autotemp_enabled); + MENU_ITEM_EDIT(float3, MSG_MIN, &autotemp_min, 0, HEATER_0_MAXTEMP - 15); + MENU_ITEM_EDIT(float3, MSG_MAX, &autotemp_max, 0, HEATER_0_MAXTEMP - 15); + MENU_ITEM_EDIT(float32, MSG_FACTOR, &autotemp_factor, 0.0, 1.0); +#endif +#ifdef PIDTEMP + MENU_ITEM_EDIT(float52, MSG_PID_P, &Kp, 1, 9990); + // i is typically a small value so allows values below 1 + MENU_ITEM_EDIT_CALLBACK(float52, MSG_PID_I, &raw_Ki, 0.01, 9990, copy_and_scalePID_i); + MENU_ITEM_EDIT_CALLBACK(float52, MSG_PID_D, &raw_Kd, 1, 9990, copy_and_scalePID_d); +# ifdef PID_ADD_EXTRUSION_RATE + MENU_ITEM_EDIT(float3, MSG_PID_C, &Kc, 1, 9990); +# endif//PID_ADD_EXTRUSION_RATE +#endif//PIDTEMP + MENU_ITEM(submenu, MSG_PREHEAT_PLA_SETTINGS, lcd_control_temperature_preheat_pla_settings_menu); + MENU_ITEM(submenu, MSG_PREHEAT_ABS_SETTINGS, lcd_control_temperature_preheat_abs_settings_menu); + END_MENU(); +} + +static void lcd_control_temperature_preheat_pla_settings_menu() +{ + START_MENU(); + MENU_ITEM(back, MSG_TEMPERATURE, lcd_control_temperature_menu); + MENU_ITEM_EDIT(int3, MSG_FAN_SPEED, &plaPreheatFanSpeed, 0, 255); + MENU_ITEM_EDIT(int3, MSG_NOZZLE, &plaPreheatHotendTemp, 0, HEATER_0_MAXTEMP - 15); +#if TEMP_SENSOR_BED != 0 + MENU_ITEM_EDIT(int3, MSG_BED, &plaPreheatHPBTemp, 0, BED_MAXTEMP - 15); +#endif +#ifdef EEPROM_SETTINGS + MENU_ITEM(function, MSG_STORE_EPROM, Config_StoreSettings); +#endif + END_MENU(); +} + +static void lcd_control_temperature_preheat_abs_settings_menu() +{ + START_MENU(); + MENU_ITEM(back, MSG_TEMPERATURE, lcd_control_temperature_menu); + MENU_ITEM_EDIT(int3, MSG_FAN_SPEED, &absPreheatFanSpeed, 0, 255); + MENU_ITEM_EDIT(int3, MSG_NOZZLE, &absPreheatHotendTemp, 0, HEATER_0_MAXTEMP - 15); +#if TEMP_SENSOR_BED != 0 + MENU_ITEM_EDIT(int3, MSG_BED, &absPreheatHPBTemp, 0, BED_MAXTEMP - 15); +#endif +#ifdef EEPROM_SETTINGS + MENU_ITEM(function, MSG_STORE_EPROM, Config_StoreSettings); +#endif + END_MENU(); +} + +static void lcd_control_motion_menu() +{ + START_MENU(); + MENU_ITEM(back, MSG_CONTROL, lcd_control_menu); +#ifdef ENABLE_AUTO_BED_LEVELING + MENU_ITEM_EDIT(float32, MSG_ZPROBE_ZOFFSET, &zprobe_zoffset, 0.5, 50); +#endif + MENU_ITEM_EDIT(float5, MSG_ACC, &acceleration, 500, 99000); + MENU_ITEM_EDIT(float3, MSG_VXY_JERK, &max_xy_jerk, 1, 990); + MENU_ITEM_EDIT(float52, MSG_VZ_JERK, &max_z_jerk, 0.1, 990); + MENU_ITEM_EDIT(float3, MSG_VE_JERK, &max_e_jerk, 1, 990); + MENU_ITEM_EDIT(float3, MSG_VMAX MSG_X, &max_feedrate[X_AXIS], 1, 999); + MENU_ITEM_EDIT(float3, MSG_VMAX MSG_Y, &max_feedrate[Y_AXIS], 1, 999); + MENU_ITEM_EDIT(float3, MSG_VMAX MSG_Z, &max_feedrate[Z_AXIS], 1, 999); + MENU_ITEM_EDIT(float3, MSG_VMAX MSG_E, &max_feedrate[E_AXIS], 1, 999); + MENU_ITEM_EDIT(float3, MSG_VMIN, &minimumfeedrate, 0, 999); + MENU_ITEM_EDIT(float3, MSG_VTRAV_MIN, &mintravelfeedrate, 0, 999); + MENU_ITEM_EDIT_CALLBACK(long5, MSG_AMAX MSG_X, &max_acceleration_units_per_sq_second[X_AXIS], 100, 99000, reset_acceleration_rates); + MENU_ITEM_EDIT_CALLBACK(long5, MSG_AMAX MSG_Y, &max_acceleration_units_per_sq_second[Y_AXIS], 100, 99000, reset_acceleration_rates); + MENU_ITEM_EDIT_CALLBACK(long5, MSG_AMAX MSG_Z, &max_acceleration_units_per_sq_second[Z_AXIS], 100, 99000, reset_acceleration_rates); + MENU_ITEM_EDIT_CALLBACK(long5, MSG_AMAX MSG_E, &max_acceleration_units_per_sq_second[E_AXIS], 100, 99000, reset_acceleration_rates); + MENU_ITEM_EDIT(float5, MSG_A_RETRACT, &retract_acceleration, 100, 99000); + MENU_ITEM_EDIT(float52, MSG_XSTEPS, &axis_steps_per_unit[X_AXIS], 5, 9999); + MENU_ITEM_EDIT(float52, MSG_YSTEPS, &axis_steps_per_unit[Y_AXIS], 5, 9999); + MENU_ITEM_EDIT(float51, MSG_ZSTEPS, &axis_steps_per_unit[Z_AXIS], 5, 9999); + MENU_ITEM_EDIT(float51, MSG_ESTEPS, &axis_steps_per_unit[E_AXIS], 5, 9999); +#ifdef ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED + MENU_ITEM_EDIT(bool, MSG_ENDSTOP_ABORT, &abort_on_endstop_hit); +#endif +#ifdef SCARA + MENU_ITEM_EDIT(float74, MSG_XSCALE, &axis_scaling[X_AXIS],0.5,2); + MENU_ITEM_EDIT(float74, MSG_YSCALE, &axis_scaling[Y_AXIS],0.5,2); +#endif + END_MENU(); +} + +#ifdef DOGLCD +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(MSG_CONTRAST), itostr2(lcd_contrast)); + } + if (LCD_CLICKED) + { + lcd_quick_feedback(); + currentMenu = lcd_control_menu; + encoderPosition = 0; + } +} +#endif + +#ifdef FWRETRACT +static void lcd_control_retract_menu() +{ + START_MENU(); + MENU_ITEM(back, MSG_CONTROL, lcd_control_menu); + MENU_ITEM_EDIT(bool, MSG_AUTORETRACT, &autoretract_enabled); + MENU_ITEM_EDIT(float52, MSG_CONTROL_RETRACT, &retract_length, 0, 100); + #if EXTRUDERS > 1 + MENU_ITEM_EDIT(float52, MSG_CONTROL_RETRACT_SWAP, &retract_length_swap, 0, 100); + #endif + MENU_ITEM_EDIT(float3, MSG_CONTROL_RETRACTF, &retract_feedrate, 1, 999); + MENU_ITEM_EDIT(float52, MSG_CONTROL_RETRACT_ZLIFT, &retract_zlift, 0, 999); + MENU_ITEM_EDIT(float52, MSG_CONTROL_RETRACT_RECOVER, &retract_recover_length, 0, 100); + #if EXTRUDERS > 1 + MENU_ITEM_EDIT(float52, MSG_CONTROL_RETRACT_RECOVER_SWAP, &retract_recover_length_swap, 0, 100); + #endif + MENU_ITEM_EDIT(float3, MSG_CONTROL_RETRACT_RECOVERF, &retract_recover_feedrate, 1, 999); + END_MENU(); +} +#endif + +#if SDCARDDETECT == -1 +static void lcd_sd_refresh() +{ + card.initsd(); + currentMenuViewOffset = 0; +} +#endif +static void lcd_sd_updir() +{ + card.updir(); + currentMenuViewOffset = 0; +} + +void lcd_sdcard_menu() +{ + if (lcdDrawUpdate == 0 && LCD_CLICKED == 0) + return; // nothing to do (so don't thrash the SD card) + uint16_t fileCnt = card.getnrfilenames(); + START_MENU(); + MENU_ITEM(back, MSG_MAIN, lcd_main_menu); + card.getWorkDirName(); + if(card.filename[0]=='/') + { +#if SDCARDDETECT == -1 + MENU_ITEM(function, LCD_STR_REFRESH MSG_REFRESH, lcd_sd_refresh); +#endif + }else{ + MENU_ITEM(function, LCD_STR_FOLDER "..", lcd_sd_updir); + } + + for(uint16_t i=0;i maxEditValue) \ + encoderPosition = maxEditValue; \ + if (lcdDrawUpdate) \ + lcd_implementation_drawedit(editLabel, _strFunc(((_type)encoderPosition) / scale)); \ + if (LCD_CLICKED) \ + { \ + *((_type*)editValue) = ((_type)encoderPosition) / scale; \ + lcd_quick_feedback(); \ + currentMenu = prevMenu; \ + encoderPosition = prevEncoderPosition; \ + } \ + } \ + void menu_edit_callback_ ## _name () \ + { \ + if ((int32_t)encoderPosition < minEditValue) \ + encoderPosition = minEditValue; \ + if ((int32_t)encoderPosition > maxEditValue) \ + encoderPosition = maxEditValue; \ + if (lcdDrawUpdate) \ + lcd_implementation_drawedit(editLabel, _strFunc(((_type)encoderPosition) / scale)); \ + if (LCD_CLICKED) \ + { \ + *((_type*)editValue) = ((_type)encoderPosition) / scale; \ + lcd_quick_feedback(); \ + currentMenu = prevMenu; \ + encoderPosition = prevEncoderPosition; \ + (*callbackFunc)();\ + } \ + } \ + static void menu_action_setting_edit_ ## _name (const char* pstr, _type* ptr, _type minValue, _type maxValue) \ + { \ + prevMenu = currentMenu; \ + prevEncoderPosition = encoderPosition; \ + \ + lcdDrawUpdate = 2; \ + currentMenu = menu_edit_ ## _name; \ + \ + editLabel = pstr; \ + editValue = ptr; \ + minEditValue = minValue * scale; \ + maxEditValue = maxValue * scale; \ + encoderPosition = (*ptr) * scale; \ + }\ + static void menu_action_setting_edit_callback_ ## _name (const char* pstr, _type* ptr, _type minValue, _type maxValue, menuFunc_t callback) \ + { \ + prevMenu = currentMenu; \ + prevEncoderPosition = encoderPosition; \ + \ + lcdDrawUpdate = 2; \ + currentMenu = menu_edit_callback_ ## _name; \ + \ + editLabel = pstr; \ + editValue = ptr; \ + minEditValue = minValue * scale; \ + maxEditValue = maxValue * scale; \ + encoderPosition = (*ptr) * scale; \ + callbackFunc = callback;\ + } +menu_edit_type(int, int3, itostr3, 1) +menu_edit_type(float, float3, ftostr3, 1) +menu_edit_type(float, float32, ftostr32, 100) +menu_edit_type(float, float5, ftostr5, 0.01) +menu_edit_type(float, float51, ftostr51, 10) +menu_edit_type(float, float52, ftostr52, 100) +menu_edit_type(unsigned long, long5, ftostr5, 0.01) + +#ifdef REPRAPWORLD_KEYPAD + static void reprapworld_keypad_move_z_up() { + encoderPosition = 1; + move_menu_scale = REPRAPWORLD_KEYPAD_MOVE_STEP; + lcd_move_z(); + } + static void reprapworld_keypad_move_z_down() { + encoderPosition = -1; + move_menu_scale = REPRAPWORLD_KEYPAD_MOVE_STEP; + lcd_move_z(); + } + static void reprapworld_keypad_move_x_left() { + encoderPosition = -1; + move_menu_scale = REPRAPWORLD_KEYPAD_MOVE_STEP; + lcd_move_x(); + } + static void reprapworld_keypad_move_x_right() { + encoderPosition = 1; + move_menu_scale = REPRAPWORLD_KEYPAD_MOVE_STEP; + lcd_move_x(); + } + static void reprapworld_keypad_move_y_down() { + encoderPosition = 1; + move_menu_scale = REPRAPWORLD_KEYPAD_MOVE_STEP; + lcd_move_y(); + } + static void reprapworld_keypad_move_y_up() { + encoderPosition = -1; + move_menu_scale = REPRAPWORLD_KEYPAD_MOVE_STEP; + lcd_move_y(); + } + static void reprapworld_keypad_move_home() { + enquecommand_P((PSTR("G28"))); // move all axis home + } +#endif + +/** End of menus **/ + +static void lcd_quick_feedback() +{ + lcdDrawUpdate = 2; + blocking_enc = millis() + 500; + lcd_implementation_quick_feedback(); +} + +/** Menu action functions **/ +static void menu_action_back(menuFunc_t data) +{ + currentMenu = data; + encoderPosition = 0; +} +static void menu_action_submenu(menuFunc_t data) +{ + currentMenu = data; + encoderPosition = 0; +} +static void menu_action_gcode(const char* pgcode) +{ + enquecommand_P(pgcode); +} +static void menu_action_function(menuFunc_t data) +{ + (*data)(); +} +static void menu_action_sdfile(const char* filename, char* longFilename) +{ + char cmd[30]; + char* c; + sprintf_P(cmd, PSTR("M23 %s"), filename); + for(c = &cmd[4]; *c; c++) + *c = tolower(*c); + enquecommand(cmd); + enquecommand_P(PSTR("M24")); + lcd_return_to_status(); +} +static void menu_action_sddirectory(const char* filename, char* longFilename) +{ + card.chdir(filename); + encoderPosition = 0; +} +static void menu_action_setting_edit_bool(const char* pstr, bool* ptr) +{ + *ptr = !(*ptr); +} +#endif//ULTIPANEL + +/** LCD API **/ +void lcd_init() +{ + lcd_implementation_init(); + +#ifdef NEWPANEL + pinMode(BTN_EN1,INPUT); + pinMode(BTN_EN2,INPUT); + WRITE(BTN_EN1,HIGH); + WRITE(BTN_EN2,HIGH); + #if BTN_ENC > 0 + pinMode(BTN_ENC,INPUT); + WRITE(BTN_ENC,HIGH); + #endif + #ifdef REPRAPWORLD_KEYPAD + pinMode(SHIFT_CLK,OUTPUT); + pinMode(SHIFT_LD,OUTPUT); + pinMode(SHIFT_OUT,INPUT); + WRITE(SHIFT_OUT,HIGH); + WRITE(SHIFT_LD,HIGH); + #endif +#else // Not NEWPANEL + #ifdef SR_LCD_2W_NL // Non latching 2 wire shift register + pinMode (SR_DATA_PIN, OUTPUT); + pinMode (SR_CLK_PIN, OUTPUT); + #elif defined(SHIFT_CLK) + pinMode(SHIFT_CLK,OUTPUT); + pinMode(SHIFT_LD,OUTPUT); + pinMode(SHIFT_EN,OUTPUT); + pinMode(SHIFT_OUT,INPUT); + WRITE(SHIFT_OUT,HIGH); + WRITE(SHIFT_LD,HIGH); + WRITE(SHIFT_EN,LOW); + #else + #ifdef ULTIPANEL + #error ULTIPANEL requires an encoder + #endif + #endif // SR_LCD_2W_NL +#endif//!NEWPANEL + +#if defined (SDSUPPORT) && defined(SDCARDDETECT) && (SDCARDDETECT > 0) + pinMode(SDCARDDETECT,INPUT); + WRITE(SDCARDDETECT, HIGH); + lcd_oldcardstatus = IS_SD_INSERTED; +#endif//(SDCARDDETECT > 0) +#ifdef LCD_HAS_SLOW_BUTTONS + slow_buttons = 0; +#endif + lcd_buttons_update(); +#ifdef ULTIPANEL + encoderDiff = 0; +#endif +} + +void lcd_update() +{ + static unsigned long timeoutToStatus = 0; + + #ifdef LCD_HAS_SLOW_BUTTONS + slow_buttons = lcd_implementation_read_slow_buttons(); // buttons which take too long to read in interrupt context + #endif + + lcd_buttons_update(); + + #if (SDCARDDETECT > 0) + if((IS_SD_INSERTED != lcd_oldcardstatus)) + { + lcdDrawUpdate = 2; + lcd_oldcardstatus = IS_SD_INSERTED; + lcd_implementation_init(); // to maybe revive the LCD if static electricity killed it. + + if(lcd_oldcardstatus) + { + card.initsd(); + LCD_MESSAGEPGM(MSG_SD_INSERTED); + } + else + { + card.release(); + LCD_MESSAGEPGM(MSG_SD_REMOVED); + } + } + #endif//CARDINSERTED + + if (lcd_next_update_millis < millis()) + { +#ifdef ULTIPANEL + #ifdef REPRAPWORLD_KEYPAD + if (REPRAPWORLD_KEYPAD_MOVE_Z_UP) { + reprapworld_keypad_move_z_up(); + } + if (REPRAPWORLD_KEYPAD_MOVE_Z_DOWN) { + reprapworld_keypad_move_z_down(); + } + if (REPRAPWORLD_KEYPAD_MOVE_X_LEFT) { + reprapworld_keypad_move_x_left(); + } + if (REPRAPWORLD_KEYPAD_MOVE_X_RIGHT) { + reprapworld_keypad_move_x_right(); + } + if (REPRAPWORLD_KEYPAD_MOVE_Y_DOWN) { + reprapworld_keypad_move_y_down(); + } + if (REPRAPWORLD_KEYPAD_MOVE_Y_UP) { + reprapworld_keypad_move_y_up(); + } + if (REPRAPWORLD_KEYPAD_MOVE_HOME) { + reprapworld_keypad_move_home(); + } + #endif + if (abs(encoderDiff) >= ENCODER_PULSES_PER_STEP) + { + lcdDrawUpdate = 1; + encoderPosition += encoderDiff / ENCODER_PULSES_PER_STEP; + encoderDiff = 0; + timeoutToStatus = millis() + LCD_TIMEOUT_TO_STATUS; + } + if (LCD_CLICKED) + timeoutToStatus = millis() + LCD_TIMEOUT_TO_STATUS; +#endif//ULTIPANEL + +#ifdef DOGLCD // Changes due to different driver architecture of the DOGM display + blink++; // Variable for fan animation and alive dot + u8g.firstPage(); + do + { + u8g.setFont(u8g_font_6x10_marlin); + u8g.setPrintPos(125,0); + if (blink % 2) u8g.setColorIndex(1); else u8g.setColorIndex(0); // Set color for the alive dot + u8g.drawPixel(127,63); // draw alive dot + u8g.setColorIndex(1); // black on white + (*currentMenu)(); + if (!lcdDrawUpdate) break; // Terminate display update, when nothing new to draw. This must be done before the last dogm.next() + } while( u8g.nextPage() ); +#else + (*currentMenu)(); +#endif + +#ifdef LCD_HAS_STATUS_INDICATORS + lcd_implementation_update_indicators(); +#endif + +#ifdef ULTIPANEL + if(timeoutToStatus < millis() && currentMenu != lcd_status_screen) + { + lcd_return_to_status(); + lcdDrawUpdate = 2; + } +#endif//ULTIPANEL + if (lcdDrawUpdate == 2) + lcd_implementation_clear(); + if (lcdDrawUpdate) + lcdDrawUpdate--; + lcd_next_update_millis = millis() + 100; + } +} + +void lcd_setstatus(const char* message) +{ + if (lcd_status_message_level > 0) + return; + strncpy(lcd_status_message, message, LCD_WIDTH); + lcdDrawUpdate = 2; +} +void lcd_setstatuspgm(const char* message) +{ + if (lcd_status_message_level > 0) + return; + strncpy_P(lcd_status_message, message, LCD_WIDTH); + lcdDrawUpdate = 2; +} +void lcd_setalertstatuspgm(const char* message) +{ + lcd_setstatuspgm(message); + lcd_status_message_level = 1; +#ifdef ULTIPANEL + lcd_return_to_status(); +#endif//ULTIPANEL +} +void lcd_reset_alert_level() +{ + lcd_status_message_level = 0; +} + +#ifdef DOGLCD +void lcd_setcontrast(uint8_t value) +{ + lcd_contrast = value & 63; + u8g.setContrast(lcd_contrast); +} +#endif + +#ifdef ULTIPANEL +/* Warning: This function is called from interrupt context */ +void lcd_buttons_update() +{ +#ifdef NEWPANEL + uint8_t newbutton=0; + if(READ(BTN_EN1)==0) newbutton|=EN_A; + if(READ(BTN_EN2)==0) newbutton|=EN_B; + #if BTN_ENC > 0 + if((blocking_enc>1; + if(READ(SHIFT_OUT)) + newbutton_reprapworld_keypad|=(1<<7); + WRITE(SHIFT_CLK,HIGH); + WRITE(SHIFT_CLK,LOW); + } + buttons_reprapworld_keypad=~newbutton_reprapworld_keypad; //invert it, because a pressed switch produces a logical 0 + #endif +#else //read it from the shift register + uint8_t newbutton=0; + WRITE(SHIFT_LD,LOW); + WRITE(SHIFT_LD,HIGH); + unsigned char tmp_buttons=0; + for(int8_t i=0;i<8;i++) + { + newbutton = newbutton>>1; + if(READ(SHIFT_OUT)) + newbutton|=(1<<7); + WRITE(SHIFT_CLK,HIGH); + WRITE(SHIFT_CLK,LOW); + } + buttons=~newbutton; //invert it, because a pressed switch produces a logical 0 +#endif//!NEWPANEL + + //manage encoder rotation + uint8_t enc=0; + if(buttons&EN_A) + enc|=(1<<0); + if(buttons&EN_B) + enc|=(1<<1); + if(enc != lastEncoderBits) + { + switch(enc) + { + case encrot0: + if(lastEncoderBits==encrot3) + encoderDiff++; + else if(lastEncoderBits==encrot1) + encoderDiff--; + break; + case encrot1: + if(lastEncoderBits==encrot0) + encoderDiff++; + else if(lastEncoderBits==encrot2) + encoderDiff--; + break; + case encrot2: + if(lastEncoderBits==encrot1) + encoderDiff++; + else if(lastEncoderBits==encrot3) + encoderDiff--; + break; + case encrot3: + if(lastEncoderBits==encrot2) + encoderDiff++; + else if(lastEncoderBits==encrot0) + encoderDiff--; + break; + } + } + lastEncoderBits = enc; +} + +void lcd_buzz(long duration, uint16_t freq) +{ +#ifdef LCD_USE_I2C_BUZZER + lcd.buzz(duration,freq); +#endif +} + +bool lcd_clicked() +{ + return LCD_CLICKED; +} +#endif//ULTIPANEL + +/********************************/ +/** Float conversion utilities **/ +/********************************/ +// convert float to string with +123.4 format +char conv[8]; +char *ftostr3(const float &x) +{ + return itostr3((int)x); +} + +char *itostr2(const uint8_t &x) +{ + //sprintf(conv,"%5.1f",x); + int xx=x; + conv[0]=(xx/10)%10+'0'; + conv[1]=(xx)%10+'0'; + conv[2]=0; + return conv; +} + +// convert float to string with +123.4 format +char *ftostr31(const float &x) +{ + int xx=x*10; + conv[0]=(xx>=0)?'+':'-'; + xx=abs(xx); + conv[1]=(xx/1000)%10+'0'; + conv[2]=(xx/100)%10+'0'; + conv[3]=(xx/10)%10+'0'; + conv[4]='.'; + conv[5]=(xx)%10+'0'; + conv[6]=0; + return conv; +} + +// convert float to string with 123.4 format +char *ftostr31ns(const float &x) +{ + int xx=x*10; + //conv[0]=(xx>=0)?'+':'-'; + xx=abs(xx); + conv[0]=(xx/1000)%10+'0'; + conv[1]=(xx/100)%10+'0'; + conv[2]=(xx/10)%10+'0'; + conv[3]='.'; + conv[4]=(xx)%10+'0'; + conv[5]=0; + return conv; +} + +char *ftostr32(const float &x) +{ + long xx=x*100; + if (xx >= 0) + conv[0]=(xx/10000)%10+'0'; + else + conv[0]='-'; + xx=abs(xx); + conv[1]=(xx/1000)%10+'0'; + conv[2]=(xx/100)%10+'0'; + conv[3]='.'; + conv[4]=(xx/10)%10+'0'; + conv[5]=(xx)%10+'0'; + conv[6]=0; + return conv; +} + +char *itostr31(const int &xx) +{ + conv[0]=(xx>=0)?'+':'-'; + conv[1]=(xx/1000)%10+'0'; + conv[2]=(xx/100)%10+'0'; + conv[3]=(xx/10)%10+'0'; + conv[4]='.'; + conv[5]=(xx)%10+'0'; + conv[6]=0; + return conv; +} + +char *itostr3(const int &xx) +{ + if (xx >= 100) + conv[0]=(xx/100)%10+'0'; + else + conv[0]=' '; + if (xx >= 10) + conv[1]=(xx/10)%10+'0'; + else + conv[1]=' '; + conv[2]=(xx)%10+'0'; + conv[3]=0; + return conv; +} + +char *itostr3left(const int &xx) +{ + if (xx >= 100) + { + conv[0]=(xx/100)%10+'0'; + conv[1]=(xx/10)%10+'0'; + conv[2]=(xx)%10+'0'; + conv[3]=0; + } + else if (xx >= 10) + { + conv[0]=(xx/10)%10+'0'; + conv[1]=(xx)%10+'0'; + conv[2]=0; + } + else + { + conv[0]=(xx)%10+'0'; + conv[1]=0; + } + return conv; +} + +char *itostr4(const int &xx) +{ + if (xx >= 1000) + conv[0]=(xx/1000)%10+'0'; + else + conv[0]=' '; + if (xx >= 100) + conv[1]=(xx/100)%10+'0'; + else + conv[1]=' '; + if (xx >= 10) + conv[2]=(xx/10)%10+'0'; + else + conv[2]=' '; + conv[3]=(xx)%10+'0'; + conv[4]=0; + return conv; +} + +// convert float to string with 12345 format +char *ftostr5(const float &x) +{ + long xx=abs(x); + if (xx >= 10000) + conv[0]=(xx/10000)%10+'0'; + else + conv[0]=' '; + if (xx >= 1000) + conv[1]=(xx/1000)%10+'0'; + else + conv[1]=' '; + if (xx >= 100) + conv[2]=(xx/100)%10+'0'; + else + conv[2]=' '; + if (xx >= 10) + conv[3]=(xx/10)%10+'0'; + else + conv[3]=' '; + conv[4]=(xx)%10+'0'; + conv[5]=0; + return conv; +} + +// convert float to string with +1234.5 format +char *ftostr51(const float &x) +{ + long xx=x*10; + conv[0]=(xx>=0)?'+':'-'; + xx=abs(xx); + conv[1]=(xx/10000)%10+'0'; + conv[2]=(xx/1000)%10+'0'; + conv[3]=(xx/100)%10+'0'; + conv[4]=(xx/10)%10+'0'; + conv[5]='.'; + conv[6]=(xx)%10+'0'; + conv[7]=0; + return conv; +} + +// convert float to string with +123.45 format +char *ftostr52(const float &x) +{ + long xx=x*100; + conv[0]=(xx>=0)?'+':'-'; + xx=abs(xx); + conv[1]=(xx/10000)%10+'0'; + conv[2]=(xx/1000)%10+'0'; + conv[3]=(xx/100)%10+'0'; + conv[4]='.'; + conv[5]=(xx/10)%10+'0'; + conv[6]=(xx)%10+'0'; + conv[7]=0; + return conv; +} + +// Callback for after editing PID i value +// grab the PID i value out of the temp variable; scale it; then update the PID driver +void copy_and_scalePID_i() +{ +#ifdef PIDTEMP + Ki = scalePID_i(raw_Ki); + updatePID(); +#endif +} + +// Callback for after editing PID d value +// grab the PID d value out of the temp variable; scale it; then update the PID driver +void copy_and_scalePID_d() +{ +#ifdef PIDTEMP + Kd = scalePID_d(raw_Kd); + updatePID(); +#endif +} + +#endif //ULTRA_LCD \ No newline at end of file diff --git a/Marlin/ultralcd.h b/Marlin/ultralcd.h index f4570f6a58..9bf685805d 100644 --- a/Marlin/ultralcd.h +++ b/Marlin/ultralcd.h @@ -42,6 +42,8 @@ extern int absPreheatHotendTemp; extern int absPreheatHPBTemp; extern int absPreheatFanSpeed; + + extern bool cancel_heatup; void lcd_buzz(long duration,uint16_t freq); bool lcd_clicked();