From 45e43137a52a37ee594fc9693f8b3e28115aa36c Mon Sep 17 00:00:00 2001 From: Alex Voinea Date: Tue, 22 Feb 2022 14:17:26 +0100 Subject: [PATCH] Filament sensor refactoring initial --- Firmware/Filament_sensor.cpp | 3 + Firmware/Filament_sensor.h | 163 +++++++++++++++++++++++++++++++++++ Firmware/Marlin_main.cpp | 115 ++++-------------------- Firmware/menu.cpp | 2 + Firmware/temperature.cpp | 2 + Firmware/ultralcd.cpp | 1 + 6 files changed, 188 insertions(+), 98 deletions(-) create mode 100644 Firmware/Filament_sensor.cpp create mode 100644 Firmware/Filament_sensor.h diff --git a/Firmware/Filament_sensor.cpp b/Firmware/Filament_sensor.cpp new file mode 100644 index 000000000..7f8898d44 --- /dev/null +++ b/Firmware/Filament_sensor.cpp @@ -0,0 +1,3 @@ +#include "Filament_sensor.h" + +IR_sensor_analog fsensor; \ No newline at end of file diff --git a/Firmware/Filament_sensor.h b/Firmware/Filament_sensor.h new file mode 100644 index 000000000..52b75dd4f --- /dev/null +++ b/Firmware/Filament_sensor.h @@ -0,0 +1,163 @@ +#pragma once + +#include +#include +#include + +#include "Marlin.h" +#include "ultralcd.h" +#include "menu.h" +#include "cardreader.h" +#include "temperature.h" +#include "cmdqueue.h" +#include "eeprom.h" +#include "pins.h" +#include "fastio.h" + +class Filament_sensor { +public: + virtual void init() = 0; + virtual void update() = 0; + virtual bool getFilamentPresent() = 0; + + enum class SensorActionOnError : uint8_t { + _Continue = 0, + _Pause = 1, + _Undef = EEPROM_EMPTY_VALUE + }; + + void setAutoLoadEnabled(bool state, bool updateEEPROM = false) { + autoLoadEnabled = state; + if (updateEEPROM) { + eeprom_update_byte((uint8_t *)EEPROM_FSENS_AUTOLOAD_ENABLED, state); + } + } + + void setRunoutEnabled(bool state, bool updateEEPROM = false) { + runoutEnabled = state; + if (updateEEPROM) { + eeprom_update_byte((uint8_t *)EEPROM_FSENSOR, state); + } + } + +protected: + void settings_init() { + autoLoadEnabled = eeprom_read_byte((uint8_t*)EEPROM_FSENS_AUTOLOAD_ENABLED); + runoutEnabled = eeprom_read_byte((uint8_t*)EEPROM_FSENSOR); + sensorActionOnError = (SensorActionOnError)eeprom_read_byte((uint8_t*)EEPROM_FSENSOR_ACTION_NA); + if (sensorActionOnError == SensorActionOnError::_Undef) { + sensorActionOnError = SensorActionOnError::_Pause; + } + } + + void checkFilamentEvents() { + if (!ready) + return; + + bool newFilamentPresent = getFilamentPresent(); + if (oldFilamentPresent != newFilamentPresent) { + oldFilamentPresent = newFilamentPresent; + if (newFilamentPresent) { //filament insertion + puts_P(PSTR("filament inserted")); + triggerFilamentInserted(); + } + else { //filament removal + puts_P(PSTR("filament removed")); + triggerFilamentRemoved(); + } + } + }; + + void triggerFilamentInserted() { + if (autoLoadEnabled/* && (eFilamentAction == FilamentAction::None) */ && !(moves_planned() || IS_SD_PRINTING || usb_timer.running() || (lcd_commands_type == LcdCommands::Layer1Cal) || eeprom_read_byte((uint8_t*)EEPROM_WIZARD_ACTIVE))) { + eFilamentAction = FilamentAction::AutoLoad; + if(target_temperature[0] >= EXTRUDE_MINTEMP){ + bFilamentPreheatState = true; + menu_submenu(mFilamentItemForce); + } else { + menu_submenu(lcd_generic_preheat_menu); + lcd_timeoutToStatus.start(); + } + } + } + + void triggerFilamentRemoved() { + if (runoutEnabled/* && (eFilamentAction == FilamentAction::None) */ && !saved_printing && (moves_planned() || IS_SD_PRINTING || usb_timer.running() || (lcd_commands_type == LcdCommands::Layer1Cal) || eeprom_read_byte((uint8_t*)EEPROM_WIZARD_ACTIVE))) { + runoutEnabled = false; + autoLoadEnabled = false; + stop_and_save_print_to_ram(0, 0); + restore_print_from_ram_and_continue(0); + 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("M600"))); + } + } + + bool autoLoadEnabled; + bool runoutEnabled; + bool oldFilamentPresent; //for creating filament presence switching events. + bool ready; + SensorActionOnError sensorActionOnError; +}; + +class IR_sensor: public Filament_sensor { +public: + void init() { + SET_INPUT(IR_SENSOR_PIN); //input mode + WRITE(IR_SENSOR_PIN, 1); //pullup + settings_init(); + } + + void update() { + if (!ready) { + ready = true; //the IR sensor gets ready instantly as it's just a gpio read operation. + oldFilamentPresent = getFilamentPresent(); //initialize the current filament state so that we don't create a switching event right after the sensor is ready. + } + checkFilamentEvents(); + ;// + } + + bool getFilamentPresent() { + return !READ(IR_SENSOR_PIN); + } + + void settings_init() { + Filament_sensor::settings_init(); + } +protected: +}; + +class IR_sensor_analog: public IR_sensor { +public: + void init() { + IR_sensor::init(); + ;// + } + + void update() { + IR_sensor::update(); + ;// + } + + void voltUpdate(uint16_t raw) { //to be called from the ADC ISR when a cycle is finished + voltRaw = raw; + voltReady = true; + } + + void settings_init() { + IR_sensor::settings_init(); + sensorRevision = (SensorRevision)eeprom_read_byte((uint8_t*)EEPROM_FSENSOR_PCB); + } + + enum class SensorRevision : uint8_t { + _Old = 0, + _Rev04 = 1, + _Undef = EEPROM_EMPTY_VALUE + }; +private: + SensorRevision sensorRevision; + bool voltReady; //this gets set by the adc ISR + uint16_t voltRaw; +}; + +extern IR_sensor_analog fsensor; diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp index f5199ed41..314d62497 100644 --- a/Firmware/Marlin_main.cpp +++ b/Firmware/Marlin_main.cpp @@ -96,6 +96,7 @@ #include "spi.h" #ifdef FILAMENT_SENSOR +#include "Filament_sensor.h" #include "fsensor.h" #ifdef IR_SENSOR #include "pat9125.h" // for pat9125_probe @@ -1365,6 +1366,7 @@ void setup() xflash_err_msg(); #ifdef FILAMENT_SENSOR + fsensor.init(); fsensor_init(); #endif //FILAMENT_SENSOR @@ -3608,6 +3610,10 @@ static void gcode_M600(bool automatic, float x_position, float y_position, float fsensor_check_autoload(); #endif //IR_SENSOR +#ifdef FILAMENT_SENSOR + fsensor.settings_init(); +#endif + lcd_setstatuspgm(MSG_WELCOME); custom_message_type = CustomMsg::Status; } @@ -3616,7 +3622,12 @@ void gcode_M701() { printf_P(PSTR("gcode_M701 begin\n")); - prusa_statistics(22); +#ifdef FILAMENT_SENSOR + fsensor.setRunoutEnabled(false); //suppress filament runouts while loading filament. + fsensor.setAutoLoadEnabled(false); //suppress filament autoloads while loading filament. +#endif + + prusa_statistics(22); if (mmu_enabled) { @@ -3672,6 +3683,10 @@ void gcode_M701() } #endif //FSENSOR_QUALITY } + +#ifdef FILAMENT_SENSOR + fsensor.settings_init(); //restore filament runout state. +#endif } /** * @brief Get serial number from 32U2 processor @@ -9426,105 +9441,9 @@ void manage_inactivity_IR_ANALOG_Check(uint16_t &nFSCheckCount, ClFsensorPCB isV void manage_inactivity(bool ignore_stepper_queue/*=false*/) //default argument set in Marlin.h { #ifdef FILAMENT_SENSOR -bool bInhibitFlag = false; -#ifdef IR_SENSOR_ANALOG -static uint16_t nFSCheckCount=0; + fsensor.update(); #endif // IR_SENSOR_ANALOG - if (mmu_enabled == false) - { -//-// if (mcode_in_progress != 600) //M600 not in progress - if (!printer_active()) bInhibitFlag=(menu_menu==lcd_menu_show_sensors_state); //Block Filament sensor actions if PRINTER is not active and Support::SensorInfo menu active -#ifdef IR_SENSOR_ANALOG - bInhibitFlag=bInhibitFlag||bMenuFSDetect; // Block Filament sensor actions if Settings::HWsetup::FSdetect menu active -#endif // IR_SENSOR_ANALOG - if ((mcode_in_progress != 600) && (eFilamentAction != FilamentAction::AutoLoad) && (!bInhibitFlag) && (menu_menu != lcd_move_e)) //M600 not in progress, preHeat @ autoLoad menu not active - { - if (!moves_planned() && !IS_SD_PRINTING && !usb_timer.running() && (lcd_commands_type != LcdCommands::Layer1Cal) && ! eeprom_read_byte((uint8_t*)EEPROM_WIZARD_ACTIVE)) - { -#ifdef IR_SENSOR_ANALOG - static uint16_t minVolt = Voltage2Raw(6.F), maxVolt = 0; - // detect min-max, some long term sliding window for filtration may be added - // avoiding floating point operations, thus computing in raw - if( current_voltage_raw_IR > maxVolt )maxVolt = current_voltage_raw_IR; - if( current_voltage_raw_IR < minVolt )minVolt = current_voltage_raw_IR; - -#if 0 // Start: IR Sensor debug info - { // debug print - static uint16_t lastVolt = ~0U; - if( current_voltage_raw_IR != lastVolt ){ - printf_P(PSTR("fs volt=%4.2fV (min=%4.2f max=%4.2f)\n"), Raw2Voltage(current_voltage_raw_IR), Raw2Voltage(minVolt), Raw2Voltage(maxVolt) ); - lastVolt = current_voltage_raw_IR; - } - } -#endif // End: IR Sensor debug info - //! The trouble is, I can hold the filament in the hole in such a way, that it creates the exact voltage - //! to be detected as the new fsensor - //! We can either fake it by extending the detection window to a looooong time - //! or do some other countermeasures - - //! what we want to detect: - //! if minvolt gets below ~0.3V, it means there is an old fsensor - //! if maxvolt gets above 4.6V, it means we either have an old fsensor or broken cables/fsensor - //! So I'm waiting for a situation, when minVolt gets to range <0, 1.5> and maxVolt gets into range <3.0, 5> - //! If and only if minVolt is in range <0.3, 1.5> and maxVolt is in range <3.0, 4.6>, I'm considering a situation with the new fsensor - if( minVolt >= IRsensor_Ldiode_TRESHOLD && minVolt <= IRsensor_Lmax_TRESHOLD - && maxVolt >= IRsensor_Hmin_TRESHOLD && maxVolt <= IRsensor_Hopen_TRESHOLD - ){ - manage_inactivity_IR_ANALOG_Check(nFSCheckCount, ClFsensorPCB::_Old, ClFsensorPCB::_Rev04, _i("FS v0.4 or newer") ); ////MSG_FS_V_04_OR_NEWER c=18 - } - //! If and only if minVolt is in range <0.0, 0.3> and maxVolt is in range <4.6, 5.0V>, I'm considering a situation with the old fsensor - //! Note, we are not relying on one voltage here - getting just +5V can mean an old fsensor or a broken new sensor - that's why - //! we need to have both voltages detected correctly to allow switching back to the old fsensor. - else if( minVolt < IRsensor_Ldiode_TRESHOLD - && maxVolt > IRsensor_Hopen_TRESHOLD && maxVolt <= IRsensor_VMax_TRESHOLD - ){ - manage_inactivity_IR_ANALOG_Check(nFSCheckCount, ClFsensorPCB::_Rev04, oFsensorPCB=ClFsensorPCB::_Old, _i("FS v0.3 or older")); ////MSG_FS_V_03_OR_OLDER c=18 - } -#endif // IR_SENSOR_ANALOG - if (fsensor_check_autoload()) - { -#ifdef PAT9125 - fsensor_autoload_check_stop(); -#endif //PAT9125 -//-// if ((int)degHotend0() > extrude_min_temp) -if(0) - { - Sound_MakeCustom(50,1000,false); - loading_flag = true; - enquecommand_front_P((PSTR("M701"))); - } - else - { -/* - lcd_update_enable(false); - show_preheat_nozzle_warning(); - lcd_update_enable(true); -*/ - eFilamentAction=FilamentAction::AutoLoad; - if(target_temperature[0] >= extrude_min_temp){ - bFilamentPreheatState=true; -// mFilamentItem(target_temperature[0],target_temperature_bed); - menu_submenu(mFilamentItemForce); - } else { - menu_submenu(lcd_generic_preheat_menu); - lcd_timeoutToStatus.start(); - } - } - } - } - else - { -#ifdef PAT9125 - fsensor_autoload_check_stop(); -#endif //PAT9125 - if (fsensor_enabled && !saved_printing) - fsensor_update(); - } - } - } -#endif //FILAMENT_SENSOR - #ifdef SAFETYTIMER handleSafetyTimer(); #endif //SAFETYTIMER diff --git a/Firmware/menu.cpp b/Firmware/menu.cpp index b4761304f..dd3c8e84e 100755 --- a/Firmware/menu.cpp +++ b/Firmware/menu.cpp @@ -130,6 +130,8 @@ void menu_back_if_clicked_fb(void) void menu_submenu(menu_func_t submenu) { + if (menu_menu == submenu) + return; //do not enter into the current menu. if (menu_depth < MENU_DEPTH_MAX) { menu_stack[menu_depth].menu = menu_menu; diff --git a/Firmware/temperature.cpp b/Firmware/temperature.cpp index ab4d5d3eb..906c15b0b 100755 --- a/Firmware/temperature.cpp +++ b/Firmware/temperature.cpp @@ -97,6 +97,8 @@ #include "temp_model.h" #endif +#include "Filament_sensor.h" + //=========================================================================== //=============================public variables============================ //=========================================================================== diff --git a/Firmware/ultralcd.cpp b/Firmware/ultralcd.cpp index 18efd1278..908084d0d 100755 --- a/Firmware/ultralcd.cpp +++ b/Firmware/ultralcd.cpp @@ -5186,6 +5186,7 @@ static void mmu_cut_filament_menu() else { eFilamentAction=FilamentAction::MmuCut; + bFilamentFirstRun=false; if(target_temperature[0] >= extrude_min_temp) { bFilamentPreheatState=true;