Explorar o código

Filament sensor refactoring initial

Alex Voinea %!s(int64=3) %!d(string=hai) anos
pai
achega
45e43137a5

+ 3 - 0
Firmware/Filament_sensor.cpp

@@ -0,0 +1,3 @@
+#include "Filament_sensor.h"
+
+IR_sensor_analog fsensor;

+ 163 - 0
Firmware/Filament_sensor.h

@@ -0,0 +1,163 @@
+#pragma once
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <avr/pgmspace.h>
+
+#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;

+ 17 - 98
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

+ 2 - 0
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;

+ 2 - 0
Firmware/temperature.cpp

@@ -97,6 +97,8 @@
 #include "temp_model.h"
 #endif
 
+#include "Filament_sensor.h"
+
 //===========================================================================
 //=============================public variables============================
 //===========================================================================

+ 1 - 0
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;