Merge pull request #1869 from DRracer/fix_mintemp_and_fsensor

Fix MINTEMP errors and fsensor runout
This commit is contained in:
Marek Běl 2019-05-27 16:32:22 +02:00 committed by GitHub
commit 9c3b93f900
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 175 additions and 17 deletions

View File

@ -390,6 +390,13 @@ extern LongTimer safetyTimer;
#define PRINT_PERCENT_DONE_INIT 0xff
#define PRINTER_ACTIVE (IS_SD_PRINTING || is_usb_printing || isPrintPaused || (custom_message_type == CUSTOM_MSG_TYPE_TEMCAL) || saved_printing || (lcd_commands_type == LCD_COMMAND_V2_CAL) || card.paused || mmu_print_saved)
//! Beware - mcode_in_progress is set as soon as the command gets really processed,
//! which is not the same as posting the M600 command into the command queue
//! There can be a considerable lag between posting M600 and its real processing which might result
//! in posting multiple M600's into the command queue
//! Instead, the fsensor uses another state variable :( , which is set to true, when the M600 command is enqued
//! and is reset to false when the fsensor returns into its filament runout finished handler
//! I'd normally change this macro, but who knows what would happen in the MMU :)
#define CHECK_FSENSOR ((IS_SD_PRINTING || is_usb_printing) && (mcode_in_progress != 600) && !saved_printing && e_active())
extern void calculate_extruder_multipliers();

View File

@ -3554,6 +3554,10 @@ void process_commands()
enquecommand_P(PSTR("M24"));
}
#ifdef FILAMENT_SENSOR
else if (code_seen("fsensor_recover_IR")) //! PRUSA fsensor_recover_IR
{
fsensor_restore_print_and_continue_IR();
}
else if (code_seen("fsensor_recover")) //! PRUSA fsensor_recover
{
fsensor_restore_print_and_continue();

View File

@ -57,6 +57,11 @@ bool fsensor_not_responding = false;
bool fsensor_printing_saved = false;
//! enable/disable quality meassurement
bool fsensor_oq_meassure_enabled = false;
//! as explained in the CHECK_FSENSOR macro: this flag is set to true when fsensor posts
//! the M600 into the command queue, which elliminates the hazard of having posted multiple M600's
//! before the first one gets read and started processing.
//! Btw., the IR fsensor could do up to 6 posts before the command queue managed to start processing the first M600 ;)
static bool fsensor_m600_enqueued = false;
//! number of errors, updated in ISR
uint8_t fsensor_err_cnt = 0;
@ -118,11 +123,17 @@ void fsensor_stop_and_save_print(void)
stop_and_save_print_to_ram(0, 0); //XYZE - no change
}
void fsensor_restore_print_and_continue_IR(void)
{
fsensor_watch_runout = true;
fsensor_err_cnt = 0;
fsensor_m600_enqueued = false;
}
void fsensor_restore_print_and_continue(void)
{
printf_P(PSTR("fsensor_restore_print_and_continue\n"));
fsensor_watch_runout = true;
fsensor_err_cnt = 0;
fsensor_restore_print_and_continue_IR();
restore_print_from_ram_and_continue(0); //XYZ = orig, E - no change
}
@ -575,14 +586,15 @@ void fsensor_update(void)
fsensor_oq_meassure_enabled = oq_meassure_enabled_tmp;
}
#else //PAT9125
if ((digitalRead(IR_SENSOR_PIN) == 1) && CHECK_FSENSOR && fsensor_enabled && ir_sensor_detected)
{
fsensor_stop_and_save_print();
printf_P(PSTR("fsensor_update - M600\n"));
eeprom_update_byte((uint8_t*)EEPROM_FERROR_COUNT, eeprom_read_byte((uint8_t*)EEPROM_FERROR_COUNT) + 1);
eeprom_update_word((uint16_t*)EEPROM_FERROR_COUNT_TOT, eeprom_read_word((uint16_t*)EEPROM_FERROR_COUNT_TOT) + 1);
enquecommand_front_P(PSTR("PRUSA fsensor_recover"));
enquecommand_front_P((PSTR("M600")));
if ((digitalRead(IR_SENSOR_PIN) == 1) && CHECK_FSENSOR && fsensor_enabled && ir_sensor_detected && ( ! fsensor_m600_enqueued) )
{ // just plan a simple M600 without any additional position save/restore,
// which caused weird heating issues standing directly over the print
printf_P(PSTR("fsensor_update - M600\n"));
eeprom_update_byte((uint8_t*)EEPROM_FERROR_COUNT, eeprom_read_byte((uint8_t*)EEPROM_FERROR_COUNT) + 1);
eeprom_update_word((uint16_t*)EEPROM_FERROR_COUNT_TOT, eeprom_read_word((uint16_t*)EEPROM_FERROR_COUNT_TOT) + 1);
enquecommand_front_P(PSTR("PRUSA fsensor_recover_IR"));
fsensor_m600_enqueued = true;
enquecommand_front_P((PSTR("M600")));
}
#endif //PAT9125
}

View File

@ -18,6 +18,9 @@ extern bool fsensor_oq_meassure_enabled;
//! @name save restore printing
//! @{
extern void fsensor_stop_and_save_print(void);
//! special handling for the IR sensor (no restore position and heating, since this is already correctly handled in the M600 itself)
extern void fsensor_restore_print_and_continue_IR(void);
//! legacy restore print - restore position and heatup to original temperature - for the MMU and the optical fsensor
extern void fsensor_restore_print_and_continue(void);
//! @}

View File

@ -26,7 +26,7 @@ uint8_t menu_data[MENU_DATA_SIZE];
#endif
uint8_t menu_depth = 0;
uint8_t menu_block_entering_on_serious_errors = SERIOUS_ERR_NONE;
uint8_t menu_line = 0;
uint8_t menu_item = 0;
uint8_t menu_row = 0;

View File

@ -28,6 +28,27 @@ extern uint8_t menu_data[MENU_DATA_SIZE];
extern uint8_t menu_depth;
//! definition of serious errors possibly blocking the main menu
//! Use them as bit mask, so that the code may set various errors at the same time
enum ESeriousErrors {
SERIOUS_ERR_NONE = 0,
SERIOUS_ERR_MINTEMP_HEATER = 0x01,
SERIOUS_ERR_MINTEMP_BED = 0x02
}; // and possibly others in the future.
//! this is a flag for disabling entering the main menu. If this is set
//! to anything != 0, the only the main status screen will be shown on the
//! LCD and the user will be prevented from entering the menu.
//! Now used only to block doing anything with the printer when there is
//! the infamous MINTEMP error (SERIOUS_ERR_MINTEMP).
extern uint8_t menu_block_entering_on_serious_errors;
//! a pair of macros for manipulating the serious errors
//! a c++ class would have been better
#define menu_set_serious_error(x) menu_block_entering_on_serious_errors |= x;
#define menu_unset_serious_error(x) menu_block_entering_on_serious_errors &= ~x;
#define menu_is_serious_error(x) (menu_block_entering_on_serious_errors & x) != 0
extern uint8_t menu_line;
extern uint8_t menu_item;
extern uint8_t menu_row;

View File

@ -1469,6 +1469,15 @@ void disable_heater()
#endif
#endif
}
//! codes of alert messages for the LCD - it is shorter to compare an uin8_t
//! than raw const char * of the messages themselves.
//! Could be used for MAXTEMP situations too - after reaching MAXTEMP and turning off the heater automagically
//! the heater/bed may cool down and a similar alert message like "MAXTERM fixed..." may be displayed.
enum { LCDALERT_NONE = 0, LCDALERT_HEATERMINTEMP, LCDALERT_BEDMINTEMP, LCDALERT_MINTEMPFIXED, LCDALERT_PLEASERESTART };
//! remember the last alert message sent to the LCD
//! to prevent flicker and improve speed
uint8_t last_alert_sent_to_lcd = LCDALERT_NONE;
void max_temp_error(uint8_t e) {
disable_heater();
@ -1502,13 +1511,23 @@ void min_temp_error(uint8_t e) {
#endif
//if (current_temperature_ambient < MINTEMP_MINAMBIENT) return;
disable_heater();
static const char err[] PROGMEM = "Err: MINTEMP";
if(IsStopped() == false) {
SERIAL_ERROR_START;
SERIAL_ERRORLN((int)e);
SERIAL_ERRORLNPGM(": Extruder switched off. MINTEMP triggered !");
LCD_ALERTMESSAGEPGM("Err: MINTEMP");
lcd_setalertstatuspgm(err);
last_alert_sent_to_lcd = LCDALERT_HEATERMINTEMP;
} else if( last_alert_sent_to_lcd != LCDALERT_HEATERMINTEMP ){ // only update, if the lcd message is to be changed (i.e. not the same as last time)
// we are already stopped due to some error, only update the status message without flickering
lcd_updatestatuspgm(err);
last_alert_sent_to_lcd = LCDALERT_HEATERMINTEMP;
}
#ifndef BOGUS_TEMPERATURE_FAILSAFE_OVERRIDE
// if( last_alert_sent_to_lcd != LCDALERT_HEATERMINTEMP ){
// last_alert_sent_to_lcd = LCDALERT_HEATERMINTEMP;
// lcd_print_stop();
// }
Stop();
#endif
if (farm_mode) { prusa_statistics(92); }
@ -1538,10 +1557,16 @@ void bed_min_temp_error(void) {
#if HEATER_BED_PIN > -1
WRITE(HEATER_BED_PIN, 0);
#endif
static const char err[] PROGMEM = "Err: MINTEMP BED";
if(IsStopped() == false) {
SERIAL_ERROR_START;
SERIAL_ERRORLNPGM("Temperature heated bed switched off. MINTEMP triggered !");
LCD_ALERTMESSAGEPGM("Err: MINTEMP BED");
lcd_setalertstatuspgm(err);
last_alert_sent_to_lcd = LCDALERT_BEDMINTEMP;
} else if( last_alert_sent_to_lcd != LCDALERT_BEDMINTEMP ){ // only update, if the lcd message is to be changed (i.e. not the same as last time)
// we are already stopped due to some error, only update the status message without flickering
lcd_updatestatuspgm(err);
last_alert_sent_to_lcd = LCDALERT_BEDMINTEMP;
}
#ifndef BOGUS_TEMPERATURE_FAILSAFE_OVERRIDE
Stop();
@ -2015,6 +2040,58 @@ void check_max_temp()
#endif
}
//! number of repeating the same state with consecutive step() calls
//! used to slow down text switching
struct alert_automaton_mintemp {
private:
enum { ALERT_AUTOMATON_SPEED_DIV = 5 };
enum class States : uint8_t { INIT = 0, TEMP_ABOVE_MINTEMP, SHOW_PLEASE_RESTART, SHOW_MINTEMP };
States state = States::INIT;
uint8_t repeat = ALERT_AUTOMATON_SPEED_DIV;
void substep(States next_state){
if( repeat == 0 ){
state = next_state; // advance to the next state
repeat = ALERT_AUTOMATON_SPEED_DIV; // and prepare repeating for it too
} else {
--repeat;
}
}
public:
//! brief state automaton step routine
//! @param current_temp current hotend/bed temperature (for computing simple hysteresis)
//! @param mintemp minimal temperature including hysteresis to check current_temp against
void step(float current_temp, float mintemp){
static const char m2[] PROGMEM = "MINTEMP fixed";
static const char m1[] PROGMEM = "Please restart";
switch(state){
case States::INIT: // initial state - check hysteresis
if( current_temp > mintemp ){
state = States::TEMP_ABOVE_MINTEMP;
}
// otherwise keep the Err MINTEMP alert message on the display,
// i.e. do not transfer to state 1
break;
case States::TEMP_ABOVE_MINTEMP: // the temperature has risen above the hysteresis check
lcd_setalertstatuspgm(m2);
substep(States::SHOW_MINTEMP);
last_alert_sent_to_lcd = LCDALERT_MINTEMPFIXED;
break;
case States::SHOW_PLEASE_RESTART: // displaying "Please restart"
lcd_updatestatuspgm(m1);
substep(States::SHOW_MINTEMP);
last_alert_sent_to_lcd = LCDALERT_PLEASERESTART;
break;
case States::SHOW_MINTEMP: // displaying "MINTEMP fixed"
lcd_updatestatuspgm(m2);
substep(States::SHOW_PLEASE_RESTART);
last_alert_sent_to_lcd = LCDALERT_MINTEMPFIXED;
break;
}
}
};
static alert_automaton_mintemp alert_automaton_hotend, alert_automaton_bed;
void check_min_temp_heater0()
{
@ -2024,7 +2101,17 @@ void check_min_temp_heater0()
#else
if (current_temperature_raw[0] <= minttemp_raw[0]) {
#endif
menu_set_serious_error(SERIOUS_ERR_MINTEMP_HEATER);
min_temp_error(0);
} else if( menu_is_serious_error(SERIOUS_ERR_MINTEMP_HEATER) ) {
// no recovery, just force the user to restart the printer
// which is a safer variant than just continuing printing
// The automaton also checks for hysteresis - the temperature must have reached a few degrees above the MINTEMP, before
// we shall signalize, that MINTEMP has been fixed
// Code notice: normally the alert_automaton instance would have been placed here
// as static alert_automaton_mintemp alert_automaton_hotend, but
// due to stupid compiler that takes 16 more bytes.
alert_automaton_hotend.step(current_temperature[0], minttemp[0] + TEMP_HYSTERESIS);
}
}
@ -2035,7 +2122,12 @@ void check_min_temp_bed()
#else
if (current_temperature_bed_raw <= bed_minttemp_raw) {
#endif
menu_set_serious_error(SERIOUS_ERR_MINTEMP_BED);
bed_min_temp_error();
} else if( menu_is_serious_error(SERIOUS_ERR_MINTEMP_BED) ){
// no recovery, just force the user to restart the printer
// which is a safer variant than just continuing printing
alert_automaton_bed.step(current_temperature_bed, BED_MINTEMP + TEMP_HYSTERESIS);
}
}

View File

@ -252,6 +252,7 @@ static void lcd_send_status();
static void lcd_connect_printer();
#endif //FARM_CONNECT_MESSAGE
//! Beware: has side effects - forces lcd_draw_update to 2, which means clear the display
void lcd_finishstatus();
static void lcd_sdcard_menu();
@ -1018,7 +1019,10 @@ static void lcd_status_screen()
}
}
if (current_click && (lcd_commands_type != LCD_COMMAND_STOP_PRINT)) //click is aborted unless stop print finishes
if (current_click
&& (lcd_commands_type != LCD_COMMAND_STOP_PRINT) //click is aborted unless stop print finishes
&& ( menu_block_entering_on_serious_errors == SERIOUS_ERR_NONE ) // or a serious error blocks entering the menu
)
{
menu_depth = 0; //redundant, as already done in lcd_return_to_status(), just to be sure
menu_submenu(lcd_main_menu);
@ -8276,13 +8280,19 @@ void lcd_setstatus(const char* message)
strncpy(lcd_status_message, message, LCD_WIDTH);
lcd_finishstatus();
}
void lcd_updatestatuspgm(const char *message){
strncpy_P(lcd_status_message, message, LCD_WIDTH);
lcd_status_message[LCD_WIDTH] = 0;
lcd_finishstatus();
// hack lcd_draw_update to 1, i.e. without clear
lcd_draw_update = 1;
}
void lcd_setstatuspgm(const char* message)
{
if (lcd_status_message_level > 0)
return;
strncpy_P(lcd_status_message, message, LCD_WIDTH);
lcd_status_message[LCD_WIDTH] = 0;
lcd_finishstatus();
lcd_updatestatuspgm(message);
}
void lcd_setalertstatuspgm(const char* message)
{

View File

@ -18,7 +18,16 @@ extern void menu_lcd_lcdupdate_func(void);
void ultralcd_init();
void lcd_setstatus(const char* message);
void lcd_setstatuspgm(const char* message);
//! return to the main status screen and display the alert message
//! Beware - it has sideeffects:
//! - always returns the display to the main status screen
//! - always makes lcd_reset (which is slow and causes flicker)
//! - does not update the message if there is already one (i.e. lcd_status_message_level > 0)
void lcd_setalertstatuspgm(const char* message);
//! only update the alert message on the main status screen
//! has no sideeffects, may be called multiple times
void lcd_updatestatuspgm(const char *message);
void lcd_reset_alert_level();
uint8_t get_message_level();
void lcd_adjust_z();